mirror of
https://github.com/sigp/lighthouse.git
synced 2026-06-29 19:04:27 +00:00
Merge remote-tracking branch 'origin/unstable' into tree-states
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
name = "ef_tests"
|
||||
version = "0.2.0"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
[features]
|
||||
# `ef_tests` feature must be enabled to actually run the tests
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
TESTS_TAG := v1.1.8
|
||||
TESTS_TAG := v1.1.9
|
||||
TESTS = general minimal mainnet
|
||||
TARBALLS = $(patsubst %,%-$(TESTS_TAG).tar.gz,$(TESTS))
|
||||
|
||||
|
||||
@@ -260,10 +260,7 @@ impl<E: EthSpec, T: EpochTransition<E>> LoadCase for EpochProcessing<E, T> {
|
||||
|
||||
impl<E: EthSpec, T: EpochTransition<E>> Case for EpochProcessing<E, T> {
|
||||
fn description(&self) -> String {
|
||||
self.metadata
|
||||
.description
|
||||
.clone()
|
||||
.unwrap_or_else(String::new)
|
||||
self.metadata.description.clone().unwrap_or_default()
|
||||
}
|
||||
|
||||
fn is_enabled_for_fork(fork_name: ForkName) -> bool {
|
||||
|
||||
@@ -14,15 +14,15 @@ use ssz_derive::Decode;
|
||||
use state_processing::state_advance::complete_state_advance;
|
||||
use std::time::Duration;
|
||||
use types::{
|
||||
Attestation, BeaconBlock, BeaconState, Checkpoint, Epoch, EthSpec, ForkName, Hash256,
|
||||
IndexedAttestation, SignedBeaconBlock, Slot, Uint256,
|
||||
Attestation, BeaconBlock, BeaconState, Checkpoint, Epoch, EthSpec, ExecutionBlockHash,
|
||||
ForkName, Hash256, IndexedAttestation, SignedBeaconBlock, Slot, Uint256,
|
||||
};
|
||||
|
||||
#[derive(Default, Debug, PartialEq, Clone, Deserialize, Decode)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct PowBlock {
|
||||
pub block_hash: Hash256,
|
||||
pub parent_hash: Hash256,
|
||||
pub block_hash: ExecutionBlockHash,
|
||||
pub parent_hash: ExecutionBlockHash,
|
||||
pub total_difficulty: Uint256,
|
||||
}
|
||||
|
||||
|
||||
@@ -308,10 +308,7 @@ impl<E: EthSpec, O: Operation<E>> LoadCase for Operations<E, O> {
|
||||
|
||||
impl<E: EthSpec, O: Operation<E>> Case for Operations<E, O> {
|
||||
fn description(&self) -> String {
|
||||
self.metadata
|
||||
.description
|
||||
.clone()
|
||||
.unwrap_or_else(String::new)
|
||||
self.metadata.description.clone().unwrap_or_default()
|
||||
}
|
||||
|
||||
fn is_enabled_for_fork(fork_name: ForkName) -> bool {
|
||||
|
||||
@@ -103,10 +103,7 @@ impl<E: EthSpec> LoadCase for RewardsTest<E> {
|
||||
|
||||
impl<E: EthSpec> Case for RewardsTest<E> {
|
||||
fn description(&self) -> String {
|
||||
self.metadata
|
||||
.description
|
||||
.clone()
|
||||
.unwrap_or_else(String::new)
|
||||
self.metadata.description.clone().unwrap_or_default()
|
||||
}
|
||||
|
||||
fn result(&self, _case_index: usize, fork_name: ForkName) -> Result<(), Error> {
|
||||
|
||||
@@ -56,10 +56,7 @@ impl<E: EthSpec> LoadCase for SanityBlocks<E> {
|
||||
|
||||
impl<E: EthSpec> Case for SanityBlocks<E> {
|
||||
fn description(&self) -> String {
|
||||
self.metadata
|
||||
.description
|
||||
.clone()
|
||||
.unwrap_or_else(String::new)
|
||||
self.metadata.description.clone().unwrap_or_default()
|
||||
}
|
||||
|
||||
fn result(&self, _case_index: usize, fork_name: ForkName) -> Result<(), Error> {
|
||||
|
||||
@@ -50,10 +50,7 @@ impl<E: EthSpec> LoadCase for SanitySlots<E> {
|
||||
|
||||
impl<E: EthSpec> Case for SanitySlots<E> {
|
||||
fn description(&self) -> String {
|
||||
self.metadata
|
||||
.description
|
||||
.clone()
|
||||
.unwrap_or_else(String::new)
|
||||
self.metadata.description.clone().unwrap_or_default()
|
||||
}
|
||||
|
||||
fn result(&self, _case_index: usize, fork_name: ForkName) -> Result<(), Error> {
|
||||
|
||||
@@ -307,11 +307,6 @@ pub struct RandomHandler<E>(PhantomData<E>);
|
||||
impl<E: EthSpec + TypeName> Handler for RandomHandler<E> {
|
||||
type Case = cases::SanityBlocks<E>;
|
||||
|
||||
// FIXME(merge): enable merge tests once available
|
||||
fn is_enabled_for_fork(&self, fork_name: ForkName) -> bool {
|
||||
fork_name != ForkName::Merge
|
||||
}
|
||||
|
||||
fn config_name() -> &'static str {
|
||||
E::name()
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name = "eth1_test_rig"
|
||||
version = "0.2.0"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
tokio = { version = "1.14.0", features = ["time"] }
|
||||
@@ -10,3 +10,4 @@ web3 = { version = "0.17.0", default-features = false, features = ["http-tls", "
|
||||
types = { path = "../../consensus/types"}
|
||||
serde_json = "1.0.58"
|
||||
deposit_contract = { path = "../../common/deposit_contract"}
|
||||
unused_port = { path = "../../common/unused_port" }
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use serde_json::json;
|
||||
use std::io::prelude::*;
|
||||
use std::io::BufReader;
|
||||
use std::net::TcpListener;
|
||||
use std::process::{Child, Command, Stdio};
|
||||
use std::time::{Duration, Instant};
|
||||
use unused_port::unused_tcp_port;
|
||||
use web3::{transports::Http, Transport, Web3};
|
||||
|
||||
/// How long we will wait for ganache to indicate that it is ready.
|
||||
@@ -72,7 +72,7 @@ impl GanacheInstance {
|
||||
/// Start a new `ganache-cli` 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_port()?;
|
||||
let port = unused_tcp_port()?;
|
||||
let binary = match cfg!(windows) {
|
||||
true => "ganache-cli.cmd",
|
||||
false => "ganache-cli",
|
||||
@@ -108,7 +108,7 @@ impl GanacheInstance {
|
||||
}
|
||||
|
||||
pub fn fork(&self) -> Result<Self, String> {
|
||||
let port = unused_port()?;
|
||||
let port = unused_tcp_port()?;
|
||||
let binary = match cfg!(windows) {
|
||||
true => "ganache-cli.cmd",
|
||||
false => "ganache-cli",
|
||||
@@ -188,24 +188,6 @@ fn endpoint(port: u16) -> String {
|
||||
format!("http://localhost:{}", port)
|
||||
}
|
||||
|
||||
/// A bit of hack to find an unused TCP port.
|
||||
///
|
||||
/// Does not guarantee that the given port is unused after the function exists, just that it was
|
||||
/// unused before the function started (i.e., it does not reserve a port).
|
||||
pub fn unused_port() -> Result<u16, String> {
|
||||
let listener = TcpListener::bind("127.0.0.1:0")
|
||||
.map_err(|e| format!("Failed to create TCP listener to find unused port: {:?}", e))?;
|
||||
|
||||
let local_addr = listener.local_addr().map_err(|e| {
|
||||
format!(
|
||||
"Failed to read TCP listener local_addr to find unused port: {:?}",
|
||||
e
|
||||
)
|
||||
})?;
|
||||
|
||||
Ok(local_addr.port())
|
||||
}
|
||||
|
||||
impl Drop for GanacheInstance {
|
||||
fn drop(&mut self) {
|
||||
if cfg!(windows) {
|
||||
|
||||
1
testing/execution_engine_integration/.gitignore
vendored
Normal file
1
testing/execution_engine_integration/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
execution_clients/
|
||||
19
testing/execution_engine_integration/Cargo.toml
Normal file
19
testing/execution_engine_integration/Cargo.toml
Normal file
@@ -0,0 +1,19 @@
|
||||
[package]
|
||||
name = "execution_engine_integration"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
build = "build.rs"
|
||||
|
||||
[dependencies]
|
||||
tempfile = "3.1.0"
|
||||
serde_json = "1.0.58"
|
||||
task_executor = { path = "../../common/task_executor" }
|
||||
tokio = { version = "1.14.0", features = ["rt-multi-thread", "macros"] }
|
||||
futures = "0.3.7"
|
||||
exit-future = "0.2.0"
|
||||
environment = { path = "../../lighthouse/environment" }
|
||||
execution_layer = { path = "../../beacon_node/execution_layer" }
|
||||
sensitive_url = { path = "../../common/sensitive_url" }
|
||||
types = { path = "../../consensus/types" }
|
||||
unused_port = { path = "../../common/unused_port" }
|
||||
5
testing/execution_engine_integration/Makefile
Normal file
5
testing/execution_engine_integration/Makefile
Normal file
@@ -0,0 +1,5 @@
|
||||
test:
|
||||
cargo test --release --locked
|
||||
|
||||
clean:
|
||||
rm -rf execution_clients
|
||||
62
testing/execution_engine_integration/build.rs
Normal file
62
testing/execution_engine_integration/build.rs
Normal file
@@ -0,0 +1,62 @@
|
||||
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());
|
||||
}
|
||||
131
testing/execution_engine_integration/src/execution_engine.rs
Normal file
131
testing/execution_engine_integration/src/execution_engine.rs
Normal file
@@ -0,0 +1,131 @@
|
||||
use crate::{genesis_json::geth_genesis_json, SUPPRESS_LOGS};
|
||||
use sensitive_url::SensitiveUrl;
|
||||
use std::path::PathBuf;
|
||||
use std::process::{Child, Command, Output, Stdio};
|
||||
use std::{env, fs::File};
|
||||
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;
|
||||
}
|
||||
|
||||
/// Holds handle to a running EE process, plus some other metadata.
|
||||
pub struct ExecutionEngine<E> {
|
||||
#[allow(dead_code)]
|
||||
engine: E,
|
||||
#[allow(dead_code)]
|
||||
datadir: TempDir,
|
||||
http_port: u16,
|
||||
child: Child,
|
||||
}
|
||||
|
||||
impl<E> Drop for ExecutionEngine<E> {
|
||||
fn drop(&mut self) {
|
||||
// Ensure the EE process is killed on drop.
|
||||
if let Err(e) = self.child.kill() {
|
||||
eprintln!("failed to kill child: {:?}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: GenericExecutionEngine> ExecutionEngine<E> {
|
||||
pub fn new(engine: E) -> Self {
|
||||
let datadir = E::init_datadir();
|
||||
let http_port = unused_tcp_port().unwrap();
|
||||
let child = E::start_client(&datadir, http_port);
|
||||
Self {
|
||||
engine,
|
||||
datadir,
|
||||
http_port,
|
||||
child,
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
42
testing/execution_engine_integration/src/genesis_json.rs
Normal file
42
testing/execution_engine_integration/src/genesis_json.rs
Normal file
@@ -0,0 +1,42 @@
|
||||
use serde_json::{json, Value};
|
||||
|
||||
/// Sourced from:
|
||||
///
|
||||
/// https://notes.ethereum.org/rmVErCfCRPKGqGkUe89-Kg
|
||||
pub fn geth_genesis_json() -> Value {
|
||||
json!({
|
||||
"config": {
|
||||
"chainId":1,
|
||||
"homesteadBlock":0,
|
||||
"eip150Block":0,
|
||||
"eip155Block":0,
|
||||
"eip158Block":0,
|
||||
"byzantiumBlock":0,
|
||||
"constantinopleBlock":0,
|
||||
"petersburgBlock":0,
|
||||
"istanbulBlock":0,
|
||||
"muirGlacierBlock":0,
|
||||
"berlinBlock":0,
|
||||
"londonBlock":0,
|
||||
"clique": {
|
||||
"period": 5,
|
||||
"epoch": 30000
|
||||
},
|
||||
"terminalTotalDifficulty":0
|
||||
},
|
||||
"nonce":"0x42",
|
||||
"timestamp":"0x0",
|
||||
"extraData":"0x0000000000000000000000000000000000000000000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
"gasLimit":"0x1C9C380",
|
||||
"difficulty":"0x400000000",
|
||||
"mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"coinbase":"0x0000000000000000000000000000000000000000",
|
||||
"alloc":{
|
||||
"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b":{"balance":"0x6d6172697573766477000000"}
|
||||
},
|
||||
"number":"0x0",
|
||||
"gasUsed":"0x0",
|
||||
"parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"baseFeePerGas":"0x7"
|
||||
})
|
||||
}
|
||||
12
testing/execution_engine_integration/src/lib.rs
Normal file
12
testing/execution_engine_integration/src/lib.rs
Normal file
@@ -0,0 +1,12 @@
|
||||
/// 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;
|
||||
360
testing/execution_engine_integration/src/test_rig.rs
Normal file
360
testing/execution_engine_integration/src/test_rig.rs
Normal file
@@ -0,0 +1,360 @@
|
||||
use crate::execution_engine::{ExecutionEngine, GenericExecutionEngine};
|
||||
use execution_layer::{ExecutionLayer, PayloadAttributes, PayloadStatus};
|
||||
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};
|
||||
|
||||
const EXECUTION_ENGINE_START_TIMEOUT: Duration = Duration::from_secs(10);
|
||||
|
||||
struct ExecutionPair<E> {
|
||||
/// The Lighthouse `ExecutionLayer` struct, connected to the `execution_engine` via HTTP.
|
||||
execution_layer: ExecutionLayer,
|
||||
/// A handle to external EE process, once this is dropped the process will be killed.
|
||||
#[allow(dead_code)]
|
||||
execution_engine: ExecutionEngine<E>,
|
||||
}
|
||||
|
||||
/// A rig that holds two EE processes for testing.
|
||||
///
|
||||
/// There are two EEs held here so that we can test out-of-order application of payloads, and other
|
||||
/// edge-cases.
|
||||
pub struct TestRig<E> {
|
||||
#[allow(dead_code)]
|
||||
runtime: Arc<tokio::runtime::Runtime>,
|
||||
ee_a: ExecutionPair<E>,
|
||||
ee_b: ExecutionPair<E>,
|
||||
spec: ChainSpec,
|
||||
_runtime_shutdown: exit_future::Signal,
|
||||
}
|
||||
|
||||
impl<E: GenericExecutionEngine> TestRig<E> {
|
||||
pub fn new(generic_engine: E) -> Self {
|
||||
let log = environment::null_logger().unwrap();
|
||||
let runtime = Arc::new(
|
||||
tokio::runtime::Builder::new_multi_thread()
|
||||
.enable_all()
|
||||
.build()
|
||||
.unwrap(),
|
||||
);
|
||||
let (runtime_shutdown, exit) = exit_future::signal();
|
||||
let (shutdown_tx, _) = futures::channel::mpsc::channel(1);
|
||||
let executor = TaskExecutor::new(Arc::downgrade(&runtime), exit, log.clone(), shutdown_tx);
|
||||
|
||||
let fee_recipient = None;
|
||||
|
||||
let ee_a = {
|
||||
let execution_engine = ExecutionEngine::new(generic_engine.clone());
|
||||
let urls = vec![execution_engine.http_url()];
|
||||
let execution_layer =
|
||||
ExecutionLayer::from_urls(urls, fee_recipient, executor.clone(), log.clone())
|
||||
.unwrap();
|
||||
ExecutionPair {
|
||||
execution_engine,
|
||||
execution_layer,
|
||||
}
|
||||
};
|
||||
|
||||
let ee_b = {
|
||||
let execution_engine = ExecutionEngine::new(generic_engine);
|
||||
let urls = vec![execution_engine.http_url()];
|
||||
let execution_layer =
|
||||
ExecutionLayer::from_urls(urls, fee_recipient, executor, log).unwrap();
|
||||
ExecutionPair {
|
||||
execution_engine,
|
||||
execution_layer,
|
||||
}
|
||||
};
|
||||
|
||||
let mut spec = MainnetEthSpec::default_spec();
|
||||
spec.terminal_total_difficulty = Uint256::zero();
|
||||
|
||||
Self {
|
||||
runtime,
|
||||
ee_a,
|
||||
ee_b,
|
||||
spec,
|
||||
_runtime_shutdown: runtime_shutdown,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn perform_tests_blocking(&self) {
|
||||
self.ee_a
|
||||
.execution_layer
|
||||
.block_on_generic(|_| async { self.perform_tests().await })
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub async fn wait_until_synced(&self) {
|
||||
let start_instant = Instant::now();
|
||||
|
||||
for pair in [&self.ee_a, &self.ee_b] {
|
||||
loop {
|
||||
// Run the routine to check for online nodes.
|
||||
pair.execution_layer.watchdog_task().await;
|
||||
|
||||
if pair.execution_layer.is_synced().await {
|
||||
break;
|
||||
} else if start_instant + EXECUTION_ENGINE_START_TIMEOUT > Instant::now() {
|
||||
sleep(Duration::from_millis(500)).await;
|
||||
} else {
|
||||
panic!("timeout waiting for execution engines to come online")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn perform_tests(&self) {
|
||||
self.wait_until_synced().await;
|
||||
|
||||
/*
|
||||
* Read the terminal block hash from both pairs, check it's equal.
|
||||
*/
|
||||
|
||||
let terminal_pow_block_hash = self
|
||||
.ee_a
|
||||
.execution_layer
|
||||
.get_terminal_pow_block_hash(&self.spec)
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
terminal_pow_block_hash,
|
||||
self.ee_b
|
||||
.execution_layer
|
||||
.get_terminal_pow_block_hash(&self.spec)
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
|
||||
/*
|
||||
* Execution Engine A:
|
||||
*
|
||||
* Produce a valid payload atop the terminal block.
|
||||
*/
|
||||
|
||||
let parent_hash = terminal_pow_block_hash;
|
||||
let timestamp = timestamp_now();
|
||||
let random = Hash256::zero();
|
||||
let finalized_block_hash = ExecutionBlockHash::zero();
|
||||
let proposer_index = 0;
|
||||
let valid_payload = self
|
||||
.ee_a
|
||||
.execution_layer
|
||||
.get_payload::<MainnetEthSpec>(
|
||||
parent_hash,
|
||||
timestamp,
|
||||
random,
|
||||
finalized_block_hash,
|
||||
proposer_index,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
/*
|
||||
* Execution Engine A:
|
||||
*
|
||||
* Indicate that the payload is the head of the chain, before submitting a
|
||||
* `notify_new_payload`.
|
||||
*/
|
||||
let head_block_hash = valid_payload.block_hash;
|
||||
let finalized_block_hash = ExecutionBlockHash::zero();
|
||||
let payload_attributes = None;
|
||||
let status = self
|
||||
.ee_a
|
||||
.execution_layer
|
||||
.notify_forkchoice_updated(head_block_hash, finalized_block_hash, payload_attributes)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(status, PayloadStatus::Syncing);
|
||||
|
||||
/*
|
||||
* Execution Engine A:
|
||||
*
|
||||
* Provide the valid payload back to the EE again.
|
||||
*/
|
||||
|
||||
let status = self
|
||||
.ee_a
|
||||
.execution_layer
|
||||
.notify_new_payload(&valid_payload)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(status, PayloadStatus::Valid);
|
||||
|
||||
/*
|
||||
* Execution Engine A:
|
||||
*
|
||||
* Indicate that the payload is the head of the chain.
|
||||
*
|
||||
* Do not provide payload attributes (we'll test that later).
|
||||
*/
|
||||
let head_block_hash = valid_payload.block_hash;
|
||||
let finalized_block_hash = ExecutionBlockHash::zero();
|
||||
let payload_attributes = None;
|
||||
let status = self
|
||||
.ee_a
|
||||
.execution_layer
|
||||
.notify_forkchoice_updated(head_block_hash, finalized_block_hash, payload_attributes)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(status, PayloadStatus::Valid);
|
||||
|
||||
/*
|
||||
* Execution Engine A:
|
||||
*
|
||||
* Provide an invalidated payload to the EE.
|
||||
*/
|
||||
|
||||
let mut invalid_payload = valid_payload.clone();
|
||||
invalid_payload.random = Hash256::from_low_u64_be(42);
|
||||
let status = self
|
||||
.ee_a
|
||||
.execution_layer
|
||||
.notify_new_payload(&invalid_payload)
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(matches!(status, PayloadStatus::InvalidBlockHash { .. }));
|
||||
|
||||
/*
|
||||
* Execution Engine A:
|
||||
*
|
||||
* Produce another payload atop the previous one.
|
||||
*/
|
||||
|
||||
let parent_hash = valid_payload.block_hash;
|
||||
let timestamp = valid_payload.timestamp + 1;
|
||||
let random = Hash256::zero();
|
||||
let finalized_block_hash = ExecutionBlockHash::zero();
|
||||
let proposer_index = 0;
|
||||
let second_payload = self
|
||||
.ee_a
|
||||
.execution_layer
|
||||
.get_payload::<MainnetEthSpec>(
|
||||
parent_hash,
|
||||
timestamp,
|
||||
random,
|
||||
finalized_block_hash,
|
||||
proposer_index,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
/*
|
||||
* Execution Engine A:
|
||||
*
|
||||
* Provide the second payload back to the EE again.
|
||||
*/
|
||||
|
||||
let status = self
|
||||
.ee_a
|
||||
.execution_layer
|
||||
.notify_new_payload(&second_payload)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(status, PayloadStatus::Valid);
|
||||
|
||||
/*
|
||||
* Execution Engine A:
|
||||
*
|
||||
* Indicate that the payload is the head of the chain, providing payload attributes.
|
||||
*/
|
||||
let head_block_hash = valid_payload.block_hash;
|
||||
let finalized_block_hash = ExecutionBlockHash::zero();
|
||||
let payload_attributes = Some(PayloadAttributes {
|
||||
timestamp: second_payload.timestamp + 1,
|
||||
random: Hash256::zero(),
|
||||
suggested_fee_recipient: Address::zero(),
|
||||
});
|
||||
let status = self
|
||||
.ee_a
|
||||
.execution_layer
|
||||
.notify_forkchoice_updated(head_block_hash, finalized_block_hash, payload_attributes)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(status, PayloadStatus::Valid);
|
||||
|
||||
/*
|
||||
* Execution Engine B:
|
||||
*
|
||||
* Provide the second payload, without providing the first.
|
||||
*/
|
||||
let status = self
|
||||
.ee_b
|
||||
.execution_layer
|
||||
.notify_new_payload(&second_payload)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(status, PayloadStatus::Accepted);
|
||||
|
||||
/*
|
||||
* Execution Engine B:
|
||||
*
|
||||
* Set the second payload as the head, without providing payload attributes.
|
||||
*/
|
||||
let head_block_hash = second_payload.block_hash;
|
||||
let finalized_block_hash = ExecutionBlockHash::zero();
|
||||
let payload_attributes = None;
|
||||
let status = self
|
||||
.ee_b
|
||||
.execution_layer
|
||||
.notify_forkchoice_updated(head_block_hash, finalized_block_hash, payload_attributes)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(status, PayloadStatus::Syncing);
|
||||
|
||||
/*
|
||||
* Execution Engine B:
|
||||
*
|
||||
* Provide the first payload to the EE.
|
||||
*/
|
||||
|
||||
let status = self
|
||||
.ee_b
|
||||
.execution_layer
|
||||
.notify_new_payload(&valid_payload)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(status, PayloadStatus::Valid);
|
||||
|
||||
/*
|
||||
* Execution Engine B:
|
||||
*
|
||||
* Provide the second payload, now the first has been provided.
|
||||
*/
|
||||
let status = self
|
||||
.ee_b
|
||||
.execution_layer
|
||||
.notify_new_payload(&second_payload)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(status, PayloadStatus::Valid);
|
||||
|
||||
/*
|
||||
* Execution Engine B:
|
||||
*
|
||||
* Set the second payload as the head, without providing payload attributes.
|
||||
*/
|
||||
let head_block_hash = second_payload.block_hash;
|
||||
let finalized_block_hash = ExecutionBlockHash::zero();
|
||||
let payload_attributes = None;
|
||||
let status = self
|
||||
.ee_b
|
||||
.execution_layer
|
||||
.notify_forkchoice_updated(head_block_hash, finalized_block_hash, payload_attributes)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(status, PayloadStatus::Valid);
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the duration since the unix epoch.
|
||||
pub fn timestamp_now() -> u64 {
|
||||
SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.unwrap_or_else(|_| Duration::from_secs(0))
|
||||
.as_secs()
|
||||
}
|
||||
16
testing/execution_engine_integration/tests/tests.rs
Normal file
16
testing/execution_engine_integration/tests/tests.rs
Normal file
@@ -0,0 +1,16 @@
|
||||
#[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() {
|
||||
//
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
name = "node_test_rig"
|
||||
version = "0.2.0"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
environment = { path = "../../lighthouse/environment" }
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name = "simulator"
|
||||
version = "0.2.0"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name = "state_transition_vectors"
|
||||
version = "0.1.0"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "test-test_logger"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "web3signer_tests"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
build = "build.rs"
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ mod tests {
|
||||
/// assume it failed to start.
|
||||
const UPCHECK_TIMEOUT: Duration = Duration::from_secs(20);
|
||||
|
||||
/// Set to `true` to send the Web3Signer logs to the console during tests. Logs are useful when
|
||||
/// Set to `false` to send the Web3Signer logs to the console during tests. Logs are useful when
|
||||
/// debugging.
|
||||
const SUPPRESS_WEB3SIGNER_LOGS: bool = true;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user