Merge unstable
20230925 into deneb-free-blobs
.
This commit is contained in:
commit
c0b6b92f27
6
.github/workflows/docker.yml
vendored
6
.github/workflows/docker.yml
vendored
@ -57,7 +57,7 @@ jobs:
|
||||
build-docker-single-arch:
|
||||
name: build-docker-${{ matrix.binary }}${{ matrix.features.version_suffix }}
|
||||
# Use self-hosted runners only on the sigp repo.
|
||||
runs-on: ${{ github.repository == 'sigp/lighthouse' && fromJson('["self-hosted", "linux", "large"]') || 'ubuntu-22.04' }}
|
||||
runs-on: ${{ github.repository == 'sigp/lighthouse' && fromJson('["self-hosted", "linux", "release"]') || 'ubuntu-22.04' }}
|
||||
strategy:
|
||||
matrix:
|
||||
binary: [aarch64,
|
||||
@ -79,7 +79,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Update Rust
|
||||
if: env.SELF_HOSTED_RUNNERS == false
|
||||
if: env.SELF_HOSTED_RUNNERS == 'false'
|
||||
run: rustup update stable
|
||||
- name: Dockerhub login
|
||||
run: |
|
||||
@ -107,9 +107,11 @@ jobs:
|
||||
run: echo "MODERNITY_SUFFIX=-modern" >> $GITHUB_ENV;
|
||||
|
||||
- name: Install QEMU
|
||||
if: env.SELF_HOSTED_RUNNERS == 'false'
|
||||
run: sudo apt-get update && sudo apt-get install -y qemu-user-static
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
if: env.SELF_HOSTED_RUNNERS == 'false'
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Build and push
|
||||
|
23
.github/workflows/release.yml
vendored
23
.github/workflows/release.yml
vendored
@ -14,6 +14,8 @@ env:
|
||||
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
|
||||
REPO_NAME: ${{ github.repository_owner }}/lighthouse
|
||||
IMAGE_NAME: ${{ github.repository_owner }}/lighthouse
|
||||
# Enable self-hosted runners for the sigp repo only.
|
||||
SELF_HOSTED_RUNNERS: ${{ github.repository == 'sigp/lighthouse' }}
|
||||
|
||||
jobs:
|
||||
extract-version:
|
||||
@ -38,36 +40,37 @@ jobs:
|
||||
x86_64-windows-portable]
|
||||
include:
|
||||
- arch: aarch64-unknown-linux-gnu
|
||||
platform: ubuntu-latest
|
||||
runner: ${{ github.repository == 'sigp/lighthouse' && fromJson('["self-hosted", "linux", "release", "large"]') || 'ubuntu-latest' }}
|
||||
profile: maxperf
|
||||
- arch: aarch64-unknown-linux-gnu-portable
|
||||
platform: ubuntu-latest
|
||||
runner: ${{ github.repository == 'sigp/lighthouse' && fromJson('["self-hosted", "linux", "release", "large"]') || 'ubuntu-latest' }}
|
||||
profile: maxperf
|
||||
- arch: x86_64-unknown-linux-gnu
|
||||
platform: ubuntu-latest
|
||||
runner: ${{ github.repository == 'sigp/lighthouse' && fromJson('["self-hosted", "linux", "release", "large"]') || 'ubuntu-latest' }}
|
||||
profile: maxperf
|
||||
- arch: x86_64-unknown-linux-gnu-portable
|
||||
platform: ubuntu-latest
|
||||
runner: ${{ github.repository == 'sigp/lighthouse' && fromJson('["self-hosted", "linux", "release", "large"]') || 'ubuntu-latest' }}
|
||||
profile: maxperf
|
||||
- arch: x86_64-apple-darwin
|
||||
platform: macos-latest
|
||||
runner: macos-latest
|
||||
profile: maxperf
|
||||
- arch: x86_64-apple-darwin-portable
|
||||
platform: macos-latest
|
||||
runner: macos-latest
|
||||
profile: maxperf
|
||||
- arch: x86_64-windows
|
||||
platform: windows-2019
|
||||
runner: ${{ github.repository == 'sigp/lighthouse' && fromJson('["self-hosted", "windows", "release"]') || 'windows-2019' }}
|
||||
profile: maxperf
|
||||
- arch: x86_64-windows-portable
|
||||
platform: windows-2019
|
||||
runner: ${{ github.repository == 'sigp/lighthouse' && fromJson('["self-hosted", "windows", "release"]') || 'windows-2019' }}
|
||||
profile: maxperf
|
||||
|
||||
runs-on: ${{ matrix.platform }}
|
||||
runs-on: ${{ matrix.runner }}
|
||||
needs: extract-version
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v3
|
||||
- name: Get latest version of stable Rust
|
||||
if: env.SELF_HOSTED_RUNNERS == 'false'
|
||||
run: rustup update stable
|
||||
|
||||
# ==============================
|
||||
@ -75,7 +78,7 @@ jobs:
|
||||
# ==============================
|
||||
|
||||
- uses: KyleMayes/install-llvm-action@v1
|
||||
if: startsWith(matrix.arch, 'x86_64-windows')
|
||||
if: env.SELF_HOSTED_RUNNERS == 'false' && startsWith(matrix.arch, 'x86_64-windows')
|
||||
with:
|
||||
version: "15.0"
|
||||
directory: ${{ runner.temp }}/llvm
|
||||
|
10
.github/workflows/test-suite.yml
vendored
10
.github/workflows/test-suite.yml
vendored
@ -58,7 +58,7 @@ jobs:
|
||||
release-tests-ubuntu:
|
||||
name: release-tests-ubuntu
|
||||
# Use self-hosted runners only on the sigp repo.
|
||||
runs-on: ${{ github.repository == 'sigp/lighthouse' && fromJson('["self-hosted", "linux", "large"]') || 'ubuntu-latest' }}
|
||||
runs-on: ${{ github.repository == 'sigp/lighthouse' && fromJson('["self-hosted", "linux", "CI", "large"]') || 'ubuntu-latest' }}
|
||||
needs: cargo-fmt
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
@ -73,7 +73,7 @@ jobs:
|
||||
run: make test-release
|
||||
release-tests-windows:
|
||||
name: release-tests-windows
|
||||
runs-on: ${{ github.repository == 'sigp/lighthouse' && fromJson('["self-hosted", "windows"]') || 'windows-2019' }}
|
||||
runs-on: ${{ github.repository == 'sigp/lighthouse' && fromJson('["self-hosted", "windows", "CI"]') || 'windows-2019' }}
|
||||
needs: cargo-fmt
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
@ -98,7 +98,7 @@ jobs:
|
||||
beacon-chain-tests:
|
||||
name: beacon-chain-tests
|
||||
# Use self-hosted runners only on the sigp repo.
|
||||
runs-on: ${{ github.repository == 'sigp/lighthouse' && fromJson('["self-hosted", "linux", "large"]') || 'ubuntu-latest' }}
|
||||
runs-on: ${{ github.repository == 'sigp/lighthouse' && fromJson('["self-hosted", "linux", "CI", "large"]') || 'ubuntu-latest' }}
|
||||
needs: cargo-fmt
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
@ -140,7 +140,7 @@ jobs:
|
||||
debug-tests-ubuntu:
|
||||
name: debug-tests-ubuntu
|
||||
# Use self-hosted runners only on the sigp repo.
|
||||
runs-on: ${{ github.repository == 'sigp/lighthouse' && fromJson('["self-hosted", "linux", "large"]') || 'ubuntu-latest' }}
|
||||
runs-on: ${{ github.repository == 'sigp/lighthouse' && fromJson('["self-hosted", "linux", "CI", "large"]') || 'ubuntu-latest' }}
|
||||
needs: cargo-fmt
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
@ -166,7 +166,7 @@ jobs:
|
||||
ef-tests-ubuntu:
|
||||
name: ef-tests-ubuntu
|
||||
# Use self-hosted runners only on the sigp repo.
|
||||
runs-on: ${{ github.repository == 'sigp/lighthouse' && fromJson('["self-hosted", "linux", "small"]') || 'ubuntu-latest' }}
|
||||
runs-on: ${{ github.repository == 'sigp/lighthouse' && fromJson('["self-hosted", "linux", "CI", "small"]') || 'ubuntu-latest' }}
|
||||
needs: cargo-fmt
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
1067
Cargo.lock
generated
1067
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
137
Cargo.toml
137
Cargo.toml
@ -90,10 +90,139 @@ members = [
|
||||
]
|
||||
resolver = "2"
|
||||
|
||||
[patch]
|
||||
[patch.crates-io]
|
||||
# TODO: remove when 0.3.6 get's released.
|
||||
warp = { git = "https://github.com/seanmonstar/warp.git", rev="149913fe" }
|
||||
[workspace.package]
|
||||
edition = "2021"
|
||||
|
||||
[workspace.dependencies]
|
||||
arbitrary = { version = "1", features = ["derive"] }
|
||||
bincode = "1"
|
||||
bitvec = "1"
|
||||
byteorder = "1"
|
||||
bytes = "1"
|
||||
clap = "2"
|
||||
compare_fields_derive = { path = "common/compare_fields_derive" }
|
||||
criterion = "0.3"
|
||||
delay_map = "0.3"
|
||||
derivative = "2"
|
||||
dirs = "3"
|
||||
discv5 = { version = "0.3", features = ["libp2p"] }
|
||||
env_logger = "0.9"
|
||||
error-chain = "0.12"
|
||||
ethereum-types = "0.14"
|
||||
ethereum_hashing = "1.0.0-beta.2"
|
||||
ethereum_serde_utils = "0.5"
|
||||
ethereum_ssz = "0.5"
|
||||
ethereum_ssz_derive = "0.5"
|
||||
ethers-core = "1"
|
||||
ethers-providers = { version = "1", default-features = false }
|
||||
exit-future = "0.2"
|
||||
fnv = "1"
|
||||
fs2 = "0.4"
|
||||
futures = "0.3"
|
||||
hex = "0.4"
|
||||
hyper = "0.14"
|
||||
itertools = "0.10"
|
||||
lazy_static = "1"
|
||||
libsecp256k1 = "0.7"
|
||||
log = "0.4"
|
||||
lru = "0.7"
|
||||
maplit = "1"
|
||||
num_cpus = "1"
|
||||
parking_lot = "0.12"
|
||||
paste = "1"
|
||||
quickcheck = "1"
|
||||
quickcheck_macros = "1"
|
||||
quote = "1"
|
||||
r2d2 = "0.8"
|
||||
rand = "0.8"
|
||||
rayon = "1.7"
|
||||
regex = "1"
|
||||
reqwest = { version = "0.11", default-features = false, features = ["blocking", "json", "stream", "rustls-tls"] }
|
||||
ring = "0.16"
|
||||
rusqlite = { version = "0.28", features = ["bundled"] }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
serde_repr = "0.1"
|
||||
serde_yaml = "0.8"
|
||||
sha2 = "0.9"
|
||||
slog = { version = "2", features = ["max_level_trace", "release_max_level_trace", "nested-values"] }
|
||||
slog-async = "2"
|
||||
slog-term = "2"
|
||||
sloggers = { version = "2", features = ["json"] }
|
||||
smallvec = "1"
|
||||
snap = "1"
|
||||
ssz_types = "0.5"
|
||||
strum = { version = "0.24", features = ["derive"] }
|
||||
superstruct = "0.6"
|
||||
syn = "1"
|
||||
sysinfo = "0.26"
|
||||
tempfile = "3"
|
||||
tokio = { version = "1", features = ["rt-multi-thread", "sync"] }
|
||||
tokio-stream = { version = "0.1", features = ["sync"] }
|
||||
tokio-util = { version = "0.6", features = ["codec", "compat", "time"] }
|
||||
tree_hash = "0.5"
|
||||
tree_hash_derive = "0.5"
|
||||
url = "2"
|
||||
uuid = { version = "0.8", features = ["serde", "v4"] }
|
||||
# TODO update to warp 0.3.6 after released.
|
||||
warp = { git = "https://github.com/seanmonstar/warp.git", default-features = false, features = ["tls"] }
|
||||
zeroize = { version = "1", features = ["zeroize_derive"] }
|
||||
zip = "0.6"
|
||||
|
||||
# Local crates.
|
||||
account_utils = { path = "common/account_utils" }
|
||||
beacon_chain = { path = "beacon_node/beacon_chain" }
|
||||
beacon_node = { path = "beacon_node" }
|
||||
beacon_processor = { path = "beacon_node/beacon_processor" }
|
||||
bls = { path = "crypto/bls" }
|
||||
cached_tree_hash = { path = "consensus/cached_tree_hash" }
|
||||
clap_utils = { path = "common/clap_utils" }
|
||||
compare_fields = { path = "common/compare_fields" }
|
||||
deposit_contract = { path = "common/deposit_contract" }
|
||||
directory = { path = "common/directory" }
|
||||
environment = { path = "lighthouse/environment" }
|
||||
eth1 = { path = "beacon_node/eth1" }
|
||||
eth1_test_rig = { path = "testing/eth1_test_rig" }
|
||||
eth2 = { path = "common/eth2" }
|
||||
eth2_config = { path = "common/eth2_config" }
|
||||
eth2_key_derivation = { path = "crypto/eth2_key_derivation" }
|
||||
eth2_keystore = { path = "crypto/eth2_keystore" }
|
||||
eth2_network_config = { path = "common/eth2_network_config" }
|
||||
eth2_wallet = { path = "crypto/eth2_wallet" }
|
||||
execution_layer = { path = "beacon_node/execution_layer" }
|
||||
filesystem = { path = "common/filesystem" }
|
||||
fork_choice = { path = "consensus/fork_choice" }
|
||||
genesis = { path = "beacon_node/genesis" }
|
||||
http_api = { path = "beacon_node/http_api" }
|
||||
int_to_bytes = { path = "consensus/int_to_bytes" }
|
||||
kzg = { path = "crypto/kzg" }
|
||||
lighthouse_metrics = { path = "common/lighthouse_metrics" }
|
||||
lighthouse_network = { path = "beacon_node/lighthouse_network" }
|
||||
lighthouse_version = { path = "common/lighthouse_version" }
|
||||
lockfile = { path = "common/lockfile" }
|
||||
logging = { path = "common/logging" }
|
||||
lru_cache = { path = "common/lru_cache" }
|
||||
malloc_utils = { path = "common/malloc_utils" }
|
||||
merkle_proof = { path = "consensus/merkle_proof" }
|
||||
monitoring_api = { path = "common/monitoring_api" }
|
||||
network = { path = "beacon_node/network" }
|
||||
operation_pool = { path = "beacon_node/operation_pool" }
|
||||
pretty_reqwest_error = { path = "common/pretty_reqwest_error" }
|
||||
proto_array = { path = "consensus/proto_array" }
|
||||
safe_arith = {path = "consensus/safe_arith"}
|
||||
sensitive_url = { path = "common/sensitive_url" }
|
||||
slasher = { path = "slasher" }
|
||||
slashing_protection = { path = "validator_client/slashing_protection" }
|
||||
slot_clock = { path = "common/slot_clock" }
|
||||
state_processing = { path = "consensus/state_processing" }
|
||||
store = { path = "beacon_node/store" }
|
||||
swap_or_not_shuffle = { path = "consensus/swap_or_not_shuffle" }
|
||||
task_executor = { path = "common/task_executor" }
|
||||
types = { path = "consensus/types" }
|
||||
unused_port = { path = "common/unused_port" }
|
||||
validator_client = { path = "validator_client/" }
|
||||
validator_dir = { path = "common/validator_dir" }
|
||||
warp_utils = { path = "common/warp_utils" }
|
||||
|
||||
[profile.maxperf]
|
||||
inherits = "release"
|
||||
|
@ -1,4 +1,4 @@
|
||||
FROM rust:1.68.2-bullseye AS builder
|
||||
FROM rust:1.69.0-bullseye AS builder
|
||||
RUN apt-get update && apt-get -y upgrade && apt-get install -y cmake libclang-dev
|
||||
COPY . lighthouse
|
||||
ARG FEATURES
|
||||
|
2
Makefile
2
Makefile
@ -215,7 +215,7 @@ arbitrary-fuzz:
|
||||
# Runs cargo audit (Audit Cargo.lock files for crates with security vulnerabilities reported to the RustSec Advisory Database)
|
||||
audit:
|
||||
cargo install --force cargo-audit
|
||||
cargo audit --ignore RUSTSEC-2023-0052
|
||||
cargo audit
|
||||
|
||||
# Runs `cargo vendor` to make sure dependencies can be vendored for packaging, reproducibility and archival purpose.
|
||||
vendor:
|
||||
|
@ -5,31 +5,31 @@ authors = [
|
||||
"Paul Hauner <paul@paulhauner.com>",
|
||||
"Luke Anderson <luke@sigmaprime.io>",
|
||||
]
|
||||
edition = "2021"
|
||||
edition = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
bls = { path = "../crypto/bls" }
|
||||
clap = "2.33.3"
|
||||
types = { path = "../consensus/types" }
|
||||
environment = { path = "../lighthouse/environment" }
|
||||
eth2_network_config = { path = "../common/eth2_network_config" }
|
||||
clap_utils = { path = "../common/clap_utils" }
|
||||
directory = { path = "../common/directory" }
|
||||
eth2_wallet = { path = "../crypto/eth2_wallet" }
|
||||
bls = { workspace = true }
|
||||
clap = { workspace = true }
|
||||
types = { workspace = true }
|
||||
environment = { workspace = true }
|
||||
eth2_network_config = { workspace = true }
|
||||
clap_utils = { workspace = true }
|
||||
directory = { workspace = true }
|
||||
eth2_wallet = { workspace = true }
|
||||
eth2_wallet_manager = { path = "../common/eth2_wallet_manager" }
|
||||
validator_dir = { path = "../common/validator_dir" }
|
||||
tokio = { version = "1.14.0", features = ["full"] }
|
||||
eth2_keystore = { path = "../crypto/eth2_keystore" }
|
||||
account_utils = { path = "../common/account_utils" }
|
||||
slashing_protection = { path = "../validator_client/slashing_protection" }
|
||||
eth2 = { path = "../common/eth2" }
|
||||
safe_arith = { path = "../consensus/safe_arith" }
|
||||
slot_clock = { path = "../common/slot_clock" }
|
||||
filesystem = { path = "../common/filesystem" }
|
||||
sensitive_url = { path = "../common/sensitive_url" }
|
||||
serde = { version = "1.0.116", features = ["derive"] }
|
||||
serde_json = "1.0.58"
|
||||
slog = { version = "2.5.2" }
|
||||
validator_dir = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
eth2_keystore = { workspace = true }
|
||||
account_utils = { workspace = true }
|
||||
slashing_protection = { workspace = true }
|
||||
eth2 = { workspace = true }
|
||||
safe_arith = { workspace = true }
|
||||
slot_clock = { workspace = true }
|
||||
filesystem = { workspace = true }
|
||||
sensitive_url = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
slog = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3.1.0"
|
||||
tempfile = { workspace = true }
|
||||
|
@ -10,7 +10,6 @@ use eth2_keystore::Keystore;
|
||||
use eth2_network_config::Eth2NetworkConfig;
|
||||
use safe_arith::SafeArith;
|
||||
use sensitive_url::SensitiveUrl;
|
||||
use slog::Logger;
|
||||
use slot_clock::{SlotClock, SystemTimeSlotClock};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::time::Duration;
|
||||
@ -79,12 +78,6 @@ pub fn cli_run<E: EthSpec>(matches: &ArgMatches, env: Environment<E>) -> Result<
|
||||
let password_file_path: Option<PathBuf> =
|
||||
clap_utils::parse_optional(matches, PASSWORD_FILE_FLAG)?;
|
||||
|
||||
let genesis_state_url: Option<String> =
|
||||
clap_utils::parse_optional(matches, "genesis-state-url")?;
|
||||
let genesis_state_url_timeout =
|
||||
clap_utils::parse_required(matches, "genesis-state-url-timeout")
|
||||
.map(Duration::from_secs)?;
|
||||
|
||||
let stdin_inputs = cfg!(windows) || matches.is_present(STDIN_INPUTS_FLAG);
|
||||
let no_wait = matches.is_present(NO_WAIT);
|
||||
let no_confirmation = matches.is_present(NO_CONFIRMATION);
|
||||
@ -111,9 +104,6 @@ pub fn cli_run<E: EthSpec>(matches: &ArgMatches, env: Environment<E>) -> Result<
|
||||
ð2_network_config,
|
||||
no_wait,
|
||||
no_confirmation,
|
||||
genesis_state_url,
|
||||
genesis_state_url_timeout,
|
||||
env.core_context().log(),
|
||||
))?;
|
||||
|
||||
Ok(())
|
||||
@ -130,13 +120,10 @@ async fn publish_voluntary_exit<E: EthSpec>(
|
||||
eth2_network_config: &Eth2NetworkConfig,
|
||||
no_wait: bool,
|
||||
no_confirmation: bool,
|
||||
genesis_state_url: Option<String>,
|
||||
genesis_state_url_timeout: Duration,
|
||||
log: &Logger,
|
||||
) -> Result<(), String> {
|
||||
let genesis_data = get_geneisis_data(client).await?;
|
||||
let testnet_genesis_root = eth2_network_config
|
||||
.genesis_validators_root::<E>(genesis_state_url.as_deref(), genesis_state_url_timeout, log)?
|
||||
.genesis_validators_root::<E>()?
|
||||
.ok_or("Genesis state is unknown")?;
|
||||
|
||||
// Verify that the beacon node and validator being exited are on the same network.
|
||||
|
@ -7,7 +7,6 @@ use slashing_protection::{
|
||||
use std::fs::File;
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
use std::time::Duration;
|
||||
use types::{Epoch, EthSpec, PublicKeyBytes, Slot};
|
||||
|
||||
pub const CMD: &str = "slashing-protection";
|
||||
@ -82,24 +81,12 @@ pub fn cli_run<T: EthSpec>(
|
||||
validator_base_dir: PathBuf,
|
||||
) -> Result<(), String> {
|
||||
let slashing_protection_db_path = validator_base_dir.join(SLASHING_PROTECTION_FILENAME);
|
||||
|
||||
let genesis_state_url: Option<String> =
|
||||
clap_utils::parse_optional(matches, "genesis-state-url")?;
|
||||
let genesis_state_url_timeout =
|
||||
clap_utils::parse_required(matches, "genesis-state-url-timeout")
|
||||
.map(Duration::from_secs)?;
|
||||
|
||||
let context = env.core_context();
|
||||
let eth2_network_config = env
|
||||
.eth2_network_config
|
||||
.ok_or("Unable to get testnet configuration from the environment")?;
|
||||
|
||||
let genesis_validators_root = eth2_network_config
|
||||
.genesis_validators_root::<T>(
|
||||
genesis_state_url.as_deref(),
|
||||
genesis_state_url_timeout,
|
||||
context.log(),
|
||||
)?
|
||||
.genesis_validators_root::<T>()?
|
||||
.ok_or_else(|| "Unable to get genesis state, has genesis occurred?".to_string())?;
|
||||
|
||||
match matches.subcommand() {
|
||||
|
@ -1,11 +1,11 @@
|
||||
[package]
|
||||
name = "beacon_node"
|
||||
version = "4.4.1"
|
||||
version = "4.5.0"
|
||||
authors = [
|
||||
"Paul Hauner <paul@paulhauner.com>",
|
||||
"Age Manning <Age@AgeManning.com",
|
||||
]
|
||||
edition = "2021"
|
||||
edition = { workspace = true }
|
||||
|
||||
[lib]
|
||||
name = "beacon_node"
|
||||
@ -20,34 +20,31 @@ write_ssz_files = [
|
||||
] # Writes debugging .ssz files to /tmp during block processing.
|
||||
|
||||
[dependencies]
|
||||
eth2_config = { path = "../common/eth2_config" }
|
||||
beacon_chain = { path = "beacon_chain" }
|
||||
types = { path = "../consensus/types" }
|
||||
store = { path = "./store" }
|
||||
eth2_config = { workspace = true }
|
||||
beacon_chain = { workspace = true }
|
||||
types = { workspace = true }
|
||||
store = { workspace = true }
|
||||
client = { path = "client" }
|
||||
clap = "2.33.3"
|
||||
slog = { version = "2.5.2", features = [
|
||||
"max_level_trace",
|
||||
"release_max_level_trace",
|
||||
] }
|
||||
dirs = "3.0.1"
|
||||
directory = { path = "../common/directory" }
|
||||
futures = "0.3.7"
|
||||
environment = { path = "../lighthouse/environment" }
|
||||
task_executor = { path = "../common/task_executor" }
|
||||
genesis = { path = "genesis" }
|
||||
eth2_network_config = { path = "../common/eth2_network_config" }
|
||||
execution_layer = { path = "execution_layer" }
|
||||
lighthouse_network = { path = "./lighthouse_network" }
|
||||
serde = "1.0.116"
|
||||
serde_json = "1.0.58"
|
||||
clap_utils = { path = "../common/clap_utils" }
|
||||
hyper = "0.14.4"
|
||||
lighthouse_version = { path = "../common/lighthouse_version" }
|
||||
hex = "0.4.2"
|
||||
slasher = { path = "../slasher" }
|
||||
monitoring_api = { path = "../common/monitoring_api" }
|
||||
sensitive_url = { path = "../common/sensitive_url" }
|
||||
http_api = { path = "http_api" }
|
||||
unused_port = { path = "../common/unused_port" }
|
||||
strum = "0.24.1"
|
||||
clap = { workspace = true }
|
||||
slog = { workspace = true }
|
||||
dirs = { workspace = true }
|
||||
directory = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
environment = { workspace = true }
|
||||
task_executor = { workspace = true }
|
||||
genesis = { workspace = true }
|
||||
eth2_network_config = { workspace = true }
|
||||
execution_layer = { workspace = true }
|
||||
lighthouse_network = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
clap_utils = { workspace = true }
|
||||
hyper = { workspace = true }
|
||||
lighthouse_version = { workspace = true }
|
||||
hex = { workspace = true }
|
||||
slasher = { workspace = true }
|
||||
monitoring_api = { workspace = true }
|
||||
sensitive_url = { workspace = true }
|
||||
http_api = { workspace = true }
|
||||
unused_port = { workspace = true }
|
||||
strum = { workspace = true }
|
||||
|
@ -2,7 +2,7 @@
|
||||
name = "beacon_chain"
|
||||
version = "0.2.0"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>", "Age Manning <Age@AgeManning.com>"]
|
||||
edition = "2021"
|
||||
edition = { workspace = true }
|
||||
autotests = false # using a single test binary compiles faster
|
||||
|
||||
[features]
|
||||
@ -12,66 +12,64 @@ participation_metrics = [] # Exposes validator participation metrics to Prometh
|
||||
fork_from_env = [] # Initialise the harness chain spec from the FORK_NAME env variable
|
||||
|
||||
[dev-dependencies]
|
||||
maplit = "1.0.2"
|
||||
environment = { path = "../../lighthouse/environment" }
|
||||
serde_json = "1.0.58"
|
||||
maplit = { workspace = true }
|
||||
environment = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
serde_json = "1.0.58"
|
||||
eth2_network_config = { path = "../../common/eth2_network_config"}
|
||||
merkle_proof = { path = "../../consensus/merkle_proof" }
|
||||
store = { path = "../store" }
|
||||
parking_lot = "0.12.0"
|
||||
lazy_static = "1.4.0"
|
||||
smallvec = "1.6.1"
|
||||
lighthouse_metrics = { path = "../../common/lighthouse_metrics" }
|
||||
operation_pool = { path = "../operation_pool" }
|
||||
rayon = "1.4.1"
|
||||
serde = "1.0.116"
|
||||
serde_derive = "1.0.116"
|
||||
ethereum_serde_utils = "0.5.0"
|
||||
slog = { version = "2.5.2", features = ["max_level_trace"] }
|
||||
sloggers = { version = "2.1.1", features = ["json"] }
|
||||
slot_clock = { path = "../../common/slot_clock" }
|
||||
ethereum_hashing = "1.0.0-beta.2"
|
||||
ethereum_ssz = "0.5.0"
|
||||
ssz_types = "0.5.4"
|
||||
ethereum_ssz_derive = "0.5.3"
|
||||
state_processing = { path = "../../consensus/state_processing" }
|
||||
tree_hash_derive = "0.5.0"
|
||||
tree_hash = "0.5.2"
|
||||
types = { path = "../../consensus/types" }
|
||||
tokio = "1.14.0"
|
||||
tokio-stream = "0.1.3"
|
||||
eth1 = { path = "../eth1" }
|
||||
futures = "0.3.7"
|
||||
genesis = { path = "../genesis" }
|
||||
int_to_bytes = { path = "../../consensus/int_to_bytes" }
|
||||
rand = "0.8.5"
|
||||
proto_array = { path = "../../consensus/proto_array" }
|
||||
lru = "0.7.1"
|
||||
tempfile = "3.1.0"
|
||||
bitvec = "0.20.4"
|
||||
bls = { path = "../../crypto/bls" }
|
||||
kzg = { path = "../../crypto/kzg" }
|
||||
safe_arith = { path = "../../consensus/safe_arith" }
|
||||
fork_choice = { path = "../../consensus/fork_choice" }
|
||||
task_executor = { path = "../../common/task_executor" }
|
||||
derivative = "2.1.1"
|
||||
itertools = "0.10.0"
|
||||
slasher = { path = "../../slasher" }
|
||||
eth2 = { path = "../../common/eth2" }
|
||||
strum = { version = "0.24.0", features = ["derive"] }
|
||||
logging = { path = "../../common/logging" }
|
||||
execution_layer = { path = "../execution_layer" }
|
||||
sensitive_url = { path = "../../common/sensitive_url" }
|
||||
superstruct = "0.5.0"
|
||||
hex = "0.4.2"
|
||||
exit-future = "0.2.0"
|
||||
unused_port = {path = "../../common/unused_port"}
|
||||
oneshot_broadcast = { path = "../../common/oneshot_broadcast" }
|
||||
slog-term = "2.6.0"
|
||||
slog-async = "2.5.0"
|
||||
serde_json = { workspace = true }
|
||||
eth2_network_config = { workspace = true }
|
||||
merkle_proof = { workspace = true }
|
||||
store = { workspace = true }
|
||||
parking_lot = { workspace = true }
|
||||
lazy_static = { workspace = true }
|
||||
smallvec = { workspace = true }
|
||||
lighthouse_metrics = { workspace = true }
|
||||
operation_pool = { workspace = true }
|
||||
rayon = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
ethereum_serde_utils = { workspace = true }
|
||||
slog = { workspace = true }
|
||||
sloggers = { workspace = true }
|
||||
slot_clock = { workspace = true }
|
||||
ethereum_hashing = { workspace = true }
|
||||
ethereum_ssz = { workspace = true }
|
||||
ssz_types = { workspace = true }
|
||||
ethereum_ssz_derive = { workspace = true }
|
||||
state_processing = { workspace = true }
|
||||
tree_hash_derive = { workspace = true }
|
||||
tree_hash = { workspace = true }
|
||||
types = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
tokio-stream = { workspace = true }
|
||||
eth1 = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
genesis = { workspace = true }
|
||||
int_to_bytes = { workspace = true }
|
||||
rand = { workspace = true }
|
||||
proto_array = { workspace = true }
|
||||
lru = { workspace = true }
|
||||
tempfile = { workspace = true }
|
||||
bitvec = { workspace = true }
|
||||
bls = { workspace = true }
|
||||
kzg = { workspace = true }
|
||||
safe_arith = { workspace = true }
|
||||
fork_choice = { workspace = true }
|
||||
task_executor = { workspace = true }
|
||||
derivative = { workspace = true }
|
||||
itertools = { workspace = true }
|
||||
slasher = { workspace = true }
|
||||
eth2 = { workspace = true }
|
||||
strum = { workspace = true }
|
||||
logging = { workspace = true }
|
||||
execution_layer = { workspace = true }
|
||||
sensitive_url = { workspace = true }
|
||||
superstruct = { workspace = true }
|
||||
hex = { workspace = true }
|
||||
exit-future = { workspace = true }
|
||||
oneshot_broadcast = { path = "../../common/oneshot_broadcast/" }
|
||||
slog-term = { workspace = true }
|
||||
slog-async = { workspace = true }
|
||||
|
||||
[[test]]
|
||||
name = "beacon_chain_tests"
|
||||
|
@ -874,10 +874,10 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
///
|
||||
/// May return a database error.
|
||||
pub fn state_root_at_slot(&self, request_slot: Slot) -> Result<Option<Hash256>, Error> {
|
||||
if request_slot > self.slot()? {
|
||||
return Ok(None);
|
||||
} else if request_slot == self.spec.genesis_slot {
|
||||
if request_slot == self.spec.genesis_slot {
|
||||
return Ok(Some(self.genesis_state_root));
|
||||
} else if request_slot > self.slot()? {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
// Check limits w.r.t historic state bounds.
|
||||
@ -954,10 +954,10 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
///
|
||||
/// May return a database error.
|
||||
fn block_root_at_slot_skips_none(&self, request_slot: Slot) -> Result<Option<Hash256>, Error> {
|
||||
if request_slot > self.slot()? {
|
||||
return Ok(None);
|
||||
} else if request_slot == self.spec.genesis_slot {
|
||||
if request_slot == self.spec.genesis_slot {
|
||||
return Ok(Some(self.genesis_block_root));
|
||||
} else if request_slot > self.slot()? {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let prev_slot = request_slot.saturating_sub(1_u64);
|
||||
@ -1017,10 +1017,10 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
///
|
||||
/// May return a database error.
|
||||
fn block_root_at_slot_skips_prev(&self, request_slot: Slot) -> Result<Option<Hash256>, Error> {
|
||||
if request_slot > self.slot()? {
|
||||
return Ok(None);
|
||||
} else if request_slot == self.spec.genesis_slot {
|
||||
if request_slot == self.spec.genesis_slot {
|
||||
return Ok(Some(self.genesis_block_root));
|
||||
} else if request_slot > self.slot()? {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
// Try an optimized path of reading the root directly from the head state.
|
||||
|
@ -1,4 +1,4 @@
|
||||
use serde_derive::Serialize;
|
||||
use serde::Serialize;
|
||||
use std::sync::Arc;
|
||||
use types::{
|
||||
beacon_state::CloneConfig, AbstractExecPayload, BeaconState, EthSpec, FullPayload, Hash256,
|
||||
|
@ -811,11 +811,8 @@ impl<T: BeaconChainTypes> GossipVerifiedBlock<T> {
|
||||
// reboot if the `observed_block_producers` cache is empty. In that case, without this
|
||||
// check, we will load the parent and state from disk only to find out later that we
|
||||
// already know this block.
|
||||
if chain
|
||||
.canonical_head
|
||||
.fork_choice_read_lock()
|
||||
.contains_block(&block_root)
|
||||
{
|
||||
let fork_choice_read_lock = chain.canonical_head.fork_choice_read_lock();
|
||||
if fork_choice_read_lock.contains_block(&block_root) {
|
||||
return Err(BlockError::BlockIsAlreadyKnown);
|
||||
}
|
||||
|
||||
@ -824,9 +821,10 @@ impl<T: BeaconChainTypes> GossipVerifiedBlock<T> {
|
||||
// We check this *before* we load the parent so that we can return a more detailed error.
|
||||
let block = check_block_is_finalized_checkpoint_or_descendant(
|
||||
chain,
|
||||
&chain.canonical_head.fork_choice_read_lock(),
|
||||
&fork_choice_read_lock,
|
||||
block,
|
||||
)?;
|
||||
drop(fork_choice_read_lock);
|
||||
|
||||
let block_epoch = block.slot().epoch(T::EthSpec::slots_per_epoch());
|
||||
let (parent_block, block) = verify_parent_block_is_known(chain, block)?;
|
||||
|
@ -1,5 +1,5 @@
|
||||
pub use proto_array::{DisallowedReOrgOffsets, ReOrgThreshold};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
use types::{Checkpoint, Epoch, ProgressiveBalancesMode};
|
||||
|
||||
|
@ -149,6 +149,8 @@ pub enum BeaconChainError {
|
||||
BlockVariantLacksExecutionPayload(Hash256),
|
||||
ExecutionLayerErrorPayloadReconstruction(ExecutionBlockHash, Box<execution_layer::Error>),
|
||||
EngineGetCapabilititesFailed(Box<execution_layer::Error>),
|
||||
ExecutionLayerGetBlockByNumberFailed(Box<execution_layer::Error>),
|
||||
ExecutionLayerGetBlockByHashFailed(Box<execution_layer::Error>),
|
||||
BlockHashMissingFromExecutionLayer(ExecutionBlockHash),
|
||||
InconsistentPayloadReconstructed {
|
||||
slot: Slot,
|
||||
|
@ -1,8 +1,10 @@
|
||||
//! Provides tools for checking if a node is ready for the Bellatrix upgrade and following merge
|
||||
//! transition.
|
||||
|
||||
use crate::{BeaconChain, BeaconChainTypes};
|
||||
use crate::{BeaconChain, BeaconChainError as Error, BeaconChainTypes};
|
||||
use execution_layer::BlockByNumberQuery;
|
||||
use serde::{Deserialize, Serialize, Serializer};
|
||||
use slog::debug;
|
||||
use std::fmt;
|
||||
use std::fmt::Write;
|
||||
use types::*;
|
||||
@ -120,6 +122,25 @@ impl fmt::Display for MergeReadiness {
|
||||
}
|
||||
}
|
||||
|
||||
pub enum GenesisExecutionPayloadStatus {
|
||||
Correct(ExecutionBlockHash),
|
||||
BlockHashMismatch {
|
||||
got: ExecutionBlockHash,
|
||||
expected: ExecutionBlockHash,
|
||||
},
|
||||
TransactionsRootMismatch {
|
||||
got: Hash256,
|
||||
expected: Hash256,
|
||||
},
|
||||
WithdrawalsRootMismatch {
|
||||
got: Hash256,
|
||||
expected: Hash256,
|
||||
},
|
||||
OtherMismatch,
|
||||
Irrelevant,
|
||||
AlreadyHappened,
|
||||
}
|
||||
|
||||
impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
/// Returns `true` if user has an EL configured, or if the Bellatrix fork has occurred or will
|
||||
/// occur within `MERGE_READINESS_PREPARATION_SECONDS`.
|
||||
@ -144,9 +165,9 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
}
|
||||
|
||||
/// Attempts to connect to the EL and confirm that it is ready for the merge.
|
||||
pub async fn check_merge_readiness(&self) -> MergeReadiness {
|
||||
pub async fn check_merge_readiness(&self, current_slot: Slot) -> MergeReadiness {
|
||||
if let Some(el) = self.execution_layer.as_ref() {
|
||||
if !el.is_synced_for_notifier().await {
|
||||
if !el.is_synced_for_notifier(current_slot).await {
|
||||
// The EL is not synced.
|
||||
return MergeReadiness::NotSynced;
|
||||
}
|
||||
@ -161,6 +182,91 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
MergeReadiness::NoExecutionEndpoint
|
||||
}
|
||||
}
|
||||
|
||||
/// Check that the execution payload embedded in the genesis state matches the EL's genesis
|
||||
/// block.
|
||||
pub async fn check_genesis_execution_payload_is_correct(
|
||||
&self,
|
||||
) -> Result<GenesisExecutionPayloadStatus, Error> {
|
||||
let head_snapshot = self.head_snapshot();
|
||||
let genesis_state = &head_snapshot.beacon_state;
|
||||
|
||||
if genesis_state.slot() != 0 {
|
||||
return Ok(GenesisExecutionPayloadStatus::AlreadyHappened);
|
||||
}
|
||||
|
||||
let Ok(latest_execution_payload_header) = genesis_state.latest_execution_payload_header()
|
||||
else {
|
||||
return Ok(GenesisExecutionPayloadStatus::Irrelevant);
|
||||
};
|
||||
let fork = self.spec.fork_name_at_epoch(Epoch::new(0));
|
||||
|
||||
let execution_layer = self
|
||||
.execution_layer
|
||||
.as_ref()
|
||||
.ok_or(Error::ExecutionLayerMissing)?;
|
||||
let exec_block_hash = latest_execution_payload_header.block_hash();
|
||||
|
||||
// Use getBlockByNumber(0) to check that the block hash matches.
|
||||
// At present, Geth does not respond to engine_getPayloadBodiesByRange before genesis.
|
||||
let execution_block = execution_layer
|
||||
.get_block_by_number(BlockByNumberQuery::Tag("0x0"))
|
||||
.await
|
||||
.map_err(|e| Error::ExecutionLayerGetBlockByNumberFailed(Box::new(e)))?
|
||||
.ok_or(Error::BlockHashMissingFromExecutionLayer(exec_block_hash))?;
|
||||
|
||||
if execution_block.block_hash != exec_block_hash {
|
||||
return Ok(GenesisExecutionPayloadStatus::BlockHashMismatch {
|
||||
got: execution_block.block_hash,
|
||||
expected: exec_block_hash,
|
||||
});
|
||||
}
|
||||
|
||||
// Double-check the block by reconstructing it.
|
||||
let execution_payload = execution_layer
|
||||
.get_payload_by_hash_legacy(exec_block_hash, fork)
|
||||
.await
|
||||
.map_err(|e| Error::ExecutionLayerGetBlockByHashFailed(Box::new(e)))?
|
||||
.ok_or(Error::BlockHashMissingFromExecutionLayer(exec_block_hash))?;
|
||||
|
||||
// Verify payload integrity.
|
||||
let header_from_payload = ExecutionPayloadHeader::from(execution_payload.to_ref());
|
||||
|
||||
let got_transactions_root = header_from_payload.transactions_root();
|
||||
let expected_transactions_root = latest_execution_payload_header.transactions_root();
|
||||
let got_withdrawals_root = header_from_payload.withdrawals_root().ok();
|
||||
let expected_withdrawals_root = latest_execution_payload_header.withdrawals_root().ok();
|
||||
|
||||
if got_transactions_root != expected_transactions_root {
|
||||
return Ok(GenesisExecutionPayloadStatus::TransactionsRootMismatch {
|
||||
got: got_transactions_root,
|
||||
expected: expected_transactions_root,
|
||||
});
|
||||
}
|
||||
|
||||
if let Some(&expected) = expected_withdrawals_root {
|
||||
if let Some(&got) = got_withdrawals_root {
|
||||
if got != expected {
|
||||
return Ok(GenesisExecutionPayloadStatus::WithdrawalsRootMismatch {
|
||||
got,
|
||||
expected,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if header_from_payload.to_ref() != latest_execution_payload_header {
|
||||
debug!(
|
||||
self.log,
|
||||
"Genesis execution payload reconstruction failure";
|
||||
"consensus_node_header" => ?latest_execution_payload_header,
|
||||
"execution_node_header" => ?header_from_payload
|
||||
);
|
||||
return Ok(GenesisExecutionPayloadStatus::OtherMismatch);
|
||||
}
|
||||
|
||||
Ok(GenesisExecutionPayloadStatus::Correct(exec_block_hash))
|
||||
}
|
||||
}
|
||||
|
||||
/// Utility function to serialize a Uint256 as a decimal string.
|
||||
|
@ -20,8 +20,8 @@ use execution_layer::test_utils::generate_genesis_header;
|
||||
use execution_layer::{
|
||||
auth::JwtKey,
|
||||
test_utils::{
|
||||
ExecutionBlockGenerator, MockExecutionLayer, TestingBuilder, DEFAULT_JWT_SECRET,
|
||||
DEFAULT_TERMINAL_BLOCK,
|
||||
ExecutionBlockGenerator, MockBuilder, MockBuilderServer, MockExecutionLayer,
|
||||
DEFAULT_JWT_SECRET, DEFAULT_TERMINAL_BLOCK,
|
||||
},
|
||||
ExecutionLayer,
|
||||
};
|
||||
@ -175,7 +175,6 @@ pub struct Builder<T: BeaconChainTypes> {
|
||||
store_mutator: Option<BoxedMutator<T::EthSpec, T::HotStore, T::ColdStore>>,
|
||||
execution_layer: Option<ExecutionLayer<T::EthSpec>>,
|
||||
mock_execution_layer: Option<MockExecutionLayer<T::EthSpec>>,
|
||||
mock_builder: Option<TestingBuilder<T::EthSpec>>,
|
||||
testing_slot_clock: Option<TestingSlotClock>,
|
||||
runtime: TestRuntime,
|
||||
log: Logger,
|
||||
@ -311,7 +310,6 @@ where
|
||||
store_mutator: None,
|
||||
execution_layer: None,
|
||||
mock_execution_layer: None,
|
||||
mock_builder: None,
|
||||
testing_slot_clock: None,
|
||||
runtime,
|
||||
log,
|
||||
@ -451,50 +449,21 @@ where
|
||||
self
|
||||
}
|
||||
|
||||
pub fn mock_execution_layer(mut self) -> Self {
|
||||
pub fn mock_execution_layer(self) -> Self {
|
||||
self.mock_execution_layer_with_config()
|
||||
}
|
||||
|
||||
pub fn mock_execution_layer_with_config(mut self) -> Self {
|
||||
let mock = mock_execution_layer_from_parts::<E>(
|
||||
self.spec.as_ref().expect("cannot build without spec"),
|
||||
self.runtime.task_executor.clone(),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
self.execution_layer = Some(mock.el.clone());
|
||||
self.mock_execution_layer = Some(mock);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn mock_execution_layer_with_builder(
|
||||
mut self,
|
||||
beacon_url: SensitiveUrl,
|
||||
builder_threshold: Option<u128>,
|
||||
) -> Self {
|
||||
// Get a random unused port
|
||||
let port = unused_port::unused_tcp4_port().unwrap();
|
||||
let builder_url = SensitiveUrl::parse(format!("http://127.0.0.1:{port}").as_str()).unwrap();
|
||||
let spec = self.spec.as_ref().expect("cannot build without spec");
|
||||
let mock_el = mock_execution_layer_from_parts::<E>(
|
||||
spec,
|
||||
self.runtime.task_executor.clone(),
|
||||
Some(builder_url.clone()),
|
||||
builder_threshold,
|
||||
)
|
||||
.move_to_terminal_block();
|
||||
|
||||
let mock_el_url = SensitiveUrl::parse(mock_el.server.url().as_str()).unwrap();
|
||||
|
||||
self.mock_builder = Some(TestingBuilder::new(
|
||||
mock_el_url,
|
||||
builder_url,
|
||||
beacon_url,
|
||||
spec.clone(),
|
||||
self.runtime.task_executor.clone(),
|
||||
));
|
||||
self.execution_layer = Some(mock_el.el.clone());
|
||||
self.mock_execution_layer = Some(mock_el);
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
/// Instruct the mock execution engine to always return a "valid" response to any payload it is
|
||||
/// asked to execute.
|
||||
pub fn mock_execution_layer_all_payloads_valid(self) -> Self {
|
||||
@ -581,7 +550,7 @@ where
|
||||
shutdown_receiver: Arc::new(Mutex::new(shutdown_receiver)),
|
||||
runtime: self.runtime,
|
||||
mock_execution_layer: self.mock_execution_layer,
|
||||
mock_builder: self.mock_builder.map(Arc::new),
|
||||
mock_builder: None,
|
||||
blob_signature_cache: <_>::default(),
|
||||
rng: make_rng(),
|
||||
}
|
||||
@ -591,7 +560,6 @@ where
|
||||
pub fn mock_execution_layer_from_parts<T: EthSpec>(
|
||||
spec: &ChainSpec,
|
||||
task_executor: TaskExecutor,
|
||||
builder_url: Option<SensitiveUrl>,
|
||||
builder_threshold: Option<u128>,
|
||||
) -> MockExecutionLayer<T> {
|
||||
let shanghai_time = spec.capella_fork_epoch.map(|epoch| {
|
||||
@ -615,7 +583,6 @@ pub fn mock_execution_layer_from_parts<T: EthSpec>(
|
||||
builder_threshold,
|
||||
Some(JwtKey::from_slice(&DEFAULT_JWT_SECRET).unwrap()),
|
||||
spec.clone(),
|
||||
builder_url,
|
||||
Some(kzg),
|
||||
)
|
||||
}
|
||||
@ -639,7 +606,7 @@ pub struct BeaconChainHarness<T: BeaconChainTypes> {
|
||||
pub runtime: TestRuntime,
|
||||
|
||||
pub mock_execution_layer: Option<MockExecutionLayer<T::EthSpec>>,
|
||||
pub mock_builder: Option<Arc<TestingBuilder<T::EthSpec>>>,
|
||||
pub mock_builder: Option<Arc<MockBuilder<T::EthSpec>>>,
|
||||
|
||||
/// Cache for blob signature because we don't need them for import, but we do need them
|
||||
/// to test gossip validation. We always make them during block production but drop them
|
||||
@ -695,6 +662,49 @@ where
|
||||
.execution_block_generator()
|
||||
}
|
||||
|
||||
pub fn set_mock_builder(&mut self, beacon_url: SensitiveUrl) -> MockBuilderServer {
|
||||
let mock_el = self
|
||||
.mock_execution_layer
|
||||
.as_ref()
|
||||
.expect("harness was not built with mock execution layer");
|
||||
|
||||
let mock_el_url = SensitiveUrl::parse(mock_el.server.url().as_str()).unwrap();
|
||||
|
||||
// Create the builder, listening on a free port.
|
||||
let (mock_builder, mock_builder_server) = MockBuilder::new_for_testing(
|
||||
mock_el_url,
|
||||
beacon_url,
|
||||
self.spec.clone(),
|
||||
self.runtime.task_executor.clone(),
|
||||
);
|
||||
|
||||
// Set the builder URL in the execution layer now that its port is known.
|
||||
let builder_listen_addr = mock_builder_server.local_addr();
|
||||
let port = builder_listen_addr.port();
|
||||
mock_el
|
||||
.el
|
||||
.set_builder_url(
|
||||
SensitiveUrl::parse(format!("http://127.0.0.1:{port}").as_str()).unwrap(),
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
self.mock_builder = Some(Arc::new(mock_builder));
|
||||
|
||||
// Sanity check.
|
||||
let el_builder = self
|
||||
.chain
|
||||
.execution_layer
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.builder()
|
||||
.unwrap();
|
||||
let mock_el_builder = mock_el.el.builder().unwrap();
|
||||
assert!(Arc::ptr_eq(&el_builder, &mock_el_builder));
|
||||
|
||||
mock_builder_server
|
||||
}
|
||||
|
||||
pub fn get_head_block(&self) -> RpcBlock<E> {
|
||||
let block = self.chain.head_beacon_block();
|
||||
let block_root = block.canonical_root();
|
||||
|
@ -1,26 +1,26 @@
|
||||
[package]
|
||||
name = "beacon_processor"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
edition = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
slog = { version = "2.5.2", features = ["max_level_trace"] }
|
||||
itertools = "0.10.0"
|
||||
logging = { path = "../../common/logging" }
|
||||
tokio = { version = "1.14.0", features = ["full"] }
|
||||
tokio-util = { version = "0.6.3", features = ["time"] }
|
||||
futures = "0.3.7"
|
||||
fnv = "1.0.7"
|
||||
strum = "0.24.0"
|
||||
task_executor = { path = "../../common/task_executor" }
|
||||
slot_clock = { path = "../../common/slot_clock" }
|
||||
lighthouse_network = { path = "../lighthouse_network" }
|
||||
hex = "0.4.2"
|
||||
derivative = "2.2.0"
|
||||
types = { path = "../../consensus/types" }
|
||||
ethereum_ssz = "0.5.0"
|
||||
lazy_static = "1.4.0"
|
||||
lighthouse_metrics = { path = "../../common/lighthouse_metrics" }
|
||||
parking_lot = "0.12.0"
|
||||
num_cpus = "1.13.0"
|
||||
serde = { version = "1.0.116", features = ["derive"] }
|
||||
slog = { workspace = true }
|
||||
itertools = { workspace = true }
|
||||
logging = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
tokio-util = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
fnv = { workspace = true }
|
||||
strum = { workspace = true }
|
||||
task_executor = { workspace = true }
|
||||
slot_clock = { workspace = true }
|
||||
lighthouse_network = { workspace = true }
|
||||
hex = { workspace = true }
|
||||
derivative = { workspace = true }
|
||||
types = { workspace = true }
|
||||
ethereum_ssz = { workspace = true }
|
||||
lazy_static = { workspace = true }
|
||||
lighthouse_metrics = { workspace = true }
|
||||
parking_lot = { workspace = true }
|
||||
num_cpus = { workspace = true }
|
||||
serde = { workspace = true }
|
@ -1,13 +1,13 @@
|
||||
[package]
|
||||
name = "builder_client"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
edition = { workspace = true }
|
||||
authors = ["Sean Anderson <sean@sigmaprime.io>"]
|
||||
|
||||
[dependencies]
|
||||
reqwest = { version = "0.11.0", features = ["json","stream"] }
|
||||
sensitive_url = { path = "../../common/sensitive_url" }
|
||||
eth2 = { path = "../../common/eth2" }
|
||||
serde = { version = "1.0.116", features = ["derive"] }
|
||||
serde_json = "1.0.58"
|
||||
lighthouse_version = { path = "../../common/lighthouse_version" }
|
||||
reqwest = { workspace = true }
|
||||
sensitive_url = { workspace = true }
|
||||
eth2 = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
lighthouse_version = { workspace = true }
|
||||
|
@ -2,45 +2,46 @@
|
||||
name = "client"
|
||||
version = "0.2.0"
|
||||
authors = ["Sigma Prime <contact@sigmaprime.io>"]
|
||||
edition = "2021"
|
||||
edition = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
serde_yaml = "0.8.13"
|
||||
operation_pool = { path = "../operation_pool" }
|
||||
tokio = "1.14.0"
|
||||
serde_yaml = { workspace = true }
|
||||
state_processing = { workspace = true }
|
||||
operation_pool = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
state_processing = { path = "../../consensus/state_processing" }
|
||||
beacon_chain = { path = "../beacon_chain" }
|
||||
store = { path = "../store" }
|
||||
network = { path = "../network" }
|
||||
beacon_chain = { workspace = true }
|
||||
store = { workspace = true }
|
||||
network = { workspace = true }
|
||||
timer = { path = "../timer" }
|
||||
lighthouse_network = { path = "../lighthouse_network" }
|
||||
logging = { path = "../../common/logging" }
|
||||
parking_lot = "0.12.0"
|
||||
types = { path = "../../consensus/types" }
|
||||
eth2_config = { path = "../../common/eth2_config" }
|
||||
slot_clock = { path = "../../common/slot_clock" }
|
||||
serde = "1.0.116"
|
||||
lighthouse_network = { workspace = true }
|
||||
logging = { workspace = true }
|
||||
parking_lot = { workspace = true }
|
||||
types = { workspace = true }
|
||||
eth2_config = { workspace = true }
|
||||
slot_clock = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_derive = "1.0.116"
|
||||
error-chain = "0.12.4"
|
||||
slog = { version = "2.5.2", features = ["max_level_trace"] }
|
||||
tokio = "1.14.0"
|
||||
dirs = "3.0.1"
|
||||
eth1 = { path = "../eth1" }
|
||||
eth2 = { path = "../../common/eth2" }
|
||||
sensitive_url = { path = "../../common/sensitive_url" }
|
||||
genesis = { path = "../genesis" }
|
||||
task_executor = { path = "../../common/task_executor" }
|
||||
environment = { path = "../../lighthouse/environment" }
|
||||
lazy_static = "1.4.0"
|
||||
lighthouse_metrics = { path = "../../common/lighthouse_metrics" }
|
||||
error-chain = { workspace = true }
|
||||
slog = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
dirs = { workspace = true }
|
||||
eth1 = { workspace = true }
|
||||
eth2 = { workspace = true }
|
||||
sensitive_url = { workspace = true }
|
||||
genesis = { workspace = true }
|
||||
task_executor = { workspace = true }
|
||||
environment = { workspace = true }
|
||||
lazy_static = { workspace = true }
|
||||
lighthouse_metrics = { workspace = true }
|
||||
time = "0.3.5"
|
||||
directory = {path = "../../common/directory"}
|
||||
http_api = { path = "../http_api" }
|
||||
directory = { workspace = true }
|
||||
http_api = { workspace = true }
|
||||
http_metrics = { path = "../http_metrics" }
|
||||
slasher = { path = "../../slasher" }
|
||||
slasher = { workspace = true }
|
||||
slasher_service = { path = "../../slasher/service" }
|
||||
monitoring_api = {path = "../../common/monitoring_api"}
|
||||
execution_layer = { path = "../execution_layer" }
|
||||
beacon_processor = { path = "../beacon_processor" }
|
||||
monitoring_api = { workspace = true }
|
||||
execution_layer = { workspace = true }
|
||||
beacon_processor = { workspace = true }
|
||||
num_cpus = { workspace = true }
|
||||
|
@ -259,7 +259,7 @@ where
|
||||
"Starting from known genesis state";
|
||||
);
|
||||
|
||||
let genesis_state = genesis_state(&runtime_context, &config, log)?;
|
||||
let genesis_state = genesis_state(&runtime_context, &config, log).await?;
|
||||
|
||||
builder.genesis_state(genesis_state).map(|v| (v, None))?
|
||||
}
|
||||
@ -279,7 +279,7 @@ where
|
||||
.map_err(|e| format!("Unable to parse weak subj state SSZ: {:?}", e))?;
|
||||
let anchor_block = SignedBeaconBlock::from_ssz_bytes(&anchor_block_bytes, &spec)
|
||||
.map_err(|e| format!("Unable to parse weak subj block SSZ: {:?}", e))?;
|
||||
let genesis_state = genesis_state(&runtime_context, &config, log)?;
|
||||
let genesis_state = genesis_state(&runtime_context, &config, log).await?;
|
||||
|
||||
builder
|
||||
.weak_subjectivity_state(anchor_state, anchor_block, genesis_state)
|
||||
@ -380,7 +380,7 @@ where
|
||||
|
||||
debug!(context.log(), "Downloaded finalized block");
|
||||
|
||||
let genesis_state = genesis_state(&runtime_context, &config, log)?;
|
||||
let genesis_state = genesis_state(&runtime_context, &config, log).await?;
|
||||
|
||||
info!(
|
||||
context.log(),
|
||||
@ -1099,7 +1099,7 @@ where
|
||||
}
|
||||
|
||||
/// Obtain the genesis state from the `eth2_network_config` in `context`.
|
||||
fn genesis_state<T: EthSpec>(
|
||||
async fn genesis_state<T: EthSpec>(
|
||||
context: &RuntimeContext<T>,
|
||||
config: &ClientConfig,
|
||||
log: &Logger,
|
||||
@ -1113,6 +1113,7 @@ fn genesis_state<T: EthSpec>(
|
||||
config.genesis_state_url.as_deref(),
|
||||
config.genesis_state_url_timeout,
|
||||
log,
|
||||
)?
|
||||
)
|
||||
.await?
|
||||
.ok_or_else(|| "Genesis state is unknown".to_string())
|
||||
}
|
||||
|
@ -46,20 +46,6 @@ impl<T: BeaconChainTypes> Client<T> {
|
||||
self.http_metrics_listen_addr
|
||||
}
|
||||
|
||||
/// Returns the ipv4 port of the client's libp2p stack, if it was started.
|
||||
pub fn libp2p_listen_ipv4_port(&self) -> Option<u16> {
|
||||
self.network_globals
|
||||
.as_ref()
|
||||
.and_then(|n| n.listen_port_tcp4())
|
||||
}
|
||||
|
||||
/// Returns the ipv6 port of the client's libp2p stack, if it was started.
|
||||
pub fn libp2p_listen_ipv6_port(&self) -> Option<u16> {
|
||||
self.network_globals
|
||||
.as_ref()
|
||||
.and_then(|n| n.listen_port_tcp6())
|
||||
}
|
||||
|
||||
/// Returns the list of libp2p addresses the client is listening to.
|
||||
pub fn libp2p_listen_addresses(&self) -> Option<Vec<Multiaddr>> {
|
||||
self.network_globals.as_ref().map(|n| n.listen_multiaddrs())
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::metrics;
|
||||
use beacon_chain::{
|
||||
capella_readiness::CapellaReadiness,
|
||||
merge_readiness::{MergeConfig, MergeReadiness},
|
||||
merge_readiness::{GenesisExecutionPayloadStatus, MergeConfig, MergeReadiness},
|
||||
BeaconChain, BeaconChainTypes, ExecutionStatus,
|
||||
};
|
||||
use lighthouse_network::{types::SyncState, NetworkGlobals};
|
||||
@ -62,6 +62,9 @@ pub fn spawn_notifier<T: BeaconChainTypes>(
|
||||
"wait_time" => estimated_time_pretty(Some(next_slot.as_secs() as f64)),
|
||||
);
|
||||
eth1_logging(&beacon_chain, &log);
|
||||
merge_readiness_logging(Slot::new(0), &beacon_chain, &log).await;
|
||||
capella_readiness_logging(Slot::new(0), &beacon_chain, &log).await;
|
||||
genesis_execution_payload_logging(&beacon_chain, &log).await;
|
||||
sleep(slot_duration).await;
|
||||
}
|
||||
_ => break,
|
||||
@ -365,7 +368,7 @@ async fn merge_readiness_logging<T: BeaconChainTypes>(
|
||||
return;
|
||||
}
|
||||
|
||||
match beacon_chain.check_merge_readiness().await {
|
||||
match beacon_chain.check_merge_readiness(current_slot).await {
|
||||
MergeReadiness::Ready {
|
||||
config,
|
||||
current_difficulty,
|
||||
@ -476,6 +479,79 @@ async fn capella_readiness_logging<T: BeaconChainTypes>(
|
||||
}
|
||||
}
|
||||
|
||||
async fn genesis_execution_payload_logging<T: BeaconChainTypes>(
|
||||
beacon_chain: &BeaconChain<T>,
|
||||
log: &Logger,
|
||||
) {
|
||||
match beacon_chain
|
||||
.check_genesis_execution_payload_is_correct()
|
||||
.await
|
||||
{
|
||||
Ok(GenesisExecutionPayloadStatus::Correct(block_hash)) => {
|
||||
info!(
|
||||
log,
|
||||
"Execution enabled from genesis";
|
||||
"genesis_payload_block_hash" => ?block_hash,
|
||||
);
|
||||
}
|
||||
Ok(GenesisExecutionPayloadStatus::BlockHashMismatch { got, expected }) => {
|
||||
error!(
|
||||
log,
|
||||
"Genesis payload block hash mismatch";
|
||||
"info" => "genesis is misconfigured and likely to fail",
|
||||
"consensus_node_block_hash" => ?expected,
|
||||
"execution_node_block_hash" => ?got,
|
||||
);
|
||||
}
|
||||
Ok(GenesisExecutionPayloadStatus::TransactionsRootMismatch { got, expected }) => {
|
||||
error!(
|
||||
log,
|
||||
"Genesis payload transactions root mismatch";
|
||||
"info" => "genesis is misconfigured and likely to fail",
|
||||
"consensus_node_transactions_root" => ?expected,
|
||||
"execution_node_transactions_root" => ?got,
|
||||
);
|
||||
}
|
||||
Ok(GenesisExecutionPayloadStatus::WithdrawalsRootMismatch { got, expected }) => {
|
||||
error!(
|
||||
log,
|
||||
"Genesis payload withdrawals root mismatch";
|
||||
"info" => "genesis is misconfigured and likely to fail",
|
||||
"consensus_node_withdrawals_root" => ?expected,
|
||||
"execution_node_withdrawals_root" => ?got,
|
||||
);
|
||||
}
|
||||
Ok(GenesisExecutionPayloadStatus::OtherMismatch) => {
|
||||
error!(
|
||||
log,
|
||||
"Genesis payload header mismatch";
|
||||
"info" => "genesis is misconfigured and likely to fail",
|
||||
"detail" => "see debug logs for payload headers"
|
||||
);
|
||||
}
|
||||
Ok(GenesisExecutionPayloadStatus::Irrelevant) => {
|
||||
info!(
|
||||
log,
|
||||
"Execution is not enabled from genesis";
|
||||
);
|
||||
}
|
||||
Ok(GenesisExecutionPayloadStatus::AlreadyHappened) => {
|
||||
warn!(
|
||||
log,
|
||||
"Unable to check genesis which has already occurred";
|
||||
"info" => "this is probably a race condition or a bug"
|
||||
);
|
||||
}
|
||||
Err(e) => {
|
||||
error!(
|
||||
log,
|
||||
"Unable to check genesis execution payload";
|
||||
"error" => ?e
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn eth1_logging<T: BeaconChainTypes>(beacon_chain: &BeaconChain<T>, log: &Logger) {
|
||||
let current_slot_opt = beacon_chain.slot().ok();
|
||||
|
||||
|
@ -2,33 +2,33 @@
|
||||
name = "eth1"
|
||||
version = "0.2.0"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>"]
|
||||
edition = "2021"
|
||||
edition = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
eth1_test_rig = { path = "../../testing/eth1_test_rig" }
|
||||
serde_yaml = "0.8.13"
|
||||
sloggers = { version = "2.1.1", features = ["json"] }
|
||||
environment = { path = "../../lighthouse/environment" }
|
||||
eth1_test_rig = { workspace = true }
|
||||
serde_yaml = { workspace = true }
|
||||
sloggers = { workspace = true }
|
||||
environment = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
reqwest = { version = "0.11.0", features = ["native-tls-vendored"] }
|
||||
execution_layer = { path = "../execution_layer" }
|
||||
futures = "0.3.7"
|
||||
serde_json = "1.0.58"
|
||||
serde = { version = "1.0.116", features = ["derive"] }
|
||||
hex = "0.4.2"
|
||||
types = { path = "../../consensus/types"}
|
||||
merkle_proof = { path = "../../consensus/merkle_proof"}
|
||||
ethereum_ssz = "0.5.0"
|
||||
ethereum_ssz_derive = "0.5.3"
|
||||
tree_hash = "0.5.2"
|
||||
parking_lot = "0.12.0"
|
||||
slog = "2.5.2"
|
||||
superstruct = "0.5.0"
|
||||
tokio = { version = "1.14.0", features = ["full"] }
|
||||
state_processing = { path = "../../consensus/state_processing" }
|
||||
lighthouse_metrics = { path = "../../common/lighthouse_metrics"}
|
||||
lazy_static = "1.4.0"
|
||||
task_executor = { path = "../../common/task_executor" }
|
||||
eth2 = { path = "../../common/eth2" }
|
||||
sensitive_url = { path = "../../common/sensitive_url" }
|
||||
reqwest = { workspace = true }
|
||||
execution_layer = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
hex = { workspace = true }
|
||||
types = { workspace = true }
|
||||
merkle_proof = { workspace = true }
|
||||
ethereum_ssz = { workspace = true }
|
||||
ethereum_ssz_derive = { workspace = true }
|
||||
tree_hash = { workspace = true }
|
||||
parking_lot = { workspace = true }
|
||||
slog = { workspace = true }
|
||||
superstruct = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
state_processing = { workspace = true }
|
||||
lighthouse_metrics = { workspace = true }
|
||||
lazy_static = { workspace = true }
|
||||
task_executor = { workspace = true }
|
||||
eth2 = { workspace = true }
|
||||
sensitive_url = { workspace = true }
|
||||
|
@ -1,55 +1,58 @@
|
||||
[package]
|
||||
name = "execution_layer"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
edition = { workspace = true }
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
types = { path = "../../consensus/types"}
|
||||
tokio = { version = "1.10.0", features = ["full"] }
|
||||
types = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
async-trait = "0.1.51"
|
||||
slog = "2.5.2"
|
||||
futures = "0.3.7"
|
||||
sensitive_url = { path = "../../common/sensitive_url" }
|
||||
reqwest = { version = "0.11.0", features = ["json","stream"] }
|
||||
ethereum_serde_utils = "0.5.0"
|
||||
serde_json = "1.0.58"
|
||||
serde = { version = "1.0.116", features = ["derive"] }
|
||||
warp = { version = "0.3.2", features = ["tls"] }
|
||||
slog = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
sensitive_url = { workspace = true }
|
||||
reqwest = { workspace = true }
|
||||
ethereum_serde_utils = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
warp = { workspace = true }
|
||||
jsonwebtoken = "8"
|
||||
environment = { path = "../../lighthouse/environment" }
|
||||
bytes = "1.1.0"
|
||||
task_executor = { path = "../../common/task_executor" }
|
||||
hex = "0.4.2"
|
||||
ethereum_ssz = "0.5.0"
|
||||
ssz_types = "0.5.4"
|
||||
eth2 = { path = "../../common/eth2" }
|
||||
kzg = { path = "../../crypto/kzg" }
|
||||
state_processing = { path = "../../consensus/state_processing" }
|
||||
superstruct = "0.6.0"
|
||||
lru = "0.7.1"
|
||||
exit-future = "0.2.0"
|
||||
tree_hash = "0.5.2"
|
||||
tree_hash_derive = "0.5.0"
|
||||
parking_lot = "0.12.0"
|
||||
slot_clock = { path = "../../common/slot_clock" }
|
||||
tempfile = "3.1.0"
|
||||
rand = "0.8.5"
|
||||
zeroize = { version = "1.4.2", features = ["zeroize_derive"] }
|
||||
lighthouse_metrics = { path = "../../common/lighthouse_metrics" }
|
||||
lazy_static = "1.4.0"
|
||||
ethers-core = "1.0.2"
|
||||
environment = { workspace = true }
|
||||
bytes = { workspace = true }
|
||||
task_executor = { workspace = true }
|
||||
hex = { workspace = true }
|
||||
ethereum_ssz = { workspace = true }
|
||||
ssz_types = { workspace = true }
|
||||
eth2 = { workspace = true }
|
||||
kzg = { workspace = true }
|
||||
state_processing = { workspace = true }
|
||||
superstruct = { workspace = true }
|
||||
lru = { workspace = true }
|
||||
exit-future = { workspace = true }
|
||||
tree_hash = { workspace = true }
|
||||
tree_hash_derive = { workspace = true }
|
||||
parking_lot = { workspace = true }
|
||||
slot_clock = { workspace = true }
|
||||
tempfile = { workspace = true }
|
||||
rand = { workspace = true }
|
||||
zeroize = { workspace = true }
|
||||
lighthouse_metrics = { workspace = true }
|
||||
lazy_static = { workspace = true }
|
||||
ethers-core = { workspace = true }
|
||||
builder_client = { path = "../builder_client" }
|
||||
fork_choice = { path = "../../consensus/fork_choice" }
|
||||
fork_choice = { workspace = true }
|
||||
#PR: https://github.com/ralexstokes/mev-rs/pull/124
|
||||
mev-rs = { git = "https://github.com/jimmygchen/mev-rs", rev = "dedc77a" }
|
||||
axum = "0.6"
|
||||
hyper = "0.14"
|
||||
ethereum-consensus = { git = "https://github.com/ralexstokes/ethereum-consensus", rev = "12508c1f9b0c8f4bf4c5e9b6d441e840c1b37fd9" }
|
||||
ssz_rs = "0.9.0"
|
||||
tokio-stream = { version = "0.1.9", features = [ "sync" ] }
|
||||
strum = "0.24.0"
|
||||
tokio-stream = { workspace = true }
|
||||
strum = { workspace = true }
|
||||
keccak-hash = "0.10.0"
|
||||
hash256-std-hasher = "0.15.2"
|
||||
triehash = "0.8.4"
|
||||
hash-db = "0.15.2"
|
||||
pretty_reqwest_error = { path = "../../common/pretty_reqwest_error" }
|
||||
pretty_reqwest_error = { workspace = true }
|
||||
arc-swap = "1.6.0"
|
||||
|
@ -5,6 +5,7 @@
|
||||
//! deposit-contract functionality that the `beacon_node/eth1` crate already provides.
|
||||
|
||||
use crate::payload_cache::PayloadCache;
|
||||
use arc_swap::ArcSwapOption;
|
||||
use auth::{strip_prefix, Auth, JwtKey};
|
||||
use builder_client::BuilderHttpClient;
|
||||
pub use engine_api::EngineCapabilities;
|
||||
@ -301,7 +302,7 @@ type PayloadContentsRefTuple<'a, T> = (ExecutionPayloadRef<'a, T>, Option<&'a Bl
|
||||
|
||||
struct Inner<E: EthSpec> {
|
||||
engine: Arc<Engine>,
|
||||
builder: Option<BuilderHttpClient>,
|
||||
builder: ArcSwapOption<BuilderHttpClient>,
|
||||
execution_engine_forkchoice_lock: Mutex<()>,
|
||||
suggested_fee_recipient: Option<Address>,
|
||||
proposer_preparation_data: Mutex<HashMap<u64, ProposerPreparationDataEntry>>,
|
||||
@ -453,25 +454,9 @@ impl<T: EthSpec> ExecutionLayer<T> {
|
||||
Engine::new(api, executor.clone(), &log)
|
||||
};
|
||||
|
||||
let builder = builder_url
|
||||
.map(|url| {
|
||||
let builder_client = BuilderHttpClient::new(url.clone(), builder_user_agent)
|
||||
.map_err(Error::Builder)?;
|
||||
|
||||
info!(
|
||||
log,
|
||||
"Using external block builder";
|
||||
"builder_url" => ?url,
|
||||
"builder_profit_threshold" => builder_profit_threshold,
|
||||
"local_user_agent" => builder_client.get_user_agent(),
|
||||
);
|
||||
Ok::<_, Error>(builder_client)
|
||||
})
|
||||
.transpose()?;
|
||||
|
||||
let inner = Inner {
|
||||
engine: Arc::new(engine),
|
||||
builder,
|
||||
builder: ArcSwapOption::empty(),
|
||||
execution_engine_forkchoice_lock: <_>::default(),
|
||||
suggested_fee_recipient,
|
||||
proposer_preparation_data: Mutex::new(HashMap::new()),
|
||||
@ -486,19 +471,45 @@ impl<T: EthSpec> ExecutionLayer<T> {
|
||||
last_new_payload_errored: RwLock::new(false),
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
let el = Self {
|
||||
inner: Arc::new(inner),
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(builder_url) = builder_url {
|
||||
el.set_builder_url(builder_url, builder_user_agent)?;
|
||||
}
|
||||
|
||||
Ok(el)
|
||||
}
|
||||
|
||||
impl<T: EthSpec> ExecutionLayer<T> {
|
||||
fn engine(&self) -> &Arc<Engine> {
|
||||
&self.inner.engine
|
||||
}
|
||||
|
||||
pub fn builder(&self) -> &Option<BuilderHttpClient> {
|
||||
&self.inner.builder
|
||||
pub fn builder(&self) -> Option<Arc<BuilderHttpClient>> {
|
||||
self.inner.builder.load_full()
|
||||
}
|
||||
|
||||
/// Set the builder URL after initialization.
|
||||
///
|
||||
/// This is useful for breaking circular dependencies between mock ELs and mock builders in
|
||||
/// tests.
|
||||
pub fn set_builder_url(
|
||||
&self,
|
||||
builder_url: SensitiveUrl,
|
||||
builder_user_agent: Option<String>,
|
||||
) -> Result<(), Error> {
|
||||
let builder_client = BuilderHttpClient::new(builder_url.clone(), builder_user_agent)
|
||||
.map_err(Error::Builder)?;
|
||||
info!(
|
||||
self.log(),
|
||||
"Using external block builder";
|
||||
"builder_url" => ?builder_url,
|
||||
"builder_profit_threshold" => self.inner.builder_profit_threshold.as_u128(),
|
||||
"local_user_agent" => builder_client.get_user_agent(),
|
||||
);
|
||||
self.inner.builder.swap(Some(Arc::new(builder_client)));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Cache a full payload, keyed on the `tree_hash_root` of the payload
|
||||
@ -655,9 +666,9 @@ impl<T: EthSpec> ExecutionLayer<T> {
|
||||
///
|
||||
/// This function is a wrapper over `Self::is_synced` that makes an additional
|
||||
/// check for the execution layer sync status. Checks if the latest block has
|
||||
/// a `block_number != 0`.
|
||||
/// a `block_number != 0` *if* the `current_slot` is also `> 0`.
|
||||
/// Returns the `Self::is_synced` response if unable to get latest block.
|
||||
pub async fn is_synced_for_notifier(&self) -> bool {
|
||||
pub async fn is_synced_for_notifier(&self, current_slot: Slot) -> bool {
|
||||
let synced = self.is_synced().await;
|
||||
if synced {
|
||||
if let Ok(Some(block)) = self
|
||||
@ -666,7 +677,7 @@ impl<T: EthSpec> ExecutionLayer<T> {
|
||||
.get_block_by_number(BlockByNumberQuery::Tag(LATEST_TAG))
|
||||
.await
|
||||
{
|
||||
if block.block_number == 0 {
|
||||
if block.block_number == 0 && current_slot > 0 {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -1743,6 +1754,17 @@ impl<T: EthSpec> ExecutionLayer<T> {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_block_by_number(
|
||||
&self,
|
||||
query: BlockByNumberQuery<'_>,
|
||||
) -> Result<Option<ExecutionBlock>, Error> {
|
||||
self.engine()
|
||||
.request(|engine| async move { engine.api.get_block_by_number(query).await })
|
||||
.await
|
||||
.map_err(Box::new)
|
||||
.map_err(Error::EngineError)
|
||||
}
|
||||
|
||||
pub async fn get_payload_by_hash_legacy(
|
||||
&self,
|
||||
hash: ExecutionBlockHash,
|
||||
|
@ -42,6 +42,11 @@ use types::{
|
||||
ExecutionPayloadHeader, ForkName, ForkVersionedResponse, Hash256, Slot, Uint256,
|
||||
};
|
||||
|
||||
pub type MockBuilderServer = axum::Server<
|
||||
hyper::server::conn::AddrIncoming,
|
||||
axum::routing::IntoMakeService<axum::routing::Router>,
|
||||
>;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum Operation {
|
||||
FeeRecipient(Address),
|
||||
@ -166,19 +171,25 @@ impl BidStuff for BuilderBid {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TestingBuilder<E: EthSpec> {
|
||||
server: BlindedBlockProviderServer<MockBuilder<E>>,
|
||||
pub builder: MockBuilder<E>,
|
||||
#[derive(Clone)]
|
||||
pub struct MockBuilder<E: EthSpec> {
|
||||
el: ExecutionLayer<E>,
|
||||
beacon_client: BeaconNodeHttpClient,
|
||||
spec: ChainSpec,
|
||||
context: Arc<Context>,
|
||||
val_registration_cache: Arc<RwLock<HashMap<BlsPublicKey, SignedValidatorRegistration>>>,
|
||||
builder_sk: SecretKey,
|
||||
operations: Arc<RwLock<Vec<Operation>>>,
|
||||
invalidate_signatures: Arc<RwLock<bool>>,
|
||||
}
|
||||
|
||||
impl<E: EthSpec> TestingBuilder<E> {
|
||||
pub fn new(
|
||||
impl<E: EthSpec> MockBuilder<E> {
|
||||
pub fn new_for_testing(
|
||||
mock_el_url: SensitiveUrl,
|
||||
builder_url: SensitiveUrl,
|
||||
beacon_url: SensitiveUrl,
|
||||
spec: ChainSpec,
|
||||
executor: TaskExecutor,
|
||||
) -> Self {
|
||||
) -> (Self, MockBuilderServer) {
|
||||
let file = NamedTempFile::new().unwrap();
|
||||
let path = file.path().into();
|
||||
std::fs::write(&path, hex::encode(DEFAULT_JWT_SECRET)).unwrap();
|
||||
@ -207,39 +218,13 @@ impl<E: EthSpec> TestingBuilder<E> {
|
||||
spec,
|
||||
context,
|
||||
);
|
||||
let port = builder_url.full.port().unwrap();
|
||||
let host: Ipv4Addr = builder_url
|
||||
.full
|
||||
.host_str()
|
||||
.unwrap()
|
||||
.to_string()
|
||||
.parse()
|
||||
.unwrap();
|
||||
let server = BlindedBlockProviderServer::new(host, port, builder.clone());
|
||||
Self { server, builder }
|
||||
let host: Ipv4Addr = Ipv4Addr::LOCALHOST;
|
||||
let port = 0;
|
||||
let provider = BlindedBlockProviderServer::new(host, port, builder.clone());
|
||||
let server = provider.serve();
|
||||
(builder, server)
|
||||
}
|
||||
|
||||
pub async fn run(&self) {
|
||||
let server = self.server.serve();
|
||||
if let Err(err) = server.await {
|
||||
println!("error while listening for incoming: {err}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct MockBuilder<E: EthSpec> {
|
||||
el: ExecutionLayer<E>,
|
||||
beacon_client: BeaconNodeHttpClient,
|
||||
spec: ChainSpec,
|
||||
context: Arc<Context>,
|
||||
val_registration_cache: Arc<RwLock<HashMap<BlsPublicKey, SignedValidatorRegistration>>>,
|
||||
builder_sk: SecretKey,
|
||||
operations: Arc<RwLock<Vec<Operation>>>,
|
||||
invalidate_signatures: Arc<RwLock<bool>>,
|
||||
}
|
||||
|
||||
impl<E: EthSpec> MockBuilder<E> {
|
||||
pub fn new(
|
||||
el: ExecutionLayer<E>,
|
||||
beacon_client: BeaconNodeHttpClient,
|
||||
|
@ -34,7 +34,6 @@ impl<T: EthSpec> MockExecutionLayer<T> {
|
||||
Some(JwtKey::from_slice(&DEFAULT_JWT_SECRET).unwrap()),
|
||||
spec,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
@ -47,7 +46,6 @@ impl<T: EthSpec> MockExecutionLayer<T> {
|
||||
builder_threshold: Option<u128>,
|
||||
jwt_key: Option<JwtKey>,
|
||||
spec: ChainSpec,
|
||||
builder_url: Option<SensitiveUrl>,
|
||||
kzg: Option<Kzg<T::Kzg>>,
|
||||
) -> Self {
|
||||
let handle = executor.handle().unwrap();
|
||||
@ -72,7 +70,6 @@ impl<T: EthSpec> MockExecutionLayer<T> {
|
||||
|
||||
let config = Config {
|
||||
execution_endpoints: vec![url],
|
||||
builder_url,
|
||||
secret_files: vec![path],
|
||||
suggested_fee_recipient: Some(Address::repeat_byte(42)),
|
||||
builder_profit_threshold: builder_threshold.unwrap_or(DEFAULT_BUILDER_THRESHOLD_WEI),
|
||||
|
@ -31,7 +31,7 @@ pub use execution_block_generator::{
|
||||
pub use hook::Hook;
|
||||
pub use mock_builder::{
|
||||
convert_err, custom_err, from_ssz_rs, to_ssz_rs, Context as MockBuilderContext, MockBuilder,
|
||||
Operation, TestingBuilder,
|
||||
MockBuilderServer, Operation,
|
||||
};
|
||||
pub use mock_execution_layer::MockExecutionLayer;
|
||||
|
||||
|
@ -2,23 +2,23 @@
|
||||
name = "genesis"
|
||||
version = "0.2.0"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>"]
|
||||
edition = "2021"
|
||||
edition = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
eth1_test_rig = { path = "../../testing/eth1_test_rig" }
|
||||
sensitive_url = { path = "../../common/sensitive_url" }
|
||||
eth1_test_rig = { workspace = true }
|
||||
sensitive_url = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
futures = "0.3.7"
|
||||
types = { path = "../../consensus/types"}
|
||||
environment = { path = "../../lighthouse/environment"}
|
||||
eth1 = { path = "../eth1"}
|
||||
rayon = "1.4.1"
|
||||
state_processing = { path = "../../consensus/state_processing" }
|
||||
merkle_proof = { path = "../../consensus/merkle_proof" }
|
||||
ethereum_ssz = "0.5.0"
|
||||
ethereum_hashing = "1.0.0-beta.2"
|
||||
tree_hash = "0.5.2"
|
||||
tokio = { version = "1.14.0", features = ["full"] }
|
||||
slog = "2.5.2"
|
||||
int_to_bytes = { path = "../../consensus/int_to_bytes" }
|
||||
futures = { workspace = true }
|
||||
types = { workspace = true }
|
||||
environment = { workspace = true }
|
||||
eth1 = { workspace = true }
|
||||
rayon = { workspace = true }
|
||||
state_processing = { workspace = true }
|
||||
merkle_proof = { workspace = true }
|
||||
ethereum_ssz = { workspace = true }
|
||||
ethereum_hashing = { workspace = true }
|
||||
tree_hash = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
slog = { workspace = true }
|
||||
int_to_bytes = { workspace = true }
|
||||
|
@ -2,54 +2,53 @@
|
||||
name = "http_api"
|
||||
version = "0.1.0"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>"]
|
||||
edition = "2021"
|
||||
edition = { workspace = true }
|
||||
autotests = false # using a single test binary compiles faster
|
||||
|
||||
[dependencies]
|
||||
warp = { version = "0.3.2", features = ["tls"] }
|
||||
serde = { version = "1.0.116", features = ["derive"] }
|
||||
tokio = { version = "1.14.0", features = ["macros", "sync"] }
|
||||
tokio-stream = { version = "0.1.3", features = ["sync"] }
|
||||
types = { path = "../../consensus/types" }
|
||||
hex = "0.4.2"
|
||||
beacon_chain = { path = "../beacon_chain" }
|
||||
eth2 = { path = "../../common/eth2", features = ["lighthouse"] }
|
||||
slog = "2.5.2"
|
||||
network = { path = "../network" }
|
||||
lighthouse_network = { path = "../lighthouse_network" }
|
||||
eth1 = { path = "../eth1" }
|
||||
state_processing = { path = "../../consensus/state_processing" }
|
||||
lighthouse_version = { path = "../../common/lighthouse_version" }
|
||||
lighthouse_metrics = { path = "../../common/lighthouse_metrics" }
|
||||
lazy_static = "1.4.0"
|
||||
warp_utils = { path = "../../common/warp_utils" }
|
||||
slot_clock = { path = "../../common/slot_clock" }
|
||||
ethereum_ssz = "0.5.0"
|
||||
warp = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
tokio-stream = { workspace = true }
|
||||
types = { workspace = true }
|
||||
hex = { workspace = true }
|
||||
beacon_chain = { workspace = true }
|
||||
eth2 = { workspace = true }
|
||||
slog = { workspace = true }
|
||||
network = { workspace = true }
|
||||
lighthouse_network = { workspace = true }
|
||||
eth1 = { workspace = true }
|
||||
state_processing = { workspace = true }
|
||||
lighthouse_version = { workspace = true }
|
||||
lighthouse_metrics = { workspace = true }
|
||||
lazy_static = { workspace = true }
|
||||
warp_utils = { workspace = true }
|
||||
slot_clock = { workspace = true }
|
||||
ethereum_ssz = { workspace = true }
|
||||
bs58 = "0.4.0"
|
||||
futures = "0.3.8"
|
||||
execution_layer = { path = "../execution_layer" }
|
||||
parking_lot = "0.12.0"
|
||||
safe_arith = { path = "../../consensus/safe_arith" }
|
||||
task_executor = { path = "../../common/task_executor" }
|
||||
lru = "0.7.7"
|
||||
tree_hash = "0.5.2"
|
||||
sysinfo = "0.26.5"
|
||||
futures = { workspace = true }
|
||||
execution_layer = { workspace = true }
|
||||
parking_lot = { workspace = true }
|
||||
safe_arith = { workspace = true }
|
||||
task_executor = { workspace = true }
|
||||
lru = { workspace = true }
|
||||
tree_hash = { workspace = true }
|
||||
sysinfo = { workspace = true }
|
||||
system_health = { path = "../../common/system_health" }
|
||||
directory = { path = "../../common/directory" }
|
||||
logging = { path = "../../common/logging" }
|
||||
ethereum_serde_utils = "0.5.0"
|
||||
operation_pool = { path = "../operation_pool" }
|
||||
sensitive_url = { path = "../../common/sensitive_url" }
|
||||
unused_port = { path = "../../common/unused_port" }
|
||||
store = { path = "../store" }
|
||||
bytes = "1.1.0"
|
||||
beacon_processor = { path = "../beacon_processor" }
|
||||
directory = { workspace = true }
|
||||
logging = { workspace = true }
|
||||
ethereum_serde_utils = { workspace = true }
|
||||
operation_pool = { workspace = true }
|
||||
sensitive_url = { workspace = true }
|
||||
store = { workspace = true }
|
||||
bytes = { workspace = true }
|
||||
beacon_processor = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
environment = { path = "../../lighthouse/environment" }
|
||||
serde_json = "1.0.58"
|
||||
proto_array = { path = "../../consensus/proto_array" }
|
||||
genesis = { path = "../genesis" }
|
||||
environment = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
proto_array = { workspace = true }
|
||||
genesis = { workspace = true }
|
||||
|
||||
[[test]]
|
||||
name = "bn_http_api_tests"
|
||||
|
@ -2869,12 +2869,8 @@ pub fn serve<T: BeaconChainTypes>(
|
||||
})?;
|
||||
|
||||
if let Some(peer_info) = network_globals.peers.read().peer_info(&peer_id) {
|
||||
let address = if let Some(socket_addr) = peer_info.seen_addresses().next() {
|
||||
let mut addr = lighthouse_network::Multiaddr::from(socket_addr.ip());
|
||||
addr.push(lighthouse_network::multiaddr::Protocol::Tcp(
|
||||
socket_addr.port(),
|
||||
));
|
||||
addr.to_string()
|
||||
let address = if let Some(multiaddr) = peer_info.seen_multiaddrs().next() {
|
||||
multiaddr.to_string()
|
||||
} else if let Some(addr) = peer_info.listening_addresses().first() {
|
||||
addr.to_string()
|
||||
} else {
|
||||
@ -2922,13 +2918,8 @@ pub fn serve<T: BeaconChainTypes>(
|
||||
.peers()
|
||||
.for_each(|(peer_id, peer_info)| {
|
||||
let address =
|
||||
if let Some(socket_addr) = peer_info.seen_addresses().next() {
|
||||
let mut addr =
|
||||
lighthouse_network::Multiaddr::from(socket_addr.ip());
|
||||
addr.push(lighthouse_network::multiaddr::Protocol::Tcp(
|
||||
socket_addr.port(),
|
||||
));
|
||||
addr.to_string()
|
||||
if let Some(multiaddr) = peer_info.seen_multiaddrs().next() {
|
||||
multiaddr.to_string()
|
||||
} else if let Some(addr) = peer_info.listening_addresses().first() {
|
||||
addr.to_string()
|
||||
} else {
|
||||
@ -3055,6 +3046,7 @@ pub fn serve<T: BeaconChainTypes>(
|
||||
.and(warp::path::end())
|
||||
.and(not_while_syncing_filter.clone())
|
||||
.and(warp::query::<api_types::ValidatorBlocksQuery>())
|
||||
.and(warp::header::optional::<api_types::Accept>("accept"))
|
||||
.and(task_spawner_filter.clone())
|
||||
.and(chain_filter.clone())
|
||||
.and(log_filter.clone())
|
||||
@ -3062,6 +3054,7 @@ pub fn serve<T: BeaconChainTypes>(
|
||||
|endpoint_version: EndpointVersion,
|
||||
slot: Slot,
|
||||
query: api_types::ValidatorBlocksQuery,
|
||||
accept_header: Option<api_types::Accept>,
|
||||
task_spawner: TaskSpawner<T::EthSpec>,
|
||||
chain: Arc<BeaconChain<T>>,
|
||||
log: Logger| {
|
||||
@ -3109,9 +3102,24 @@ pub fn serve<T: BeaconChainTypes>(
|
||||
let block_contents =
|
||||
build_block_contents::build_block_contents(fork_name, block, maybe_blobs)?;
|
||||
|
||||
fork_versioned_response(endpoint_version, fork_name, block_contents)
|
||||
.map(|response| warp::reply::json(&response).into_response())
|
||||
.map(|res| add_consensus_version_header(res, fork_name))
|
||||
match accept_header {
|
||||
Some(api_types::Accept::Ssz) => Response::builder()
|
||||
.status(200)
|
||||
.header("Content-Type", "application/octet-stream")
|
||||
.body(block_contents.as_ssz_bytes().into())
|
||||
.map(|res: Response<Bytes>| {
|
||||
add_consensus_version_header(res, fork_name)
|
||||
})
|
||||
.map_err(|e| {
|
||||
warp_utils::reject::custom_server_error(format!(
|
||||
"failed to create response: {}",
|
||||
e
|
||||
))
|
||||
}),
|
||||
_ => fork_versioned_response(endpoint_version, fork_name, block_contents)
|
||||
.map(|response| warp::reply::json(&response).into_response())
|
||||
.map(|res| add_consensus_version_header(res, fork_name)),
|
||||
}
|
||||
})
|
||||
},
|
||||
);
|
||||
@ -3128,11 +3136,13 @@ pub fn serve<T: BeaconChainTypes>(
|
||||
.and(warp::path::end())
|
||||
.and(not_while_syncing_filter.clone())
|
||||
.and(warp::query::<api_types::ValidatorBlocksQuery>())
|
||||
.and(warp::header::optional::<api_types::Accept>("accept"))
|
||||
.and(task_spawner_filter.clone())
|
||||
.and(chain_filter.clone())
|
||||
.then(
|
||||
|slot: Slot,
|
||||
query: api_types::ValidatorBlocksQuery,
|
||||
accept_header: Option<api_types::Accept>,
|
||||
task_spawner: TaskSpawner<T::EthSpec>,
|
||||
chain: Arc<BeaconChain<T>>| {
|
||||
task_spawner.spawn_async_with_rejection(Priority::P0, async move {
|
||||
@ -3176,10 +3186,25 @@ pub fn serve<T: BeaconChainTypes>(
|
||||
maybe_blobs,
|
||||
)?;
|
||||
|
||||
// Pose as a V2 endpoint so we return the fork `version`.
|
||||
fork_versioned_response(V2, fork_name, block_contents)
|
||||
.map(|response| warp::reply::json(&response).into_response())
|
||||
.map(|res| add_consensus_version_header(res, fork_name))
|
||||
match accept_header {
|
||||
Some(api_types::Accept::Ssz) => Response::builder()
|
||||
.status(200)
|
||||
.header("Content-Type", "application/octet-stream")
|
||||
.body(block_contents.as_ssz_bytes().into())
|
||||
.map(|res: Response<Bytes>| {
|
||||
add_consensus_version_header(res, fork_name)
|
||||
})
|
||||
.map_err(|e| {
|
||||
warp_utils::reject::custom_server_error(format!(
|
||||
"failed to create response: {}",
|
||||
e
|
||||
))
|
||||
}),
|
||||
// Pose as a V2 endpoint so we return the fork `version`.
|
||||
_ => fork_versioned_response(V2, fork_name, block_contents)
|
||||
.map(|response| warp::reply::json(&response).into_response())
|
||||
.map(|res| add_consensus_version_header(res, fork_name)),
|
||||
}
|
||||
})
|
||||
},
|
||||
);
|
||||
@ -3697,12 +3722,13 @@ pub fn serve<T: BeaconChainTypes>(
|
||||
// send the response back to our original HTTP request
|
||||
// task via a channel.
|
||||
let builder_future = async move {
|
||||
let builder = chain
|
||||
let arc_builder = chain
|
||||
.execution_layer
|
||||
.as_ref()
|
||||
.ok_or(BeaconChainError::ExecutionLayerMissing)
|
||||
.map_err(warp_utils::reject::beacon_chain_error)?
|
||||
.builder()
|
||||
.builder();
|
||||
let builder = arc_builder
|
||||
.as_ref()
|
||||
.ok_or(BeaconChainError::BuilderMissing)
|
||||
.map_err(warp_utils::reject::beacon_chain_error)?;
|
||||
@ -4363,7 +4389,8 @@ pub fn serve<T: BeaconChainTypes>(
|
||||
.then(
|
||||
|task_spawner: TaskSpawner<T::EthSpec>, chain: Arc<BeaconChain<T>>| {
|
||||
task_spawner.spawn_async_with_rejection(Priority::P1, async move {
|
||||
let merge_readiness = chain.check_merge_readiness().await;
|
||||
let current_slot = chain.slot_clock.now_or_genesis().unwrap_or(Slot::new(0));
|
||||
let merge_readiness = chain.check_merge_readiness(current_slot).await;
|
||||
Ok::<_, warp::reject::Rejection>(
|
||||
warp::reply::json(&api_types::GenericResponse::from(merge_readiness))
|
||||
.into_response(),
|
||||
|
@ -126,17 +126,9 @@ pub async fn create_api_server<T: BeaconChainTypes>(
|
||||
test_runtime: &TestRuntime,
|
||||
log: Logger,
|
||||
) -> ApiServer<T::EthSpec, impl Future<Output = ()>> {
|
||||
// Get a random unused port.
|
||||
let port = unused_port::unused_tcp4_port().unwrap();
|
||||
create_api_server_on_port(chain, test_runtime, log, port).await
|
||||
}
|
||||
// Use port 0 to allocate a new unused port.
|
||||
let port = 0;
|
||||
|
||||
pub async fn create_api_server_on_port<T: BeaconChainTypes>(
|
||||
chain: Arc<BeaconChain<T>>,
|
||||
test_runtime: &TestRuntime,
|
||||
log: Logger,
|
||||
port: u16,
|
||||
) -> ApiServer<T::EthSpec, impl Future<Output = ()>> {
|
||||
let (network_senders, network_receivers) = NetworkSenders::new();
|
||||
|
||||
// Default metadata
|
||||
@ -149,8 +141,6 @@ pub async fn create_api_server_on_port<T: BeaconChainTypes>(
|
||||
let enr = EnrBuilder::new("v4").build(&enr_key).unwrap();
|
||||
let network_globals = Arc::new(NetworkGlobals::new(
|
||||
enr.clone(),
|
||||
Some(TCP_PORT),
|
||||
None,
|
||||
meta_data,
|
||||
vec![],
|
||||
false,
|
||||
|
@ -10,15 +10,14 @@ use eth2::{
|
||||
types::{BlockId as CoreBlockId, ForkChoiceNode, StateId as CoreStateId, *},
|
||||
BeaconNodeHttpClient, Error, StatusCode, Timeouts,
|
||||
};
|
||||
use execution_layer::test_utils::TestingBuilder;
|
||||
use execution_layer::test_utils::DEFAULT_BUILDER_THRESHOLD_WEI;
|
||||
use execution_layer::test_utils::{
|
||||
Operation, DEFAULT_BUILDER_PAYLOAD_VALUE_WEI, DEFAULT_MOCK_EL_PAYLOAD_VALUE_WEI,
|
||||
MockBuilder, Operation, DEFAULT_BUILDER_PAYLOAD_VALUE_WEI, DEFAULT_BUILDER_THRESHOLD_WEI,
|
||||
DEFAULT_MOCK_EL_PAYLOAD_VALUE_WEI,
|
||||
};
|
||||
use futures::stream::{Stream, StreamExt};
|
||||
use futures::FutureExt;
|
||||
use http_api::{
|
||||
test_utils::{create_api_server, create_api_server_on_port, ApiServer},
|
||||
test_utils::{create_api_server, ApiServer},
|
||||
BlockId, StateId,
|
||||
};
|
||||
use lighthouse_network::{Enr, EnrExt, PeerId};
|
||||
@ -73,7 +72,7 @@ struct ApiTester {
|
||||
network_rx: NetworkReceivers<E>,
|
||||
local_enr: Enr,
|
||||
external_peer_id: PeerId,
|
||||
mock_builder: Option<Arc<TestingBuilder<E>>>,
|
||||
mock_builder: Option<Arc<MockBuilder<E>>>,
|
||||
}
|
||||
|
||||
struct ApiTesterConfig {
|
||||
@ -120,24 +119,28 @@ impl ApiTester {
|
||||
}
|
||||
|
||||
pub async fn new_from_config(config: ApiTesterConfig) -> Self {
|
||||
// Get a random unused port
|
||||
let spec = config.spec;
|
||||
let port = unused_port::unused_tcp4_port().unwrap();
|
||||
let beacon_url = SensitiveUrl::parse(format!("http://127.0.0.1:{port}").as_str()).unwrap();
|
||||
|
||||
let harness = Arc::new(
|
||||
BeaconChainHarness::builder(MainnetEthSpec)
|
||||
.spec(spec.clone())
|
||||
.chain_config(ChainConfig {
|
||||
reconstruct_historic_states: config.retain_historic_states,
|
||||
..ChainConfig::default()
|
||||
})
|
||||
.logger(logging::test_logger())
|
||||
.deterministic_keypairs(VALIDATOR_COUNT)
|
||||
.fresh_ephemeral_store()
|
||||
.mock_execution_layer_with_builder(beacon_url.clone(), config.builder_threshold)
|
||||
.build(),
|
||||
);
|
||||
let mut harness = BeaconChainHarness::builder(MainnetEthSpec)
|
||||
.spec(spec.clone())
|
||||
.chain_config(ChainConfig {
|
||||
reconstruct_historic_states: config.retain_historic_states,
|
||||
..ChainConfig::default()
|
||||
})
|
||||
.logger(logging::test_logger())
|
||||
.deterministic_keypairs(VALIDATOR_COUNT)
|
||||
.fresh_ephemeral_store()
|
||||
.mock_execution_layer_with_config()
|
||||
.build();
|
||||
|
||||
harness
|
||||
.mock_execution_layer
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.server
|
||||
.execution_block_generator()
|
||||
.move_to_terminal_block()
|
||||
.unwrap();
|
||||
|
||||
harness.advance_slot();
|
||||
|
||||
@ -247,29 +250,40 @@ impl ApiTester {
|
||||
|
||||
let ApiServer {
|
||||
server,
|
||||
listening_socket: _,
|
||||
listening_socket,
|
||||
network_rx,
|
||||
local_enr,
|
||||
external_peer_id,
|
||||
} = create_api_server_on_port(chain.clone(), &harness.runtime, log, port).await;
|
||||
} = create_api_server(chain.clone(), &harness.runtime, log).await;
|
||||
|
||||
harness.runtime.task_executor.spawn(server, "api_server");
|
||||
|
||||
// Late-initalize the mock builder now that the mock execution node and beacon API ports
|
||||
// have been allocated.
|
||||
let beacon_api_port = listening_socket.port();
|
||||
let beacon_url =
|
||||
SensitiveUrl::parse(format!("http://127.0.0.1:{beacon_api_port}").as_str()).unwrap();
|
||||
let mock_builder_server = harness.set_mock_builder(beacon_url.clone());
|
||||
|
||||
// Start the mock builder service prior to building the chain out.
|
||||
harness.runtime.task_executor.spawn(
|
||||
async move {
|
||||
if let Err(e) = mock_builder_server.await {
|
||||
panic!("error in mock builder server: {e:?}");
|
||||
}
|
||||
},
|
||||
"mock_builder_server",
|
||||
);
|
||||
|
||||
let mock_builder = harness.mock_builder.clone();
|
||||
|
||||
let client = BeaconNodeHttpClient::new(
|
||||
beacon_url,
|
||||
Timeouts::set_all(Duration::from_secs(SECONDS_PER_SLOT)),
|
||||
);
|
||||
|
||||
let builder_ref = harness.mock_builder.as_ref().unwrap().clone();
|
||||
harness.runtime.task_executor.spawn(
|
||||
async move { builder_ref.run().await },
|
||||
"mock_builder_server",
|
||||
);
|
||||
|
||||
let mock_builder = harness.mock_builder.clone();
|
||||
|
||||
Self {
|
||||
harness,
|
||||
harness: Arc::new(harness),
|
||||
chain,
|
||||
client,
|
||||
next_block,
|
||||
@ -383,7 +397,6 @@ impl ApiTester {
|
||||
.mock_builder
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.builder
|
||||
.add_operation(Operation::Value(Uint256::from(
|
||||
DEFAULT_BUILDER_THRESHOLD_WEI,
|
||||
)));
|
||||
@ -406,7 +419,6 @@ impl ApiTester {
|
||||
.mock_builder
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.builder
|
||||
.add_operation(Operation::Value(Uint256::from(
|
||||
DEFAULT_BUILDER_PAYLOAD_VALUE_WEI,
|
||||
)));
|
||||
@ -2528,6 +2540,70 @@ impl ApiTester {
|
||||
self
|
||||
}
|
||||
|
||||
pub async fn test_block_production_ssz(self) -> Self {
|
||||
let fork = self.chain.canonical_head.cached_head().head_fork();
|
||||
let genesis_validators_root = self.chain.genesis_validators_root;
|
||||
|
||||
for _ in 0..E::slots_per_epoch() * 3 {
|
||||
let slot = self.chain.slot().unwrap();
|
||||
let epoch = self.chain.epoch().unwrap();
|
||||
|
||||
let proposer_pubkey_bytes = self
|
||||
.client
|
||||
.get_validator_duties_proposer(epoch)
|
||||
.await
|
||||
.unwrap()
|
||||
.data
|
||||
.into_iter()
|
||||
.find(|duty| duty.slot == slot)
|
||||
.map(|duty| duty.pubkey)
|
||||
.unwrap();
|
||||
let proposer_pubkey = (&proposer_pubkey_bytes).try_into().unwrap();
|
||||
|
||||
let sk = self
|
||||
.validator_keypairs()
|
||||
.iter()
|
||||
.find(|kp| kp.pk == proposer_pubkey)
|
||||
.map(|kp| kp.sk.clone())
|
||||
.unwrap();
|
||||
|
||||
let randao_reveal = {
|
||||
let domain = self.chain.spec.get_domain(
|
||||
epoch,
|
||||
Domain::Randao,
|
||||
&fork,
|
||||
genesis_validators_root,
|
||||
);
|
||||
let message = epoch.signing_root(domain);
|
||||
sk.sign(message).into()
|
||||
};
|
||||
|
||||
let block_bytes = self
|
||||
.client
|
||||
.get_validator_blocks_ssz::<E, FullPayload<E>>(slot, &randao_reveal, None)
|
||||
.await
|
||||
.unwrap()
|
||||
.expect("block bytes");
|
||||
|
||||
let block =
|
||||
BeaconBlock::<E, FullPayload<E>>::from_ssz_bytes(&block_bytes, &self.chain.spec)
|
||||
.expect("block bytes can be decoded");
|
||||
|
||||
let signed_block = block.sign(&sk, &fork, genesis_validators_root, &self.chain.spec);
|
||||
|
||||
self.client
|
||||
.post_beacon_blocks_ssz(&signed_block)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(self.chain.head_beacon_block().as_ref(), &signed_block);
|
||||
|
||||
self.chain.slot_clock.set_slot(slot.as_u64() + 1);
|
||||
}
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub async fn test_block_production_no_verify_randao(self) -> Self {
|
||||
for _ in 0..E::slots_per_epoch() {
|
||||
let slot = self.chain.slot().unwrap();
|
||||
@ -2713,12 +2789,18 @@ impl ApiTester {
|
||||
sk.sign(message).into()
|
||||
};
|
||||
|
||||
let block_contents = self
|
||||
let block_contents_bytes = self
|
||||
.client
|
||||
.get_validator_blinded_blocks::<E, Payload>(slot, &randao_reveal, None)
|
||||
.get_validator_blinded_blocks_ssz::<E, Payload>(slot, &randao_reveal, None)
|
||||
.await
|
||||
.unwrap()
|
||||
.data;
|
||||
.expect("block bytes");
|
||||
|
||||
let block_contents = BlockContents::<E, Payload>::from_ssz_bytes(
|
||||
&block_contents_bytes,
|
||||
&self.chain.spec,
|
||||
)
|
||||
.expect("block bytes can be decoded");
|
||||
|
||||
let signed_block_contents =
|
||||
block_contents.sign(&sk, &fork, genesis_validators_root, &self.chain.spec);
|
||||
@ -3309,6 +3391,7 @@ impl ApiTester {
|
||||
.unwrap()
|
||||
.get_payload_by_root(&payload.tree_hash_root())
|
||||
.is_none());
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
@ -3317,7 +3400,6 @@ impl ApiTester {
|
||||
self.mock_builder
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.builder
|
||||
.add_operation(Operation::GasLimit(30_000_000));
|
||||
|
||||
let slot = self.chain.slot().unwrap();
|
||||
@ -3361,7 +3443,6 @@ impl ApiTester {
|
||||
self.mock_builder
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.builder
|
||||
.add_operation(Operation::FeeRecipient(test_fee_recipient));
|
||||
|
||||
let slot = self.chain.slot().unwrap();
|
||||
@ -3404,7 +3485,6 @@ impl ApiTester {
|
||||
self.mock_builder
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.builder
|
||||
.add_operation(Operation::ParentHash(invalid_parent_hash));
|
||||
|
||||
let slot = self.chain.slot().unwrap();
|
||||
@ -3454,7 +3534,6 @@ impl ApiTester {
|
||||
self.mock_builder
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.builder
|
||||
.add_operation(Operation::PrevRandao(invalid_prev_randao));
|
||||
|
||||
let slot = self.chain.slot().unwrap();
|
||||
@ -3500,7 +3579,6 @@ impl ApiTester {
|
||||
self.mock_builder
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.builder
|
||||
.add_operation(Operation::BlockNumber(invalid_block_number));
|
||||
|
||||
let slot = self.chain.slot().unwrap();
|
||||
@ -3548,7 +3626,6 @@ impl ApiTester {
|
||||
self.mock_builder
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.builder
|
||||
.add_operation(Operation::Timestamp(invalid_timestamp));
|
||||
|
||||
let slot = self.chain.slot().unwrap();
|
||||
@ -3589,11 +3666,7 @@ impl ApiTester {
|
||||
}
|
||||
|
||||
pub async fn test_payload_rejects_invalid_signature(self) -> Self {
|
||||
self.mock_builder
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.builder
|
||||
.invalid_signatures();
|
||||
self.mock_builder.as_ref().unwrap().invalid_signatures();
|
||||
|
||||
let slot = self.chain.slot().unwrap();
|
||||
let epoch = self.chain.epoch().unwrap();
|
||||
@ -3878,7 +3951,6 @@ impl ApiTester {
|
||||
self.mock_builder
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.builder
|
||||
.add_operation(Operation::Value(Uint256::from(
|
||||
DEFAULT_BUILDER_THRESHOLD_WEI - 1,
|
||||
)));
|
||||
@ -3916,7 +3988,6 @@ impl ApiTester {
|
||||
self.mock_builder
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.builder
|
||||
.add_operation(Operation::Value(Uint256::from(
|
||||
DEFAULT_MOCK_EL_PAYLOAD_VALUE_WEI + 1,
|
||||
)));
|
||||
@ -3954,7 +4025,6 @@ impl ApiTester {
|
||||
self.mock_builder
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.builder
|
||||
.add_operation(Operation::Value(Uint256::from(
|
||||
DEFAULT_MOCK_EL_PAYLOAD_VALUE_WEI,
|
||||
)));
|
||||
@ -3992,7 +4062,6 @@ impl ApiTester {
|
||||
self.mock_builder
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.builder
|
||||
.add_operation(Operation::Value(Uint256::from(
|
||||
DEFAULT_MOCK_EL_PAYLOAD_VALUE_WEI - 1,
|
||||
)));
|
||||
@ -4030,7 +4099,6 @@ impl ApiTester {
|
||||
self.mock_builder
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.builder
|
||||
.add_operation(Operation::Value(Uint256::from(
|
||||
DEFAULT_MOCK_EL_PAYLOAD_VALUE_WEI + 1,
|
||||
)));
|
||||
@ -4104,7 +4172,6 @@ impl ApiTester {
|
||||
self.mock_builder
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.builder
|
||||
.add_operation(Operation::Value(Uint256::from(
|
||||
DEFAULT_MOCK_EL_PAYLOAD_VALUE_WEI + 1,
|
||||
)));
|
||||
@ -4112,7 +4179,6 @@ impl ApiTester {
|
||||
self.mock_builder
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.builder
|
||||
.add_operation(Operation::WithdrawalsRoot(Hash256::repeat_byte(0x42)));
|
||||
|
||||
let slot = self.chain.slot().unwrap();
|
||||
@ -4976,6 +5042,20 @@ async fn block_production_verify_randao_invalid() {
|
||||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn block_production_ssz_full_payload() {
|
||||
ApiTester::new().await.test_block_production_ssz().await;
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn block_production_ssz_with_skip_slots() {
|
||||
ApiTester::new()
|
||||
.await
|
||||
.skip_slots(E::slots_per_epoch() * 2)
|
||||
.test_block_production_ssz()
|
||||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn blinded_block_production_full_payload_premerge() {
|
||||
ApiTester::new()
|
||||
|
@ -2,25 +2,25 @@
|
||||
name = "http_metrics"
|
||||
version = "0.1.0"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>"]
|
||||
edition = "2021"
|
||||
edition = { workspace = true }
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
warp = "0.3.2"
|
||||
serde = { version = "1.0.116", features = ["derive"] }
|
||||
slog = "2.5.2"
|
||||
beacon_chain = { path = "../beacon_chain" }
|
||||
store = { path = "../store" }
|
||||
lighthouse_network = { path = "../lighthouse_network" }
|
||||
slot_clock = { path = "../../common/slot_clock" }
|
||||
lighthouse_metrics = { path = "../../common/lighthouse_metrics" }
|
||||
lighthouse_version = { path = "../../common/lighthouse_version" }
|
||||
warp_utils = { path = "../../common/warp_utils" }
|
||||
malloc_utils = { path = "../../common/malloc_utils" }
|
||||
warp = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
slog = { workspace = true }
|
||||
beacon_chain = { workspace = true }
|
||||
store = { workspace = true }
|
||||
lighthouse_network = { workspace = true }
|
||||
slot_clock = { workspace = true }
|
||||
lighthouse_metrics = { workspace = true }
|
||||
lighthouse_version = { workspace = true }
|
||||
warp_utils = { workspace = true }
|
||||
malloc_utils = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
tokio = { version = "1.14.0", features = ["sync"] }
|
||||
reqwest = { version = "0.11.0", features = ["json"] }
|
||||
environment = { path = "../../lighthouse/environment" }
|
||||
types = { path = "../../consensus/types" }
|
||||
tokio = { workspace = true }
|
||||
reqwest = { workspace = true }
|
||||
environment = { workspace = true }
|
||||
types = { workspace = true }
|
||||
|
@ -2,63 +2,64 @@
|
||||
name = "lighthouse_network"
|
||||
version = "0.2.0"
|
||||
authors = ["Sigma Prime <contact@sigmaprime.io>"]
|
||||
edition = "2021"
|
||||
edition = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
discv5 = { version = "0.3.1", features = ["libp2p"] }
|
||||
unsigned-varint = { version = "0.6.0", features = ["codec"] }
|
||||
types = { path = "../../consensus/types" }
|
||||
ssz_types = "0.5.4"
|
||||
serde = { version = "1.0.116", features = ["derive"] }
|
||||
serde_derive = "1.0.116"
|
||||
ethereum_ssz = "0.5.0"
|
||||
ethereum_ssz_derive = "0.5.3"
|
||||
tree_hash = "0.5.2"
|
||||
tree_hash_derive = "0.5.0"
|
||||
slog = { version = "2.5.2", features = ["max_level_trace"] }
|
||||
lighthouse_version = { path = "../../common/lighthouse_version" }
|
||||
tokio = { version = "1.14.0", features = ["time", "macros"] }
|
||||
futures = "0.3.7"
|
||||
error-chain = "0.12.4"
|
||||
dirs = "3.0.1"
|
||||
fnv = "1.0.7"
|
||||
lazy_static = "1.4.0"
|
||||
lighthouse_metrics = { path = "../../common/lighthouse_metrics" }
|
||||
smallvec = "1.6.1"
|
||||
tokio-io-timeout = "1.1.1"
|
||||
lru = "0.7.1"
|
||||
lru_cache = { path = "../../common/lru_cache" }
|
||||
parking_lot = "0.12.0"
|
||||
sha2 = "0.10"
|
||||
snap = "1.0.1"
|
||||
hex = "0.4.2"
|
||||
tokio-util = { version = "0.6.2", features = ["codec", "compat", "time"] }
|
||||
tiny-keccak = "2.0.2"
|
||||
task_executor = { path = "../../common/task_executor" }
|
||||
rand = "0.8.5"
|
||||
directory = { path = "../../common/directory" }
|
||||
regex = "1.5.5"
|
||||
strum = { version = "0.24.0", features = ["derive"] }
|
||||
superstruct = "0.5.0"
|
||||
discv5 = { workspace = true }
|
||||
unsigned-varint = { version = "0.6", features = ["codec"] }
|
||||
ssz_types = { workspace = true }
|
||||
types = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_derive = "1"
|
||||
ethereum_ssz = { workspace = true }
|
||||
ethereum_ssz_derive = { workspace = true }
|
||||
tree_hash = { workspace = true }
|
||||
tree_hash_derive = { workspace = true }
|
||||
slog = { workspace = true }
|
||||
lighthouse_version = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
error-chain = { workspace = true }
|
||||
dirs = { workspace = true }
|
||||
fnv = { workspace = true }
|
||||
lazy_static = { workspace = true }
|
||||
lighthouse_metrics = { workspace = true }
|
||||
smallvec = { workspace = true }
|
||||
tokio-io-timeout = "1"
|
||||
lru = { workspace = true }
|
||||
lru_cache = { workspace = true }
|
||||
parking_lot = { workspace = true }
|
||||
sha2 = { workspace = true }
|
||||
snap = { workspace = true }
|
||||
hex = { workspace = true }
|
||||
tokio-util = { workspace = true }
|
||||
tiny-keccak = "2"
|
||||
task_executor = { workspace = true }
|
||||
rand = { workspace = true }
|
||||
directory = { workspace = true }
|
||||
regex = { workspace = true }
|
||||
strum = { workspace = true }
|
||||
superstruct = { workspace = true }
|
||||
prometheus-client = "0.21.0"
|
||||
unused_port = { path = "../../common/unused_port" }
|
||||
delay_map = "0.3.0"
|
||||
unused_port = { workspace = true }
|
||||
delay_map = { workspace = true }
|
||||
void = "1"
|
||||
libp2p-quic= { version = "0.9.2", features=["tokio"]}
|
||||
libp2p-mplex = "0.40.0"
|
||||
|
||||
[dependencies.libp2p]
|
||||
version = "0.52"
|
||||
default-features = false
|
||||
features = ["websocket", "identify", "yamux", "noise", "gossipsub", "dns", "tcp", "tokio", "plaintext", "secp256k1", "macros", "ecdsa"]
|
||||
features = ["identify", "yamux", "noise", "gossipsub", "dns", "tcp", "tokio", "plaintext", "secp256k1", "macros", "ecdsa"]
|
||||
|
||||
[dev-dependencies]
|
||||
slog-term = "2.6.0"
|
||||
slog-async = "2.5.0"
|
||||
tempfile = "3.1.0"
|
||||
exit-future = "0.2.0"
|
||||
void = "1"
|
||||
quickcheck = "0.9.2"
|
||||
quickcheck_macros = "0.9.1"
|
||||
slog-term = { workspace = true }
|
||||
slog-async = { workspace = true }
|
||||
tempfile = { workspace = true }
|
||||
exit-future = { workspace = true }
|
||||
quickcheck = { workspace = true }
|
||||
quickcheck_macros = { workspace = true }
|
||||
|
||||
[features]
|
||||
libp2p-websocket = []
|
||||
libp2p-websocket = []
|
||||
|
||||
|
@ -58,18 +58,24 @@ pub struct Config {
|
||||
/// that no discovery address has been set in the CLI args.
|
||||
pub enr_address: (Option<Ipv4Addr>, Option<Ipv6Addr>),
|
||||
|
||||
/// The udp4 port to broadcast to peers in order to reach back for discovery.
|
||||
/// The udp ipv4 port to broadcast to peers in order to reach back for discovery.
|
||||
pub enr_udp4_port: Option<u16>,
|
||||
|
||||
/// The tcp4 port to broadcast to peers in order to reach back for libp2p services.
|
||||
/// The quic ipv4 port to broadcast to peers in order to reach back for libp2p services.
|
||||
pub enr_quic4_port: Option<u16>,
|
||||
|
||||
/// The tcp ipv4 port to broadcast to peers in order to reach back for libp2p services.
|
||||
pub enr_tcp4_port: Option<u16>,
|
||||
|
||||
/// The udp6 port to broadcast to peers in order to reach back for discovery.
|
||||
/// The udp ipv6 port to broadcast to peers in order to reach back for discovery.
|
||||
pub enr_udp6_port: Option<u16>,
|
||||
|
||||
/// The tcp6 port to broadcast to peers in order to reach back for libp2p services.
|
||||
/// The tcp ipv6 port to broadcast to peers in order to reach back for libp2p services.
|
||||
pub enr_tcp6_port: Option<u16>,
|
||||
|
||||
/// The quic ipv6 port to broadcast to peers in order to reach back for libp2p services.
|
||||
pub enr_quic6_port: Option<u16>,
|
||||
|
||||
/// Target number of connected peers.
|
||||
pub target_peers: usize,
|
||||
|
||||
@ -102,6 +108,9 @@ pub struct Config {
|
||||
/// Disables the discovery protocol from starting.
|
||||
pub disable_discovery: bool,
|
||||
|
||||
/// Disables quic support.
|
||||
pub disable_quic_support: bool,
|
||||
|
||||
/// Attempt to construct external port mappings with UPnP.
|
||||
pub upnp_enabled: bool,
|
||||
|
||||
@ -149,57 +158,76 @@ impl Config {
|
||||
/// Sets the listening address to use an ipv4 address. The discv5 ip_mode and table filter are
|
||||
/// adjusted accordingly to ensure addresses that are present in the enr are globally
|
||||
/// reachable.
|
||||
pub fn set_ipv4_listening_address(&mut self, addr: Ipv4Addr, tcp_port: u16, udp_port: u16) {
|
||||
pub fn set_ipv4_listening_address(
|
||||
&mut self,
|
||||
addr: Ipv4Addr,
|
||||
tcp_port: u16,
|
||||
disc_port: u16,
|
||||
quic_port: u16,
|
||||
) {
|
||||
self.listen_addresses = ListenAddress::V4(ListenAddr {
|
||||
addr,
|
||||
udp_port,
|
||||
disc_port,
|
||||
quic_port,
|
||||
tcp_port,
|
||||
});
|
||||
self.discv5_config.listen_config = discv5::ListenConfig::from_ip(addr.into(), udp_port);
|
||||
self.discv5_config.listen_config = discv5::ListenConfig::from_ip(addr.into(), disc_port);
|
||||
self.discv5_config.table_filter = |enr| enr.ip4().as_ref().map_or(false, is_global_ipv4)
|
||||
}
|
||||
|
||||
/// Sets the listening address to use an ipv6 address. The discv5 ip_mode and table filter is
|
||||
/// adjusted accordingly to ensure addresses that are present in the enr are globally
|
||||
/// reachable.
|
||||
pub fn set_ipv6_listening_address(&mut self, addr: Ipv6Addr, tcp_port: u16, udp_port: u16) {
|
||||
pub fn set_ipv6_listening_address(
|
||||
&mut self,
|
||||
addr: Ipv6Addr,
|
||||
tcp_port: u16,
|
||||
disc_port: u16,
|
||||
quic_port: u16,
|
||||
) {
|
||||
self.listen_addresses = ListenAddress::V6(ListenAddr {
|
||||
addr,
|
||||
udp_port,
|
||||
disc_port,
|
||||
quic_port,
|
||||
tcp_port,
|
||||
});
|
||||
|
||||
self.discv5_config.listen_config = discv5::ListenConfig::from_ip(addr.into(), udp_port);
|
||||
self.discv5_config.listen_config = discv5::ListenConfig::from_ip(addr.into(), disc_port);
|
||||
self.discv5_config.table_filter = |enr| enr.ip6().as_ref().map_or(false, is_global_ipv6)
|
||||
}
|
||||
|
||||
/// Sets the listening address to use both an ipv4 and ipv6 address. The discv5 ip_mode and
|
||||
/// table filter is adjusted accordingly to ensure addresses that are present in the enr are
|
||||
/// globally reachable.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn set_ipv4_ipv6_listening_addresses(
|
||||
&mut self,
|
||||
v4_addr: Ipv4Addr,
|
||||
tcp4_port: u16,
|
||||
udp4_port: u16,
|
||||
disc4_port: u16,
|
||||
quic4_port: u16,
|
||||
v6_addr: Ipv6Addr,
|
||||
tcp6_port: u16,
|
||||
udp6_port: u16,
|
||||
disc6_port: u16,
|
||||
quic6_port: u16,
|
||||
) {
|
||||
self.listen_addresses = ListenAddress::DualStack(
|
||||
ListenAddr {
|
||||
addr: v4_addr,
|
||||
udp_port: udp4_port,
|
||||
disc_port: disc4_port,
|
||||
quic_port: quic4_port,
|
||||
tcp_port: tcp4_port,
|
||||
},
|
||||
ListenAddr {
|
||||
addr: v6_addr,
|
||||
udp_port: udp6_port,
|
||||
disc_port: disc6_port,
|
||||
quic_port: quic6_port,
|
||||
tcp_port: tcp6_port,
|
||||
},
|
||||
);
|
||||
self.discv5_config.listen_config = discv5::ListenConfig::default()
|
||||
.with_ipv4(v4_addr, udp4_port)
|
||||
.with_ipv6(v6_addr, udp6_port);
|
||||
.with_ipv4(v4_addr, disc4_port)
|
||||
.with_ipv6(v6_addr, disc6_port);
|
||||
|
||||
self.discv5_config.table_filter = |enr| match (&enr.ip4(), &enr.ip6()) {
|
||||
(None, None) => false,
|
||||
@ -213,27 +241,32 @@ impl Config {
|
||||
match listen_addr {
|
||||
ListenAddress::V4(ListenAddr {
|
||||
addr,
|
||||
udp_port,
|
||||
disc_port,
|
||||
quic_port,
|
||||
tcp_port,
|
||||
}) => self.set_ipv4_listening_address(addr, tcp_port, udp_port),
|
||||
}) => self.set_ipv4_listening_address(addr, tcp_port, disc_port, quic_port),
|
||||
ListenAddress::V6(ListenAddr {
|
||||
addr,
|
||||
udp_port,
|
||||
disc_port,
|
||||
quic_port,
|
||||
tcp_port,
|
||||
}) => self.set_ipv6_listening_address(addr, tcp_port, udp_port),
|
||||
}) => self.set_ipv6_listening_address(addr, tcp_port, disc_port, quic_port),
|
||||
ListenAddress::DualStack(
|
||||
ListenAddr {
|
||||
addr: ip4addr,
|
||||
udp_port: udp4_port,
|
||||
disc_port: disc4_port,
|
||||
quic_port: quic4_port,
|
||||
tcp_port: tcp4_port,
|
||||
},
|
||||
ListenAddr {
|
||||
addr: ip6addr,
|
||||
udp_port: udp6_port,
|
||||
disc_port: disc6_port,
|
||||
quic_port: quic6_port,
|
||||
tcp_port: tcp6_port,
|
||||
},
|
||||
) => self.set_ipv4_ipv6_listening_addresses(
|
||||
ip4addr, tcp4_port, udp4_port, ip6addr, tcp6_port, udp6_port,
|
||||
ip4addr, tcp4_port, disc4_port, quic4_port, ip6addr, tcp6_port, disc6_port,
|
||||
quic6_port,
|
||||
),
|
||||
}
|
||||
}
|
||||
@ -272,7 +305,8 @@ impl Default for Config {
|
||||
);
|
||||
let listen_addresses = ListenAddress::V4(ListenAddr {
|
||||
addr: Ipv4Addr::UNSPECIFIED,
|
||||
udp_port: 9000,
|
||||
disc_port: 9000,
|
||||
quic_port: 9001,
|
||||
tcp_port: 9000,
|
||||
});
|
||||
|
||||
@ -305,10 +339,11 @@ impl Default for Config {
|
||||
network_dir,
|
||||
listen_addresses,
|
||||
enr_address: (None, None),
|
||||
|
||||
enr_udp4_port: None,
|
||||
enr_quic4_port: None,
|
||||
enr_tcp4_port: None,
|
||||
enr_udp6_port: None,
|
||||
enr_quic6_port: None,
|
||||
enr_tcp6_port: None,
|
||||
target_peers: 50,
|
||||
gs_config,
|
||||
@ -320,6 +355,7 @@ impl Default for Config {
|
||||
disable_peer_scoring: false,
|
||||
client_version: lighthouse_version::version_with_platform(),
|
||||
disable_discovery: false,
|
||||
disable_quic_support: false,
|
||||
upnp_enabled: true,
|
||||
network_load: 3,
|
||||
private: false,
|
||||
@ -417,7 +453,7 @@ pub fn gossipsub_config(
|
||||
// We use the first 8 bytes of SHA256(topic, data) for content addressing
|
||||
let fast_gossip_message_id = |message: &gossipsub::RawMessage| {
|
||||
let data = [message.topic.as_str().as_bytes(), &message.data].concat();
|
||||
gossipsub::FastMessageId::from(&Sha256::digest(data)[..8])
|
||||
gossipsub::FastMessageId::from(&Sha256::digest(&data)[..8])
|
||||
};
|
||||
fn prefix(
|
||||
prefix: [u8; 4],
|
||||
|
@ -17,6 +17,8 @@ use std::path::Path;
|
||||
use std::str::FromStr;
|
||||
use types::{EnrForkId, EthSpec};
|
||||
|
||||
use super::enr_ext::{EnrExt, QUIC6_ENR_KEY, QUIC_ENR_KEY};
|
||||
|
||||
/// The ENR field specifying the fork id.
|
||||
pub const ETH2_ENR_KEY: &str = "eth2";
|
||||
/// The ENR field specifying the attestation subnet bitfield.
|
||||
@ -142,7 +144,7 @@ pub fn build_or_load_enr<T: EthSpec>(
|
||||
|
||||
pub fn create_enr_builder_from_config<T: EnrKey>(
|
||||
config: &NetworkConfig,
|
||||
enable_tcp: bool,
|
||||
enable_libp2p: bool,
|
||||
) -> EnrBuilder<T> {
|
||||
let mut builder = EnrBuilder::new("v4");
|
||||
let (maybe_ipv4_address, maybe_ipv6_address) = &config.enr_address;
|
||||
@ -163,7 +165,28 @@ pub fn create_enr_builder_from_config<T: EnrKey>(
|
||||
builder.udp6(udp6_port);
|
||||
}
|
||||
|
||||
if enable_tcp {
|
||||
if enable_libp2p {
|
||||
// Add QUIC fields to the ENR.
|
||||
// Since QUIC is used as an alternative transport for the libp2p protocols,
|
||||
// the related fields should only be added when both QUIC and libp2p are enabled
|
||||
if !config.disable_quic_support {
|
||||
// If we are listening on ipv4, add the quic ipv4 port.
|
||||
if let Some(quic4_port) = config
|
||||
.enr_quic4_port
|
||||
.or_else(|| config.listen_addrs().v4().map(|v4_addr| v4_addr.quic_port))
|
||||
{
|
||||
builder.add_value(QUIC_ENR_KEY, &quic4_port);
|
||||
}
|
||||
|
||||
// If we are listening on ipv6, add the quic ipv6 port.
|
||||
if let Some(quic6_port) = config
|
||||
.enr_quic6_port
|
||||
.or_else(|| config.listen_addrs().v6().map(|v6_addr| v6_addr.quic_port))
|
||||
{
|
||||
builder.add_value(QUIC6_ENR_KEY, &quic6_port);
|
||||
}
|
||||
}
|
||||
|
||||
// If the ENR port is not set, and we are listening over that ip version, use the listening port instead.
|
||||
let tcp4_port = config
|
||||
.enr_tcp4_port
|
||||
@ -218,6 +241,9 @@ fn compare_enr(local_enr: &Enr, disk_enr: &Enr) -> bool {
|
||||
// tcp ports must match
|
||||
&& local_enr.tcp4() == disk_enr.tcp4()
|
||||
&& local_enr.tcp6() == disk_enr.tcp6()
|
||||
// quic ports must match
|
||||
&& local_enr.quic4() == disk_enr.quic4()
|
||||
&& local_enr.quic6() == disk_enr.quic6()
|
||||
// must match on the same fork
|
||||
&& local_enr.get(ETH2_ENR_KEY) == disk_enr.get(ETH2_ENR_KEY)
|
||||
// take preference over disk udp port if one is not specified
|
||||
|
@ -6,12 +6,15 @@ use libp2p::core::multiaddr::Protocol;
|
||||
use libp2p::identity::{ed25519, secp256k1, KeyType, Keypair, PublicKey};
|
||||
use tiny_keccak::{Hasher, Keccak};
|
||||
|
||||
pub const QUIC_ENR_KEY: &str = "quic";
|
||||
pub const QUIC6_ENR_KEY: &str = "quic6";
|
||||
|
||||
/// Extend ENR for libp2p types.
|
||||
pub trait EnrExt {
|
||||
/// The libp2p `PeerId` for the record.
|
||||
fn peer_id(&self) -> PeerId;
|
||||
|
||||
/// Returns a list of multiaddrs if the ENR has an `ip` and either a `tcp` or `udp` key **or** an `ip6` and either a `tcp6` or `udp6`.
|
||||
/// Returns a list of multiaddrs if the ENR has an `ip` and one of [`tcp`,`udp`,`quic`] key **or** an `ip6` and one of [`tcp6`,`udp6`,`quic6`].
|
||||
/// The vector remains empty if these fields are not defined.
|
||||
fn multiaddr(&self) -> Vec<Multiaddr>;
|
||||
|
||||
@ -26,6 +29,15 @@ pub trait EnrExt {
|
||||
|
||||
/// Returns any multiaddrs that contain the TCP protocol.
|
||||
fn multiaddr_tcp(&self) -> Vec<Multiaddr>;
|
||||
|
||||
/// Returns any QUIC multiaddrs that are registered in this ENR.
|
||||
fn multiaddr_quic(&self) -> Vec<Multiaddr>;
|
||||
|
||||
/// Returns the quic port if one is set.
|
||||
fn quic4(&self) -> Option<u16>;
|
||||
|
||||
/// Returns the quic6 port if one is set.
|
||||
fn quic6(&self) -> Option<u16>;
|
||||
}
|
||||
|
||||
/// Extend ENR CombinedPublicKey for libp2p types.
|
||||
@ -49,7 +61,17 @@ impl EnrExt for Enr {
|
||||
self.public_key().as_peer_id()
|
||||
}
|
||||
|
||||
/// Returns a list of multiaddrs if the ENR has an `ip` and either a `tcp` or `udp` key **or** an `ip6` and either a `tcp6` or `udp6`.
|
||||
/// Returns the quic port if one is set.
|
||||
fn quic4(&self) -> Option<u16> {
|
||||
self.get_decodable(QUIC_ENR_KEY).and_then(Result::ok)
|
||||
}
|
||||
|
||||
/// Returns the quic6 port if one is set.
|
||||
fn quic6(&self) -> Option<u16> {
|
||||
self.get_decodable(QUIC6_ENR_KEY).and_then(Result::ok)
|
||||
}
|
||||
|
||||
/// Returns a list of multiaddrs if the ENR has an `ip` and either a `tcp`, `quic` or `udp` key **or** an `ip6` and either a `tcp6` `quic6` or `udp6`.
|
||||
/// The vector remains empty if these fields are not defined.
|
||||
fn multiaddr(&self) -> Vec<Multiaddr> {
|
||||
let mut multiaddrs: Vec<Multiaddr> = Vec::new();
|
||||
@ -59,6 +81,12 @@ impl EnrExt for Enr {
|
||||
multiaddr.push(Protocol::Udp(udp));
|
||||
multiaddrs.push(multiaddr);
|
||||
}
|
||||
if let Some(quic) = self.quic4() {
|
||||
let mut multiaddr: Multiaddr = ip.into();
|
||||
multiaddr.push(Protocol::Udp(quic));
|
||||
multiaddr.push(Protocol::QuicV1);
|
||||
multiaddrs.push(multiaddr);
|
||||
}
|
||||
|
||||
if let Some(tcp) = self.tcp4() {
|
||||
let mut multiaddr: Multiaddr = ip.into();
|
||||
@ -73,6 +101,13 @@ impl EnrExt for Enr {
|
||||
multiaddrs.push(multiaddr);
|
||||
}
|
||||
|
||||
if let Some(quic6) = self.quic6() {
|
||||
let mut multiaddr: Multiaddr = ip6.into();
|
||||
multiaddr.push(Protocol::Udp(quic6));
|
||||
multiaddr.push(Protocol::QuicV1);
|
||||
multiaddrs.push(multiaddr);
|
||||
}
|
||||
|
||||
if let Some(tcp6) = self.tcp6() {
|
||||
let mut multiaddr: Multiaddr = ip6.into();
|
||||
multiaddr.push(Protocol::Tcp(tcp6));
|
||||
@ -174,8 +209,30 @@ impl EnrExt for Enr {
|
||||
multiaddrs
|
||||
}
|
||||
|
||||
/// Returns a list of multiaddrs if the ENR has an `ip` and a `quic` key **or** an `ip6` and a `quic6`.
|
||||
fn multiaddr_quic(&self) -> Vec<Multiaddr> {
|
||||
let mut multiaddrs: Vec<Multiaddr> = Vec::new();
|
||||
if let Some(quic_port) = self.quic4() {
|
||||
if let Some(ip) = self.ip4() {
|
||||
let mut multiaddr: Multiaddr = ip.into();
|
||||
multiaddr.push(Protocol::Udp(quic_port));
|
||||
multiaddr.push(Protocol::QuicV1);
|
||||
multiaddrs.push(multiaddr);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(quic6_port) = self.quic6() {
|
||||
if let Some(ip6) = self.ip6() {
|
||||
let mut multiaddr: Multiaddr = ip6.into();
|
||||
multiaddr.push(Protocol::Udp(quic6_port));
|
||||
multiaddr.push(Protocol::QuicV1);
|
||||
multiaddrs.push(multiaddr);
|
||||
}
|
||||
}
|
||||
multiaddrs
|
||||
}
|
||||
|
||||
/// Returns a list of multiaddrs if the ENR has an `ip` and either a `tcp` or `udp` key **or** an `ip6` and either a `tcp6` or `udp6`.
|
||||
/// The vector remains empty if these fields are not defined.
|
||||
fn multiaddr_tcp(&self) -> Vec<Multiaddr> {
|
||||
let mut multiaddrs: Vec<Multiaddr> = Vec::new();
|
||||
if let Some(ip) = self.ip4() {
|
||||
|
@ -21,7 +21,6 @@ pub use libp2p::identity::{Keypair, PublicKey};
|
||||
use enr::{ATTESTATION_BITFIELD_ENR_KEY, ETH2_ENR_KEY, SYNC_COMMITTEE_BITFIELD_ENR_KEY};
|
||||
use futures::prelude::*;
|
||||
use futures::stream::FuturesUnordered;
|
||||
use libp2p::multiaddr::Protocol;
|
||||
use libp2p::swarm::behaviour::{DialFailure, FromSwarm};
|
||||
use libp2p::swarm::THandlerInEvent;
|
||||
pub use libp2p::{
|
||||
@ -75,7 +74,7 @@ const DURATION_DIFFERENCE: Duration = Duration::from_millis(1);
|
||||
/// of the peer if it is specified.
|
||||
#[derive(Debug)]
|
||||
pub struct DiscoveredPeers {
|
||||
pub peers: HashMap<PeerId, Option<Instant>>,
|
||||
pub peers: HashMap<Enr, Option<Instant>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
@ -208,7 +207,8 @@ impl<TSpec: EthSpec> Discovery<TSpec> {
|
||||
let local_node_id = local_enr.node_id();
|
||||
|
||||
info!(log, "ENR Initialised"; "enr" => local_enr.to_base64(), "seq" => local_enr.seq(), "id"=> %local_enr.node_id(),
|
||||
"ip4" => ?local_enr.ip4(), "udp4"=> ?local_enr.udp4(), "tcp4" => ?local_enr.tcp4(), "tcp6" => ?local_enr.tcp6(), "udp6" => ?local_enr.udp6()
|
||||
"ip4" => ?local_enr.ip4(), "udp4"=> ?local_enr.udp4(), "tcp4" => ?local_enr.tcp4(), "tcp6" => ?local_enr.tcp6(), "udp6" => ?local_enr.udp6(),
|
||||
"quic4" => ?local_enr.quic4(), "quic6" => ?local_enr.quic6()
|
||||
);
|
||||
|
||||
// convert the keypair into an ENR key
|
||||
@ -230,7 +230,8 @@ impl<TSpec: EthSpec> Discovery<TSpec> {
|
||||
"peer_id" => %bootnode_enr.peer_id(),
|
||||
"ip" => ?bootnode_enr.ip4(),
|
||||
"udp" => ?bootnode_enr.udp4(),
|
||||
"tcp" => ?bootnode_enr.tcp4()
|
||||
"tcp" => ?bootnode_enr.tcp4(),
|
||||
"quic" => ?bootnode_enr.quic4()
|
||||
);
|
||||
let repr = bootnode_enr.to_string();
|
||||
let _ = discv5.add_enr(bootnode_enr).map_err(|e| {
|
||||
@ -281,7 +282,8 @@ impl<TSpec: EthSpec> Discovery<TSpec> {
|
||||
"peer_id" => %enr.peer_id(),
|
||||
"ip" => ?enr.ip4(),
|
||||
"udp" => ?enr.udp4(),
|
||||
"tcp" => ?enr.tcp4()
|
||||
"tcp" => ?enr.tcp4(),
|
||||
"quic" => ?enr.quic4()
|
||||
);
|
||||
let _ = discv5.add_enr(enr).map_err(|e| {
|
||||
error!(
|
||||
@ -383,20 +385,6 @@ impl<TSpec: EthSpec> Discovery<TSpec> {
|
||||
self.discv5.table_entries_enr()
|
||||
}
|
||||
|
||||
/// Returns the ENR of a known peer if it exists.
|
||||
pub fn enr_of_peer(&mut self, peer_id: &PeerId) -> Option<Enr> {
|
||||
// first search the local cache
|
||||
if let Some(enr) = self.cached_enrs.get(peer_id) {
|
||||
return Some(enr.clone());
|
||||
}
|
||||
// not in the local cache, look in the routing table
|
||||
if let Ok(node_id) = enr_ext::peer_id_to_node_id(peer_id) {
|
||||
self.discv5.find_enr(&node_id)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Updates the local ENR TCP port.
|
||||
/// There currently isn't a case to update the address here. We opt for discovery to
|
||||
/// automatically update the external address.
|
||||
@ -414,6 +402,23 @@ impl<TSpec: EthSpec> Discovery<TSpec> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// TODO: Group these functions here once the ENR is shared across discv5 and lighthouse and
|
||||
// Lighthouse can modify the ENR directly.
|
||||
// This currently doesn't support ipv6. All of these functions should be removed and
|
||||
// addressed properly in the following issue.
|
||||
// https://github.com/sigp/lighthouse/issues/4706
|
||||
pub fn update_enr_quic_port(&mut self, port: u16) -> Result<(), String> {
|
||||
self.discv5
|
||||
.enr_insert("quic", &port)
|
||||
.map_err(|e| format!("{:?}", e))?;
|
||||
|
||||
// replace the global version
|
||||
*self.network_globals.local_enr.write() = self.discv5.local_enr();
|
||||
// persist modified enr to disk
|
||||
enr::save_enr_to_disk(Path::new(&self.enr_dir), &self.local_enr(), &self.log);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Updates the local ENR UDP socket.
|
||||
///
|
||||
/// This is with caution. Discovery should automatically maintain this. This should only be
|
||||
@ -733,23 +738,6 @@ impl<TSpec: EthSpec> Discovery<TSpec> {
|
||||
target_peers: usize,
|
||||
additional_predicate: impl Fn(&Enr) -> bool + Send + 'static,
|
||||
) {
|
||||
// Make sure there are subnet queries included
|
||||
let contains_queries = match &query {
|
||||
QueryType::Subnet(queries) => !queries.is_empty(),
|
||||
QueryType::FindPeers => true,
|
||||
};
|
||||
|
||||
if !contains_queries {
|
||||
debug!(
|
||||
self.log,
|
||||
"No subnets included in this request. Skipping discovery request."
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Generate a random target node id.
|
||||
let random_node = NodeId::random();
|
||||
|
||||
let enr_fork_id = match self.local_enr().eth2() {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
@ -773,7 +761,8 @@ impl<TSpec: EthSpec> Discovery<TSpec> {
|
||||
// Build the future
|
||||
let query_future = self
|
||||
.discv5
|
||||
.find_node_predicate(random_node, predicate, target_peers)
|
||||
// Generate a random target node id.
|
||||
.find_node_predicate(NodeId::random(), predicate, target_peers)
|
||||
.map(|v| QueryResult {
|
||||
query_type: query,
|
||||
result: v,
|
||||
@ -787,7 +776,7 @@ impl<TSpec: EthSpec> Discovery<TSpec> {
|
||||
fn process_completed_queries(
|
||||
&mut self,
|
||||
query: QueryResult,
|
||||
) -> Option<HashMap<PeerId, Option<Instant>>> {
|
||||
) -> Option<HashMap<Enr, Option<Instant>>> {
|
||||
match query.query_type {
|
||||
QueryType::FindPeers => {
|
||||
self.find_peer_active = false;
|
||||
@ -797,12 +786,14 @@ impl<TSpec: EthSpec> Discovery<TSpec> {
|
||||
}
|
||||
Ok(r) => {
|
||||
debug!(self.log, "Discovery query completed"; "peers_found" => r.len());
|
||||
let mut results: HashMap<_, Option<Instant>> = HashMap::new();
|
||||
r.iter().for_each(|enr| {
|
||||
// cache the found ENR's
|
||||
self.cached_enrs.put(enr.peer_id(), enr.clone());
|
||||
results.insert(enr.peer_id(), None);
|
||||
});
|
||||
let results = r
|
||||
.into_iter()
|
||||
.map(|enr| {
|
||||
// cache the found ENR's
|
||||
self.cached_enrs.put(enr.peer_id(), enr.clone());
|
||||
(enr, None)
|
||||
})
|
||||
.collect();
|
||||
return Some(results);
|
||||
}
|
||||
Err(e) => {
|
||||
@ -850,17 +841,17 @@ impl<TSpec: EthSpec> Discovery<TSpec> {
|
||||
let subnet_predicate =
|
||||
subnet_predicate::<TSpec>(vec![query.subnet], &self.log);
|
||||
|
||||
r.iter()
|
||||
r.clone()
|
||||
.into_iter()
|
||||
.filter(|enr| subnet_predicate(enr))
|
||||
.map(|enr| enr.peer_id())
|
||||
.for_each(|peer_id| {
|
||||
.for_each(|enr| {
|
||||
if let Some(v) = metrics::get_int_counter(
|
||||
&metrics::SUBNET_PEERS_FOUND,
|
||||
&[query_str],
|
||||
) {
|
||||
v.inc();
|
||||
}
|
||||
let other_min_ttl = mapped_results.get_mut(&peer_id);
|
||||
let other_min_ttl = mapped_results.get_mut(&enr);
|
||||
|
||||
// map peer IDs to the min_ttl furthest in the future
|
||||
match (query.min_ttl, other_min_ttl) {
|
||||
@ -878,15 +869,11 @@ impl<TSpec: EthSpec> Discovery<TSpec> {
|
||||
}
|
||||
// update the mapping if we have a specified min_ttl
|
||||
(Some(min_ttl), Some(None)) => {
|
||||
mapped_results.insert(peer_id, Some(min_ttl));
|
||||
mapped_results.insert(enr, Some(min_ttl));
|
||||
}
|
||||
// first seen min_ttl for this enr
|
||||
(Some(min_ttl), None) => {
|
||||
mapped_results.insert(peer_id, Some(min_ttl));
|
||||
}
|
||||
// first seen min_ttl for this enr
|
||||
(None, None) => {
|
||||
mapped_results.insert(peer_id, None);
|
||||
(min_ttl, None) => {
|
||||
mapped_results.insert(enr, min_ttl);
|
||||
}
|
||||
(None, Some(Some(_))) => {} // Don't replace the existing specific min_ttl
|
||||
(None, Some(None)) => {} // No-op because this is a duplicate
|
||||
@ -910,7 +897,7 @@ impl<TSpec: EthSpec> Discovery<TSpec> {
|
||||
}
|
||||
|
||||
/// Drives the queries returning any results from completed queries.
|
||||
fn poll_queries(&mut self, cx: &mut Context) -> Option<HashMap<PeerId, Option<Instant>>> {
|
||||
fn poll_queries(&mut self, cx: &mut Context) -> Option<HashMap<Enr, Option<Instant>>> {
|
||||
while let Poll::Ready(Some(query_result)) = self.active_queries.poll_next_unpin(cx) {
|
||||
let result = self.process_completed_queries(query_result);
|
||||
if result.is_some() {
|
||||
@ -957,23 +944,6 @@ impl<TSpec: EthSpec> NetworkBehaviour for Discovery<TSpec> {
|
||||
) {
|
||||
}
|
||||
|
||||
fn handle_pending_outbound_connection(
|
||||
&mut self,
|
||||
_connection_id: ConnectionId,
|
||||
maybe_peer: Option<PeerId>,
|
||||
_addresses: &[Multiaddr],
|
||||
_effective_role: libp2p::core::Endpoint,
|
||||
) -> Result<Vec<Multiaddr>, libp2p::swarm::ConnectionDenied> {
|
||||
if let Some(enr) = maybe_peer.and_then(|peer_id| self.enr_of_peer(&peer_id)) {
|
||||
// ENR's may have multiple Multiaddrs. The multi-addr associated with the UDP
|
||||
// port is removed, which is assumed to be associated with the discv5 protocol (and
|
||||
// therefore irrelevant for other libp2p components).
|
||||
Ok(enr.multiaddr_tcp())
|
||||
} else {
|
||||
Ok(vec![])
|
||||
}
|
||||
}
|
||||
|
||||
// Main execution loop to drive the behaviour
|
||||
fn poll(
|
||||
&mut self,
|
||||
@ -1047,25 +1017,8 @@ impl<TSpec: EthSpec> NetworkBehaviour for Discovery<TSpec> {
|
||||
// update network globals
|
||||
*self.network_globals.local_enr.write() = enr;
|
||||
// A new UDP socket has been detected.
|
||||
// Build a multiaddr to report to libp2p
|
||||
let addr = match socket_addr.ip() {
|
||||
IpAddr::V4(v4_addr) => {
|
||||
self.network_globals.listen_port_tcp4().map(|tcp4_port| {
|
||||
Multiaddr::from(v4_addr).with(Protocol::Tcp(tcp4_port))
|
||||
})
|
||||
}
|
||||
IpAddr::V6(v6_addr) => {
|
||||
self.network_globals.listen_port_tcp6().map(|tcp6_port| {
|
||||
Multiaddr::from(v6_addr).with(Protocol::Tcp(tcp6_port))
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(address) = addr {
|
||||
// NOTE: This doesn't actually track the external TCP port. More sophisticated NAT handling
|
||||
// should handle this.
|
||||
return Poll::Ready(ToSwarm::NewExternalAddrCandidate(address));
|
||||
}
|
||||
// NOTE: We assume libp2p itself can keep track of IP changes and we do
|
||||
// not inform it about IP changes found via discovery.
|
||||
}
|
||||
Discv5Event::EnrAdded { .. }
|
||||
| Discv5Event::TalkRequest(_)
|
||||
@ -1152,8 +1105,6 @@ mod tests {
|
||||
let log = build_log(slog::Level::Debug, false);
|
||||
let globals = NetworkGlobals::new(
|
||||
enr,
|
||||
Some(9000),
|
||||
None,
|
||||
MetaData::V2(MetaDataV2 {
|
||||
seq_number: 0,
|
||||
attnets: Default::default(),
|
||||
@ -1261,6 +1212,6 @@ mod tests {
|
||||
assert_eq!(results.len(), 2);
|
||||
|
||||
// when a peer belongs to multiple subnet ids, we use the highest ttl.
|
||||
assert_eq!(results.get(&enr1.peer_id()).unwrap(), &instant1);
|
||||
assert_eq!(results.get(&enr1).unwrap(), &instant1);
|
||||
}
|
||||
}
|
||||
|
@ -6,14 +6,23 @@ use serde::{Deserialize, Serialize};
|
||||
/// A listening address composed by an Ip, an UDP port and a TCP port.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct ListenAddr<Ip> {
|
||||
/// The IP address we will listen on.
|
||||
pub addr: Ip,
|
||||
pub udp_port: u16,
|
||||
/// The UDP port that discovery will listen on.
|
||||
pub disc_port: u16,
|
||||
/// The UDP port that QUIC will listen on.
|
||||
pub quic_port: u16,
|
||||
/// The TCP port that libp2p will listen on.
|
||||
pub tcp_port: u16,
|
||||
}
|
||||
|
||||
impl<Ip: Into<IpAddr> + Clone> ListenAddr<Ip> {
|
||||
pub fn udp_socket_addr(&self) -> SocketAddr {
|
||||
(self.addr.clone().into(), self.udp_port).into()
|
||||
pub fn discovery_socket_addr(&self) -> SocketAddr {
|
||||
(self.addr.clone().into(), self.disc_port).into()
|
||||
}
|
||||
|
||||
pub fn quic_socket_addr(&self) -> SocketAddr {
|
||||
(self.addr.clone().into(), self.quic_port).into()
|
||||
}
|
||||
|
||||
pub fn tcp_socket_addr(&self) -> SocketAddr {
|
||||
@ -46,22 +55,41 @@ impl ListenAddress {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the TCP addresses.
|
||||
pub fn tcp_addresses(&self) -> impl Iterator<Item = Multiaddr> + '_ {
|
||||
let v4_multiaddr = self
|
||||
/// Returns the addresses the Swarm will listen on, given the setup.
|
||||
pub fn libp2p_addresses(&self) -> impl Iterator<Item = Multiaddr> {
|
||||
let v4_tcp_multiaddr = self
|
||||
.v4()
|
||||
.map(|v4_addr| Multiaddr::from(v4_addr.addr).with(Protocol::Tcp(v4_addr.tcp_port)));
|
||||
let v6_multiaddr = self
|
||||
|
||||
let v4_quic_multiaddr = self.v4().map(|v4_addr| {
|
||||
Multiaddr::from(v4_addr.addr)
|
||||
.with(Protocol::Udp(v4_addr.quic_port))
|
||||
.with(Protocol::QuicV1)
|
||||
});
|
||||
|
||||
let v6_quic_multiaddr = self.v6().map(|v6_addr| {
|
||||
Multiaddr::from(v6_addr.addr)
|
||||
.with(Protocol::Udp(v6_addr.quic_port))
|
||||
.with(Protocol::QuicV1)
|
||||
});
|
||||
|
||||
let v6_tcp_multiaddr = self
|
||||
.v6()
|
||||
.map(|v6_addr| Multiaddr::from(v6_addr.addr).with(Protocol::Tcp(v6_addr.tcp_port)));
|
||||
v4_multiaddr.into_iter().chain(v6_multiaddr)
|
||||
|
||||
v4_tcp_multiaddr
|
||||
.into_iter()
|
||||
.chain(v4_quic_multiaddr)
|
||||
.chain(v6_quic_multiaddr)
|
||||
.chain(v6_tcp_multiaddr)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn unused_v4_ports() -> Self {
|
||||
ListenAddress::V4(ListenAddr {
|
||||
addr: Ipv4Addr::UNSPECIFIED,
|
||||
udp_port: unused_port::unused_udp4_port().unwrap(),
|
||||
disc_port: unused_port::unused_udp4_port().unwrap(),
|
||||
quic_port: unused_port::unused_udp4_port().unwrap(),
|
||||
tcp_port: unused_port::unused_tcp4_port().unwrap(),
|
||||
})
|
||||
}
|
||||
@ -70,7 +98,8 @@ impl ListenAddress {
|
||||
pub fn unused_v6_ports() -> Self {
|
||||
ListenAddress::V6(ListenAddr {
|
||||
addr: Ipv6Addr::UNSPECIFIED,
|
||||
udp_port: unused_port::unused_udp6_port().unwrap(),
|
||||
disc_port: unused_port::unused_udp6_port().unwrap(),
|
||||
quic_port: unused_port::unused_udp6_port().unwrap(),
|
||||
tcp_port: unused_port::unused_tcp6_port().unwrap(),
|
||||
})
|
||||
}
|
||||
@ -84,12 +113,14 @@ impl slog::KV for ListenAddress {
|
||||
) -> slog::Result {
|
||||
if let Some(v4_addr) = self.v4() {
|
||||
serializer.emit_arguments("ip4_address", &format_args!("{}", v4_addr.addr))?;
|
||||
serializer.emit_u16("udp4_port", v4_addr.udp_port)?;
|
||||
serializer.emit_u16("disc4_port", v4_addr.disc_port)?;
|
||||
serializer.emit_u16("quic4_port", v4_addr.quic_port)?;
|
||||
serializer.emit_u16("tcp4_port", v4_addr.tcp_port)?;
|
||||
}
|
||||
if let Some(v6_addr) = self.v6() {
|
||||
serializer.emit_arguments("ip6_address", &format_args!("{}", v6_addr.addr))?;
|
||||
serializer.emit_u16("udp6_port", v6_addr.udp_port)?;
|
||||
serializer.emit_u16("disc6_port", v6_addr.disc_port)?;
|
||||
serializer.emit_u16("quic6_port", v6_addr.quic_port)?;
|
||||
serializer.emit_u16("tcp6_port", v6_addr.tcp_port)?;
|
||||
}
|
||||
slog::Result::Ok(())
|
||||
|
@ -14,6 +14,16 @@ lazy_static! {
|
||||
"Count of libp2p peers currently connected"
|
||||
);
|
||||
|
||||
pub static ref TCP_PEERS_CONNECTED: Result<IntGauge> = try_create_int_gauge(
|
||||
"libp2p_tcp_peers",
|
||||
"Count of libp2p peers currently connected via TCP"
|
||||
);
|
||||
|
||||
pub static ref QUIC_PEERS_CONNECTED: Result<IntGauge> = try_create_int_gauge(
|
||||
"libp2p_quic_peers",
|
||||
"Count of libp2p peers currently connected via QUIC"
|
||||
);
|
||||
|
||||
pub static ref PEER_CONNECT_EVENT_COUNT: Result<IntCounter> = try_create_int_counter(
|
||||
"libp2p_peer_connect_event_total",
|
||||
"Count of libp2p peer connect events (not the current number of connected peers)"
|
||||
|
@ -1,5 +1,6 @@
|
||||
//! Implementation of Lighthouse's peer management system.
|
||||
|
||||
use crate::discovery::enr_ext::EnrExt;
|
||||
use crate::rpc::{GoodbyeReason, MetaData, Protocol, RPCError, RPCResponseErrorCode};
|
||||
use crate::service::TARGET_SUBNET_PEERS;
|
||||
use crate::{error, metrics, Gossipsub};
|
||||
@ -13,7 +14,6 @@ use peerdb::{client::ClientKind, BanOperation, BanResult, ScoreUpdateResult};
|
||||
use rand::seq::SliceRandom;
|
||||
use slog::{debug, error, trace, warn};
|
||||
use smallvec::SmallVec;
|
||||
use std::collections::BTreeMap;
|
||||
use std::{
|
||||
sync::Arc,
|
||||
time::{Duration, Instant},
|
||||
@ -78,7 +78,7 @@ pub struct PeerManager<TSpec: EthSpec> {
|
||||
/// The target number of peers we would like to connect to.
|
||||
target_peers: usize,
|
||||
/// Peers queued to be dialed.
|
||||
peers_to_dial: BTreeMap<PeerId, Option<Enr>>,
|
||||
peers_to_dial: Vec<Enr>,
|
||||
/// The number of temporarily banned peers. This is used to prevent instantaneous
|
||||
/// reconnection.
|
||||
// NOTE: This just prevents re-connections. The state of the peer is otherwise unaffected. A
|
||||
@ -312,16 +312,12 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
|
||||
/// Peers that have been returned by discovery requests that are suitable for dialing are
|
||||
/// returned here.
|
||||
///
|
||||
/// NOTE: By dialing `PeerId`s and not multiaddrs, libp2p requests the multiaddr associated
|
||||
/// with a new `PeerId` which involves a discovery routing table lookup. We could dial the
|
||||
/// multiaddr here, however this could relate to duplicate PeerId's etc. If the lookup
|
||||
/// proves resource constraining, we should switch to multiaddr dialling here.
|
||||
/// This function decides whether or not to dial these peers.
|
||||
#[allow(clippy::mutable_key_type)]
|
||||
pub fn peers_discovered(&mut self, results: HashMap<PeerId, Option<Instant>>) -> Vec<PeerId> {
|
||||
let mut to_dial_peers = Vec::with_capacity(4);
|
||||
|
||||
pub fn peers_discovered(&mut self, results: HashMap<Enr, Option<Instant>>) {
|
||||
let mut to_dial_peers = 0;
|
||||
let connected_or_dialing = self.network_globals.connected_or_dialing_peers();
|
||||
for (peer_id, min_ttl) in results {
|
||||
for (enr, min_ttl) in results {
|
||||
// There are two conditions in deciding whether to dial this peer.
|
||||
// 1. If we are less than our max connections. Discovery queries are executed to reach
|
||||
// our target peers, so its fine to dial up to our max peers (which will get pruned
|
||||
@ -330,10 +326,8 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
|
||||
// considered a priority. We have pre-allocated some extra priority slots for these
|
||||
// peers as specified by PRIORITY_PEER_EXCESS. Therefore we dial these peers, even
|
||||
// if we are already at our max_peer limit.
|
||||
if (min_ttl.is_some()
|
||||
&& connected_or_dialing + to_dial_peers.len() < self.max_priority_peers()
|
||||
|| connected_or_dialing + to_dial_peers.len() < self.max_peers())
|
||||
&& self.network_globals.peers.read().should_dial(&peer_id)
|
||||
if min_ttl.is_some() && connected_or_dialing + to_dial_peers < self.max_priority_peers()
|
||||
|| connected_or_dialing + to_dial_peers < self.max_peers()
|
||||
{
|
||||
// This should be updated with the peer dialing. In fact created once the peer is
|
||||
// dialed
|
||||
@ -341,16 +335,16 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
|
||||
self.network_globals
|
||||
.peers
|
||||
.write()
|
||||
.update_min_ttl(&peer_id, min_ttl);
|
||||
.update_min_ttl(&enr.peer_id(), min_ttl);
|
||||
}
|
||||
to_dial_peers.push(peer_id);
|
||||
debug!(self.log, "Dialing discovered peer"; "peer_id" => %enr.peer_id());
|
||||
self.dial_peer(enr);
|
||||
to_dial_peers += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Queue another discovery if we need to
|
||||
self.maintain_peer_count(to_dial_peers.len());
|
||||
|
||||
to_dial_peers
|
||||
self.maintain_peer_count(to_dial_peers);
|
||||
}
|
||||
|
||||
/// A STATUS message has been received from a peer. This resets the status timer.
|
||||
@ -406,9 +400,16 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
|
||||
|
||||
/* Notifications from the Swarm */
|
||||
|
||||
// A peer is being dialed.
|
||||
pub fn dial_peer(&mut self, peer_id: &PeerId, enr: Option<Enr>) {
|
||||
self.peers_to_dial.insert(*peer_id, enr);
|
||||
/// A peer is being dialed.
|
||||
pub fn dial_peer(&mut self, peer: Enr) {
|
||||
if self
|
||||
.network_globals
|
||||
.peers
|
||||
.read()
|
||||
.should_dial(&peer.peer_id())
|
||||
{
|
||||
self.peers_to_dial.push(peer);
|
||||
}
|
||||
}
|
||||
|
||||
/// Reports if a peer is banned or not.
|
||||
@ -2208,7 +2209,7 @@ mod tests {
|
||||
}
|
||||
|
||||
impl Arbitrary for PeerCondition {
|
||||
fn arbitrary<G: Gen>(g: &mut G) -> Self {
|
||||
fn arbitrary(g: &mut Gen) -> Self {
|
||||
let attestation_net_bitfield = {
|
||||
let len = <E as EthSpec>::SubnetBitfieldLength::to_usize();
|
||||
let mut bitfield = Vec::with_capacity(len);
|
||||
|
@ -3,7 +3,7 @@
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use futures::StreamExt;
|
||||
use libp2p::core::ConnectedPoint;
|
||||
use libp2p::core::{multiaddr, ConnectedPoint};
|
||||
use libp2p::identity::PeerId;
|
||||
use libp2p::swarm::behaviour::{ConnectionClosed, ConnectionEstablished, DialFailure, FromSwarm};
|
||||
use libp2p::swarm::dial_opts::{DialOpts, PeerCondition};
|
||||
@ -12,6 +12,7 @@ use libp2p::swarm::{ConnectionId, NetworkBehaviour, PollParameters, ToSwarm};
|
||||
use slog::{debug, error};
|
||||
use types::EthSpec;
|
||||
|
||||
use crate::discovery::enr_ext::EnrExt;
|
||||
use crate::rpc::GoodbyeReason;
|
||||
use crate::types::SyncState;
|
||||
use crate::{metrics, ClearDialError};
|
||||
@ -95,11 +96,23 @@ impl<TSpec: EthSpec> NetworkBehaviour for PeerManager<TSpec> {
|
||||
self.events.shrink_to_fit();
|
||||
}
|
||||
|
||||
if let Some((peer_id, maybe_enr)) = self.peers_to_dial.pop_first() {
|
||||
self.inject_peer_connection(&peer_id, ConnectingType::Dialing, maybe_enr);
|
||||
if let Some(enr) = self.peers_to_dial.pop() {
|
||||
let peer_id = enr.peer_id();
|
||||
self.inject_peer_connection(&peer_id, ConnectingType::Dialing, Some(enr.clone()));
|
||||
let quic_multiaddrs = enr.multiaddr_quic();
|
||||
if !quic_multiaddrs.is_empty() {
|
||||
debug!(self.log, "Dialing QUIC supported peer"; "peer_id"=> %peer_id, "quic_multiaddrs" => ?quic_multiaddrs);
|
||||
}
|
||||
|
||||
// Prioritize Quic connections over Tcp ones.
|
||||
let multiaddrs = quic_multiaddrs
|
||||
.into_iter()
|
||||
.chain(enr.multiaddr_tcp())
|
||||
.collect();
|
||||
return Poll::Ready(ToSwarm::Dial {
|
||||
opts: DialOpts::peer_id(peer_id)
|
||||
.condition(PeerCondition::Disconnected)
|
||||
.addresses(multiaddrs)
|
||||
.build(),
|
||||
});
|
||||
}
|
||||
@ -124,9 +137,11 @@ impl<TSpec: EthSpec> NetworkBehaviour for PeerManager<TSpec> {
|
||||
}
|
||||
FromSwarm::ConnectionClosed(ConnectionClosed {
|
||||
peer_id,
|
||||
endpoint,
|
||||
|
||||
remaining_established,
|
||||
..
|
||||
}) => self.on_connection_closed(peer_id, remaining_established),
|
||||
}) => self.on_connection_closed(peer_id, endpoint, remaining_established),
|
||||
FromSwarm::DialFailure(DialFailure {
|
||||
peer_id,
|
||||
error,
|
||||
@ -184,7 +199,11 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
|
||||
endpoint: &ConnectedPoint,
|
||||
other_established: usize,
|
||||
) {
|
||||
debug!(self.log, "Connection established"; "peer_id" => %peer_id, "connection" => ?endpoint.to_endpoint());
|
||||
debug!(self.log, "Connection established"; "peer_id" => %peer_id,
|
||||
"multiaddr" => %endpoint.get_remote_address(),
|
||||
"connection" => ?endpoint.to_endpoint()
|
||||
);
|
||||
|
||||
if other_established == 0 {
|
||||
self.events.push(PeerManagerEvent::MetaData(peer_id));
|
||||
}
|
||||
@ -194,6 +213,34 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
|
||||
metrics::check_nat();
|
||||
}
|
||||
|
||||
// increment prometheus metrics
|
||||
if self.metrics_enabled {
|
||||
let remote_addr = match endpoint {
|
||||
ConnectedPoint::Dialer { address, .. } => address,
|
||||
ConnectedPoint::Listener { send_back_addr, .. } => send_back_addr,
|
||||
};
|
||||
match remote_addr.iter().find(|proto| {
|
||||
matches!(
|
||||
proto,
|
||||
multiaddr::Protocol::QuicV1 | multiaddr::Protocol::Tcp(_)
|
||||
)
|
||||
}) {
|
||||
Some(multiaddr::Protocol::QuicV1) => {
|
||||
metrics::inc_gauge(&metrics::QUIC_PEERS_CONNECTED);
|
||||
}
|
||||
Some(multiaddr::Protocol::Tcp(_)) => {
|
||||
metrics::inc_gauge(&metrics::TCP_PEERS_CONNECTED);
|
||||
}
|
||||
Some(_) => unreachable!(),
|
||||
None => {
|
||||
error!(self.log, "Connection established via unknown transport"; "addr" => %remote_addr)
|
||||
}
|
||||
};
|
||||
|
||||
self.update_connected_peer_metrics();
|
||||
metrics::inc_counter(&metrics::PEER_CONNECT_EVENT_COUNT);
|
||||
}
|
||||
|
||||
// Check to make sure the peer is not supposed to be banned
|
||||
match self.ban_status(&peer_id) {
|
||||
// TODO: directly emit the ban event?
|
||||
@ -245,14 +292,15 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
|
||||
self.events
|
||||
.push(PeerManagerEvent::PeerConnectedOutgoing(peer_id));
|
||||
}
|
||||
}
|
||||
|
||||
// increment prometheus metrics
|
||||
self.update_connected_peer_metrics();
|
||||
metrics::inc_counter(&metrics::PEER_CONNECT_EVENT_COUNT);
|
||||
};
|
||||
}
|
||||
|
||||
fn on_connection_closed(&mut self, peer_id: PeerId, remaining_established: usize) {
|
||||
fn on_connection_closed(
|
||||
&mut self,
|
||||
peer_id: PeerId,
|
||||
endpoint: &ConnectedPoint,
|
||||
remaining_established: usize,
|
||||
) {
|
||||
if remaining_established > 0 {
|
||||
return;
|
||||
}
|
||||
@ -278,9 +326,31 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
|
||||
// reference so that peer manager can track this peer.
|
||||
self.inject_disconnect(&peer_id);
|
||||
|
||||
let remote_addr = match endpoint {
|
||||
ConnectedPoint::Listener { send_back_addr, .. } => send_back_addr,
|
||||
ConnectedPoint::Dialer { address, .. } => address,
|
||||
};
|
||||
|
||||
// Update the prometheus metrics
|
||||
self.update_connected_peer_metrics();
|
||||
metrics::inc_counter(&metrics::PEER_DISCONNECT_EVENT_COUNT);
|
||||
if self.metrics_enabled {
|
||||
match remote_addr.iter().find(|proto| {
|
||||
matches!(
|
||||
proto,
|
||||
multiaddr::Protocol::QuicV1 | multiaddr::Protocol::Tcp(_)
|
||||
)
|
||||
}) {
|
||||
Some(multiaddr::Protocol::QuicV1) => {
|
||||
metrics::dec_gauge(&metrics::QUIC_PEERS_CONNECTED);
|
||||
}
|
||||
Some(multiaddr::Protocol::Tcp(_)) => {
|
||||
metrics::dec_gauge(&metrics::TCP_PEERS_CONNECTED);
|
||||
}
|
||||
// If it's an unknown protocol we already logged when connection was established.
|
||||
_ => {}
|
||||
};
|
||||
self.update_connected_peer_metrics();
|
||||
metrics::inc_counter(&metrics::PEER_DISCONNECT_EVENT_COUNT);
|
||||
}
|
||||
}
|
||||
|
||||
/// A dial attempt has failed.
|
||||
|
@ -1,16 +1,11 @@
|
||||
use crate::{
|
||||
metrics,
|
||||
multiaddr::{Multiaddr, Protocol},
|
||||
types::Subnet,
|
||||
Enr, Gossipsub, PeerId,
|
||||
};
|
||||
use crate::{metrics, multiaddr::Multiaddr, types::Subnet, Enr, Gossipsub, PeerId};
|
||||
use peer_info::{ConnectionDirection, PeerConnectionStatus, PeerInfo};
|
||||
use rand::seq::SliceRandom;
|
||||
use score::{PeerAction, ReportSource, Score, ScoreState};
|
||||
use slog::{crit, debug, error, trace, warn};
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::net::{IpAddr, SocketAddr};
|
||||
use std::net::IpAddr;
|
||||
use std::time::Instant;
|
||||
use sync_status::SyncStatus;
|
||||
use types::EthSpec;
|
||||
@ -764,28 +759,10 @@ impl<TSpec: EthSpec> PeerDB<TSpec> {
|
||||
| PeerConnectionStatus::Dialing { .. } => {}
|
||||
}
|
||||
|
||||
// Add the seen ip address and port to the peer's info
|
||||
let socket_addr = match seen_address.iter().fold(
|
||||
(None, None),
|
||||
|(found_ip, found_port), protocol| match protocol {
|
||||
Protocol::Ip4(ip) => (Some(ip.into()), found_port),
|
||||
Protocol::Ip6(ip) => (Some(ip.into()), found_port),
|
||||
Protocol::Tcp(port) => (found_ip, Some(port)),
|
||||
_ => (found_ip, found_port),
|
||||
},
|
||||
) {
|
||||
(Some(ip), Some(port)) => Some(SocketAddr::new(ip, port)),
|
||||
(Some(_ip), None) => {
|
||||
crit!(self.log, "Connected peer has an IP but no TCP port"; "peer_id" => %peer_id);
|
||||
None
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
|
||||
// Update the connection state
|
||||
match direction {
|
||||
ConnectionDirection::Incoming => info.connect_ingoing(socket_addr),
|
||||
ConnectionDirection::Outgoing => info.connect_outgoing(socket_addr),
|
||||
ConnectionDirection::Incoming => info.connect_ingoing(Some(seen_address)),
|
||||
ConnectionDirection::Outgoing => info.connect_outgoing(Some(seen_address)),
|
||||
}
|
||||
}
|
||||
|
||||
@ -1274,6 +1251,7 @@ impl BannedPeersCount {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use libp2p::core::multiaddr::Protocol;
|
||||
use libp2p::core::Multiaddr;
|
||||
use slog::{o, Drain};
|
||||
use std::net::{Ipv4Addr, Ipv6Addr};
|
||||
|
@ -2,15 +2,15 @@ use super::client::Client;
|
||||
use super::score::{PeerAction, Score, ScoreState};
|
||||
use super::sync_status::SyncStatus;
|
||||
use crate::discovery::Eth2Enr;
|
||||
use crate::Multiaddr;
|
||||
use crate::{rpc::MetaData, types::Subnet};
|
||||
use discv5::Enr;
|
||||
use libp2p::core::multiaddr::{Multiaddr, Protocol};
|
||||
use serde::{
|
||||
ser::{SerializeStruct, Serializer},
|
||||
Serialize,
|
||||
};
|
||||
use std::collections::HashSet;
|
||||
use std::net::{IpAddr, SocketAddr};
|
||||
use std::net::IpAddr;
|
||||
use std::time::Instant;
|
||||
use strum::AsRefStr;
|
||||
use types::EthSpec;
|
||||
@ -29,9 +29,9 @@ pub struct PeerInfo<T: EthSpec> {
|
||||
/// The known listening addresses of this peer. This is given by identify and can be arbitrary
|
||||
/// (including local IPs).
|
||||
listening_addresses: Vec<Multiaddr>,
|
||||
/// This is addresses we have physically seen and this is what we use for banning/un-banning
|
||||
/// These are the multiaddrs we have physically seen and is what we use for banning/un-banning
|
||||
/// peers.
|
||||
seen_addresses: HashSet<SocketAddr>,
|
||||
seen_multiaddrs: HashSet<Multiaddr>,
|
||||
/// The current syncing state of the peer. The state may be determined after it's initial
|
||||
/// connection.
|
||||
sync_status: SyncStatus,
|
||||
@ -60,7 +60,7 @@ impl<TSpec: EthSpec> Default for PeerInfo<TSpec> {
|
||||
client: Client::default(),
|
||||
connection_status: Default::default(),
|
||||
listening_addresses: Vec::new(),
|
||||
seen_addresses: HashSet::new(),
|
||||
seen_multiaddrs: HashSet::new(),
|
||||
subnets: HashSet::new(),
|
||||
sync_status: SyncStatus::Unknown,
|
||||
meta_data: None,
|
||||
@ -227,15 +227,21 @@ impl<T: EthSpec> PeerInfo<T> {
|
||||
}
|
||||
|
||||
/// Returns the seen addresses of the peer.
|
||||
pub fn seen_addresses(&self) -> impl Iterator<Item = &SocketAddr> + '_ {
|
||||
self.seen_addresses.iter()
|
||||
pub fn seen_multiaddrs(&self) -> impl Iterator<Item = &Multiaddr> + '_ {
|
||||
self.seen_multiaddrs.iter()
|
||||
}
|
||||
|
||||
/// Returns a list of seen IP addresses for the peer.
|
||||
pub fn seen_ip_addresses(&self) -> impl Iterator<Item = IpAddr> + '_ {
|
||||
self.seen_addresses
|
||||
.iter()
|
||||
.map(|socket_addr| socket_addr.ip())
|
||||
self.seen_multiaddrs.iter().filter_map(|multiaddr| {
|
||||
multiaddr.iter().find_map(|protocol| {
|
||||
match protocol {
|
||||
Protocol::Ip4(ip) => Some(ip.into()),
|
||||
Protocol::Ip6(ip) => Some(ip.into()),
|
||||
_ => None, // Only care for IP addresses
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the connection status of the peer.
|
||||
@ -415,7 +421,7 @@ impl<T: EthSpec> PeerInfo<T> {
|
||||
|
||||
/// Modifies the status to Connected and increases the number of ingoing
|
||||
/// connections by one
|
||||
pub(super) fn connect_ingoing(&mut self, seen_address: Option<SocketAddr>) {
|
||||
pub(super) fn connect_ingoing(&mut self, seen_multiaddr: Option<Multiaddr>) {
|
||||
match &mut self.connection_status {
|
||||
Connected { n_in, .. } => *n_in += 1,
|
||||
Disconnected { .. }
|
||||
@ -428,14 +434,14 @@ impl<T: EthSpec> PeerInfo<T> {
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(socket_addr) = seen_address {
|
||||
self.seen_addresses.insert(socket_addr);
|
||||
if let Some(multiaddr) = seen_multiaddr {
|
||||
self.seen_multiaddrs.insert(multiaddr);
|
||||
}
|
||||
}
|
||||
|
||||
/// Modifies the status to Connected and increases the number of outgoing
|
||||
/// connections by one
|
||||
pub(super) fn connect_outgoing(&mut self, seen_address: Option<SocketAddr>) {
|
||||
pub(super) fn connect_outgoing(&mut self, seen_multiaddr: Option<Multiaddr>) {
|
||||
match &mut self.connection_status {
|
||||
Connected { n_out, .. } => *n_out += 1,
|
||||
Disconnected { .. }
|
||||
@ -447,8 +453,8 @@ impl<T: EthSpec> PeerInfo<T> {
|
||||
self.connection_direction = Some(ConnectionDirection::Outgoing);
|
||||
}
|
||||
}
|
||||
if let Some(ip_addr) = seen_address {
|
||||
self.seen_addresses.insert(ip_addr);
|
||||
if let Some(multiaddr) = seen_multiaddr {
|
||||
self.seen_multiaddrs.insert(multiaddr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -160,8 +160,6 @@ impl<AppReqId: ReqId, TSpec: EthSpec> Network<AppReqId, TSpec> {
|
||||
let meta_data = utils::load_or_build_metadata(&config.network_dir, &log);
|
||||
let globals = NetworkGlobals::new(
|
||||
enr,
|
||||
config.listen_addrs().v4().map(|v4_addr| v4_addr.tcp_port),
|
||||
config.listen_addrs().v6().map(|v6_addr| v6_addr.tcp_port),
|
||||
meta_data,
|
||||
config
|
||||
.trusted_peers
|
||||
@ -371,8 +369,9 @@ impl<AppReqId: ReqId, TSpec: EthSpec> Network<AppReqId, TSpec> {
|
||||
|
||||
let (swarm, bandwidth) = {
|
||||
// Set up the transport - tcp/ws with noise and mplex
|
||||
let (transport, bandwidth) = build_transport(local_keypair.clone())
|
||||
.map_err(|e| format!("Failed to build transport: {:?}", e))?;
|
||||
let (transport, bandwidth) =
|
||||
build_transport(local_keypair.clone(), !config.disable_quic_support)
|
||||
.map_err(|e| format!("Failed to build transport: {:?}", e))?;
|
||||
|
||||
// use the executor for libp2p
|
||||
struct Executor(task_executor::TaskExecutor);
|
||||
@ -427,9 +426,16 @@ impl<AppReqId: ReqId, TSpec: EthSpec> Network<AppReqId, TSpec> {
|
||||
async fn start(&mut self, config: &crate::NetworkConfig) -> error::Result<()> {
|
||||
let enr = self.network_globals.local_enr();
|
||||
info!(self.log, "Libp2p Starting"; "peer_id" => %enr.peer_id(), "bandwidth_config" => format!("{}-{}", config.network_load, NetworkLoad::from(config.network_load).name));
|
||||
debug!(self.log, "Attempting to open listening ports"; config.listen_addrs(), "discovery_enabled" => !config.disable_discovery);
|
||||
debug!(self.log, "Attempting to open listening ports"; config.listen_addrs(), "discovery_enabled" => !config.disable_discovery, "quic_enabled" => !config.disable_quic_support);
|
||||
|
||||
for listen_multiaddr in config.listen_addrs().libp2p_addresses() {
|
||||
// If QUIC is disabled, ignore listening on QUIC ports
|
||||
if config.disable_quic_support
|
||||
&& listen_multiaddr.iter().any(|v| v == MProtocol::QuicV1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for listen_multiaddr in config.listen_addrs().tcp_addresses() {
|
||||
match self.swarm.listen_on(listen_multiaddr.clone()) {
|
||||
Ok(_) => {
|
||||
let mut log_address = listen_multiaddr;
|
||||
@ -470,6 +476,20 @@ impl<AppReqId: ReqId, TSpec: EthSpec> Network<AppReqId, TSpec> {
|
||||
boot_nodes.dedup();
|
||||
|
||||
for bootnode_enr in boot_nodes {
|
||||
// If QUIC is enabled, attempt QUIC connections first
|
||||
if !config.disable_quic_support {
|
||||
for quic_multiaddr in &bootnode_enr.multiaddr_quic() {
|
||||
if !self
|
||||
.network_globals
|
||||
.peers
|
||||
.read()
|
||||
.is_connected_or_dialing(&bootnode_enr.peer_id())
|
||||
{
|
||||
dial(quic_multiaddr.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for multiaddr in &bootnode_enr.multiaddr() {
|
||||
// ignore udp multiaddr if it exists
|
||||
let components = multiaddr.iter().collect::<Vec<_>>();
|
||||
@ -1058,30 +1078,27 @@ impl<AppReqId: ReqId, TSpec: EthSpec> Network<AppReqId, TSpec> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Dial cached enrs in discovery service that are in the given `subnet_id` and aren't
|
||||
/// Dial cached Enrs in discovery service that are in the given `subnet_id` and aren't
|
||||
/// in Connected, Dialing or Banned state.
|
||||
fn dial_cached_enrs_in_subnet(&mut self, subnet: Subnet) {
|
||||
let predicate = subnet_predicate::<TSpec>(vec![subnet], &self.log);
|
||||
let peers_to_dial: Vec<PeerId> = self
|
||||
let peers_to_dial: Vec<Enr> = self
|
||||
.discovery()
|
||||
.cached_enrs()
|
||||
.filter_map(|(peer_id, enr)| {
|
||||
let peers = self.network_globals.peers.read();
|
||||
if predicate(enr) && peers.should_dial(peer_id) {
|
||||
Some(*peer_id)
|
||||
.filter_map(|(_peer_id, enr)| {
|
||||
if predicate(enr) {
|
||||
Some(enr.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
for peer_id in peers_to_dial {
|
||||
debug!(self.log, "Dialing cached ENR peer"; "peer_id" => %peer_id);
|
||||
// Remove the ENR from the cache to prevent continual re-dialing on disconnects
|
||||
|
||||
self.discovery_mut().remove_cached_enr(&peer_id);
|
||||
// For any dial event, inform the peer manager
|
||||
let enr = self.discovery_mut().enr_of_peer(&peer_id);
|
||||
self.peer_manager_mut().dial_peer(&peer_id, enr);
|
||||
// Remove the ENR from the cache to prevent continual re-dialing on disconnects
|
||||
for enr in peers_to_dial {
|
||||
debug!(self.log, "Dialing cached ENR peer"; "peer_id" => %enr.peer_id());
|
||||
self.discovery_mut().remove_cached_enr(&enr.peer_id());
|
||||
self.peer_manager_mut().dial_peer(enr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1388,22 +1405,6 @@ impl<AppReqId: ReqId, TSpec: EthSpec> Network<AppReqId, TSpec> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Handle a discovery event.
|
||||
fn inject_discovery_event(
|
||||
&mut self,
|
||||
event: DiscoveredPeers,
|
||||
) -> Option<NetworkEvent<AppReqId, TSpec>> {
|
||||
let DiscoveredPeers { peers } = event;
|
||||
let to_dial_peers = self.peer_manager_mut().peers_discovered(peers);
|
||||
for peer_id in to_dial_peers {
|
||||
debug!(self.log, "Dialing discovered peer"; "peer_id" => %peer_id);
|
||||
// For any dial event, inform the peer manager
|
||||
let enr = self.discovery_mut().enr_of_peer(&peer_id);
|
||||
self.peer_manager_mut().dial_peer(&peer_id, enr);
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Handle an identify event.
|
||||
fn inject_identify_event(
|
||||
&mut self,
|
||||
@ -1504,7 +1505,14 @@ impl<AppReqId: ReqId, TSpec: EthSpec> Network<AppReqId, TSpec> {
|
||||
BehaviourEvent::BannedPeers(void) => void::unreachable(void),
|
||||
BehaviourEvent::Gossipsub(ge) => self.inject_gs_event(ge),
|
||||
BehaviourEvent::Eth2Rpc(re) => self.inject_rpc_event(re),
|
||||
BehaviourEvent::Discovery(de) => self.inject_discovery_event(de),
|
||||
// Inform the peer manager about discovered peers.
|
||||
//
|
||||
// The peer manager will subsequently decide which peers need to be dialed and then dial
|
||||
// them.
|
||||
BehaviourEvent::Discovery(DiscoveredPeers { peers }) => {
|
||||
self.peer_manager_mut().peers_discovered(peers);
|
||||
None
|
||||
}
|
||||
BehaviourEvent::Identify(ie) => self.inject_identify_event(ie),
|
||||
BehaviourEvent::PeerManager(pe) => self.inject_pm_event(pe),
|
||||
BehaviourEvent::ConnectionLimits(le) => void::unreachable(le),
|
||||
@ -1536,7 +1544,7 @@ impl<AppReqId: ReqId, TSpec: EthSpec> Network<AppReqId, TSpec> {
|
||||
format!("Dialing local peer id {endpoint:?}")
|
||||
}
|
||||
libp2p::swarm::ListenError::Denied { cause } => {
|
||||
format!("Connection was denied with cause {cause}")
|
||||
format!("Connection was denied with cause: {cause:?}")
|
||||
}
|
||||
libp2p::swarm::ListenError::Transport(t) => match t {
|
||||
libp2p::TransportError::MultiaddrNotSupported(m) => {
|
||||
@ -1586,13 +1594,7 @@ impl<AppReqId: ReqId, TSpec: EthSpec> Network<AppReqId, TSpec> {
|
||||
None
|
||||
}
|
||||
}
|
||||
SwarmEvent::Dialing {
|
||||
peer_id,
|
||||
connection_id: _,
|
||||
} => {
|
||||
debug!(self.log, "Swarm Dialing"; "peer_id" => ?peer_id);
|
||||
None
|
||||
}
|
||||
SwarmEvent::Dialing { .. } => None,
|
||||
};
|
||||
|
||||
if let Some(ev) = maybe_event {
|
||||
|
@ -4,11 +4,13 @@ use crate::types::{
|
||||
error, EnrAttestationBitfield, EnrSyncCommitteeBitfield, GossipEncoding, GossipKind,
|
||||
};
|
||||
use crate::{GossipTopic, NetworkConfig};
|
||||
use futures::future::Either;
|
||||
use libp2p::bandwidth::BandwidthSinks;
|
||||
use libp2p::core::{multiaddr::Multiaddr, muxing::StreamMuxerBox, transport::Boxed};
|
||||
use libp2p::gossipsub;
|
||||
use libp2p::identity::{secp256k1, Keypair};
|
||||
use libp2p::{core, noise, yamux, PeerId, Transport, TransportExt};
|
||||
use libp2p_quic;
|
||||
use prometheus_client::registry::Registry;
|
||||
use slog::{debug, warn};
|
||||
use ssz::Decode;
|
||||
@ -37,19 +39,12 @@ pub struct Context<'a> {
|
||||
|
||||
type BoxedTransport = Boxed<(PeerId, StreamMuxerBox)>;
|
||||
|
||||
/// The implementation supports TCP/IP, WebSockets over TCP/IP, noise as the encryption layer, and
|
||||
/// mplex as the multiplexing layer.
|
||||
/// The implementation supports TCP/IP, QUIC (experimental) over UDP, noise as the encryption layer, and
|
||||
/// mplex/yamux as the multiplexing layer (when using TCP).
|
||||
pub fn build_transport(
|
||||
local_private_key: Keypair,
|
||||
quic_support: bool,
|
||||
) -> std::io::Result<(BoxedTransport, Arc<BandwidthSinks>)> {
|
||||
let tcp = libp2p::tcp::tokio::Transport::new(libp2p::tcp::Config::default().nodelay(true));
|
||||
let transport = libp2p::dns::TokioDnsConfig::system(tcp)?;
|
||||
#[cfg(feature = "libp2p-websocket")]
|
||||
let transport = {
|
||||
let trans_clone = transport.clone();
|
||||
transport.or_transport(libp2p::websocket::WsConfig::new(trans_clone))
|
||||
};
|
||||
|
||||
// mplex config
|
||||
let mut mplex_config = libp2p_mplex::MplexConfig::new();
|
||||
mplex_config.set_max_buffer_size(256);
|
||||
@ -58,18 +53,34 @@ pub fn build_transport(
|
||||
// yamux config
|
||||
let mut yamux_config = yamux::Config::default();
|
||||
yamux_config.set_window_update_mode(yamux::WindowUpdateMode::on_read());
|
||||
let (transport, bandwidth) = transport
|
||||
|
||||
// Creates the TCP transport layer
|
||||
let tcp = libp2p::tcp::tokio::Transport::new(libp2p::tcp::Config::default().nodelay(true))
|
||||
.upgrade(core::upgrade::Version::V1)
|
||||
.authenticate(generate_noise_config(&local_private_key))
|
||||
.multiplex(core::upgrade::SelectUpgrade::new(
|
||||
yamux_config,
|
||||
mplex_config,
|
||||
))
|
||||
.timeout(Duration::from_secs(10))
|
||||
.boxed()
|
||||
.with_bandwidth_logging();
|
||||
.timeout(Duration::from_secs(10));
|
||||
|
||||
let (transport, bandwidth) = if quic_support {
|
||||
// Enables Quic
|
||||
// The default quic configuration suits us for now.
|
||||
let quic_config = libp2p_quic::Config::new(&local_private_key);
|
||||
tcp.or_transport(libp2p_quic::tokio::Transport::new(quic_config))
|
||||
.map(|either_output, _| match either_output {
|
||||
Either::Left((peer_id, muxer)) => (peer_id, StreamMuxerBox::new(muxer)),
|
||||
Either::Right((peer_id, muxer)) => (peer_id, StreamMuxerBox::new(muxer)),
|
||||
})
|
||||
.with_bandwidth_logging()
|
||||
} else {
|
||||
tcp.with_bandwidth_logging()
|
||||
};
|
||||
|
||||
// // Enables DNS over the transport.
|
||||
let transport = libp2p::dns::TokioDnsConfig::system(transport)?.boxed();
|
||||
|
||||
// Authentication
|
||||
Ok((transport, bandwidth))
|
||||
}
|
||||
|
||||
|
@ -16,10 +16,6 @@ pub struct NetworkGlobals<TSpec: EthSpec> {
|
||||
pub peer_id: RwLock<PeerId>,
|
||||
/// Listening multiaddrs.
|
||||
pub listen_multiaddrs: RwLock<Vec<Multiaddr>>,
|
||||
/// The TCP port that the libp2p service is listening on over Ipv4.
|
||||
listen_port_tcp4: Option<u16>,
|
||||
/// The TCP port that the libp2p service is listening on over Ipv6.
|
||||
listen_port_tcp6: Option<u16>,
|
||||
/// The collection of known peers.
|
||||
pub peers: RwLock<PeerDB<TSpec>>,
|
||||
// The local meta data of our node.
|
||||
@ -35,8 +31,6 @@ pub struct NetworkGlobals<TSpec: EthSpec> {
|
||||
impl<TSpec: EthSpec> NetworkGlobals<TSpec> {
|
||||
pub fn new(
|
||||
enr: Enr,
|
||||
listen_port_tcp4: Option<u16>,
|
||||
listen_port_tcp6: Option<u16>,
|
||||
local_metadata: MetaData<TSpec>,
|
||||
trusted_peers: Vec<PeerId>,
|
||||
disable_peer_scoring: bool,
|
||||
@ -46,8 +40,6 @@ impl<TSpec: EthSpec> NetworkGlobals<TSpec> {
|
||||
local_enr: RwLock::new(enr.clone()),
|
||||
peer_id: RwLock::new(enr.peer_id()),
|
||||
listen_multiaddrs: RwLock::new(Vec::new()),
|
||||
listen_port_tcp4,
|
||||
listen_port_tcp6,
|
||||
local_metadata: RwLock::new(local_metadata),
|
||||
peers: RwLock::new(PeerDB::new(trusted_peers, disable_peer_scoring, log)),
|
||||
gossipsub_subscriptions: RwLock::new(HashSet::new()),
|
||||
@ -72,16 +64,6 @@ impl<TSpec: EthSpec> NetworkGlobals<TSpec> {
|
||||
self.listen_multiaddrs.read().clone()
|
||||
}
|
||||
|
||||
/// Returns the libp2p TCP port that this node has been configured to listen on.
|
||||
pub fn listen_port_tcp4(&self) -> Option<u16> {
|
||||
self.listen_port_tcp4
|
||||
}
|
||||
|
||||
/// Returns the UDP discovery port that this node has been configured to listen on.
|
||||
pub fn listen_port_tcp6(&self) -> Option<u16> {
|
||||
self.listen_port_tcp6
|
||||
}
|
||||
|
||||
/// Returns the number of libp2p connected peers.
|
||||
pub fn connected_peers(&self) -> usize {
|
||||
self.peers.read().connected_peer_ids().count()
|
||||
@ -139,8 +121,6 @@ impl<TSpec: EthSpec> NetworkGlobals<TSpec> {
|
||||
let enr = discv5::enr::EnrBuilder::new("v4").build(&enr_key).unwrap();
|
||||
NetworkGlobals::new(
|
||||
enr,
|
||||
Some(9000),
|
||||
None,
|
||||
MetaData::V2(MetaDataV2 {
|
||||
seq_number: 0,
|
||||
attnets: Default::default(),
|
||||
|
@ -13,7 +13,6 @@ use tokio::runtime::Runtime;
|
||||
use types::{
|
||||
ChainSpec, EnrForkId, Epoch, EthSpec, ForkContext, ForkName, Hash256, MinimalEthSpec, Slot,
|
||||
};
|
||||
use unused_port::unused_tcp4_port;
|
||||
|
||||
type E = MinimalEthSpec;
|
||||
type ReqId = usize;
|
||||
@ -71,15 +70,19 @@ pub fn build_log(level: slog::Level, enabled: bool) -> slog::Logger {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build_config(port: u16, mut boot_nodes: Vec<Enr>) -> NetworkConfig {
|
||||
pub fn build_config(mut boot_nodes: Vec<Enr>) -> NetworkConfig {
|
||||
let mut config = NetworkConfig::default();
|
||||
|
||||
// Find unused ports by using the 0 port.
|
||||
let port = 0;
|
||||
|
||||
let random_path: u16 = rand::random();
|
||||
let path = TempBuilder::new()
|
||||
.prefix(&format!("libp2p_test{}", port))
|
||||
.prefix(&format!("libp2p_test_{}", random_path))
|
||||
.tempdir()
|
||||
.unwrap();
|
||||
|
||||
config.set_ipv4_listening_address(std::net::Ipv4Addr::UNSPECIFIED, port, port);
|
||||
config.enr_udp4_port = Some(port);
|
||||
config.set_ipv4_listening_address(std::net::Ipv4Addr::UNSPECIFIED, port, port, port);
|
||||
config.enr_address = (Some(std::net::Ipv4Addr::LOCALHOST), None);
|
||||
config.boot_nodes_enr.append(&mut boot_nodes);
|
||||
config.network_dir = path.into_path();
|
||||
@ -99,8 +102,7 @@ pub async fn build_libp2p_instance(
|
||||
fork_name: ForkName,
|
||||
spec: &ChainSpec,
|
||||
) -> Libp2pInstance {
|
||||
let port = unused_tcp4_port().unwrap();
|
||||
let config = build_config(port, boot_nodes);
|
||||
let config = build_config(boot_nodes);
|
||||
// launch libp2p service
|
||||
|
||||
let (signal, exit) = exit_future::signal();
|
||||
@ -127,6 +129,12 @@ pub fn get_enr(node: &LibP2PService<ReqId, E>) -> Enr {
|
||||
node.local_enr()
|
||||
}
|
||||
|
||||
// Protocol for the node pair connection.
|
||||
pub enum Protocol {
|
||||
Tcp,
|
||||
Quic,
|
||||
}
|
||||
|
||||
// Constructs a pair of nodes with separate loggers. The sender dials the receiver.
|
||||
// This returns a (sender, receiver) pair.
|
||||
#[allow(dead_code)]
|
||||
@ -135,6 +143,7 @@ pub async fn build_node_pair(
|
||||
log: &slog::Logger,
|
||||
fork_name: ForkName,
|
||||
spec: &ChainSpec,
|
||||
protocol: Protocol,
|
||||
) -> (Libp2pInstance, Libp2pInstance) {
|
||||
let sender_log = log.new(o!("who" => "sender"));
|
||||
let receiver_log = log.new(o!("who" => "receiver"));
|
||||
@ -142,33 +151,57 @@ pub async fn build_node_pair(
|
||||
let mut sender = build_libp2p_instance(rt.clone(), vec![], sender_log, fork_name, spec).await;
|
||||
let mut receiver = build_libp2p_instance(rt, vec![], receiver_log, fork_name, spec).await;
|
||||
|
||||
let receiver_multiaddr = receiver.local_enr().multiaddr()[1].clone();
|
||||
|
||||
// let the two nodes set up listeners
|
||||
let sender_fut = async {
|
||||
loop {
|
||||
if let NetworkEvent::NewListenAddr(_) = sender.next_event().await {
|
||||
return;
|
||||
if let NetworkEvent::NewListenAddr(addr) = sender.next_event().await {
|
||||
// Only end once we've listened on the protocol we care about
|
||||
match protocol {
|
||||
Protocol::Tcp => {
|
||||
if addr.iter().any(|multiaddr_proto| {
|
||||
matches!(multiaddr_proto, libp2p::multiaddr::Protocol::Tcp(_))
|
||||
}) {
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
Protocol::Quic => {
|
||||
if addr.iter().any(|multiaddr_proto| {
|
||||
matches!(multiaddr_proto, libp2p::multiaddr::Protocol::QuicV1)
|
||||
}) {
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
let receiver_fut = async {
|
||||
loop {
|
||||
if let NetworkEvent::NewListenAddr(_) = receiver.next_event().await {
|
||||
return;
|
||||
if let NetworkEvent::NewListenAddr(addr) = receiver.next_event().await {
|
||||
match protocol {
|
||||
Protocol::Tcp => {
|
||||
if addr.iter().any(|multiaddr_proto| {
|
||||
matches!(multiaddr_proto, libp2p::multiaddr::Protocol::Tcp(_))
|
||||
}) {
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
Protocol::Quic => {
|
||||
if addr.iter().any(|multiaddr_proto| {
|
||||
matches!(multiaddr_proto, libp2p::multiaddr::Protocol::QuicV1)
|
||||
}) {
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let joined = futures::future::join(sender_fut, receiver_fut);
|
||||
|
||||
// wait for either both nodes to listen or a timeout
|
||||
tokio::select! {
|
||||
_ = tokio::time::sleep(Duration::from_millis(500)) => {}
|
||||
_ = joined => {}
|
||||
}
|
||||
let receiver_multiaddr = joined.await.1;
|
||||
|
||||
// sender.dial_peer(peer_id);
|
||||
match sender.testing_dial(receiver_multiaddr.clone()) {
|
||||
Ok(()) => {
|
||||
debug!(log, "Sender dialed receiver"; "address" => format!("{:?}", receiver_multiaddr))
|
||||
|
@ -1,4 +1,8 @@
|
||||
#![cfg(test)]
|
||||
|
||||
mod common;
|
||||
|
||||
use common::Protocol;
|
||||
use lighthouse_network::rpc::methods::*;
|
||||
use lighthouse_network::{rpc::max_rpc_size, NetworkEvent, ReportSource, Request, Response};
|
||||
use slog::{debug, warn, Level};
|
||||
@ -14,8 +18,6 @@ use types::{
|
||||
SignedBeaconBlock, Slot,
|
||||
};
|
||||
|
||||
mod common;
|
||||
|
||||
type E = MinimalEthSpec;
|
||||
|
||||
/// Merge block with length < max_rpc_size.
|
||||
@ -49,7 +51,7 @@ fn merge_block_large(fork_context: &ForkContext, spec: &ChainSpec) -> BeaconBloc
|
||||
// Tests the STATUS RPC message
|
||||
#[test]
|
||||
#[allow(clippy::single_match)]
|
||||
fn test_status_rpc() {
|
||||
fn test_tcp_status_rpc() {
|
||||
// set up the logging. The level and enabled logging or not
|
||||
let log_level = Level::Debug;
|
||||
let enable_logging = false;
|
||||
@ -62,8 +64,14 @@ fn test_status_rpc() {
|
||||
|
||||
rt.block_on(async {
|
||||
// get sender/receiver
|
||||
let (mut sender, mut receiver) =
|
||||
common::build_node_pair(Arc::downgrade(&rt), &log, ForkName::Base, &spec).await;
|
||||
let (mut sender, mut receiver) = common::build_node_pair(
|
||||
Arc::downgrade(&rt),
|
||||
&log,
|
||||
ForkName::Base,
|
||||
&spec,
|
||||
Protocol::Tcp,
|
||||
)
|
||||
.await;
|
||||
|
||||
// Dummy STATUS RPC message
|
||||
let rpc_request = Request::Status(StatusMessage {
|
||||
@ -141,7 +149,7 @@ fn test_status_rpc() {
|
||||
// Tests a streamed BlocksByRange RPC Message
|
||||
#[test]
|
||||
#[allow(clippy::single_match)]
|
||||
fn test_blocks_by_range_chunked_rpc() {
|
||||
fn test_tcp_blocks_by_range_chunked_rpc() {
|
||||
// set up the logging. The level and enabled logging or not
|
||||
let log_level = Level::Debug;
|
||||
let enable_logging = false;
|
||||
@ -156,8 +164,14 @@ fn test_blocks_by_range_chunked_rpc() {
|
||||
|
||||
rt.block_on(async {
|
||||
// get sender/receiver
|
||||
let (mut sender, mut receiver) =
|
||||
common::build_node_pair(Arc::downgrade(&rt), &log, ForkName::Merge, &spec).await;
|
||||
let (mut sender, mut receiver) = common::build_node_pair(
|
||||
Arc::downgrade(&rt),
|
||||
&log,
|
||||
ForkName::Merge,
|
||||
&spec,
|
||||
Protocol::Tcp,
|
||||
)
|
||||
.await;
|
||||
|
||||
// BlocksByRange Request
|
||||
let rpc_request = Request::BlocksByRange(BlocksByRangeRequest::new(0, messages_to_send));
|
||||
@ -282,8 +296,14 @@ fn test_blobs_by_range_chunked_rpc() {
|
||||
rt.block_on(async {
|
||||
// get sender/receiver
|
||||
let spec = E::default_spec();
|
||||
let (mut sender, mut receiver) =
|
||||
common::build_node_pair(Arc::downgrade(&rt), &log, ForkName::Deneb, &spec).await;
|
||||
let (mut sender, mut receiver) = common::build_node_pair(
|
||||
Arc::downgrade(&rt),
|
||||
&log,
|
||||
ForkName::Deneb,
|
||||
&spec,
|
||||
Protocol::Tcp,
|
||||
)
|
||||
.await;
|
||||
|
||||
// BlobsByRange Request
|
||||
let rpc_request = Request::BlobsByRange(BlobsByRangeRequest {
|
||||
@ -373,7 +393,7 @@ fn test_blobs_by_range_chunked_rpc() {
|
||||
// Tests rejection of blocks over `MAX_RPC_SIZE`.
|
||||
#[test]
|
||||
#[allow(clippy::single_match)]
|
||||
fn test_blocks_by_range_over_limit() {
|
||||
fn test_tcp_blocks_by_range_over_limit() {
|
||||
// set up the logging. The level and enabled logging or not
|
||||
let log_level = Level::Debug;
|
||||
let enable_logging = false;
|
||||
@ -388,8 +408,14 @@ fn test_blocks_by_range_over_limit() {
|
||||
|
||||
rt.block_on(async {
|
||||
// get sender/receiver
|
||||
let (mut sender, mut receiver) =
|
||||
common::build_node_pair(Arc::downgrade(&rt), &log, ForkName::Merge, &spec).await;
|
||||
let (mut sender, mut receiver) = common::build_node_pair(
|
||||
Arc::downgrade(&rt),
|
||||
&log,
|
||||
ForkName::Merge,
|
||||
&spec,
|
||||
Protocol::Tcp,
|
||||
)
|
||||
.await;
|
||||
|
||||
// BlocksByRange Request
|
||||
let rpc_request = Request::BlocksByRange(BlocksByRangeRequest::new(0, messages_to_send));
|
||||
@ -456,7 +482,7 @@ fn test_blocks_by_range_over_limit() {
|
||||
|
||||
// Tests that a streamed BlocksByRange RPC Message terminates when all expected chunks were received
|
||||
#[test]
|
||||
fn test_blocks_by_range_chunked_rpc_terminates_correctly() {
|
||||
fn test_tcp_blocks_by_range_chunked_rpc_terminates_correctly() {
|
||||
// set up the logging. The level and enabled logging or not
|
||||
let log_level = Level::Debug;
|
||||
let enable_logging = false;
|
||||
@ -472,8 +498,14 @@ fn test_blocks_by_range_chunked_rpc_terminates_correctly() {
|
||||
|
||||
rt.block_on(async {
|
||||
// get sender/receiver
|
||||
let (mut sender, mut receiver) =
|
||||
common::build_node_pair(Arc::downgrade(&rt), &log, ForkName::Base, &spec).await;
|
||||
let (mut sender, mut receiver) = common::build_node_pair(
|
||||
Arc::downgrade(&rt),
|
||||
&log,
|
||||
ForkName::Base,
|
||||
&spec,
|
||||
Protocol::Tcp,
|
||||
)
|
||||
.await;
|
||||
|
||||
// BlocksByRange Request
|
||||
let rpc_request = Request::BlocksByRange(BlocksByRangeRequest::new(0, messages_to_send));
|
||||
@ -582,7 +614,7 @@ fn test_blocks_by_range_chunked_rpc_terminates_correctly() {
|
||||
// Tests an empty response to a BlocksByRange RPC Message
|
||||
#[test]
|
||||
#[allow(clippy::single_match)]
|
||||
fn test_blocks_by_range_single_empty_rpc() {
|
||||
fn test_tcp_blocks_by_range_single_empty_rpc() {
|
||||
// set up the logging. The level and enabled logging or not
|
||||
let log_level = Level::Trace;
|
||||
let enable_logging = false;
|
||||
@ -594,8 +626,14 @@ fn test_blocks_by_range_single_empty_rpc() {
|
||||
|
||||
rt.block_on(async {
|
||||
// get sender/receiver
|
||||
let (mut sender, mut receiver) =
|
||||
common::build_node_pair(Arc::downgrade(&rt), &log, ForkName::Base, &spec).await;
|
||||
let (mut sender, mut receiver) = common::build_node_pair(
|
||||
Arc::downgrade(&rt),
|
||||
&log,
|
||||
ForkName::Base,
|
||||
&spec,
|
||||
Protocol::Tcp,
|
||||
)
|
||||
.await;
|
||||
|
||||
// BlocksByRange Request
|
||||
let rpc_request = Request::BlocksByRange(BlocksByRangeRequest::new(0, 10));
|
||||
@ -682,7 +720,7 @@ fn test_blocks_by_range_single_empty_rpc() {
|
||||
// serves to test the snappy framing format as well.
|
||||
#[test]
|
||||
#[allow(clippy::single_match)]
|
||||
fn test_blocks_by_root_chunked_rpc() {
|
||||
fn test_tcp_blocks_by_root_chunked_rpc() {
|
||||
// set up the logging. The level and enabled logging or not
|
||||
let log_level = Level::Debug;
|
||||
let enable_logging = false;
|
||||
@ -695,8 +733,14 @@ fn test_blocks_by_root_chunked_rpc() {
|
||||
let rt = Arc::new(Runtime::new().unwrap());
|
||||
// get sender/receiver
|
||||
rt.block_on(async {
|
||||
let (mut sender, mut receiver) =
|
||||
common::build_node_pair(Arc::downgrade(&rt), &log, ForkName::Merge, &spec).await;
|
||||
let (mut sender, mut receiver) = common::build_node_pair(
|
||||
Arc::downgrade(&rt),
|
||||
&log,
|
||||
ForkName::Merge,
|
||||
&spec,
|
||||
Protocol::Tcp,
|
||||
)
|
||||
.await;
|
||||
|
||||
// BlocksByRoot Request
|
||||
let rpc_request =
|
||||
@ -808,7 +852,7 @@ fn test_blocks_by_root_chunked_rpc() {
|
||||
|
||||
// Tests a streamed, chunked BlocksByRoot RPC Message terminates when all expected reponses have been received
|
||||
#[test]
|
||||
fn test_blocks_by_root_chunked_rpc_terminates_correctly() {
|
||||
fn test_tcp_blocks_by_root_chunked_rpc_terminates_correctly() {
|
||||
// set up the logging. The level and enabled logging or not
|
||||
let log_level = Level::Debug;
|
||||
let enable_logging = false;
|
||||
@ -822,8 +866,14 @@ fn test_blocks_by_root_chunked_rpc_terminates_correctly() {
|
||||
let rt = Arc::new(Runtime::new().unwrap());
|
||||
// get sender/receiver
|
||||
rt.block_on(async {
|
||||
let (mut sender, mut receiver) =
|
||||
common::build_node_pair(Arc::downgrade(&rt), &log, ForkName::Base, &spec).await;
|
||||
let (mut sender, mut receiver) = common::build_node_pair(
|
||||
Arc::downgrade(&rt),
|
||||
&log,
|
||||
ForkName::Base,
|
||||
&spec,
|
||||
Protocol::Tcp,
|
||||
)
|
||||
.await;
|
||||
|
||||
// BlocksByRoot Request
|
||||
let rpc_request =
|
||||
@ -939,14 +989,9 @@ fn test_blocks_by_root_chunked_rpc_terminates_correctly() {
|
||||
})
|
||||
}
|
||||
|
||||
// Tests a Goodbye RPC message
|
||||
#[test]
|
||||
#[allow(clippy::single_match)]
|
||||
fn test_goodbye_rpc() {
|
||||
// set up the logging. The level and enabled logging or not
|
||||
let log_level = Level::Trace;
|
||||
let enable_logging = false;
|
||||
|
||||
/// Establishes a pair of nodes and disconnects the pair based on the selected protocol via an RPC
|
||||
/// Goodbye message.
|
||||
fn goodbye_test(log_level: Level, enable_logging: bool, protocol: Protocol) {
|
||||
let log = common::build_log(log_level, enable_logging);
|
||||
|
||||
let rt = Arc::new(Runtime::new().unwrap());
|
||||
@ -956,7 +1001,8 @@ fn test_goodbye_rpc() {
|
||||
// get sender/receiver
|
||||
rt.block_on(async {
|
||||
let (mut sender, mut receiver) =
|
||||
common::build_node_pair(Arc::downgrade(&rt), &log, ForkName::Base, &spec).await;
|
||||
common::build_node_pair(Arc::downgrade(&rt), &log, ForkName::Base, &spec, protocol)
|
||||
.await;
|
||||
|
||||
// build the sender future
|
||||
let sender_future = async {
|
||||
@ -982,12 +1028,9 @@ fn test_goodbye_rpc() {
|
||||
// build the receiver future
|
||||
let receiver_future = async {
|
||||
loop {
|
||||
match receiver.next_event().await {
|
||||
NetworkEvent::PeerDisconnected(_) => {
|
||||
// Should receive sent RPC request
|
||||
return;
|
||||
}
|
||||
_ => {} // Ignore other events
|
||||
if let NetworkEvent::PeerDisconnected(_) = receiver.next_event().await {
|
||||
// Should receive sent RPC request
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -1002,3 +1045,23 @@ fn test_goodbye_rpc() {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Tests a Goodbye RPC message
|
||||
#[test]
|
||||
#[allow(clippy::single_match)]
|
||||
fn tcp_test_goodbye_rpc() {
|
||||
// set up the logging. The level and enabled logging or not
|
||||
let log_level = Level::Debug;
|
||||
let enable_logging = true;
|
||||
goodbye_test(log_level, enable_logging, Protocol::Tcp);
|
||||
}
|
||||
|
||||
// Tests a Goodbye RPC message
|
||||
#[test]
|
||||
#[allow(clippy::single_match)]
|
||||
fn quic_test_goodbye_rpc() {
|
||||
// set up the logging. The level and enabled logging or not
|
||||
let log_level = Level::Debug;
|
||||
let enable_logging = true;
|
||||
goodbye_test(log_level, enable_logging, Protocol::Quic);
|
||||
}
|
||||
|
@ -2,53 +2,54 @@
|
||||
name = "network"
|
||||
version = "0.2.0"
|
||||
authors = ["Sigma Prime <contact@sigmaprime.io>"]
|
||||
edition = "2021"
|
||||
edition = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
sloggers = { version = "2.1.1", features = ["json"] }
|
||||
genesis = { path = "../genesis" }
|
||||
sloggers = { workspace = true }
|
||||
genesis = { workspace = true }
|
||||
matches = "0.1.8"
|
||||
exit-future = "0.2.0"
|
||||
slog-term = "2.6.0"
|
||||
slog-async = "2.5.0"
|
||||
eth2 = {path="../../common/eth2"}
|
||||
exit-future = { workspace = true }
|
||||
slog-term = { workspace = true }
|
||||
slog-async = { workspace = true }
|
||||
eth2 = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
beacon_chain = { path = "../beacon_chain" }
|
||||
store = { path = "../store" }
|
||||
lighthouse_network = { path = "../lighthouse_network" }
|
||||
types = { path = "../../consensus/types" }
|
||||
slot_clock = { path = "../../common/slot_clock" }
|
||||
slog = { version = "2.5.2", features = ["max_level_trace", "nested-values"] }
|
||||
hex = "0.4.2"
|
||||
ethereum_ssz = "0.5.0"
|
||||
ssz_types = "0.5.4"
|
||||
futures = "0.3.7"
|
||||
error-chain = "0.12.4"
|
||||
tokio = { version = "1.14.0", features = ["full"] }
|
||||
tokio-stream = "0.1.3"
|
||||
smallvec = "1.6.1"
|
||||
rand = "0.8.5"
|
||||
fnv = "1.0.7"
|
||||
beacon_chain = { workspace = true }
|
||||
store = { workspace = true }
|
||||
lighthouse_network = { workspace = true }
|
||||
types = { workspace = true }
|
||||
slot_clock = { workspace = true }
|
||||
slog = { workspace = true }
|
||||
hex = { workspace = true }
|
||||
ethereum_ssz = { workspace = true }
|
||||
ssz_types = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
error-chain = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
tokio-stream = { workspace = true }
|
||||
smallvec = { workspace = true }
|
||||
rand = { workspace = true }
|
||||
fnv = { workspace = true }
|
||||
rlp = "0.5.0"
|
||||
lazy_static = "1.4.0"
|
||||
lighthouse_metrics = { path = "../../common/lighthouse_metrics" }
|
||||
logging = { path = "../../common/logging" }
|
||||
task_executor = { path = "../../common/task_executor" }
|
||||
lazy_static = { workspace = true }
|
||||
lighthouse_metrics = { workspace = true }
|
||||
logging = { workspace = true }
|
||||
task_executor = { workspace = true }
|
||||
igd = "0.12.1"
|
||||
itertools = "0.10.0"
|
||||
lru_cache = { path = "../../common/lru_cache" }
|
||||
itertools = { workspace = true }
|
||||
num_cpus = { workspace = true }
|
||||
lru_cache = { workspace = true }
|
||||
if-addrs = "0.6.4"
|
||||
strum = "0.24.0"
|
||||
tokio-util = { version = "0.6.3", features = ["time"] }
|
||||
derivative = "2.2.0"
|
||||
delay_map = "0.3.0"
|
||||
ethereum-types = { version = "0.14.1", optional = true }
|
||||
operation_pool = { path = "../operation_pool" }
|
||||
execution_layer = { path = "../execution_layer" }
|
||||
beacon_processor = { path = "../beacon_processor" }
|
||||
parking_lot = "0.12.0"
|
||||
environment = { path = "../../lighthouse/environment" }
|
||||
strum = { workspace = true }
|
||||
tokio-util = { workspace = true }
|
||||
derivative = { workspace = true }
|
||||
delay_map = { workspace = true }
|
||||
ethereum-types = { workspace = true }
|
||||
operation_pool = { workspace = true }
|
||||
execution_layer = { workspace = true }
|
||||
beacon_processor = { workspace = true }
|
||||
parking_lot = { workspace = true }
|
||||
environment = { workspace = true }
|
||||
|
||||
[features]
|
||||
# NOTE: This can be run via cargo build --bin lighthouse --features network/disable-backfill
|
||||
|
@ -12,20 +12,49 @@ use types::EthSpec;
|
||||
|
||||
/// Configuration required to construct the UPnP port mappings.
|
||||
pub struct UPnPConfig {
|
||||
/// The local tcp port.
|
||||
/// The local TCP port.
|
||||
tcp_port: u16,
|
||||
/// The local udp port.
|
||||
udp_port: u16,
|
||||
/// The local UDP discovery port.
|
||||
disc_port: u16,
|
||||
/// The local UDP quic port.
|
||||
quic_port: u16,
|
||||
/// Whether discovery is enabled or not.
|
||||
disable_discovery: bool,
|
||||
/// Whether quic is enabled or not.
|
||||
disable_quic_support: bool,
|
||||
}
|
||||
|
||||
/// Contains mappings that managed to be established.
|
||||
#[derive(Default, Debug)]
|
||||
pub struct EstablishedUPnPMappings {
|
||||
/// A TCP port mapping for libp2p.
|
||||
pub tcp_port: Option<u16>,
|
||||
/// A UDP port for the QUIC libp2p transport.
|
||||
pub udp_quic_port: Option<u16>,
|
||||
/// A UDP port for discv5.
|
||||
pub udp_disc_port: Option<u16>,
|
||||
}
|
||||
|
||||
impl EstablishedUPnPMappings {
|
||||
/// Returns true if at least one value is set.
|
||||
pub fn is_some(&self) -> bool {
|
||||
self.tcp_port.is_some() || self.udp_quic_port.is_some() || self.udp_disc_port.is_some()
|
||||
}
|
||||
|
||||
// Iterator over the UDP ports
|
||||
pub fn udp_ports(&self) -> impl Iterator<Item = &u16> {
|
||||
self.udp_quic_port.iter().chain(self.udp_disc_port.iter())
|
||||
}
|
||||
}
|
||||
|
||||
impl UPnPConfig {
|
||||
pub fn from_config(config: &NetworkConfig) -> Option<Self> {
|
||||
config.listen_addrs().v4().map(|v4_addr| UPnPConfig {
|
||||
tcp_port: v4_addr.tcp_port,
|
||||
udp_port: v4_addr.udp_port,
|
||||
disc_port: v4_addr.disc_port,
|
||||
quic_port: v4_addr.quic_port,
|
||||
disable_discovery: config.disable_discovery,
|
||||
disable_quic_support: config.disable_quic_support,
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -68,6 +97,8 @@ pub fn construct_upnp_mappings<T: EthSpec>(
|
||||
|
||||
debug!(log, "UPnP Local IP Discovered"; "ip" => ?local_ip);
|
||||
|
||||
let mut mappings = EstablishedUPnPMappings::default();
|
||||
|
||||
match local_ip {
|
||||
IpAddr::V4(address) => {
|
||||
let libp2p_socket = SocketAddrV4::new(address, config.tcp_port);
|
||||
@ -76,39 +107,46 @@ pub fn construct_upnp_mappings<T: EthSpec>(
|
||||
// one.
|
||||
// I've found this to be more reliable. If multiple users are behind a single
|
||||
// router, they should ideally try to set different port numbers.
|
||||
let tcp_socket = add_port_mapping(
|
||||
mappings.tcp_port = add_port_mapping(
|
||||
&gateway,
|
||||
igd::PortMappingProtocol::TCP,
|
||||
libp2p_socket,
|
||||
"tcp",
|
||||
&log,
|
||||
).and_then(|_| {
|
||||
).map(|_| {
|
||||
let external_socket = external_ip.as_ref().map(|ip| SocketAddr::new((*ip).into(), config.tcp_port)).map_err(|_| ());
|
||||
info!(log, "UPnP TCP route established"; "external_socket" => format!("{}:{}", external_socket.as_ref().map(|ip| ip.to_string()).unwrap_or_else(|_| "".into()), config.tcp_port));
|
||||
external_socket
|
||||
config.tcp_port
|
||||
}).ok();
|
||||
|
||||
let udp_socket = if !config.disable_discovery {
|
||||
let discovery_socket = SocketAddrV4::new(address, config.udp_port);
|
||||
let set_udp_mapping = |udp_port| {
|
||||
let udp_socket = SocketAddrV4::new(address, udp_port);
|
||||
add_port_mapping(
|
||||
&gateway,
|
||||
igd::PortMappingProtocol::UDP,
|
||||
discovery_socket,
|
||||
udp_socket,
|
||||
"udp",
|
||||
&log,
|
||||
).and_then(|_| {
|
||||
let external_socket = external_ip
|
||||
.map(|ip| SocketAddr::new(ip.into(), config.udp_port)).map_err(|_| ());
|
||||
info!(log, "UPnP UDP route established"; "external_socket" => format!("{}:{}", external_socket.as_ref().map(|ip| ip.to_string()).unwrap_or_else(|_| "".into()), config.udp_port));
|
||||
external_socket
|
||||
}).ok()
|
||||
} else {
|
||||
None
|
||||
).map(|_| {
|
||||
info!(log, "UPnP UDP route established"; "external_socket" => format!("{}:{}", external_ip.as_ref().map(|ip| ip.to_string()).unwrap_or_else(|_| "".into()), udp_port));
|
||||
})
|
||||
};
|
||||
|
||||
// Set the discovery UDP port mapping
|
||||
if !config.disable_discovery && set_udp_mapping(config.disc_port).is_ok() {
|
||||
mappings.udp_disc_port = Some(config.disc_port);
|
||||
}
|
||||
|
||||
// Set the quic UDP port mapping
|
||||
if !config.disable_quic_support && set_udp_mapping(config.quic_port).is_ok() {
|
||||
mappings.udp_quic_port = Some(config.quic_port);
|
||||
}
|
||||
|
||||
// report any updates to the network service.
|
||||
network_send.send(NetworkMessage::UPnPMappingEstablished{ tcp_socket, udp_socket })
|
||||
.unwrap_or_else(|e| debug!(log, "Could not send message to the network service"; "error" => %e));
|
||||
if mappings.is_some() {
|
||||
network_send.send(NetworkMessage::UPnPMappingEstablished{ mappings })
|
||||
.unwrap_or_else(|e| debug!(log, "Could not send message to the network service"; "error" => %e));
|
||||
}
|
||||
}
|
||||
_ => debug!(log, "UPnP no routes constructed. IPv6 not supported"),
|
||||
}
|
||||
@ -161,12 +199,12 @@ fn add_port_mapping(
|
||||
}
|
||||
|
||||
/// Removes the specified TCP and UDP port mappings.
|
||||
pub fn remove_mappings(tcp_port: Option<u16>, udp_port: Option<u16>, log: &slog::Logger) {
|
||||
if tcp_port.is_some() || udp_port.is_some() {
|
||||
pub fn remove_mappings(mappings: &EstablishedUPnPMappings, log: &slog::Logger) {
|
||||
if mappings.is_some() {
|
||||
debug!(log, "Removing UPnP port mappings");
|
||||
match igd::search_gateway(Default::default()) {
|
||||
Ok(gateway) => {
|
||||
if let Some(tcp_port) = tcp_port {
|
||||
if let Some(tcp_port) = mappings.tcp_port {
|
||||
match gateway.remove_port(igd::PortMappingProtocol::TCP, tcp_port) {
|
||||
Ok(()) => debug!(log, "UPnP Removed TCP port mapping"; "port" => tcp_port),
|
||||
Err(e) => {
|
||||
@ -174,8 +212,8 @@ pub fn remove_mappings(tcp_port: Option<u16>, udp_port: Option<u16>, log: &slog:
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(udp_port) = udp_port {
|
||||
match gateway.remove_port(igd::PortMappingProtocol::UDP, udp_port) {
|
||||
for udp_port in mappings.udp_ports() {
|
||||
match gateway.remove_port(igd::PortMappingProtocol::UDP, *udp_port) {
|
||||
Ok(()) => debug!(log, "UPnP Removed UDP port mapping"; "port" => udp_port),
|
||||
Err(e) => {
|
||||
debug!(log, "UPnP Failed to remove UDP port mapping"; "port" => udp_port, "error" => %e)
|
||||
|
@ -42,7 +42,6 @@ const VALIDATOR_COUNT: usize = SLOTS_PER_EPOCH as usize;
|
||||
const SMALL_CHAIN: u64 = 2;
|
||||
const LONG_CHAIN: u64 = SLOTS_PER_EPOCH * 2;
|
||||
|
||||
const TCP_PORT: u16 = 42;
|
||||
const SEQ_NUMBER: u64 = 0;
|
||||
|
||||
/// The default time to wait for `BeaconProcessor` events.
|
||||
@ -202,15 +201,7 @@ impl TestRig {
|
||||
});
|
||||
let enr_key = CombinedKey::generate_secp256k1();
|
||||
let enr = EnrBuilder::new("v4").build(&enr_key).unwrap();
|
||||
let network_globals = Arc::new(NetworkGlobals::new(
|
||||
enr,
|
||||
Some(TCP_PORT),
|
||||
None,
|
||||
meta_data,
|
||||
vec![],
|
||||
false,
|
||||
&log,
|
||||
));
|
||||
let network_globals = Arc::new(NetworkGlobals::new(enr, meta_data, vec![], false, &log));
|
||||
|
||||
let executor = harness.runtime.task_executor.clone();
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
use super::sync::manager::RequestId as SyncId;
|
||||
use crate::nat::EstablishedUPnPMappings;
|
||||
use crate::network_beacon_processor::InvalidBlockStorage;
|
||||
use crate::persisted_dht::{clear_dht, load_dht, persist_dht};
|
||||
use crate::router::{Router, RouterMessage};
|
||||
@ -26,7 +27,7 @@ use lighthouse_network::{
|
||||
MessageId, NetworkEvent, NetworkGlobals, PeerId,
|
||||
};
|
||||
use slog::{crit, debug, error, info, o, trace, warn};
|
||||
use std::{collections::HashSet, net::SocketAddr, pin::Pin, sync::Arc, time::Duration};
|
||||
use std::{collections::HashSet, pin::Pin, sync::Arc, time::Duration};
|
||||
use store::HotColdDB;
|
||||
use strum::IntoStaticStr;
|
||||
use task_executor::ShutdownReason;
|
||||
@ -93,12 +94,10 @@ pub enum NetworkMessage<T: EthSpec> {
|
||||
/// The result of the validation
|
||||
validation_result: MessageAcceptance,
|
||||
},
|
||||
/// Called if a known external TCP socket address has been updated.
|
||||
/// Called if UPnP managed to establish an external port mapping.
|
||||
UPnPMappingEstablished {
|
||||
/// The external TCP address has been updated.
|
||||
tcp_socket: Option<SocketAddr>,
|
||||
/// The external UDP address has been updated.
|
||||
udp_socket: Option<SocketAddr>,
|
||||
/// The mappings that were established.
|
||||
mappings: EstablishedUPnPMappings,
|
||||
},
|
||||
/// Reports a peer to the peer manager for performing an action.
|
||||
ReportPeer {
|
||||
@ -190,11 +189,8 @@ pub struct NetworkService<T: BeaconChainTypes> {
|
||||
/// A collection of global variables, accessible outside of the network service.
|
||||
network_globals: Arc<NetworkGlobals<T::EthSpec>>,
|
||||
/// Stores potentially created UPnP mappings to be removed on shutdown. (TCP port and UDP
|
||||
/// port).
|
||||
upnp_mappings: (Option<u16>, Option<u16>),
|
||||
/// Keeps track of if discovery is auto-updating or not. This is used to inform us if we should
|
||||
/// update the UDP socket of discovery if the UPnP mappings get established.
|
||||
discovery_auto_update: bool,
|
||||
/// ports).
|
||||
upnp_mappings: EstablishedUPnPMappings,
|
||||
/// A delay that expires when a new fork takes place.
|
||||
next_fork_update: Pin<Box<OptionFuture<Sleep>>>,
|
||||
/// A delay that expires when we need to subscribe to a new fork's topics.
|
||||
@ -359,8 +355,7 @@ impl<T: BeaconChainTypes> NetworkService<T> {
|
||||
router_send,
|
||||
store,
|
||||
network_globals: network_globals.clone(),
|
||||
upnp_mappings: (None, None),
|
||||
discovery_auto_update: config.discv5_config.enr_update,
|
||||
upnp_mappings: EstablishedUPnPMappings::default(),
|
||||
next_fork_update,
|
||||
next_fork_subscriptions,
|
||||
next_unsubscribe,
|
||||
@ -617,32 +612,18 @@ impl<T: BeaconChainTypes> NetworkService<T> {
|
||||
} => {
|
||||
self.libp2p.send_error_reponse(peer_id, id, error, reason);
|
||||
}
|
||||
NetworkMessage::UPnPMappingEstablished {
|
||||
tcp_socket,
|
||||
udp_socket,
|
||||
} => {
|
||||
self.upnp_mappings = (tcp_socket.map(|s| s.port()), udp_socket.map(|s| s.port()));
|
||||
NetworkMessage::UPnPMappingEstablished { mappings } => {
|
||||
self.upnp_mappings = mappings;
|
||||
// If there is an external TCP port update, modify our local ENR.
|
||||
if let Some(tcp_socket) = tcp_socket {
|
||||
if let Err(e) = self
|
||||
.libp2p
|
||||
.discovery_mut()
|
||||
.update_enr_tcp_port(tcp_socket.port())
|
||||
{
|
||||
if let Some(tcp_port) = self.upnp_mappings.tcp_port {
|
||||
if let Err(e) = self.libp2p.discovery_mut().update_enr_tcp_port(tcp_port) {
|
||||
warn!(self.log, "Failed to update ENR"; "error" => e);
|
||||
}
|
||||
}
|
||||
// if the discovery service is not auto-updating, update it with the
|
||||
// UPnP mappings
|
||||
if !self.discovery_auto_update {
|
||||
if let Some(udp_socket) = udp_socket {
|
||||
if let Err(e) = self
|
||||
.libp2p
|
||||
.discovery_mut()
|
||||
.update_enr_udp_socket(udp_socket)
|
||||
{
|
||||
warn!(self.log, "Failed to update ENR"; "error" => e);
|
||||
}
|
||||
// If there is an external QUIC port update, modify our local ENR.
|
||||
if let Some(quic_port) = self.upnp_mappings.udp_quic_port {
|
||||
if let Err(e) = self.libp2p.discovery_mut().update_enr_quic_port(quic_port) {
|
||||
warn!(self.log, "Failed to update ENR"; "error" => e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -997,7 +978,7 @@ impl<T: BeaconChainTypes> Drop for NetworkService<T> {
|
||||
}
|
||||
|
||||
// attempt to remove port mappings
|
||||
crate::nat::remove_mappings(self.upnp_mappings.0, self.upnp_mappings.1, &self.log);
|
||||
crate::nat::remove_mappings(&self.upnp_mappings, &self.log);
|
||||
|
||||
info!(self.log, "Network service shutdown");
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ mod tests {
|
||||
);
|
||||
|
||||
let mut config = NetworkConfig::default();
|
||||
config.set_ipv4_listening_address(std::net::Ipv4Addr::UNSPECIFIED, 21212, 21212);
|
||||
config.set_ipv4_listening_address(std::net::Ipv4Addr::UNSPECIFIED, 21212, 21212, 21213);
|
||||
config.discv5_config.table_filter = |_| true; // Do not ignore local IPs
|
||||
config.upnp_enabled = false;
|
||||
config.boot_nodes_enr = enrs.clone();
|
||||
|
@ -2,26 +2,26 @@
|
||||
name = "operation_pool"
|
||||
version = "0.2.0"
|
||||
authors = ["Michael Sproul <michael@sigmaprime.io>"]
|
||||
edition = "2021"
|
||||
edition = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
derivative = "2.1.1"
|
||||
itertools = "0.10.0"
|
||||
lazy_static = "1.4.0"
|
||||
lighthouse_metrics = { path = "../../common/lighthouse_metrics" }
|
||||
parking_lot = "0.12.0"
|
||||
types = { path = "../../consensus/types" }
|
||||
state_processing = { path = "../../consensus/state_processing" }
|
||||
ethereum_ssz = "0.5.0"
|
||||
ethereum_ssz_derive = "0.5.3"
|
||||
rayon = "1.5.0"
|
||||
serde = "1.0.116"
|
||||
derivative = { workspace = true }
|
||||
itertools = { workspace = true }
|
||||
lazy_static = { workspace = true }
|
||||
lighthouse_metrics = { workspace = true }
|
||||
parking_lot = { workspace = true }
|
||||
types = { workspace = true }
|
||||
state_processing = { workspace = true }
|
||||
ethereum_ssz = { workspace = true }
|
||||
ethereum_ssz_derive = { workspace = true }
|
||||
rayon = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_derive = "1.0.116"
|
||||
store = { path = "../store" }
|
||||
bitvec = "1"
|
||||
rand = "0.8.5"
|
||||
store = { workspace = true }
|
||||
bitvec = { workspace = true }
|
||||
rand = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
beacon_chain = { path = "../beacon_chain" }
|
||||
tokio = { version = "1.14.0", features = ["rt-multi-thread"] }
|
||||
maplit = "1.0.2"
|
||||
beacon_chain = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
maplit = { workspace = true }
|
||||
|
@ -1,4 +1,4 @@
|
||||
use clap::{App, Arg};
|
||||
use clap::{App, Arg, ArgGroup};
|
||||
use strum::VariantNames;
|
||||
use types::ProgressiveBalancesMode;
|
||||
|
||||
@ -82,11 +82,11 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
|
||||
.help("The address lighthouse will listen for UDP and TCP connections. To listen \
|
||||
over IpV4 and IpV6 set this flag twice with the different values.\n\
|
||||
Examples:\n\
|
||||
- --listen-address '0.0.0.0' will listen over Ipv4.\n\
|
||||
- --listen-address '::' will listen over Ipv6.\n\
|
||||
- --listen-address '0.0.0.0' will listen over IPv4.\n\
|
||||
- --listen-address '::' will listen over IPv6.\n\
|
||||
- --listen-address '0.0.0.0' --listen-address '::' will listen over both \
|
||||
Ipv4 and Ipv6. The order of the given addresses is not relevant. However, \
|
||||
multiple Ipv4, or multiple Ipv6 addresses will not be accepted.")
|
||||
IPv4 and IPv6. The order of the given addresses is not relevant. However, \
|
||||
multiple IPv4, or multiple IPv6 addresses will not be accepted.")
|
||||
.multiple(true)
|
||||
.max_values(2)
|
||||
.default_value("0.0.0.0")
|
||||
@ -96,9 +96,10 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
|
||||
Arg::with_name("port")
|
||||
.long("port")
|
||||
.value_name("PORT")
|
||||
.help("The TCP/UDP port to listen on. The UDP port can be modified by the \
|
||||
--discovery-port flag. If listening over both Ipv4 and Ipv6 the --port flag \
|
||||
will apply to the Ipv4 address and --port6 to the Ipv6 address.")
|
||||
.help("The TCP/UDP ports to listen on. There are two UDP ports. \
|
||||
The discovery UDP port will be set to this value and the Quic UDP port will be set to this value + 1. The discovery port can be modified by the \
|
||||
--discovery-port flag and the quic port can be modified by the --quic-port flag. If listening over both IPv4 and IPv6 the --port flag \
|
||||
will apply to the IPv4 address and --port6 to the IPv6 address.")
|
||||
.default_value("9000")
|
||||
.takes_value(true),
|
||||
)
|
||||
@ -106,8 +107,8 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
|
||||
Arg::with_name("port6")
|
||||
.long("port6")
|
||||
.value_name("PORT")
|
||||
.help("The TCP/UDP port to listen on over IpV6 when listening over both Ipv4 and \
|
||||
Ipv6. Defaults to 9090 when required.")
|
||||
.help("The TCP/UDP ports to listen on over IPv6 when listening over both IPv4 and \
|
||||
IPv6. Defaults to 9090 when required. The Quic UDP port will be set to this value + 1.")
|
||||
.default_value("9090")
|
||||
.takes_value(true),
|
||||
)
|
||||
@ -118,12 +119,27 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
|
||||
.help("The UDP port that discovery will listen on. Defaults to `port`")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("quic-port")
|
||||
.long("quic-port")
|
||||
.value_name("PORT")
|
||||
.help("The UDP port that quic will listen on. Defaults to `port` + 1")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("discovery-port6")
|
||||
.long("discovery-port6")
|
||||
.value_name("PORT")
|
||||
.help("The UDP port that discovery will listen on over IpV6 if listening over \
|
||||
both Ipv4 and IpV6. Defaults to `port6`")
|
||||
.help("The UDP port that discovery will listen on over IPv6 if listening over \
|
||||
both IPv4 and IPv6. Defaults to `port6`")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("quic-port6")
|
||||
.long("quic-port6")
|
||||
.value_name("PORT")
|
||||
.help("The UDP port that quic will listen on over IPv6 if listening over \
|
||||
both IPv4 and IPv6. Defaults to `port6` + 1")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
@ -166,7 +182,15 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
|
||||
.long("enr-udp-port")
|
||||
.value_name("PORT")
|
||||
.help("The UDP4 port of the local ENR. Set this only if you are sure other nodes \
|
||||
can connect to your local node on this port over IpV4.")
|
||||
can connect to your local node on this port over IPv4.")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("enr-quic-port")
|
||||
.long("enr-quic-port")
|
||||
.value_name("PORT")
|
||||
.help("The quic UDP4 port that will be set on the local ENR. Set this only if you are sure other nodes \
|
||||
can connect to your local node on this port over IPv4.")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
@ -174,7 +198,15 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
|
||||
.long("enr-udp6-port")
|
||||
.value_name("PORT")
|
||||
.help("The UDP6 port of the local ENR. Set this only if you are sure other nodes \
|
||||
can connect to your local node on this port over IpV6.")
|
||||
can connect to your local node on this port over IPv6.")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("enr-quic6-port")
|
||||
.long("enr-quic6-port")
|
||||
.value_name("PORT")
|
||||
.help("The quic UDP6 port that will be set on the local ENR. Set this only if you are sure other nodes \
|
||||
can connect to your local node on this port over IPv6.")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
@ -182,7 +214,7 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
|
||||
.long("enr-tcp-port")
|
||||
.value_name("PORT")
|
||||
.help("The TCP4 port of the local ENR. Set this only if you are sure other nodes \
|
||||
can connect to your local node on this port over IpV4. The --port flag is \
|
||||
can connect to your local node on this port over IPv4. The --port flag is \
|
||||
used if this is not set.")
|
||||
.takes_value(true),
|
||||
)
|
||||
@ -191,7 +223,7 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
|
||||
.long("enr-tcp6-port")
|
||||
.value_name("PORT")
|
||||
.help("The TCP6 port of the local ENR. Set this only if you are sure other nodes \
|
||||
can connect to your local node on this port over IpV6. The --port6 flag is \
|
||||
can connect to your local node on this port over IPv6. The --port6 flag is \
|
||||
used if this is not set.")
|
||||
.takes_value(true),
|
||||
)
|
||||
@ -232,11 +264,18 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
|
||||
without an ENR.")
|
||||
.takes_value(true),
|
||||
)
|
||||
// NOTE: This is hidden because it is primarily a developer feature for testnets and
|
||||
// debugging. We remove it from the list to avoid clutter.
|
||||
.arg(
|
||||
Arg::with_name("disable-discovery")
|
||||
.long("disable-discovery")
|
||||
.help("Disables the discv5 discovery protocol. The node will not search for new peers or participate in the discovery protocol.")
|
||||
.takes_value(false),
|
||||
.hidden(true)
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("disable-quic")
|
||||
.long("disable-quic")
|
||||
.help("Disables the quic transport. The node will rely solely on the TCP transport for libp2p connections.")
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("disable-peer-scoring")
|
||||
@ -323,22 +362,25 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
|
||||
.arg(
|
||||
Arg::with_name("http-address")
|
||||
.long("http-address")
|
||||
.requires("enable_http")
|
||||
.value_name("ADDRESS")
|
||||
.help("Set the listen address for the RESTful HTTP API server.")
|
||||
.default_value("127.0.0.1")
|
||||
.default_value_if("enable_http", None, "127.0.0.1")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("http-port")
|
||||
.long("http-port")
|
||||
.requires("enable_http")
|
||||
.value_name("PORT")
|
||||
.help("Set the listen TCP port for the RESTful HTTP API server.")
|
||||
.default_value("5052")
|
||||
.default_value_if("enable_http", None, "5052")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("http-allow-origin")
|
||||
.long("http-allow-origin")
|
||||
.requires("enable_http")
|
||||
.value_name("ORIGIN")
|
||||
.help("Set the value of the Access-Control-Allow-Origin response HTTP header. \
|
||||
Use * to allow any origin (not recommended in production). \
|
||||
@ -349,11 +391,13 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
|
||||
.arg(
|
||||
Arg::with_name("http-disable-legacy-spec")
|
||||
.long("http-disable-legacy-spec")
|
||||
.requires("enable_http")
|
||||
.hidden(true)
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("http-spec-fork")
|
||||
.long("http-spec-fork")
|
||||
.requires("enable_http")
|
||||
.value_name("FORK")
|
||||
.help("Serve the spec for a specific hard fork on /eth/v1/config/spec. It should \
|
||||
not be necessary to set this flag.")
|
||||
@ -371,6 +415,7 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
|
||||
.arg(
|
||||
Arg::with_name("http-tls-cert")
|
||||
.long("http-tls-cert")
|
||||
.requires("enable_http")
|
||||
.help("The path of the certificate to be used when serving the HTTP API server \
|
||||
over TLS.")
|
||||
.takes_value(true)
|
||||
@ -378,6 +423,7 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
|
||||
.arg(
|
||||
Arg::with_name("http-tls-key")
|
||||
.long("http-tls-key")
|
||||
.requires("enable_http")
|
||||
.help("The path of the private key to be used when serving the HTTP API server \
|
||||
over TLS. Must not be password-protected.")
|
||||
.takes_value(true)
|
||||
@ -385,6 +431,7 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
|
||||
.arg(
|
||||
Arg::with_name("http-allow-sync-stalled")
|
||||
.long("http-allow-sync-stalled")
|
||||
.requires("enable_http")
|
||||
.help("Forces the HTTP to indicate that the node is synced when sync is actually \
|
||||
stalled. This is useful for very small testnets. TESTING ONLY. DO NOT USE ON \
|
||||
MAINNET.")
|
||||
@ -392,8 +439,9 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
|
||||
.arg(
|
||||
Arg::with_name("http-sse-capacity-multiplier")
|
||||
.long("http-sse-capacity-multiplier")
|
||||
.requires("enable_http")
|
||||
.takes_value(true)
|
||||
.default_value("1")
|
||||
.default_value_if("enable_http", None, "1")
|
||||
.value_name("N")
|
||||
.help("Multiplier to apply to the length of HTTP server-sent-event (SSE) channels. \
|
||||
Increasing this value can prevent messages from being dropped.")
|
||||
@ -401,8 +449,9 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
|
||||
.arg(
|
||||
Arg::with_name("http-duplicate-block-status")
|
||||
.long("http-duplicate-block-status")
|
||||
.requires("enable_http")
|
||||
.takes_value(true)
|
||||
.default_value("202")
|
||||
.default_value_if("enable_http", None, "202")
|
||||
.value_name("STATUS_CODE")
|
||||
.help("Status code to send when a block that is already known is POSTed to the \
|
||||
HTTP API.")
|
||||
@ -410,13 +459,14 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
|
||||
.arg(
|
||||
Arg::with_name("http-enable-beacon-processor")
|
||||
.long("http-enable-beacon-processor")
|
||||
.requires("enable_http")
|
||||
.value_name("BOOLEAN")
|
||||
.help("The beacon processor is a scheduler which provides quality-of-service and \
|
||||
DoS protection. When set to \"true\", HTTP API requests will be queued and scheduled \
|
||||
alongside other tasks. When set to \"false\", HTTP API responses will be executed \
|
||||
immediately.")
|
||||
.takes_value(true)
|
||||
.default_value("true")
|
||||
.default_value_if("enable_http", None, "true")
|
||||
)
|
||||
/* Prometheus metrics HTTP server related arguments */
|
||||
.arg(
|
||||
@ -429,22 +479,25 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
|
||||
Arg::with_name("metrics-address")
|
||||
.long("metrics-address")
|
||||
.value_name("ADDRESS")
|
||||
.requires("metrics")
|
||||
.help("Set the listen address for the Prometheus metrics HTTP server.")
|
||||
.default_value("127.0.0.1")
|
||||
.default_value_if("metrics", None, "127.0.0.1")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("metrics-port")
|
||||
.long("metrics-port")
|
||||
.requires("metrics")
|
||||
.value_name("PORT")
|
||||
.help("Set the listen TCP port for the Prometheus metrics HTTP server.")
|
||||
.default_value("5054")
|
||||
.default_value_if("metrics", None, "5054")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("metrics-allow-origin")
|
||||
.long("metrics-allow-origin")
|
||||
.value_name("ORIGIN")
|
||||
.requires("metrics")
|
||||
.help("Set the value of the Access-Control-Allow-Origin response HTTP header. \
|
||||
Use * to allow any origin (not recommended in production). \
|
||||
If no value is supplied, the CORS allowed origin is set to the listen \
|
||||
@ -1283,4 +1336,5 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
|
||||
.default_value("64")
|
||||
.takes_value(true)
|
||||
)
|
||||
.group(ArgGroup::with_name("enable_http").args(&["http", "gui", "staking"]).multiple(true))
|
||||
}
|
||||
|
@ -95,70 +95,70 @@ pub fn get_config<E: EthSpec>(
|
||||
* Http API server
|
||||
*/
|
||||
|
||||
if cli_args.is_present("http") {
|
||||
if cli_args.is_present("enable_http") {
|
||||
client_config.http_api.enabled = true;
|
||||
|
||||
if let Some(address) = cli_args.value_of("http-address") {
|
||||
client_config.http_api.listen_addr = address
|
||||
.parse::<IpAddr>()
|
||||
.map_err(|_| "http-address is not a valid IP address.")?;
|
||||
}
|
||||
|
||||
if let Some(port) = cli_args.value_of("http-port") {
|
||||
client_config.http_api.listen_port = port
|
||||
.parse::<u16>()
|
||||
.map_err(|_| "http-port is not a valid u16.")?;
|
||||
}
|
||||
|
||||
if let Some(allow_origin) = cli_args.value_of("http-allow-origin") {
|
||||
// Pre-validate the config value to give feedback to the user on node startup, instead of
|
||||
// as late as when the first API response is produced.
|
||||
hyper::header::HeaderValue::from_str(allow_origin)
|
||||
.map_err(|_| "Invalid allow-origin value")?;
|
||||
|
||||
client_config.http_api.allow_origin = Some(allow_origin.to_string());
|
||||
}
|
||||
|
||||
if cli_args.is_present("http-disable-legacy-spec") {
|
||||
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") {
|
||||
client_config.http_api.tls_config = Some(TlsConfig {
|
||||
cert: cli_args
|
||||
.value_of("http-tls-cert")
|
||||
.ok_or("--http-tls-cert was not provided.")?
|
||||
.parse::<PathBuf>()
|
||||
.map_err(|_| "http-tls-cert is not a valid path name.")?,
|
||||
key: cli_args
|
||||
.value_of("http-tls-key")
|
||||
.ok_or("--http-tls-key was not provided.")?
|
||||
.parse::<PathBuf>()
|
||||
.map_err(|_| "http-tls-key is not a valid path name.")?,
|
||||
});
|
||||
}
|
||||
|
||||
if cli_args.is_present("http-allow-sync-stalled") {
|
||||
client_config.http_api.allow_sync_stalled = true;
|
||||
}
|
||||
|
||||
client_config.http_api.sse_capacity_multiplier =
|
||||
parse_required(cli_args, "http-sse-capacity-multiplier")?;
|
||||
|
||||
client_config.http_api.enable_beacon_processor =
|
||||
parse_required(cli_args, "http-enable-beacon-processor")?;
|
||||
|
||||
client_config.http_api.duplicate_block_status_code =
|
||||
parse_required(cli_args, "http-duplicate-block-status")?;
|
||||
}
|
||||
|
||||
if let Some(address) = cli_args.value_of("http-address") {
|
||||
client_config.http_api.listen_addr = address
|
||||
.parse::<IpAddr>()
|
||||
.map_err(|_| "http-address is not a valid IP address.")?;
|
||||
}
|
||||
|
||||
if let Some(port) = cli_args.value_of("http-port") {
|
||||
client_config.http_api.listen_port = port
|
||||
.parse::<u16>()
|
||||
.map_err(|_| "http-port is not a valid u16.")?;
|
||||
}
|
||||
|
||||
if let Some(allow_origin) = cli_args.value_of("http-allow-origin") {
|
||||
// Pre-validate the config value to give feedback to the user on node startup, instead of
|
||||
// as late as when the first API response is produced.
|
||||
hyper::header::HeaderValue::from_str(allow_origin)
|
||||
.map_err(|_| "Invalid allow-origin value")?;
|
||||
|
||||
client_config.http_api.allow_origin = Some(allow_origin.to_string());
|
||||
}
|
||||
|
||||
if cli_args.is_present("http-disable-legacy-spec") {
|
||||
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") {
|
||||
client_config.http_api.tls_config = Some(TlsConfig {
|
||||
cert: cli_args
|
||||
.value_of("http-tls-cert")
|
||||
.ok_or("--http-tls-cert was not provided.")?
|
||||
.parse::<PathBuf>()
|
||||
.map_err(|_| "http-tls-cert is not a valid path name.")?,
|
||||
key: cli_args
|
||||
.value_of("http-tls-key")
|
||||
.ok_or("--http-tls-key was not provided.")?
|
||||
.parse::<PathBuf>()
|
||||
.map_err(|_| "http-tls-key is not a valid path name.")?,
|
||||
});
|
||||
}
|
||||
|
||||
if cli_args.is_present("http-allow-sync-stalled") {
|
||||
client_config.http_api.allow_sync_stalled = true;
|
||||
}
|
||||
|
||||
client_config.http_api.sse_capacity_multiplier =
|
||||
parse_required(cli_args, "http-sse-capacity-multiplier")?;
|
||||
|
||||
client_config.http_api.enable_beacon_processor =
|
||||
parse_required(cli_args, "http-enable-beacon-processor")?;
|
||||
|
||||
client_config.http_api.duplicate_block_status_code =
|
||||
parse_required(cli_args, "http-duplicate-block-status")?;
|
||||
|
||||
if let Some(cache_size) = clap_utils::parse_optional(cli_args, "shuffling-cache-size")? {
|
||||
client_config.chain.shuffling_cache_size = cache_size;
|
||||
}
|
||||
@ -952,15 +952,15 @@ pub fn parse_listening_addresses(
|
||||
.map_err(|parse_error| format!("Failed to parse --port6 as an integer: {parse_error}"))?
|
||||
.unwrap_or(9090);
|
||||
|
||||
// parse the possible udp ports
|
||||
let maybe_udp_port = cli_args
|
||||
// parse the possible discovery ports.
|
||||
let maybe_disc_port = cli_args
|
||||
.value_of("discovery-port")
|
||||
.map(str::parse::<u16>)
|
||||
.transpose()
|
||||
.map_err(|parse_error| {
|
||||
format!("Failed to parse --discovery-port as an integer: {parse_error}")
|
||||
})?;
|
||||
let maybe_udp6_port = cli_args
|
||||
let maybe_disc6_port = cli_args
|
||||
.value_of("discovery-port6")
|
||||
.map(str::parse::<u16>)
|
||||
.transpose()
|
||||
@ -968,6 +968,24 @@ pub fn parse_listening_addresses(
|
||||
format!("Failed to parse --discovery-port6 as an integer: {parse_error}")
|
||||
})?;
|
||||
|
||||
// parse the possible quic port.
|
||||
let maybe_quic_port = cli_args
|
||||
.value_of("quic-port")
|
||||
.map(str::parse::<u16>)
|
||||
.transpose()
|
||||
.map_err(|parse_error| {
|
||||
format!("Failed to parse --quic-port as an integer: {parse_error}")
|
||||
})?;
|
||||
|
||||
// parse the possible quic port.
|
||||
let maybe_quic6_port = cli_args
|
||||
.value_of("quic-port6")
|
||||
.map(str::parse::<u16>)
|
||||
.transpose()
|
||||
.map_err(|parse_error| {
|
||||
format!("Failed to parse --quic6-port as an integer: {parse_error}")
|
||||
})?;
|
||||
|
||||
// Now put everything together
|
||||
let listening_addresses = match (maybe_ipv4, maybe_ipv6) {
|
||||
(None, None) => {
|
||||
@ -978,7 +996,7 @@ pub fn parse_listening_addresses(
|
||||
// A single ipv6 address was provided. Set the ports
|
||||
|
||||
if cli_args.is_present("port6") {
|
||||
warn!(log, "When listening only over IpV6, use the --port flag. The value of --port6 will be ignored.")
|
||||
warn!(log, "When listening only over IPv6, use the --port flag. The value of --port6 will be ignored.")
|
||||
}
|
||||
// use zero ports if required. If not, use the given port.
|
||||
let tcp_port = use_zero_ports
|
||||
@ -986,20 +1004,32 @@ pub fn parse_listening_addresses(
|
||||
.transpose()?
|
||||
.unwrap_or(port);
|
||||
|
||||
if maybe_udp6_port.is_some() {
|
||||
warn!(log, "When listening only over IpV6, use the --discovery-port flag. The value of --discovery-port6 will be ignored.")
|
||||
if maybe_disc6_port.is_some() {
|
||||
warn!(log, "When listening only over IPv6, use the --discovery-port flag. The value of --discovery-port6 will be ignored.")
|
||||
}
|
||||
|
||||
if maybe_quic6_port.is_some() {
|
||||
warn!(log, "When listening only over IPv6, use the --quic-port flag. The value of --quic-port6 will be ignored.")
|
||||
}
|
||||
|
||||
// use zero ports if required. If not, use the specific udp port. If none given, use
|
||||
// the tcp port.
|
||||
let udp_port = use_zero_ports
|
||||
let disc_port = use_zero_ports
|
||||
.then(unused_port::unused_udp6_port)
|
||||
.transpose()?
|
||||
.or(maybe_udp_port)
|
||||
.or(maybe_disc_port)
|
||||
.unwrap_or(port);
|
||||
|
||||
let quic_port = use_zero_ports
|
||||
.then(unused_port::unused_udp6_port)
|
||||
.transpose()?
|
||||
.or(maybe_quic_port)
|
||||
.unwrap_or(port + 1);
|
||||
|
||||
ListenAddress::V6(lighthouse_network::ListenAddr {
|
||||
addr: ipv6,
|
||||
udp_port,
|
||||
quic_port,
|
||||
disc_port,
|
||||
tcp_port,
|
||||
})
|
||||
}
|
||||
@ -1011,16 +1041,25 @@ pub fn parse_listening_addresses(
|
||||
.then(unused_port::unused_tcp4_port)
|
||||
.transpose()?
|
||||
.unwrap_or(port);
|
||||
// use zero ports if required. If not, use the specific udp port. If none given, use
|
||||
// use zero ports if required. If not, use the specific discovery port. If none given, use
|
||||
// the tcp port.
|
||||
let udp_port = use_zero_ports
|
||||
let disc_port = use_zero_ports
|
||||
.then(unused_port::unused_udp4_port)
|
||||
.transpose()?
|
||||
.or(maybe_udp_port)
|
||||
.or(maybe_disc_port)
|
||||
.unwrap_or(port);
|
||||
// use zero ports if required. If not, use the specific quic port. If none given, use
|
||||
// the tcp port + 1.
|
||||
let quic_port = use_zero_ports
|
||||
.then(unused_port::unused_udp4_port)
|
||||
.transpose()?
|
||||
.or(maybe_quic_port)
|
||||
.unwrap_or(port + 1);
|
||||
|
||||
ListenAddress::V4(lighthouse_network::ListenAddr {
|
||||
addr: ipv4,
|
||||
udp_port,
|
||||
disc_port,
|
||||
quic_port,
|
||||
tcp_port,
|
||||
})
|
||||
}
|
||||
@ -1029,31 +1068,44 @@ pub fn parse_listening_addresses(
|
||||
.then(unused_port::unused_tcp4_port)
|
||||
.transpose()?
|
||||
.unwrap_or(port);
|
||||
let ipv4_udp_port = use_zero_ports
|
||||
let ipv4_disc_port = use_zero_ports
|
||||
.then(unused_port::unused_udp4_port)
|
||||
.transpose()?
|
||||
.or(maybe_udp_port)
|
||||
.or(maybe_disc_port)
|
||||
.unwrap_or(ipv4_tcp_port);
|
||||
let ipv4_quic_port = use_zero_ports
|
||||
.then(unused_port::unused_udp4_port)
|
||||
.transpose()?
|
||||
.or(maybe_quic_port)
|
||||
.unwrap_or(port + 1);
|
||||
|
||||
// Defaults to 9090 when required
|
||||
let ipv6_tcp_port = use_zero_ports
|
||||
.then(unused_port::unused_tcp6_port)
|
||||
.transpose()?
|
||||
.unwrap_or(port6);
|
||||
let ipv6_udp_port = use_zero_ports
|
||||
let ipv6_disc_port = use_zero_ports
|
||||
.then(unused_port::unused_udp6_port)
|
||||
.transpose()?
|
||||
.or(maybe_udp6_port)
|
||||
.or(maybe_disc6_port)
|
||||
.unwrap_or(ipv6_tcp_port);
|
||||
let ipv6_quic_port = use_zero_ports
|
||||
.then(unused_port::unused_udp6_port)
|
||||
.transpose()?
|
||||
.or(maybe_quic6_port)
|
||||
.unwrap_or(ipv6_tcp_port + 1);
|
||||
|
||||
ListenAddress::DualStack(
|
||||
lighthouse_network::ListenAddr {
|
||||
addr: ipv4,
|
||||
udp_port: ipv4_udp_port,
|
||||
disc_port: ipv4_disc_port,
|
||||
quic_port: ipv4_quic_port,
|
||||
tcp_port: ipv4_tcp_port,
|
||||
},
|
||||
lighthouse_network::ListenAddr {
|
||||
addr: ipv6,
|
||||
udp_port: ipv6_udp_port,
|
||||
disc_port: ipv6_disc_port,
|
||||
quic_port: ipv6_quic_port,
|
||||
tcp_port: ipv6_tcp_port,
|
||||
},
|
||||
)
|
||||
@ -1169,6 +1221,14 @@ pub fn set_network_config(
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(enr_quic_port_str) = cli_args.value_of("enr-quic-port") {
|
||||
config.enr_quic4_port = Some(
|
||||
enr_quic_port_str
|
||||
.parse::<u16>()
|
||||
.map_err(|_| format!("Invalid quic port: {}", enr_quic_port_str))?,
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(enr_tcp_port_str) = cli_args.value_of("enr-tcp-port") {
|
||||
config.enr_tcp4_port = Some(
|
||||
enr_tcp_port_str
|
||||
@ -1185,6 +1245,14 @@ pub fn set_network_config(
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(enr_quic_port_str) = cli_args.value_of("enr-quic6-port") {
|
||||
config.enr_quic6_port = Some(
|
||||
enr_quic_port_str
|
||||
.parse::<u16>()
|
||||
.map_err(|_| format!("Invalid quic port: {}", enr_quic_port_str))?,
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(enr_tcp_port_str) = cli_args.value_of("enr-tcp6-port") {
|
||||
config.enr_tcp6_port = Some(
|
||||
enr_tcp_port_str
|
||||
@ -1194,9 +1262,9 @@ pub fn set_network_config(
|
||||
}
|
||||
|
||||
if cli_args.is_present("enr-match") {
|
||||
// Match the Ip and UDP port in the enr.
|
||||
// Match the IP and UDP port in the ENR.
|
||||
|
||||
// set the enr address to localhost if the address is unspecified
|
||||
// Set the ENR address to localhost if the address is unspecified.
|
||||
if let Some(ipv4_addr) = config.listen_addrs().v4().cloned() {
|
||||
let ipv4_enr_addr = if ipv4_addr.addr == Ipv4Addr::UNSPECIFIED {
|
||||
Ipv4Addr::LOCALHOST
|
||||
@ -1204,7 +1272,7 @@ pub fn set_network_config(
|
||||
ipv4_addr.addr
|
||||
};
|
||||
config.enr_address.0 = Some(ipv4_enr_addr);
|
||||
config.enr_udp4_port = Some(ipv4_addr.udp_port);
|
||||
config.enr_udp4_port = Some(ipv4_addr.disc_port);
|
||||
}
|
||||
|
||||
if let Some(ipv6_addr) = config.listen_addrs().v6().cloned() {
|
||||
@ -1214,7 +1282,7 @@ pub fn set_network_config(
|
||||
ipv6_addr.addr
|
||||
};
|
||||
config.enr_address.1 = Some(ipv6_enr_addr);
|
||||
config.enr_udp6_port = Some(ipv6_addr.udp_port);
|
||||
config.enr_udp6_port = Some(ipv6_addr.disc_port);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1247,11 +1315,11 @@ pub fn set_network_config(
|
||||
// actually matters. Just use the udp port.
|
||||
|
||||
let port = match config.listen_addrs() {
|
||||
ListenAddress::V4(v4_addr) => v4_addr.udp_port,
|
||||
ListenAddress::V6(v6_addr) => v6_addr.udp_port,
|
||||
ListenAddress::V4(v4_addr) => v4_addr.disc_port,
|
||||
ListenAddress::V6(v6_addr) => v6_addr.disc_port,
|
||||
ListenAddress::DualStack(v4_addr, _v6_addr) => {
|
||||
// NOTE: slight preference for ipv4 that I don't think is of importance.
|
||||
v4_addr.udp_port
|
||||
v4_addr.disc_port
|
||||
}
|
||||
};
|
||||
|
||||
@ -1310,6 +1378,10 @@ pub fn set_network_config(
|
||||
warn!(log, "Discovery is disabled. New peers will not be found");
|
||||
}
|
||||
|
||||
if cli_args.is_present("disable-quic") {
|
||||
config.disable_quic_support = true;
|
||||
}
|
||||
|
||||
if cli_args.is_present("disable-upnp") {
|
||||
config.upnp_enabled = false;
|
||||
}
|
||||
|
@ -2,27 +2,27 @@
|
||||
name = "store"
|
||||
version = "0.2.0"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>"]
|
||||
edition = "2021"
|
||||
edition = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3.1.0"
|
||||
beacon_chain = {path = "../beacon_chain"}
|
||||
tempfile = { workspace = true }
|
||||
beacon_chain = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
db-key = "0.0.5"
|
||||
leveldb = { version = "0.8.6" }
|
||||
parking_lot = "0.12.0"
|
||||
itertools = "0.10.0"
|
||||
ethereum_ssz = "0.5.0"
|
||||
ethereum_ssz_derive = "0.5.3"
|
||||
types = { path = "../../consensus/types" }
|
||||
state_processing = { path = "../../consensus/state_processing" }
|
||||
slog = "2.5.2"
|
||||
serde = "1.0.116"
|
||||
leveldb = { version = "0.8" }
|
||||
parking_lot = { workspace = true }
|
||||
itertools = { workspace = true }
|
||||
ethereum_ssz = { workspace = true }
|
||||
ethereum_ssz_derive = { workspace = true }
|
||||
types = { workspace = true }
|
||||
state_processing = { workspace = true }
|
||||
slog = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_derive = "1.0.116"
|
||||
lazy_static = "1.4.0"
|
||||
lighthouse_metrics = { path = "../../common/lighthouse_metrics" }
|
||||
lru = "0.7.1"
|
||||
sloggers = { version = "2.1.1", features = ["json"] }
|
||||
directory = { path = "../../common/directory" }
|
||||
strum = { version = "0.24.0", features = ["derive"] }
|
||||
lazy_static = { workspace = true }
|
||||
lighthouse_metrics = { workspace = true }
|
||||
lru = { workspace = true }
|
||||
sloggers = { workspace = true }
|
||||
directory = { workspace = true }
|
||||
strum = { workspace = true }
|
||||
|
@ -2,11 +2,11 @@
|
||||
name = "timer"
|
||||
version = "0.2.0"
|
||||
authors = ["Sigma Prime <contact@sigmaprime.io>"]
|
||||
edition = "2021"
|
||||
edition = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
beacon_chain = { path = "../beacon_chain" }
|
||||
slot_clock = { path = "../../common/slot_clock" }
|
||||
tokio = { version = "1.14.0", features = ["full"] }
|
||||
slog = "2.5.2"
|
||||
task_executor = { path = "../../common/task_executor" }
|
||||
beacon_chain = { workspace = true }
|
||||
slot_clock = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
slog = { workspace = true }
|
||||
task_executor = { workspace = true }
|
||||
|
@ -56,3 +56,4 @@
|
||||
* [Contributing](./contributing.md)
|
||||
* [Development Environment](./setup.md)
|
||||
* [FAQs](./faq.md)
|
||||
* [Protocol Developers](./developers.md)
|
51
book/src/developers.md
Normal file
51
book/src/developers.md
Normal file
@ -0,0 +1,51 @@
|
||||
# For Protocol Developers
|
||||
|
||||
_Documentation for protocol developers._
|
||||
|
||||
This section lists Lighthouse-specific decisions that are not strictly spec'd and may be useful for
|
||||
other protocol developers wishing to interact with lighthouse.
|
||||
|
||||
|
||||
## Custom ENR Fields
|
||||
|
||||
Lighthouse currently uses the following ENR fields:
|
||||
|
||||
### Ethereum Consensus Specified
|
||||
|
||||
| Field | Description |
|
||||
| ---- | ---- |
|
||||
| `eth2` | The `ENRForkId` in SSZ bytes specifying which fork the node is on |
|
||||
| `attnets` | An SSZ bitfield which indicates which of the 64 subnets the node is subscribed to for an extended period of time |
|
||||
| `syncnets` | An SSZ bitfield which indicates which of the sync committee subnets the node is subscribed to |
|
||||
|
||||
|
||||
### Lighthouse Custom Fields
|
||||
|
||||
Lighthouse is currently using the following custom ENR fields.
|
||||
| Field | Description |
|
||||
| ---- | ---- |
|
||||
| `quic` | The UDP port on which the QUIC transport is listening on IPv4 |
|
||||
| `quic6` | The UDP port on which the QUIC transport is listening on IPv6 |
|
||||
|
||||
|
||||
## Custom RPC Messages
|
||||
|
||||
The specification leaves room for implementation-specific errors. Lighthouse uses the following
|
||||
custom RPC error messages.
|
||||
|
||||
### Goodbye Reason Codes
|
||||
|
||||
| Code | Message | Description |
|
||||
| ---- | ---- | ---- |
|
||||
| 128 | Unable to Verify Network | Teku uses this, so we adopted it. It relates to having a fork mismatch |
|
||||
| 129 | Too Many Peers | Lighthouse can close a connection because it has reached its peer-limit and pruned excess peers |
|
||||
| 250 | Bad Score | The node has been dropped due to having a bad peer score |
|
||||
| 251 | Banned | The peer has been banned and disconnected |
|
||||
| 252 | Banned IP | The IP the node is connected to us with has been banned |
|
||||
|
||||
|
||||
### Error Codes
|
||||
|
||||
| Code | Message | Description |
|
||||
| ---- | ---- | ---- |
|
||||
| 139 | Rate Limited | The peer has been rate limited so we return this error as a response |
|
@ -14,7 +14,7 @@ The additional requirements for developers are:
|
||||
don't have `anvil` available on your `PATH`.
|
||||
- [`cmake`](https://cmake.org/cmake/help/latest/command/install.html). Used by
|
||||
some dependencies. See [`Installation Guide`](./installation.md) for more info.
|
||||
- [`java 11 runtime`](https://openjdk.java.net/projects/jdk/). 11 is the minimum,
|
||||
- [`java 17 runtime`](https://openjdk.java.net/projects/jdk/). 17 is the minimum,
|
||||
used by web3signer_tests.
|
||||
- [`libpq-dev`](https://www.postgresql.org/docs/devel/libpq.html). Also know as
|
||||
`libpq-devel` on some systems.
|
||||
|
@ -1,27 +1,27 @@
|
||||
[package]
|
||||
name = "boot_node"
|
||||
version = "4.4.1"
|
||||
version = "4.5.0"
|
||||
authors = ["Sigma Prime <contact@sigmaprime.io>"]
|
||||
edition = "2021"
|
||||
edition = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
beacon_node = { path = "../beacon_node" }
|
||||
clap = "2.33.3"
|
||||
clap_utils = { path = "../common/clap_utils" }
|
||||
lighthouse_network = { path = "../beacon_node/lighthouse_network" }
|
||||
types = { path = "../consensus/types" }
|
||||
ethereum_ssz = "0.5.0"
|
||||
slog = "2.5.2"
|
||||
tokio = "1.14.0"
|
||||
log = "0.4.11"
|
||||
slog-term = "2.6.0"
|
||||
logging = { path = "../common/logging" }
|
||||
slog-async = "2.5.0"
|
||||
beacon_node = { workspace = true }
|
||||
clap = { workspace = true }
|
||||
clap_utils = { workspace = true }
|
||||
lighthouse_network = { workspace = true }
|
||||
types = { workspace = true }
|
||||
ethereum_ssz = { workspace = true }
|
||||
slog = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
log = { workspace = true }
|
||||
slog-term = { workspace = true }
|
||||
logging = { workspace = true }
|
||||
slog-async = { workspace = true }
|
||||
slog-scope = "4.3.0"
|
||||
slog-stdlog = "4.0.0"
|
||||
hex = "0.4.2"
|
||||
serde = "1.0.116"
|
||||
hex = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_derive = "1.0.116"
|
||||
serde_json = "1.0.66"
|
||||
serde_yaml = "0.8.13"
|
||||
eth2_network_config = { path = "../common/eth2_network_config" }
|
||||
serde_json = { workspace = true }
|
||||
serde_yaml = { workspace = true }
|
||||
eth2_network_config = { workspace = true }
|
||||
|
@ -25,7 +25,7 @@ pub struct BootNodeConfig<T: EthSpec> {
|
||||
}
|
||||
|
||||
impl<T: EthSpec> BootNodeConfig<T> {
|
||||
pub fn new(
|
||||
pub async fn new(
|
||||
matches: &ArgMatches<'_>,
|
||||
eth2_network_config: &Eth2NetworkConfig,
|
||||
) -> Result<Self, String> {
|
||||
@ -58,12 +58,12 @@ impl<T: EthSpec> BootNodeConfig<T> {
|
||||
|
||||
set_network_config(&mut network_config, matches, &data_dir, &logger)?;
|
||||
|
||||
// Set the Enr UDP ports to the listening ports if not present.
|
||||
// Set the Enr Discovery ports to the listening ports if not present.
|
||||
if let Some(listening_addr_v4) = network_config.listen_addrs().v4() {
|
||||
network_config.enr_udp4_port = Some(
|
||||
network_config
|
||||
.enr_udp4_port
|
||||
.unwrap_or(listening_addr_v4.udp_port),
|
||||
.unwrap_or(listening_addr_v4.disc_port),
|
||||
)
|
||||
};
|
||||
|
||||
@ -71,7 +71,7 @@ impl<T: EthSpec> BootNodeConfig<T> {
|
||||
network_config.enr_udp6_port = Some(
|
||||
network_config
|
||||
.enr_udp6_port
|
||||
.unwrap_or(listening_addr_v6.udp_port),
|
||||
.unwrap_or(listening_addr_v6.disc_port),
|
||||
)
|
||||
};
|
||||
|
||||
@ -99,7 +99,7 @@ impl<T: EthSpec> BootNodeConfig<T> {
|
||||
|
||||
if eth2_network_config.genesis_state_is_known() {
|
||||
let genesis_state = eth2_network_config
|
||||
.genesis_state::<T>(genesis_state_url.as_deref(), genesis_state_url_timeout, &logger)?
|
||||
.genesis_state::<T>(genesis_state_url.as_deref(), genesis_state_url_timeout, &logger).await?
|
||||
.ok_or_else(|| {
|
||||
"The genesis state for this network is not known, this is an unsupported mode"
|
||||
.to_string()
|
||||
|
@ -7,7 +7,7 @@ mod cli;
|
||||
pub mod config;
|
||||
mod server;
|
||||
pub use cli::cli_app;
|
||||
use config::{BootNodeConfig, BootNodeConfigSerialization};
|
||||
use config::BootNodeConfig;
|
||||
use types::{EthSpec, EthSpecId};
|
||||
|
||||
const LOG_CHANNEL_SIZE: usize = 2048;
|
||||
@ -81,20 +81,13 @@ fn main<T: EthSpec>(
|
||||
.build()
|
||||
.map_err(|e| format!("Failed to build runtime: {}", e))?;
|
||||
|
||||
// parse the CLI args into a useable config
|
||||
let config: BootNodeConfig<T> = BootNodeConfig::new(bn_matches, eth2_network_config)?;
|
||||
|
||||
// Dump configs if `dump-config` or `dump-chain-config` flags are set
|
||||
let config_sz = BootNodeConfigSerialization::from_config_ref(&config);
|
||||
clap_utils::check_dump_configs::<_, T>(
|
||||
lh_matches,
|
||||
&config_sz,
|
||||
ð2_network_config.chain_spec::<T>()?,
|
||||
)?;
|
||||
|
||||
// Run the boot node
|
||||
if !lh_matches.is_present("immediate-shutdown") {
|
||||
runtime.block_on(server::run(config, log));
|
||||
}
|
||||
runtime.block_on(server::run::<T>(
|
||||
lh_matches,
|
||||
bn_matches,
|
||||
eth2_network_config,
|
||||
log,
|
||||
))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
//! The main bootnode server execution.
|
||||
|
||||
use super::BootNodeConfig;
|
||||
use crate::config::BootNodeConfigSerialization;
|
||||
use clap::ArgMatches;
|
||||
use eth2_network_config::Eth2NetworkConfig;
|
||||
use lighthouse_network::{
|
||||
discv5::{enr::NodeId, Discv5, Discv5Event},
|
||||
EnrExt, Eth2Enr,
|
||||
@ -8,7 +11,27 @@ use lighthouse_network::{
|
||||
use slog::info;
|
||||
use types::EthSpec;
|
||||
|
||||
pub async fn run<T: EthSpec>(config: BootNodeConfig<T>, log: slog::Logger) {
|
||||
pub async fn run<T: EthSpec>(
|
||||
lh_matches: &ArgMatches<'_>,
|
||||
bn_matches: &ArgMatches<'_>,
|
||||
eth2_network_config: &Eth2NetworkConfig,
|
||||
log: slog::Logger,
|
||||
) -> Result<(), String> {
|
||||
// parse the CLI args into a useable config
|
||||
let config: BootNodeConfig<T> = BootNodeConfig::new(bn_matches, eth2_network_config).await?;
|
||||
|
||||
// Dump configs if `dump-config` or `dump-chain-config` flags are set
|
||||
let config_sz = BootNodeConfigSerialization::from_config_ref(&config);
|
||||
clap_utils::check_dump_configs::<_, T>(
|
||||
lh_matches,
|
||||
&config_sz,
|
||||
ð2_network_config.chain_spec::<T>()?,
|
||||
)?;
|
||||
|
||||
if lh_matches.is_present("immediate-shutdown") {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let BootNodeConfig {
|
||||
boot_nodes,
|
||||
local_enr,
|
||||
@ -65,8 +88,7 @@ pub async fn run<T: EthSpec>(config: BootNodeConfig<T>, log: slog::Logger) {
|
||||
|
||||
// start the server
|
||||
if let Err(e) = discv5.start().await {
|
||||
slog::crit!(log, "Could not start discv5 server"; "error" => %e);
|
||||
return;
|
||||
return Err(format!("Could not start discv5 server: {e:?}"));
|
||||
}
|
||||
|
||||
// if there are peers in the local routing table, establish a session by running a query
|
||||
@ -82,8 +104,7 @@ pub async fn run<T: EthSpec>(config: BootNodeConfig<T>, log: slog::Logger) {
|
||||
let mut event_stream = match discv5.event_stream().await {
|
||||
Ok(stream) => stream,
|
||||
Err(e) => {
|
||||
slog::crit!(log, "Failed to obtain event stream"; "error" => %e);
|
||||
return;
|
||||
return Err(format!("Failed to obtain event stream: {e:?}"));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -2,22 +2,22 @@
|
||||
name = "account_utils"
|
||||
version = "0.1.0"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>"]
|
||||
edition = "2021"
|
||||
edition = { workspace = true }
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
rand = "0.8.5"
|
||||
eth2_wallet = { path = "../../crypto/eth2_wallet" }
|
||||
eth2_keystore = { path = "../../crypto/eth2_keystore" }
|
||||
filesystem = { path = "../filesystem" }
|
||||
zeroize = { version = "1.4.2", features = ["zeroize_derive"] }
|
||||
serde = "1.0.116"
|
||||
rand = { workspace = true }
|
||||
eth2_wallet = { workspace = true }
|
||||
eth2_keystore = { workspace = true }
|
||||
filesystem = { workspace = true }
|
||||
zeroize = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_derive = "1.0.116"
|
||||
serde_yaml = "0.8.13"
|
||||
slog = { version = "2.5.2", features = ["max_level_trace", "release_max_level_trace"] }
|
||||
types = { path = "../../consensus/types" }
|
||||
validator_dir = { path = "../validator_dir" }
|
||||
regex = "1.5.5"
|
||||
serde_yaml = { workspace = true }
|
||||
slog = { workspace = true }
|
||||
types = { workspace = true }
|
||||
validator_dir = { workspace = true }
|
||||
regex = { workspace = true }
|
||||
rpassword = "5.0.0"
|
||||
directory = { path = "../directory" }
|
||||
directory = { workspace = true }
|
||||
|
@ -2,18 +2,18 @@
|
||||
name = "clap_utils"
|
||||
version = "0.1.0"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>"]
|
||||
edition = "2021"
|
||||
edition = { workspace = true }
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
clap = "2.33.3"
|
||||
hex = "0.4.2"
|
||||
dirs = "3.0.1"
|
||||
eth2_network_config = { path = "../eth2_network_config" }
|
||||
ethereum_ssz = "0.5.0"
|
||||
ethereum-types = "0.14.1"
|
||||
serde = "1.0.116"
|
||||
serde_json = "1.0.59"
|
||||
serde_yaml = "0.8.13"
|
||||
types = { path = "../../consensus/types"}
|
||||
clap = { workspace = true }
|
||||
hex = { workspace = true }
|
||||
dirs = { workspace = true }
|
||||
eth2_network_config = { workspace = true }
|
||||
ethereum_ssz = { workspace = true }
|
||||
ethereum-types = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
serde_yaml = { workspace = true }
|
||||
types = { workspace = true }
|
||||
|
@ -2,10 +2,10 @@
|
||||
name = "compare_fields"
|
||||
version = "0.2.0"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>"]
|
||||
edition = "2021"
|
||||
edition = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
compare_fields_derive = { path = "../compare_fields_derive" }
|
||||
compare_fields_derive = { workspace = true }
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
development = ["compare_fields_derive"] # used in doc-tests
|
||||
|
@ -2,11 +2,11 @@
|
||||
name = "compare_fields_derive"
|
||||
version = "0.2.0"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>"]
|
||||
edition = "2021"
|
||||
edition = { workspace = true }
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
syn = "1.0.42"
|
||||
quote = "1.0.7"
|
||||
syn = { workspace = true }
|
||||
quote = { workspace = true }
|
||||
|
@ -2,18 +2,18 @@
|
||||
name = "deposit_contract"
|
||||
version = "0.2.0"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>"]
|
||||
edition = "2021"
|
||||
edition = { workspace = true }
|
||||
|
||||
build = "build.rs"
|
||||
|
||||
[build-dependencies]
|
||||
reqwest = { version = "0.11.0", features = ["blocking", "json", "native-tls-vendored"] }
|
||||
serde_json = "1.0.58"
|
||||
sha2 = "0.10"
|
||||
hex = "0.4.2"
|
||||
reqwest = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
sha2 = { workspace = true }
|
||||
hex = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
types = { path = "../../consensus/types"}
|
||||
ethereum_ssz = "0.5.0"
|
||||
tree_hash = "0.5.2"
|
||||
types = { workspace = true }
|
||||
ethereum_ssz = { workspace = true }
|
||||
tree_hash = { workspace = true }
|
||||
ethabi = "16.0.0"
|
||||
|
@ -2,11 +2,11 @@
|
||||
name = "directory"
|
||||
version = "0.1.0"
|
||||
authors = ["pawan <pawandhananjay@gmail.com>"]
|
||||
edition = "2021"
|
||||
edition = { workspace = true }
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
clap = "2.33.3"
|
||||
clap_utils = {path = "../clap_utils"}
|
||||
eth2_network_config = { path = "../eth2_network_config" }
|
||||
clap = { workspace = true }
|
||||
clap_utils = { workspace = true }
|
||||
eth2_network_config = { workspace = true }
|
||||
|
@ -2,38 +2,38 @@
|
||||
name = "eth2"
|
||||
version = "0.1.0"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>"]
|
||||
edition = "2021"
|
||||
edition = { workspace = true }
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
serde = { version = "1.0.116", features = ["derive"] }
|
||||
serde_json = "1.0.58"
|
||||
ssz_types = "0.5.4"
|
||||
tree_hash = "0.5.2"
|
||||
types = { path = "../../consensus/types" }
|
||||
reqwest = { version = "0.11.0", features = ["json", "stream"] }
|
||||
lighthouse_network = { path = "../../beacon_node/lighthouse_network" }
|
||||
proto_array = { path = "../../consensus/proto_array", optional = true }
|
||||
ethereum_serde_utils = "0.5.0"
|
||||
eth2_keystore = { path = "../../crypto/eth2_keystore" }
|
||||
libsecp256k1 = "0.7.0"
|
||||
ring = "0.16.19"
|
||||
bytes = "1.0.1"
|
||||
account_utils = { path = "../../common/account_utils" }
|
||||
sensitive_url = { path = "../../common/sensitive_url" }
|
||||
ethereum_ssz = "0.5.0"
|
||||
ethereum_ssz_derive = "0.5.3"
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
ssz_types = { workspace = true }
|
||||
tree_hash = { workspace = true }
|
||||
types = { workspace = true }
|
||||
reqwest = { workspace = true }
|
||||
lighthouse_network = { workspace = true }
|
||||
proto_array = { workspace = true }
|
||||
ethereum_serde_utils = { workspace = true }
|
||||
eth2_keystore = { workspace = true }
|
||||
libsecp256k1 = { workspace = true }
|
||||
ring = { workspace = true }
|
||||
bytes = { workspace = true }
|
||||
account_utils = { workspace = true }
|
||||
sensitive_url = { workspace = true }
|
||||
ethereum_ssz = { workspace = true }
|
||||
ethereum_ssz_derive = { workspace = true }
|
||||
futures-util = "0.3.8"
|
||||
futures = "0.3.8"
|
||||
store = { path = "../../beacon_node/store", optional = true }
|
||||
slashing_protection = { path = "../../validator_client/slashing_protection", optional = true }
|
||||
futures = { workspace = true }
|
||||
store = { workspace = true }
|
||||
slashing_protection = { workspace = true }
|
||||
mediatype = "0.19.13"
|
||||
mime = "0.3.16"
|
||||
pretty_reqwest_error = { path = "../../common/pretty_reqwest_error" }
|
||||
pretty_reqwest_error = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
tokio = { version = "1.14.0", features = ["full"] }
|
||||
tokio = { workspace = true }
|
||||
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
psutil = { version = "3.2.2", optional = true }
|
||||
@ -41,4 +41,4 @@ procfs = { version = "0.15.1", optional = true }
|
||||
|
||||
[features]
|
||||
default = ["lighthouse"]
|
||||
lighthouse = ["proto_array", "psutil", "procfs", "store", "slashing_protection"]
|
||||
lighthouse = ["psutil", "procfs"]
|
||||
|
@ -120,6 +120,7 @@ pub struct Timeouts {
|
||||
pub get_beacon_blocks_ssz: Duration,
|
||||
pub get_debug_beacon_states: Duration,
|
||||
pub get_deposit_snapshot: Duration,
|
||||
pub get_validator_block_ssz: Duration,
|
||||
}
|
||||
|
||||
impl Timeouts {
|
||||
@ -135,6 +136,7 @@ impl Timeouts {
|
||||
get_beacon_blocks_ssz: timeout,
|
||||
get_debug_beacon_states: timeout,
|
||||
get_deposit_snapshot: timeout,
|
||||
get_validator_block_ssz: timeout,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1629,14 +1631,14 @@ impl BeaconNodeHttpClient {
|
||||
.await
|
||||
}
|
||||
|
||||
/// `GET v2/validator/blocks/{slot}`
|
||||
pub async fn get_validator_blocks_modular<T: EthSpec, Payload: AbstractExecPayload<T>>(
|
||||
/// returns `GET v2/validator/blocks/{slot}` URL path
|
||||
pub async fn get_validator_blocks_path<T: EthSpec, Payload: AbstractExecPayload<T>>(
|
||||
&self,
|
||||
slot: Slot,
|
||||
randao_reveal: &SignatureBytes,
|
||||
graffiti: Option<&Graffiti>,
|
||||
skip_randao_verification: SkipRandaoVerification,
|
||||
) -> Result<ForkVersionedResponse<BlockContents<T, Payload>>, Error> {
|
||||
) -> Result<Url, Error> {
|
||||
let mut path = self.eth_path(V2)?;
|
||||
|
||||
path.path_segments_mut()
|
||||
@ -1658,9 +1660,66 @@ impl BeaconNodeHttpClient {
|
||||
.append_pair("skip_randao_verification", "");
|
||||
}
|
||||
|
||||
Ok(path)
|
||||
}
|
||||
|
||||
/// `GET v2/validator/blocks/{slot}`
|
||||
pub async fn get_validator_blocks_modular<T: EthSpec, Payload: AbstractExecPayload<T>>(
|
||||
&self,
|
||||
slot: Slot,
|
||||
randao_reveal: &SignatureBytes,
|
||||
graffiti: Option<&Graffiti>,
|
||||
skip_randao_verification: SkipRandaoVerification,
|
||||
) -> Result<ForkVersionedResponse<BlockContents<T, Payload>>, Error> {
|
||||
let path = self
|
||||
.get_validator_blocks_path::<T, Payload>(
|
||||
slot,
|
||||
randao_reveal,
|
||||
graffiti,
|
||||
skip_randao_verification,
|
||||
)
|
||||
.await?;
|
||||
|
||||
self.get(path).await
|
||||
}
|
||||
|
||||
/// `GET v2/validator/blocks/{slot}` in ssz format
|
||||
pub async fn get_validator_blocks_ssz<T: EthSpec, Payload: AbstractExecPayload<T>>(
|
||||
&self,
|
||||
slot: Slot,
|
||||
randao_reveal: &SignatureBytes,
|
||||
graffiti: Option<&Graffiti>,
|
||||
) -> Result<Option<Vec<u8>>, Error> {
|
||||
self.get_validator_blocks_modular_ssz::<T, Payload>(
|
||||
slot,
|
||||
randao_reveal,
|
||||
graffiti,
|
||||
SkipRandaoVerification::No,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
/// `GET v2/validator/blocks/{slot}` in ssz format
|
||||
pub async fn get_validator_blocks_modular_ssz<T: EthSpec, Payload: AbstractExecPayload<T>>(
|
||||
&self,
|
||||
slot: Slot,
|
||||
randao_reveal: &SignatureBytes,
|
||||
graffiti: Option<&Graffiti>,
|
||||
skip_randao_verification: SkipRandaoVerification,
|
||||
) -> Result<Option<Vec<u8>>, Error> {
|
||||
let path = self
|
||||
.get_validator_blocks_path::<T, Payload>(
|
||||
slot,
|
||||
randao_reveal,
|
||||
graffiti,
|
||||
skip_randao_verification,
|
||||
)
|
||||
.await?;
|
||||
|
||||
self.get_bytes_opt_accept_header(path, Accept::Ssz, self.timeouts.get_validator_block_ssz)
|
||||
.await
|
||||
}
|
||||
|
||||
/// `GET v2/validator/blinded_blocks/{slot}`
|
||||
pub async fn get_validator_blinded_blocks<T: EthSpec, Payload: AbstractExecPayload<T>>(
|
||||
&self,
|
||||
@ -1677,17 +1736,14 @@ impl BeaconNodeHttpClient {
|
||||
.await
|
||||
}
|
||||
|
||||
/// `GET v1/validator/blinded_blocks/{slot}`
|
||||
pub async fn get_validator_blinded_blocks_modular<
|
||||
T: EthSpec,
|
||||
Payload: AbstractExecPayload<T>,
|
||||
>(
|
||||
/// returns `GET v1/validator/blinded_blocks/{slot}` URL path
|
||||
pub async fn get_validator_blinded_blocks_path<T: EthSpec, Payload: AbstractExecPayload<T>>(
|
||||
&self,
|
||||
slot: Slot,
|
||||
randao_reveal: &SignatureBytes,
|
||||
graffiti: Option<&Graffiti>,
|
||||
skip_randao_verification: SkipRandaoVerification,
|
||||
) -> Result<ForkVersionedResponse<BlockContents<T, Payload>>, Error> {
|
||||
) -> Result<Url, Error> {
|
||||
let mut path = self.eth_path(V1)?;
|
||||
|
||||
path.path_segments_mut()
|
||||
@ -1709,9 +1765,71 @@ impl BeaconNodeHttpClient {
|
||||
.append_key_only("skip_randao_verification");
|
||||
}
|
||||
|
||||
Ok(path)
|
||||
}
|
||||
|
||||
/// `GET v1/validator/blinded_blocks/{slot}`
|
||||
pub async fn get_validator_blinded_blocks_modular<
|
||||
T: EthSpec,
|
||||
Payload: AbstractExecPayload<T>,
|
||||
>(
|
||||
&self,
|
||||
slot: Slot,
|
||||
randao_reveal: &SignatureBytes,
|
||||
graffiti: Option<&Graffiti>,
|
||||
skip_randao_verification: SkipRandaoVerification,
|
||||
) -> Result<ForkVersionedResponse<BlockContents<T, Payload>>, Error> {
|
||||
let path = self
|
||||
.get_validator_blinded_blocks_path::<T, Payload>(
|
||||
slot,
|
||||
randao_reveal,
|
||||
graffiti,
|
||||
skip_randao_verification,
|
||||
)
|
||||
.await?;
|
||||
|
||||
self.get(path).await
|
||||
}
|
||||
|
||||
/// `GET v2/validator/blinded_blocks/{slot}` in ssz format
|
||||
pub async fn get_validator_blinded_blocks_ssz<T: EthSpec, Payload: AbstractExecPayload<T>>(
|
||||
&self,
|
||||
slot: Slot,
|
||||
randao_reveal: &SignatureBytes,
|
||||
graffiti: Option<&Graffiti>,
|
||||
) -> Result<Option<Vec<u8>>, Error> {
|
||||
self.get_validator_blinded_blocks_modular_ssz::<T, Payload>(
|
||||
slot,
|
||||
randao_reveal,
|
||||
graffiti,
|
||||
SkipRandaoVerification::No,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_validator_blinded_blocks_modular_ssz<
|
||||
T: EthSpec,
|
||||
Payload: AbstractExecPayload<T>,
|
||||
>(
|
||||
&self,
|
||||
slot: Slot,
|
||||
randao_reveal: &SignatureBytes,
|
||||
graffiti: Option<&Graffiti>,
|
||||
skip_randao_verification: SkipRandaoVerification,
|
||||
) -> Result<Option<Vec<u8>>, Error> {
|
||||
let path = self
|
||||
.get_validator_blinded_blocks_path::<T, Payload>(
|
||||
slot,
|
||||
randao_reveal,
|
||||
graffiti,
|
||||
skip_randao_verification,
|
||||
)
|
||||
.await?;
|
||||
|
||||
self.get_bytes_opt_accept_header(path, Accept::Ssz, self.timeouts.get_validator_block_ssz)
|
||||
.await
|
||||
}
|
||||
|
||||
/// `GET validator/attestation_data?slot,committee_index`
|
||||
pub async fn get_validator_attestation_data(
|
||||
&self,
|
||||
|
@ -666,7 +666,7 @@ impl ValidatorClientHttpClient {
|
||||
&self,
|
||||
pubkey: &PublicKeyBytes,
|
||||
epoch: Option<Epoch>,
|
||||
) -> Result<SignedVoluntaryExit, Error> {
|
||||
) -> Result<GenericResponse<SignedVoluntaryExit>, Error> {
|
||||
let mut path = self.server.full.clone();
|
||||
|
||||
path.path_segments_mut()
|
||||
|
@ -1468,9 +1468,10 @@ mod tests {
|
||||
}
|
||||
|
||||
/// A wrapper over a [`BeaconBlock`] or a [`BeaconBlockAndBlobSidecars`].
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[derive(Debug, Encode, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
#[serde(bound = "T: EthSpec")]
|
||||
#[ssz(enum_behaviour = "transparent")]
|
||||
pub enum BlockContents<T: EthSpec, Payload: AbstractExecPayload<T>> {
|
||||
BlockAndBlobSidecars(BeaconBlockAndBlobSidecars<T, Payload>),
|
||||
BlindedBlockAndBlobSidecars(BlindedBeaconBlockAndBlobSidecars<T, Payload>),
|
||||
|
@ -2,8 +2,8 @@
|
||||
name = "eth2_config"
|
||||
version = "0.2.0"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>"]
|
||||
edition = "2021"
|
||||
edition = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
types = { path = "../../consensus/types" }
|
||||
paste = "1.0.5"
|
||||
types = { workspace = true }
|
||||
paste = { workspace = true }
|
||||
|
@ -29,7 +29,7 @@ const HOLESKY_GENESIS_STATE_SOURCE: GenesisStateSource = GenesisStateSource::Url
|
||||
// more details.
|
||||
"https://sigp-public-genesis-states.s3.ap-southeast-2.amazonaws.com/holesky/",
|
||||
],
|
||||
checksum: "0x76631cd0b9ddc5b2c766b496e23f16759ce1181446a4efb40e5540cd15b78a07",
|
||||
checksum: "0xd750639607c337bbb192b15c27f447732267bf72d1650180a0e44c2d93a80741",
|
||||
genesis_validators_root: "0x9143aa7c615a7f7115e2b6aac319c03529df8242ae705fba9df39b79c59fa8b1",
|
||||
};
|
||||
|
||||
|
@ -2,19 +2,19 @@
|
||||
name = "eth2_interop_keypairs"
|
||||
version = "0.2.0"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>"]
|
||||
edition = "2021"
|
||||
edition = { workspace = true }
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
lazy_static = "1.4.0"
|
||||
lazy_static = { workspace = true }
|
||||
num-bigint = "0.4.2"
|
||||
ethereum_hashing = "1.0.0-beta.2"
|
||||
hex = "0.4.2"
|
||||
serde_yaml = "0.8.13"
|
||||
serde = "1.0.116"
|
||||
ethereum_hashing = { workspace = true }
|
||||
hex = { workspace = true }
|
||||
serde_yaml = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_derive = "1.0.116"
|
||||
bls = { path = "../../crypto/bls" }
|
||||
bls = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
base64 = "0.13.0"
|
||||
|
@ -2,29 +2,31 @@
|
||||
name = "eth2_network_config"
|
||||
version = "0.2.0"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>"]
|
||||
edition = "2021"
|
||||
edition = { workspace = true }
|
||||
|
||||
build = "build.rs"
|
||||
|
||||
[build-dependencies]
|
||||
zip = "0.6"
|
||||
eth2_config = { path = "../eth2_config" }
|
||||
zip = { workspace = true }
|
||||
eth2_config = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3.1.0"
|
||||
tempfile = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
serde_yaml = "0.8.13"
|
||||
serde_json = "1.0.58"
|
||||
types = { path = "../../consensus/types" }
|
||||
kzg = { path = "../../crypto/kzg" }
|
||||
ethereum_ssz = "0.5.0"
|
||||
eth2_config = { path = "../eth2_config" }
|
||||
discv5 = "0.3.1"
|
||||
reqwest = { version = "0.11.0", features = ["blocking"] }
|
||||
pretty_reqwest_error = { path = "../pretty_reqwest_error" }
|
||||
sha2 = "0.10"
|
||||
url = "2.2.2"
|
||||
sensitive_url = { path = "../sensitive_url" }
|
||||
slog = "2.5.2"
|
||||
logging = { path = "../logging" }
|
||||
serde_yaml = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
types = { workspace = true }
|
||||
kzg = { workspace = true }
|
||||
ethereum_ssz = { workspace = true }
|
||||
eth2_config = { workspace = true }
|
||||
discv5 = { workspace = true }
|
||||
reqwest = { workspace = true }
|
||||
pretty_reqwest_error = { workspace = true }
|
||||
sha2 = { workspace = true }
|
||||
url = { workspace = true }
|
||||
sensitive_url = { workspace = true }
|
||||
slog = { workspace = true }
|
||||
logging = { workspace = true }
|
||||
bytes = { workspace = true }
|
||||
|
@ -1,8 +1,9 @@
|
||||
# EF
|
||||
- enr:-Iq4QJk4WqRkjsX5c2CXtOra6HnxN-BMXnWhmhEQO9Bn9iABTJGdjUOurM7Btj1ouKaFkvTRoju5vz2GPmVON2dffQKGAX53x8JigmlkgnY0gmlwhLKAlv6Jc2VjcDI1NmsxoQK6S-Cii_KmfFdUJL2TANL3ksaKUnNXvTCv1tLwXs0QgIN1ZHCCIyk
|
||||
- enr:-KG4QF6d6vMSboSujAXTI4vYqArccm0eIlXfcxf2Lx_VE1q6IkQo_2D5LAO3ZSBVUs0w5rrVDmABJZuMzISe_pZundADhGV0aDKQqX6DZjABcAAAAQAAAAAAAIJpZIJ2NIJpcISygIjpiXNlY3AyNTZrMaEDF3aSa7QSCvdqLpANNd8GML4PLEZVg45fKQwMWhDZjd2DdGNwgiMog3VkcIIjKA
|
||||
- enr:-Ly4QJLXSSAj3ggPBIcodvBU6IyfpU_yW7E9J-5syoJorBuvcYj_Fokcjr303bQoTdWXADf8po0ssh75Mr5wVGzZZsMBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpCpfoNmMAFwAAABAAAAAAAAgmlkgnY0gmlwhJK-DYCJc2VjcDI1NmsxoQJrIlXIQDvQ6t9yDySqJYDXgZgLXzTvq8W7OI51jfmxJohzeW5jbmV0cwCDdGNwgiMog3VkcIIjKA
|
||||
- enr:-Ku4QFo-9q73SspYI8cac_4kTX7yF800VXqJW4Lj3HkIkb5CMqFLxciNHePmMt4XdJzHvhrCC5ADI4D_GkAsxGJRLnQBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpAhnTT-AQFwAP__________gmlkgnY0gmlwhLKAiOmJc2VjcDI1NmsxoQORcM6e19T1T9gi7jxEZjk_sjVLGFscUNqAY9obgZaxbIN1ZHCCIyk
|
||||
- enr:-Ku4QPG7F72mbKx3gEQEx07wpYYusGDh-ni6SNkLvOS-hhN-BxIggN7tKlmalb0L5JPoAfqD-akTZ-gX06hFeBEz4WoBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpAhnTT-AQFwAP__________gmlkgnY0gmlwhJK-DYCJc2VjcDI1NmsxoQKLVXFOhp2uX6jeT0DvvDpPcU8FWMjQdR4wMuORMhpX24N1ZHCCIyk
|
||||
- enr:-LK4QPxe-mDiSOtEB_Y82ozvxn9aQM07Ui8A-vQHNgYGMMthfsfOabaaTHhhJHFCBQQVRjBww_A5bM1rf8MlkJU_l68Eh2F0dG5ldHOIAADAAAAAAACEZXRoMpBpt9l0BAFwAAABAAAAAAAAgmlkgnY0gmlwhLKAiOmJc2VjcDI1NmsxoQJu6T9pclPObAzEVQ53DpVQqjadmVxdTLL-J3h9NFoCeIN0Y3CCIyiDdWRwgiMo
|
||||
- enr:-Ly4QGbOw4xNel5EhmDsJJ-QhC9XycWtsetnWoZ0uRy381GHdHsNHJiCwDTOkb3S1Ade0SFQkWJX_pgb3g8Jfh93rvMBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpBpt9l0BAFwAAABAAAAAAAAgmlkgnY0gmlwhJK-DYCJc2VjcDI1NmsxoQOxKv9sv3zKF8GDewgFGGHKP5HCZZpPpTrwl9eXKAWGxIhzeW5jbmV0cwCDdGNwgiMog3VkcIIjKA
|
||||
# Teku
|
||||
- enr:-LK4QMlzEff6d-M0A1pSFG5lJ2c56i_I-ZftdojZbW3ehkGNM4pkQuHQqzVvF1BG9aDjIakjnmO23mCBFFZ2w5zOsugEh2F0dG5ldHOIAAAAAAYAAACEZXRoMpCpfoNmMAFwAAABAAAAAAAAgmlkgnY0gmlwhKyuI_mJc2VjcDI1NmsxoQIH1kQRCZW-4AIVyAeXj5o49m_IqNFKRHp6tSpfXMUrSYN0Y3CCIyiDdWRwgiMo
|
||||
- enr:-LS4QG0uV4qvcpJ-HFDJRGBmnlD3TJo7yc4jwK8iP7iKaTlfQ5kZvIDspLMJhk7j9KapuL9yyHaZmwTEZqr10k9XumyCEcmHYXR0bmV0c4gAAAAABgAAAIRldGgykGm32XQEAXAAAAEAAAAAAACCaWSCdjSCaXCErK4j-YlzZWNwMjU2azGhAgfWRBEJlb7gAhXIB5ePmjj2b8io0UpEenq1Kl9cxStJg3RjcIIjKIN1ZHCCIyg
|
||||
# Sigma Prime
|
||||
- enr:-Le4QI88slOwzz66Ksq8Vnz324DPb1BzSiY-WYPvnoJIl-lceW9bmSJnwDzgNbCjp5wsBigg76x4tValvGgQPxxSjrMBhGV0aDKQqX6DZjABcAAAAQAAAAAAAIJpZIJ2NIJpcIQ5gR6Wg2lwNpAgAUHQBwEQAAAAAAAAADR-iXNlY3AyNTZrMaEDPMSNdcL92uNIyCsS177Z6KTXlbZakQqxv3aQcWawNXeDdWRwgiMohHVkcDaCI4I
|
||||
- enr:-Le4QLoE1wFHSlGcm48a9ZESb_MRLqPPu6G0vHqu4MaUcQNDHS69tsy-zkN0K6pglyzX8m24mkb-LtBcbjAYdP1uxm4BhGV0aDKQabfZdAQBcAAAAQAAAAAAAIJpZIJ2NIJpcIQ5gR6Wg2lwNpAgAUHQBwEQAAAAAAAAADR-iXNlY3AyNTZrMaEDPMSNdcL92uNIyCsS177Z6KTXlbZakQqxv3aQcWawNXeDdWRwgiMohHVkcDaCI4I
|
||||
|
@ -6,9 +6,9 @@ CONFIG_NAME: holesky
|
||||
# ---------------------------------------------------------------
|
||||
# `2**14` (= 16,384)
|
||||
MIN_GENESIS_ACTIVE_VALIDATOR_COUNT: 16384
|
||||
# Sep-15-2023 13:55:00 +UTC
|
||||
MIN_GENESIS_TIME: 1694786100
|
||||
GENESIS_FORK_VERSION: 0x00017000
|
||||
# Sep-28-2023 11:55:00 +UTC
|
||||
MIN_GENESIS_TIME: 1695902100
|
||||
GENESIS_FORK_VERSION: 0x01017000
|
||||
# Genesis delay 5 mins
|
||||
GENESIS_DELAY: 300
|
||||
|
||||
@ -20,23 +20,19 @@ GENESIS_DELAY: 300
|
||||
# - Temporarily set to max uint64 value: 2**64 - 1
|
||||
|
||||
# Altair
|
||||
ALTAIR_FORK_VERSION: 0x10017000
|
||||
ALTAIR_FORK_VERSION: 0x02017000
|
||||
ALTAIR_FORK_EPOCH: 0
|
||||
# Merge
|
||||
BELLATRIX_FORK_VERSION: 0x20017000
|
||||
BELLATRIX_FORK_VERSION: 0x03017000
|
||||
BELLATRIX_FORK_EPOCH: 0
|
||||
TERMINAL_TOTAL_DIFFICULTY: 0
|
||||
TERMINAL_BLOCK_HASH: 0x0000000000000000000000000000000000000000000000000000000000000000
|
||||
TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH: 18446744073709551615
|
||||
|
||||
# Capella
|
||||
CAPELLA_FORK_VERSION: 0x30017000
|
||||
CAPELLA_FORK_VERSION: 0x04017000
|
||||
CAPELLA_FORK_EPOCH: 256
|
||||
|
||||
# DENEB
|
||||
DENEB_FORK_VERSION: 0x40017000
|
||||
DENEB_FORK_EPOCH: 18446744073709551615
|
||||
|
||||
# Time parameters
|
||||
# ---------------------------------------------------------------
|
||||
# 12 seconds
|
||||
|
@ -10,11 +10,13 @@
|
||||
- enr:-Ku4QEWzdnVtXc2Q0ZVigfCGggOVB2Vc1ZCPEc6j21NIFLODSJbvNaef1g4PxhPwl_3kax86YPheFUSLXPRs98vvYsoBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpC1MD8qAAAAAP__________gmlkgnY0gmlwhDZBrP2Jc2VjcDI1NmsxoQM6jr8Rb1ktLEsVcKAPa08wCsKUmvoQ8khiOl_SLozf9IN1ZHCCIyg
|
||||
# Teku team (Consensys)
|
||||
- enr:-KG4QOtcP9X1FbIMOe17QNMKqDxCpm14jcX5tiOE4_TyMrFqbmhPZHK_ZPG2Gxb1GE2xdtodOfx9-cgvNtxnRyHEmC0ghGV0aDKQ9aX9QgAAAAD__________4JpZIJ2NIJpcIQDE8KdiXNlY3AyNTZrMaEDhpehBDbZjM_L9ek699Y7vhUJ-eAdMyQW_Fil522Y0fODdGNwgiMog3VkcIIjKA
|
||||
- enr:-KG4QDyytgmE4f7AnvW-ZaUOIi9i79qX4JwjRAiXBZCU65wOfBu-3Nb5I7b_Rmg3KCOcZM_C3y5pg7EBU5XGrcLTduQEhGV0aDKQ9aX9QgAAAAD__________4JpZIJ2NIJpcIQ2_DUbiXNlY3AyNTZrMaEDKnz_-ps3UUOfHWVYaskI5kWYO_vtYMGYCQRAR3gHDouDdGNwgiMog3VkcIIjKA
|
||||
- enr:-KG4QL-eqFoHy0cI31THvtZjpYUu_Jdw_MO7skQRJxY1g5HTN1A0epPCU6vi0gLGUgrzpU-ygeMSS8ewVxDpKfYmxMMGhGV0aDKQtTA_KgAAAAD__________4JpZIJ2NIJpcIQ2_DUbiXNlY3AyNTZrMaED8GJ2vzUqgL6-KD1xalo1CsmY4X1HaDnyl6Y_WayCo9GDdGNwgiMog3VkcIIjKA
|
||||
- enr:-KG4QMOEswP62yzDjSwWS4YEjtTZ5PO6r65CPqYBkgTTkrpaedQ8uEUo1uMALtJIvb2w_WWEVmg5yt1UAuK1ftxUU7QDhGV0aDKQu6TalgMAAAD__________4JpZIJ2NIJpcIQEnfA2iXNlY3AyNTZrMaEDfol8oLr6XJ7FsdAYE7lpJhKMls4G_v6qQOGKJUWGb_uDdGNwgiMog3VkcIIjKA
|
||||
- enr:-KG4QF4B5WrlFcRhUU6dZETwY5ZzAXnA0vGC__L1Kdw602nDZwXSTs5RFXFIFUnbQJmhNGVU6OIX7KVrCSTODsz1tK4DhGV0aDKQu6TalgMAAAD__________4JpZIJ2NIJpcIQExNYEiXNlY3AyNTZrMaECQmM9vp7KhaXhI-nqL_R0ovULLCFSFTa9CPPSdb1zPX6DdGNwgiMog3VkcIIjKA
|
||||
# Prysm team (Prysmatic Labs)
|
||||
- enr:-Ku4QImhMc1z8yCiNJ1TyUxdcfNucje3BGwEHzodEZUan8PherEo4sF7pPHPSIB1NNuSg5fZy7qFsjmUKs2ea1Whi0EBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpD1pf1CAAAAAP__________gmlkgnY0gmlwhBLf22SJc2VjcDI1NmsxoQOVphkDqal4QzPMksc5wnpuC3gvSC8AfbFOnZY_On34wIN1ZHCCIyg
|
||||
- enr:-Ku4QP2xDnEtUXIjzJ_DhlCRN9SN99RYQPJL92TMlSv7U5C1YnYLjwOQHgZIUXw6c-BvRg2Yc2QsZxxoS_pPRVe0yK8Bh2F0dG5ldHOIAAAAAAAAAACEZXRoMpD1pf1CAAAAAP__________gmlkgnY0gmlwhBLf22SJc2VjcDI1NmsxoQMeFF5GrS7UZpAH2Ly84aLK-TyvH-dRo0JM1i8yygH50YN1ZHCCJxA
|
||||
- enr:-Ku4QPp9z1W4tAO8Ber_NQierYaOStqhDqQdOPY3bB3jDgkjcbk6YrEnVYIiCBbTxuar3CzS528d2iE7TdJsrL-dEKoBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpD1pf1CAAAAAP__________gmlkgnY0gmlwhBLf22SJc2VjcDI1NmsxoQMw5fqqkw2hHC4F5HZZDPsNmPdB1Gi8JPQK7pRc9XHh-oN1ZHCCKvg
|
||||
# Nimbus team
|
||||
- enr:-LK4QA8FfhaAjlb_BXsXxSfiysR7R52Nhi9JBt4F8SPssu8hdE1BXQQEtVDC3qStCW60LSO7hEsVHv5zm8_6Vnjhcn0Bh2F0dG5ldHOIAAAAAAAAAACEZXRoMpC1MD8qAAAAAP__________gmlkgnY0gmlwhAN4aBKJc2VjcDI1NmsxoQJerDhsJ-KxZ8sHySMOCmTO6sHM3iCFQ6VMvLTe948MyYN0Y3CCI4yDdWRwgiOM
|
||||
- enr:-LK4QKWrXTpV9T78hNG6s8AM6IO4XH9kFT91uZtFg1GcsJ6dKovDOr1jtAAFPnS2lvNltkOGA9k29BUN7lFh_sjuc9QBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpC1MD8qAAAAAP__________gmlkgnY0gmlwhANAdd-Jc2VjcDI1NmsxoQLQa6ai7y9PMN5hpLe5HmiJSlYzMuzP7ZhwRiwHvqNXdoN0Y3CCI4yDdWRwgiOM
|
||||
- enr:-LK4QKWrXTpV9T78hNG6s8AM6IO4XH9kFT91uZtFg1GcsJ6dKovDOr1jtAAFPnS2lvNltkOGA9k29BUN7lFh_sjuc9QBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpC1MD8qAAAAAP__________gmlkgnY0gmlwhANAdd-Jc2VjcDI1NmsxoQLQa6ai7y9PMN5hpLe5HmiJSlYzMuzP7ZhwRiwHvqNXdoN0Y3CCI4yDdWRwgiOM
|
||||
|
@ -11,11 +11,12 @@
|
||||
//! To add a new built-in testnet, add it to the `define_hardcoded_nets` invocation in the `eth2_config`
|
||||
//! crate.
|
||||
|
||||
use bytes::Bytes;
|
||||
use discv5::enr::{CombinedKey, Enr};
|
||||
use eth2_config::{instantiate_hardcoded_nets, HardcodedNet};
|
||||
use kzg::{KzgPreset, KzgPresetId, TrustedSetup};
|
||||
use pretty_reqwest_error::PrettyReqwestError;
|
||||
use reqwest::blocking::Client;
|
||||
use reqwest::{Client, Error};
|
||||
use sensitive_url::SensitiveUrl;
|
||||
use sha2::{Digest, Sha256};
|
||||
use slog::{info, warn, Logger};
|
||||
@ -168,14 +169,8 @@ impl Eth2NetworkConfig {
|
||||
self.genesis_state_source != GenesisStateSource::Unknown
|
||||
}
|
||||
|
||||
/// The `genesis_validators_root` of the genesis state. May download the
|
||||
/// genesis state if the value is not already available.
|
||||
pub fn genesis_validators_root<E: EthSpec>(
|
||||
&self,
|
||||
genesis_state_url: Option<&str>,
|
||||
timeout: Duration,
|
||||
log: &Logger,
|
||||
) -> Result<Option<Hash256>, String> {
|
||||
/// The `genesis_validators_root` of the genesis state.
|
||||
pub fn genesis_validators_root<E: EthSpec>(&self) -> Result<Option<Hash256>, String> {
|
||||
if let GenesisStateSource::Url {
|
||||
genesis_validators_root,
|
||||
..
|
||||
@ -190,10 +185,8 @@ impl Eth2NetworkConfig {
|
||||
)
|
||||
})
|
||||
} else {
|
||||
self.genesis_state::<E>(genesis_state_url, timeout, log)?
|
||||
.map(|state| state.genesis_validators_root())
|
||||
.map(Result::Ok)
|
||||
.transpose()
|
||||
self.get_genesis_state_from_bytes::<E>()
|
||||
.map(|state| Some(state.genesis_validators_root()))
|
||||
}
|
||||
}
|
||||
|
||||
@ -211,7 +204,7 @@ impl Eth2NetworkConfig {
|
||||
///
|
||||
/// If the genesis state is configured to be downloaded from a URL, then the
|
||||
/// `genesis_state_url` will override the built-in list of download URLs.
|
||||
pub fn genesis_state<E: EthSpec>(
|
||||
pub async fn genesis_state<E: EthSpec>(
|
||||
&self,
|
||||
genesis_state_url: Option<&str>,
|
||||
timeout: Duration,
|
||||
@ -221,15 +214,7 @@ impl Eth2NetworkConfig {
|
||||
match &self.genesis_state_source {
|
||||
GenesisStateSource::Unknown => Ok(None),
|
||||
GenesisStateSource::IncludedBytes => {
|
||||
let state = self
|
||||
.genesis_state_bytes
|
||||
.as_ref()
|
||||
.map(|bytes| {
|
||||
BeaconState::from_ssz_bytes(bytes.as_ref(), &spec).map_err(|e| {
|
||||
format!("Built-in genesis state SSZ bytes are invalid: {:?}", e)
|
||||
})
|
||||
})
|
||||
.ok_or("Genesis state bytes missing from Eth2NetworkConfig")??;
|
||||
let state = self.get_genesis_state_from_bytes()?;
|
||||
Ok(Some(state))
|
||||
}
|
||||
GenesisStateSource::Url {
|
||||
@ -241,9 +226,9 @@ impl Eth2NetworkConfig {
|
||||
format!("Unable to parse genesis state bytes checksum: {:?}", e)
|
||||
})?;
|
||||
let bytes = if let Some(specified_url) = genesis_state_url {
|
||||
download_genesis_state(&[specified_url], timeout, checksum, log)
|
||||
download_genesis_state(&[specified_url], timeout, checksum, log).await
|
||||
} else {
|
||||
download_genesis_state(built_in_urls, timeout, checksum, log)
|
||||
download_genesis_state(built_in_urls, timeout, checksum, log).await
|
||||
}?;
|
||||
let state = BeaconState::from_ssz_bytes(bytes.as_ref(), &spec).map_err(|e| {
|
||||
format!("Downloaded genesis state SSZ bytes are invalid: {:?}", e)
|
||||
@ -269,6 +254,17 @@ impl Eth2NetworkConfig {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_genesis_state_from_bytes<E: EthSpec>(&self) -> Result<BeaconState<E>, String> {
|
||||
let spec = self.chain_spec::<E>()?;
|
||||
self.genesis_state_bytes
|
||||
.as_ref()
|
||||
.map(|bytes| {
|
||||
BeaconState::from_ssz_bytes(bytes.as_ref(), &spec)
|
||||
.map_err(|e| format!("Built-in genesis state SSZ bytes are invalid: {:?}", e))
|
||||
})
|
||||
.ok_or("Genesis state bytes missing from Eth2NetworkConfig")?
|
||||
}
|
||||
|
||||
/// Write the files to the directory.
|
||||
///
|
||||
/// Overwrites files if specified to do so.
|
||||
@ -396,7 +392,7 @@ impl Eth2NetworkConfig {
|
||||
/// Try to download a genesis state from each of the `urls` in the order they
|
||||
/// are defined. Return `Ok` if any url returns a response that matches the
|
||||
/// given `checksum`.
|
||||
fn download_genesis_state(
|
||||
async fn download_genesis_state(
|
||||
urls: &[&str],
|
||||
timeout: Duration,
|
||||
checksum: Hash256,
|
||||
@ -428,12 +424,7 @@ fn download_genesis_state(
|
||||
);
|
||||
|
||||
let client = Client::new();
|
||||
let response = client
|
||||
.get(url)
|
||||
.header("Accept", "application/octet-stream")
|
||||
.timeout(timeout)
|
||||
.send()
|
||||
.and_then(|r| r.error_for_status().and_then(|r| r.bytes()));
|
||||
let response = get_state_bytes(timeout, url, client).await;
|
||||
|
||||
match response {
|
||||
Ok(bytes) => {
|
||||
@ -463,6 +454,18 @@ fn download_genesis_state(
|
||||
))
|
||||
}
|
||||
|
||||
async fn get_state_bytes(timeout: Duration, url: Url, client: Client) -> Result<Bytes, Error> {
|
||||
client
|
||||
.get(url)
|
||||
.header("Accept", "application/octet-stream")
|
||||
.timeout(timeout)
|
||||
.send()
|
||||
.await?
|
||||
.error_for_status()?
|
||||
.bytes()
|
||||
.await
|
||||
}
|
||||
|
||||
/// Parses the `url` and joins the necessary state download path.
|
||||
fn parse_state_download_url(url: &str) -> Result<Url, String> {
|
||||
Url::parse(url)
|
||||
@ -507,11 +510,12 @@ mod tests {
|
||||
assert_eq!(spec, config.chain_spec::<GnosisEthSpec>().unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mainnet_genesis_state() {
|
||||
#[tokio::test]
|
||||
async fn mainnet_genesis_state() {
|
||||
let config = Eth2NetworkConfig::from_hardcoded_net(&MAINNET).unwrap();
|
||||
config
|
||||
.genesis_state::<E>(None, Duration::from_secs(1), &logging::test_logger())
|
||||
.await
|
||||
.expect("beacon state can decode");
|
||||
}
|
||||
|
||||
|
@ -2,13 +2,13 @@
|
||||
name = "eth2_wallet_manager"
|
||||
version = "0.1.0"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>"]
|
||||
edition = "2021"
|
||||
edition = { workspace = true }
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
eth2_wallet = { path = "../../crypto/eth2_wallet" }
|
||||
lockfile = { path = "../lockfile" }
|
||||
eth2_wallet = { workspace = true }
|
||||
lockfile = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3.1.0"
|
||||
tempfile = { workspace = true }
|
||||
|
@ -2,7 +2,7 @@
|
||||
name = "filesystem"
|
||||
version = "0.1.0"
|
||||
authors = ["Mark Mackey <mark@sigmaprime.io>"]
|
||||
edition = "2021"
|
||||
edition = { workspace = true }
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
@ -2,10 +2,10 @@
|
||||
name = "lighthouse_metrics"
|
||||
version = "0.2.0"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>"]
|
||||
edition = "2021"
|
||||
edition = { workspace = true }
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
lazy_static = "1.4.0"
|
||||
lazy_static = { workspace = true }
|
||||
prometheus = "0.13.0"
|
||||
|
@ -2,7 +2,7 @@
|
||||
name = "lighthouse_version"
|
||||
version = "0.1.0"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>"]
|
||||
edition = "2021"
|
||||
edition = { workspace = true }
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@ -11,4 +11,4 @@ git-version = "0.3.4"
|
||||
target_info = "0.1.0"
|
||||
|
||||
[dev-dependencies]
|
||||
regex = "1.5.5"
|
||||
regex = { workspace = true }
|
||||
|
@ -17,8 +17,8 @@ pub const VERSION: &str = git_version!(
|
||||
// NOTE: using --match instead of --exclude for compatibility with old Git
|
||||
"--match=thiswillnevermatchlol"
|
||||
],
|
||||
prefix = "Lighthouse/v4.4.1-",
|
||||
fallback = "Lighthouse/v4.4.1"
|
||||
prefix = "Lighthouse/v4.5.0-",
|
||||
fallback = "Lighthouse/v4.5.0"
|
||||
);
|
||||
|
||||
/// Returns `VERSION`, but with platform information appended to the end.
|
||||
|
@ -2,10 +2,10 @@
|
||||
name = "lockfile"
|
||||
version = "0.1.0"
|
||||
authors = ["Michael Sproul <michael@sigmaprime.io>"]
|
||||
edition = "2021"
|
||||
edition = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
fs2 = "0.4.3"
|
||||
fs2 = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3.1.0"
|
||||
tempfile = { workspace = true }
|
||||
|
@ -2,21 +2,21 @@
|
||||
name = "logging"
|
||||
version = "0.2.0"
|
||||
authors = ["blacktemplar <blacktemplar@a1.net>"]
|
||||
edition = "2021"
|
||||
edition = { workspace = true }
|
||||
|
||||
[features]
|
||||
test_logger = [] # Print log output to stderr when running tests instead of dropping it
|
||||
|
||||
[dependencies]
|
||||
slog = "2.5.2"
|
||||
slog-term = "2.6.0"
|
||||
tokio = { version = "1.26.0", features = ["sync"] }
|
||||
lighthouse_metrics = { path = "../lighthouse_metrics" }
|
||||
lazy_static = "1.4.0"
|
||||
sloggers = { version = "2.1.1", features = ["json"] }
|
||||
slog-async = "2.7.0"
|
||||
slog = { workspace = true }
|
||||
slog-term = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
lighthouse_metrics = { workspace = true }
|
||||
lazy_static = { workspace = true }
|
||||
sloggers = { workspace = true }
|
||||
slog-async = { workspace = true }
|
||||
take_mut = "0.2.2"
|
||||
parking_lot = "0.12.1"
|
||||
serde = "1.0.153"
|
||||
serde_json = "1.0.94"
|
||||
parking_lot = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
chrono = { version = "0.4", default-features = false, features = ["clock", "std"] }
|
||||
|
@ -2,7 +2,7 @@
|
||||
name = "lru_cache"
|
||||
version = "0.1.0"
|
||||
authors = ["Sigma Prime <contact@sigmaprime.io>"]
|
||||
edition = "2021"
|
||||
edition = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
fnv = "1.0.7"
|
||||
fnv = { workspace = true }
|
||||
|
@ -2,13 +2,13 @@
|
||||
name = "malloc_utils"
|
||||
version = "0.1.0"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>"]
|
||||
edition = "2021"
|
||||
edition = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
lighthouse_metrics = { path = "../lighthouse_metrics" }
|
||||
lazy_static = "1.4.0"
|
||||
lighthouse_metrics = { workspace = true }
|
||||
lazy_static = { workspace = true }
|
||||
libc = "0.2.79"
|
||||
parking_lot = "0.12.0"
|
||||
parking_lot = { workspace = true }
|
||||
jemalloc-ctl = { version = "0.5.0", optional = true }
|
||||
|
||||
# Jemalloc's background_threads feature requires Linux (pthreads).
|
||||
|
@ -2,22 +2,22 @@
|
||||
name = "monitoring_api"
|
||||
version = "0.1.0"
|
||||
authors = ["pawan <pawandhananjay@gmail.com>"]
|
||||
edition = "2021"
|
||||
edition = { workspace = true }
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
reqwest = { version = "0.11.0", features = ["json","stream"] }
|
||||
task_executor = { path = "../task_executor" }
|
||||
tokio = "1.14.0"
|
||||
eth2 = {path = "../eth2"}
|
||||
serde_json = "1.0.58"
|
||||
serde = "1.0.116"
|
||||
reqwest = { workspace = true }
|
||||
task_executor = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
eth2 = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
serde_derive = "1.0.116"
|
||||
lighthouse_version = { path = "../lighthouse_version"}
|
||||
lighthouse_metrics = { path = "../lighthouse_metrics" }
|
||||
slog = "2.5.2"
|
||||
store = { path = "../../beacon_node/store" }
|
||||
lazy_static = "1.4.0"
|
||||
regex = "1.5.5"
|
||||
sensitive_url = { path = "../sensitive_url" }
|
||||
serde = { workspace = true }
|
||||
lighthouse_version = { workspace = true }
|
||||
lighthouse_metrics = { workspace = true }
|
||||
slog = { workspace = true }
|
||||
store = { workspace = true }
|
||||
lazy_static = { workspace = true }
|
||||
regex = { workspace = true }
|
||||
sensitive_url = { workspace = true }
|
||||
|
@ -1,9 +1,9 @@
|
||||
[package]
|
||||
name = "oneshot_broadcast"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
edition = { workspace = true }
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
parking_lot = "0.12.0"
|
||||
parking_lot = { workspace = true }
|
||||
|
@ -1,10 +1,10 @@
|
||||
[package]
|
||||
name = "pretty_reqwest_error"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
edition = { workspace = true }
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
reqwest = { version = "0.11.0", features = ["json","stream"] }
|
||||
sensitive_url = { path = "../sensitive_url" }
|
||||
reqwest = { workspace = true }
|
||||
sensitive_url = { workspace = true }
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user