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

This commit is contained in:
Michael Sproul
2022-03-28 09:24:09 +11:00
187 changed files with 5903 additions and 2368 deletions

View File

@@ -1,4 +1,4 @@
TESTS_TAG := v1.1.9
TESTS_TAG := v1.1.10
TESTS = general minimal mainnet
TARBALLS = $(patsubst %,%-$(TESTS_TAG).tar.gz,$(TESTS))

View File

@@ -18,7 +18,7 @@ pub fn log_file_access<P: AsRef<Path>>(file_accessed: P) {
let passed_test_list_path =
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(ACCESSED_FILE_LOG_FILENAME);
let mut file = fs::OpenOptions::new()
let mut file = fs::File::options()
.append(true)
.create(true)
.open(passed_test_list_path)

View File

@@ -36,14 +36,14 @@ impl GanacheInstance {
loop {
if start + Duration::from_millis(GANACHE_STARTUP_TIMEOUT_MILLIS) <= Instant::now() {
break Err(
"Timed out waiting for ganache to start. Is ganache-cli installed?".to_string(),
"Timed out waiting for ganache to start. Is ganache installed?".to_string(),
);
}
let mut line = String::new();
if let Err(e) = reader.read_line(&mut line) {
break Err(format!("Failed to read line from ganache process: {:?}", e));
} else if line.starts_with("Listening on") {
} else if line.starts_with("RPC Listening on") {
break Ok(());
} else {
continue;
@@ -69,13 +69,13 @@ impl GanacheInstance {
})
}
/// Start a new `ganache-cli` process, waiting until it indicates that it is ready to accept
/// Start a new `ganache` process, waiting until it indicates that it is ready to accept
/// RPC connections.
pub fn new(network_id: u64, chain_id: u64) -> Result<Self, String> {
let port = unused_tcp_port()?;
let binary = match cfg!(windows) {
true => "ganache-cli.cmd",
false => "ganache-cli",
true => "ganache.cmd",
false => "ganache",
};
let child = Command::new(binary)
.stdout(Stdio::piped())
@@ -85,15 +85,13 @@ impl GanacheInstance {
.arg("1000000000")
.arg("--accounts")
.arg("10")
.arg("--keepAliveTimeout")
.arg("0")
.arg("--port")
.arg(format!("{}", port))
.arg("--mnemonic")
.arg("\"vast thought differ pull jewel broom cook wrist tribe word before omit\"")
.arg("--networkId")
.arg(format!("{}", network_id))
.arg("--chainId")
.arg("--chain.chainId")
.arg(format!("{}", chain_id))
.spawn()
.map_err(|e| {
@@ -110,8 +108,8 @@ impl GanacheInstance {
pub fn fork(&self) -> Result<Self, String> {
let port = unused_tcp_port()?;
let binary = match cfg!(windows) {
true => "ganache-cli.cmd",
false => "ganache-cli",
true => "ganache.cmd",
false => "ganache",
};
let child = Command::new(binary)
.stdout(Stdio::piped())
@@ -119,9 +117,7 @@ impl GanacheInstance {
.arg(self.endpoint())
.arg("--port")
.arg(format!("{}", port))
.arg("--keepAliveTimeout")
.arg("0")
.arg("--chainId")
.arg("--chain.chainId")
.arg(format!("{}", self.chain_id))
.spawn()
.map_err(|e| {
@@ -178,8 +174,7 @@ impl GanacheInstance {
.await
.map(|_| ())
.map_err(|_| {
"utils should mine new block with evm_mine (only works with ganache-cli!)"
.to_string()
"utils should mine new block with evm_mine (only works with ganache!)".to_string()
})
}
}

View File

@@ -1,6 +1,6 @@
//! Provides utilities for deploying and manipulating the eth2 deposit contract on the eth1 chain.
//!
//! Presently used with [`ganache-cli`](https://github.com/trufflesuite/ganache-cli) to simulate
//! Presently used with [`ganache`](https://github.com/trufflesuite/ganache) to simulate
//! the deposit contract for testing beacon node eth1 integration.
//!
//! Not tested to work with actual clients (e.g., geth). It should work fine, however there may be
@@ -23,7 +23,7 @@ use web3::Web3;
pub const DEPLOYER_ACCOUNTS_INDEX: usize = 0;
pub const DEPOSIT_ACCOUNTS_INDEX: usize = 0;
/// Provides a dedicated ganache-cli instance with the deposit contract already deployed.
/// Provides a dedicated ganache instance with the deposit contract already deployed.
pub struct GanacheEth1Instance {
pub ganache: GanacheInstance,
pub deposit_contract: DepositContract,

View File

@@ -3,8 +3,6 @@ name = "execution_engine_integration"
version = "0.1.0"
edition = "2021"
build = "build.rs"
[dependencies]
tempfile = "3.1.0"
serde_json = "1.0.58"

View File

@@ -1,5 +1,5 @@
test:
cargo test --release --locked
cargo run --release --locked
clean:
rm -rf execution_clients

View File

@@ -1,62 +0,0 @@
use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;
const GETH_BRANCH: &str = "merge-kiln";
const GETH_REPO_URL: &str = "https://github.com/MariusVanDerWijden/go-ethereum";
fn main() {
let manifest_dir: PathBuf = env::var("CARGO_MANIFEST_DIR").unwrap().into();
let execution_clients_dir = manifest_dir.join("execution_clients");
if !execution_clients_dir.exists() {
fs::create_dir(&execution_clients_dir).unwrap();
}
build_geth(&execution_clients_dir);
}
fn build_geth(execution_clients_dir: &Path) {
let repo_dir = execution_clients_dir.join("go-ethereum");
if !repo_dir.exists() {
// Clone the repo
assert!(Command::new("git")
.arg("clone")
.arg(GETH_REPO_URL)
.current_dir(&execution_clients_dir)
.output()
.expect("failed to clone geth repo")
.status
.success());
}
// Checkout the correct branch
assert!(Command::new("git")
.arg("checkout")
.arg(GETH_BRANCH)
.current_dir(&repo_dir)
.output()
.expect("failed to checkout geth branch")
.status
.success());
// Update the branch
assert!(Command::new("git")
.arg("pull")
.current_dir(&repo_dir)
.output()
.expect("failed to update geth branch")
.status
.success());
// Build geth
assert!(Command::new("make")
.arg("geth")
.current_dir(&repo_dir)
.output()
.expect("failed to make geth")
.status
.success());
}

View File

@@ -0,0 +1,73 @@
use crate::SUPPRESS_LOGS;
use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::{Command, Output, Stdio};
pub fn prepare_dir() -> PathBuf {
let manifest_dir: PathBuf = env::var("CARGO_MANIFEST_DIR").unwrap().into();
let execution_clients_dir = manifest_dir.join("execution_clients");
if !execution_clients_dir.exists() {
fs::create_dir(&execution_clients_dir).unwrap();
}
execution_clients_dir
}
pub fn clone_repo(repo_dir: &Path, repo_url: &str) -> bool {
Command::new("git")
.arg("clone")
.arg(repo_url)
.arg("--recursive")
.current_dir(repo_dir)
.output()
.unwrap_or_else(|_| panic!("failed to clone repo at {}", repo_url))
.status
.success()
}
pub fn checkout_branch(repo_dir: &Path, branch_name: &str) -> bool {
Command::new("git")
.arg("checkout")
.arg(branch_name)
.current_dir(repo_dir)
.output()
.unwrap_or_else(|_| {
panic!(
"failed to checkout branch at {:?}/{}",
repo_dir, branch_name,
)
})
.status
.success()
}
pub fn update_branch(repo_dir: &Path, branch_name: &str) -> bool {
Command::new("git")
.arg("pull")
.current_dir(repo_dir)
.output()
.unwrap_or_else(|_| panic!("failed to update branch at {:?}/{}", repo_dir, branch_name))
.status
.success()
}
pub fn check_command_output(output: Output, failure_msg: &'static str) {
if !output.status.success() {
if !SUPPRESS_LOGS {
dbg!(String::from_utf8_lossy(&output.stdout));
dbg!(String::from_utf8_lossy(&output.stderr));
}
panic!("{}", failure_msg);
}
}
/// Builds the stdout/stderr handler for commands which might output to the terminal.
pub fn build_stdio() -> Stdio {
if SUPPRESS_LOGS {
Stdio::null()
} else {
Stdio::inherit()
}
}

View File

@@ -1,15 +1,19 @@
use crate::{genesis_json::geth_genesis_json, SUPPRESS_LOGS};
use execution_layer::DEFAULT_JWT_FILE;
use sensitive_url::SensitiveUrl;
use std::path::PathBuf;
use std::process::{Child, Command, Output, Stdio};
use std::{env, fs::File};
use std::process::Child;
use tempfile::TempDir;
use unused_port::unused_tcp_port;
/// Defined for each EE type (e.g., Geth, Nethermind, etc).
pub trait GenericExecutionEngine: Clone {
fn init_datadir() -> TempDir;
fn start_client(datadir: &TempDir, http_port: u16) -> Child;
fn start_client(
datadir: &TempDir,
http_port: u16,
http_auth_port: u16,
jwt_secret_path: PathBuf,
) -> Child;
}
/// Holds handle to a running EE process, plus some other metadata.
@@ -19,6 +23,7 @@ pub struct ExecutionEngine<E> {
#[allow(dead_code)]
datadir: TempDir,
http_port: u16,
http_auth_port: u16,
child: Child,
}
@@ -34,12 +39,15 @@ impl<E> Drop for ExecutionEngine<E> {
impl<E: GenericExecutionEngine> ExecutionEngine<E> {
pub fn new(engine: E) -> Self {
let datadir = E::init_datadir();
let jwt_secret_path = datadir.path().join(DEFAULT_JWT_FILE);
let http_port = unused_tcp_port().unwrap();
let child = E::start_client(&datadir, http_port);
let http_auth_port = unused_tcp_port().unwrap();
let child = E::start_client(&datadir, http_port, http_auth_port, jwt_secret_path);
Self {
engine,
datadir,
http_port,
http_auth_port,
child,
}
}
@@ -47,85 +55,12 @@ impl<E: GenericExecutionEngine> ExecutionEngine<E> {
pub fn http_url(&self) -> SensitiveUrl {
SensitiveUrl::parse(&format!("http://127.0.0.1:{}", self.http_port)).unwrap()
}
}
/*
* Geth-specific Implementation
*/
#[derive(Clone)]
pub struct Geth;
impl Geth {
fn binary_path() -> PathBuf {
let manifest_dir: PathBuf = env::var("CARGO_MANIFEST_DIR").unwrap().into();
manifest_dir
.join("execution_clients")
.join("go-ethereum")
.join("build")
.join("bin")
.join("geth")
}
}
impl GenericExecutionEngine for Geth {
fn init_datadir() -> TempDir {
let datadir = TempDir::new().unwrap();
let genesis_json_path = datadir.path().join("genesis.json");
let mut file = File::create(&genesis_json_path).unwrap();
let json = geth_genesis_json();
serde_json::to_writer(&mut file, &json).unwrap();
let output = Command::new(Self::binary_path())
.arg("--datadir")
.arg(datadir.path().to_str().unwrap())
.arg("init")
.arg(genesis_json_path.to_str().unwrap())
.output()
.expect("failed to init geth");
check_command_output(output, "geth init failed");
datadir
pub fn http_auth_url(&self) -> SensitiveUrl {
SensitiveUrl::parse(&format!("http://127.0.0.1:{}", self.http_auth_port)).unwrap()
}
fn start_client(datadir: &TempDir, http_port: u16) -> Child {
let network_port = unused_tcp_port().unwrap();
Command::new(Self::binary_path())
.arg("--datadir")
.arg(datadir.path().to_str().unwrap())
.arg("--http")
.arg("--http.api")
.arg("engine,eth")
.arg("--http.port")
.arg(http_port.to_string())
.arg("--port")
.arg(network_port.to_string())
.stdout(build_stdio())
.stderr(build_stdio())
.spawn()
.expect("failed to start beacon node")
}
}
fn check_command_output(output: Output, failure_msg: &'static str) {
if !output.status.success() {
let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr);
dbg!(stdout);
dbg!(stderr);
panic!("{}", failure_msg);
}
}
/// Builds the stdout/stderr handler for commands which might output to the terminal.
fn build_stdio() -> Stdio {
if SUPPRESS_LOGS {
Stdio::null()
} else {
Stdio::inherit()
pub fn datadir(&self) -> PathBuf {
self.datadir.path().to_path_buf()
}
}

View File

@@ -40,3 +40,77 @@ pub fn geth_genesis_json() -> Value {
"baseFeePerGas":"0x7"
})
}
/// Sourced from:
///
/// https://github.com/NethermindEth/nethermind/blob/themerge_kintsugi/src/Nethermind/Chains/themerge_kintsugi_m2.json
pub fn nethermind_genesis_json() -> Value {
json!({
"name": "TheMerge_Devnet",
"engine": {
"clique": {
"params": {
"period": 5,
"epoch": 30000
}
}
},
"params": {
"gasLimitBoundDivisor": "0x400",
"accountStartNonce": "0x0",
"maximumExtraDataSize": "0x20",
"minGasLimit": "0x1388",
"networkID": 1,
"eip150Transition": "0x0",
"eip155Transition": "0x0",
"eip158Transition": "0x0",
"eip160Transition": "0x0",
"eip161abcTransition": "0x0",
"eip161dTransition": "0x0",
"eip140Transition": "0x0",
"eip211Transition": "0x0",
"eip214Transition": "0x0",
"eip658Transition": "0x0",
"eip145Transition": "0x0",
"eip1014Transition": "0x0",
"eip1052Transition": "0x0",
"eip1283Transition": "0x0",
"eip1283DisableTransition": "0x0",
"eip152Transition": "0x0",
"eip1108Transition": "0x0",
"eip1344Transition": "0x0",
"eip1884Transition": "0x0",
"eip2028Transition": "0x0",
"eip2200Transition": "0x0",
"eip2565Transition": "0x0",
"eip2929Transition": "0x0",
"eip2930Transition": "0x0",
"eip1559Transition": "0x0",
"eip3198Transition": "0x0",
"eip3529Transition": "0x0",
"eip3541Transition": "0x0"
},
"genesis": {
"seal": {
"ethereum": {
"nonce": "0x42",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
}
},
"difficulty": "0x000000000",
"author": "0x0000000000000000000000000000000000000000",
"timestamp": "0x0",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData":"0x0000000000000000000000000000000000000000000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"gasLimit":"0x1C9C380",
"author": "0x0000000000000000000000000000000000000000",
"parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000",
"baseFeePerGas":"0x7"
},
"accounts": {
"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": {
"balance":"0x6d6172697573766477000000"
}
}
})
}

View File

@@ -0,0 +1,110 @@
use crate::build_utils;
use crate::execution_engine::GenericExecutionEngine;
use crate::genesis_json::geth_genesis_json;
use std::path::{Path, PathBuf};
use std::process::{Child, Command, Output};
use std::{env, fs::File};
use tempfile::TempDir;
use unused_port::unused_tcp_port;
const GETH_BRANCH: &str = "merge-kiln-v2";
const GETH_REPO_URL: &str = "https://github.com/MariusVanDerWijden/go-ethereum";
pub fn build_result(repo_dir: &Path) -> Output {
Command::new("make")
.arg("geth")
.current_dir(&repo_dir)
.output()
.expect("failed to make geth")
}
pub fn build(execution_clients_dir: &Path) {
let repo_dir = execution_clients_dir.join("go-ethereum");
if !repo_dir.exists() {
// Clone the repo
assert!(build_utils::clone_repo(
execution_clients_dir,
GETH_REPO_URL
));
}
// Checkout the correct branch
assert!(build_utils::checkout_branch(&repo_dir, GETH_BRANCH));
// Update the branch
assert!(build_utils::update_branch(&repo_dir, GETH_BRANCH));
// Build geth
build_utils::check_command_output(build_result(&repo_dir), "make failed");
}
/*
* Geth-specific Implementation for GenericExecutionEngine
*/
#[derive(Clone)]
pub struct GethEngine;
impl GethEngine {
fn binary_path() -> PathBuf {
let manifest_dir: PathBuf = env::var("CARGO_MANIFEST_DIR").unwrap().into();
manifest_dir
.join("execution_clients")
.join("go-ethereum")
.join("build")
.join("bin")
.join("geth")
}
}
impl GenericExecutionEngine for GethEngine {
fn init_datadir() -> TempDir {
let datadir = TempDir::new().unwrap();
let genesis_json_path = datadir.path().join("genesis.json");
let mut file = File::create(&genesis_json_path).unwrap();
let json = geth_genesis_json();
serde_json::to_writer(&mut file, &json).unwrap();
let output = Command::new(Self::binary_path())
.arg("--datadir")
.arg(datadir.path().to_str().unwrap())
.arg("init")
.arg(genesis_json_path.to_str().unwrap())
.output()
.expect("failed to init geth");
build_utils::check_command_output(output, "geth init failed");
datadir
}
fn start_client(
datadir: &TempDir,
http_port: u16,
http_auth_port: u16,
jwt_secret_path: PathBuf,
) -> Child {
let network_port = unused_tcp_port().unwrap();
Command::new(Self::binary_path())
.arg("--datadir")
.arg(datadir.path().to_str().unwrap())
.arg("--http")
.arg("--http.api")
.arg("engine,eth")
.arg("--http.port")
.arg(http_port.to_string())
.arg("--authrpc.port")
.arg(http_auth_port.to_string())
.arg("--port")
.arg(network_port.to_string())
.arg("--authrpc.jwtsecret")
.arg(jwt_secret_path.as_path().to_str().unwrap())
.stdout(build_utils::build_stdio())
.stderr(build_utils::build_stdio())
.spawn()
.expect("failed to start geth")
}
}

View File

@@ -1,12 +0,0 @@
/// This library provides integration testing between Lighthouse and other execution engines.
///
/// See the `tests/tests.rs` file to run tests.
mod execution_engine;
mod genesis_json;
mod test_rig;
pub use execution_engine::Geth;
pub use test_rig::TestRig;
/// Set to `false` to send logs to the console during tests. Logs are useful when debugging.
const SUPPRESS_LOGS: bool = true;

View File

@@ -0,0 +1,39 @@
/// This binary runs integration tests between Lighthouse and execution engines.
///
/// It will first attempt to build any supported integration clients, then it will run tests.
///
/// A return code of `0` indicates the tests succeeded.
mod build_utils;
mod execution_engine;
mod genesis_json;
mod geth;
mod nethermind;
mod test_rig;
use geth::GethEngine;
use nethermind::NethermindEngine;
use test_rig::TestRig;
/// Set to `false` to send logs to the console during tests. Logs are useful when debugging.
const SUPPRESS_LOGS: bool = true;
fn main() {
if cfg!(windows) {
panic!("windows is not supported, only linux");
}
test_geth();
test_nethermind();
}
fn test_geth() {
let test_dir = build_utils::prepare_dir();
geth::build(&test_dir);
TestRig::new(GethEngine).perform_tests_blocking();
}
fn test_nethermind() {
let test_dir = build_utils::prepare_dir();
nethermind::build(&test_dir);
TestRig::new(NethermindEngine).perform_tests_blocking();
}

View File

@@ -0,0 +1,117 @@
use crate::build_utils;
use crate::execution_engine::GenericExecutionEngine;
use crate::genesis_json::nethermind_genesis_json;
use std::path::{Path, PathBuf};
use std::process::{Child, Command, Output};
use std::{env, fs::File};
use tempfile::TempDir;
use unused_port::unused_tcp_port;
const NETHERMIND_BRANCH: &str = "kiln";
const NETHERMIND_REPO_URL: &str = "https://github.com/NethermindEth/nethermind";
fn build_result(repo_dir: &Path) -> Output {
Command::new("dotnet")
.arg("build")
.arg("src/Nethermind/Nethermind.sln")
.arg("-c")
.arg("Release")
.current_dir(repo_dir)
.output()
.expect("failed to make nethermind")
}
pub fn build(execution_clients_dir: &Path) {
let repo_dir = execution_clients_dir.join("nethermind");
if !repo_dir.exists() {
// Clone the repo
assert!(build_utils::clone_repo(
execution_clients_dir,
NETHERMIND_REPO_URL
));
}
// Checkout the correct branch
assert!(build_utils::checkout_branch(&repo_dir, NETHERMIND_BRANCH));
// Update the branch
assert!(build_utils::update_branch(&repo_dir, NETHERMIND_BRANCH));
// Build nethermind
build_utils::check_command_output(build_result(&repo_dir), "dotnet build failed");
// Build nethermind a second time to enable Merge-related features.
// Not sure why this is necessary.
build_utils::check_command_output(build_result(&repo_dir), "dotnet build failed");
}
/*
* Nethermind-specific Implementation for GenericExecutionEngine
*/
#[derive(Clone)]
pub struct NethermindEngine;
impl NethermindEngine {
fn binary_path() -> PathBuf {
let manifest_dir: PathBuf = env::var("CARGO_MANIFEST_DIR").unwrap().into();
manifest_dir
.join("execution_clients")
.join("nethermind")
.join("src")
.join("Nethermind")
.join("Nethermind.Runner")
.join("bin")
.join("Release")
.join("net6.0")
.join("Nethermind.Runner")
}
}
impl GenericExecutionEngine for NethermindEngine {
fn init_datadir() -> TempDir {
let datadir = TempDir::new().unwrap();
let genesis_json_path = datadir.path().join("genesis.json");
let mut file = File::create(&genesis_json_path).unwrap();
let json = nethermind_genesis_json();
serde_json::to_writer(&mut file, &json).unwrap();
datadir
}
fn start_client(
datadir: &TempDir,
http_port: u16,
http_auth_port: u16,
jwt_secret_path: PathBuf,
) -> Child {
let network_port = unused_tcp_port().unwrap();
let genesis_json_path = datadir.path().join("genesis.json");
Command::new(Self::binary_path())
.arg("--datadir")
.arg(datadir.path().to_str().unwrap())
.arg("--config")
.arg("themerge_kiln_testvectors")
.arg("--Init.ChainSpecPath")
.arg(genesis_json_path.to_str().unwrap())
.arg("--JsonRpc.AdditionalRpcUrls")
.arg(format!("http://localhost:{}|http;ws|net;eth;subscribe;engine;web3;client|no-auth,http://localhost:{}|http;ws|net;eth;subscribe;engine;web3;client", http_port, http_auth_port))
.arg("--JsonRpc.EnabledModules")
.arg("net,eth,subscribe,web3,admin,engine")
.arg("--JsonRpc.Port")
.arg(http_port.to_string())
.arg("--Network.DiscoveryPort")
.arg(network_port.to_string())
.arg("--Network.P2PPort")
.arg(network_port.to_string())
.arg("--JsonRpc.JwtSecretFile")
.arg(jwt_secret_path.as_path().to_str().unwrap())
.stdout(build_utils::build_stdio())
.stderr(build_utils::build_stdio())
.spawn()
.expect("failed to start nethermind")
}
}

View File

@@ -4,7 +4,9 @@ use std::sync::Arc;
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
use task_executor::TaskExecutor;
use tokio::time::sleep;
use types::{Address, ChainSpec, EthSpec, ExecutionBlockHash, Hash256, MainnetEthSpec, Uint256};
use types::{
Address, ChainSpec, EthSpec, ExecutionBlockHash, Hash256, MainnetEthSpec, Slot, Uint256,
};
const EXECUTION_ENGINE_START_TIMEOUT: Duration = Duration::from_secs(10);
@@ -46,10 +48,17 @@ impl<E: GenericExecutionEngine> TestRig<E> {
let ee_a = {
let execution_engine = ExecutionEngine::new(generic_engine.clone());
let urls = vec![execution_engine.http_url()];
let urls = vec![execution_engine.http_auth_url()];
let config = execution_layer::Config {
execution_endpoints: urls,
secret_files: vec![],
suggested_fee_recipient: Some(Address::repeat_byte(42)),
default_datadir: execution_engine.datadir(),
..Default::default()
};
let execution_layer =
ExecutionLayer::from_urls(urls, fee_recipient, executor.clone(), log.clone())
.unwrap();
ExecutionLayer::from_config(config, executor.clone(), log.clone()).unwrap();
ExecutionPair {
execution_engine,
execution_layer,
@@ -59,8 +68,16 @@ impl<E: GenericExecutionEngine> TestRig<E> {
let ee_b = {
let execution_engine = ExecutionEngine::new(generic_engine);
let urls = vec![execution_engine.http_url()];
let config = execution_layer::Config {
execution_endpoints: urls,
secret_files: vec![],
suggested_fee_recipient: fee_recipient,
default_datadir: execution_engine.datadir(),
..Default::default()
};
let execution_layer =
ExecutionLayer::from_urls(urls, fee_recipient, executor, log).unwrap();
ExecutionLayer::from_config(config, executor, log.clone()).unwrap();
ExecutionPair {
execution_engine,
execution_layer,
@@ -108,6 +125,16 @@ impl<E: GenericExecutionEngine> TestRig<E> {
pub async fn perform_tests(&self) {
self.wait_until_synced().await;
/*
* Check the transition config endpoint.
*/
for ee in [&self.ee_a, &self.ee_b] {
ee.execution_layer
.exchange_transition_configuration(&self.spec)
.await
.unwrap();
}
/*
* Read the terminal block hash from both pairs, check it's equal.
*/
@@ -138,7 +165,7 @@ impl<E: GenericExecutionEngine> TestRig<E> {
let parent_hash = terminal_pow_block_hash;
let timestamp = timestamp_now();
let random = Hash256::zero();
let prev_randao = Hash256::zero();
let finalized_block_hash = ExecutionBlockHash::zero();
let proposer_index = 0;
let valid_payload = self
@@ -147,7 +174,7 @@ impl<E: GenericExecutionEngine> TestRig<E> {
.get_payload::<MainnetEthSpec>(
parent_hash,
timestamp,
random,
prev_randao,
finalized_block_hash,
proposer_index,
)
@@ -162,11 +189,12 @@ impl<E: GenericExecutionEngine> TestRig<E> {
*/
let head_block_hash = valid_payload.block_hash;
let finalized_block_hash = ExecutionBlockHash::zero();
let payload_attributes = None;
let slot = Slot::new(42);
let head_block_root = Hash256::repeat_byte(42);
let status = self
.ee_a
.execution_layer
.notify_forkchoice_updated(head_block_hash, finalized_block_hash, payload_attributes)
.notify_forkchoice_updated(head_block_hash, finalized_block_hash, slot, head_block_root)
.await
.unwrap();
assert_eq!(status, PayloadStatus::Syncing);
@@ -194,11 +222,12 @@ impl<E: GenericExecutionEngine> TestRig<E> {
*/
let head_block_hash = valid_payload.block_hash;
let finalized_block_hash = ExecutionBlockHash::zero();
let payload_attributes = None;
let slot = Slot::new(42);
let head_block_root = Hash256::repeat_byte(42);
let status = self
.ee_a
.execution_layer
.notify_forkchoice_updated(head_block_hash, finalized_block_hash, payload_attributes)
.notify_forkchoice_updated(head_block_hash, finalized_block_hash, slot, head_block_root)
.await
.unwrap();
assert_eq!(status, PayloadStatus::Valid);
@@ -210,7 +239,7 @@ impl<E: GenericExecutionEngine> TestRig<E> {
*/
let mut invalid_payload = valid_payload.clone();
invalid_payload.random = Hash256::from_low_u64_be(42);
invalid_payload.prev_randao = Hash256::from_low_u64_be(42);
let status = self
.ee_a
.execution_layer
@@ -227,7 +256,7 @@ impl<E: GenericExecutionEngine> TestRig<E> {
let parent_hash = valid_payload.block_hash;
let timestamp = valid_payload.timestamp + 1;
let random = Hash256::zero();
let prev_randao = Hash256::zero();
let finalized_block_hash = ExecutionBlockHash::zero();
let proposer_index = 0;
let second_payload = self
@@ -236,7 +265,7 @@ impl<E: GenericExecutionEngine> TestRig<E> {
.get_payload::<MainnetEthSpec>(
parent_hash,
timestamp,
random,
prev_randao,
finalized_block_hash,
proposer_index,
)
@@ -264,15 +293,22 @@ impl<E: GenericExecutionEngine> TestRig<E> {
*/
let head_block_hash = valid_payload.block_hash;
let finalized_block_hash = ExecutionBlockHash::zero();
let payload_attributes = Some(PayloadAttributes {
let payload_attributes = PayloadAttributes {
timestamp: second_payload.timestamp + 1,
random: Hash256::zero(),
prev_randao: Hash256::zero(),
suggested_fee_recipient: Address::zero(),
});
};
let slot = Slot::new(42);
let head_block_root = Hash256::repeat_byte(100);
let validator_index = 0;
self.ee_a
.execution_layer
.insert_proposer(slot, head_block_root, validator_index, payload_attributes)
.await;
let status = self
.ee_a
.execution_layer
.notify_forkchoice_updated(head_block_hash, finalized_block_hash, payload_attributes)
.notify_forkchoice_updated(head_block_hash, finalized_block_hash, slot, head_block_root)
.await
.unwrap();
assert_eq!(status, PayloadStatus::Valid);
@@ -297,11 +333,12 @@ impl<E: GenericExecutionEngine> TestRig<E> {
*/
let head_block_hash = second_payload.block_hash;
let finalized_block_hash = ExecutionBlockHash::zero();
let payload_attributes = None;
let slot = Slot::new(42);
let head_block_root = Hash256::repeat_byte(42);
let status = self
.ee_b
.execution_layer
.notify_forkchoice_updated(head_block_hash, finalized_block_hash, payload_attributes)
.notify_forkchoice_updated(head_block_hash, finalized_block_hash, slot, head_block_root)
.await
.unwrap();
assert_eq!(status, PayloadStatus::Syncing);
@@ -340,11 +377,12 @@ impl<E: GenericExecutionEngine> TestRig<E> {
*/
let head_block_hash = second_payload.block_hash;
let finalized_block_hash = ExecutionBlockHash::zero();
let payload_attributes = None;
let slot = Slot::new(42);
let head_block_root = Hash256::repeat_byte(42);
let status = self
.ee_b
.execution_layer
.notify_forkchoice_updated(head_block_hash, finalized_block_hash, payload_attributes)
.notify_forkchoice_updated(head_block_hash, finalized_block_hash, slot, head_block_root)
.await
.unwrap();
assert_eq!(status, PayloadStatus::Valid);

View File

@@ -1,16 +0,0 @@
#[cfg(not(target_family = "windows"))]
mod not_windows {
use execution_engine_integration::{Geth, TestRig};
#[test]
fn geth() {
TestRig::new(Geth).perform_tests_blocking()
}
}
#[cfg(target_family = "windows")]
mod windows {
#[test]
fn all_tests_skipped_on_windows() {
//
}
}

View File

@@ -10,7 +10,7 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
.about(
"Lighthouse Beacon Chain Simulator creates `n` beacon node and validator clients, \
each with `v` validators. A deposit contract is deployed at the start of the \
simulation using a local `ganache-cli` instance (you must have `ganache-cli` \
simulation using a local `ganache` instance (you must have `ganache` \
installed and avaliable on your path). All beacon nodes independently listen \
for genesis from the deposit contract, then start operating. \
\

View File

@@ -55,6 +55,7 @@ impl<E: EthSpec> LocalNetwork<E> {
beacon_config.network.libp2p_port = BOOTNODE_PORT;
beacon_config.network.enr_udp_port = Some(BOOTNODE_PORT);
beacon_config.network.enr_tcp_port = Some(BOOTNODE_PORT);
beacon_config.network.discv5_config.table_filter = |_| true;
let beacon_node =
LocalBeaconNode::production(context.service_context("boot_node".into()), beacon_config)
.await?;
@@ -103,6 +104,7 @@ impl<E: EthSpec> LocalNetwork<E> {
beacon_config.network.libp2p_port = BOOTNODE_PORT + count;
beacon_config.network.enr_udp_port = Some(BOOTNODE_PORT + count);
beacon_config.network.enr_tcp_port = Some(BOOTNODE_PORT + count);
beacon_config.network.discv5_config.table_filter = |_| true;
}
let mut write_lock = self_1.beacon_nodes.write();

View File

@@ -2,7 +2,7 @@
//! This crate provides a simluation that creates `n` beacon node and validator clients, each with
//! `v` validators. A deposit contract is deployed at the start of the simulation using a local
//! `ganache-cli` instance (you must have `ganache-cli` installed and avaliable on your path). All
//! `ganache` instance (you must have `ganache` installed and avaliable on your path). All
//! beacon nodes independently listen for genesis from the deposit contract, then start operating.
//!
//! As the simulation runs, there are checks made to ensure that all components are running