Add beacon_chain_sim

This commit is contained in:
Paul Hauner
2019-11-19 13:29:29 +11:00
parent c5071afdbc
commit 90d63a46c7
6 changed files with 113 additions and 15 deletions

View File

@@ -37,6 +37,7 @@ members = [
"beacon_node/eth1",
"beacon_node/beacon_chain",
"beacon_node/websocket_server",
"tests/beacon_chain_sim",
"tests/ef_tests",
"tests/eth1_test_rig",
"tests/node_test_rig",

View File

@@ -6,6 +6,7 @@ pub mod builder;
pub mod error;
use beacon_chain::BeaconChain;
use eth2_libp2p::{Enr, Multiaddr};
use exit_future::Signal;
use network::Service as NetworkService;
use std::net::SocketAddr;
@@ -48,6 +49,16 @@ impl<T: BeaconChainTypes> Client<T> {
pub fn libp2p_listen_port(&self) -> Option<u16> {
self.libp2p_network.as_ref().map(|n| n.listen_port())
}
/// Returns the list of libp2p addresses the client is listening to.
pub fn libp2p_listen_addresses(&self) -> Option<Vec<Multiaddr>> {
self.libp2p_network.as_ref().map(|n| n.listen_multiaddrs())
}
/// Returns the local libp2p ENR of this node, for network discovery.
pub fn enr(&self) -> Option<Enr> {
self.libp2p_network.as_ref().map(|n| n.local_enr())
}
}
impl<T: BeaconChainTypes> Drop for Client<T> {

View File

@@ -193,7 +193,7 @@ impl<E: EthSpec> Environment<E> {
}
/// Returns a `Context` where the `service_name` is added to the logger output.
pub fn service_context(&mut self, service_name: &'static str) -> RuntimeContext<E> {
pub fn service_context(&mut self, service_name: String) -> RuntimeContext<E> {
RuntimeContext {
executor: self.runtime.executor(),
log: self.log.new(o!("service" => service_name)),

View File

@@ -0,0 +1,11 @@
[package]
name = "beacon_chain_sim"
version = "0.1.0"
authors = ["Paul Hauner <paul@paulhauner.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
node_test_rig = { path = "../node_test_rig" }
types = { path = "../../eth2/types" }

View File

@@ -0,0 +1,77 @@
use node_test_rig::{
environment::{EnvironmentBuilder, RuntimeContext},
testing_client_config, ClientConfig, LocalBeaconNode, ProductionClient,
};
use types::EthSpec;
pub type BeaconNode<E> = LocalBeaconNode<ProductionClient<E>>;
fn main() {
match simulation(4) {
Ok(()) => println!("Simulation exited successfully"),
Err(e) => println!("Simulation exited with error: {}", e),
}
}
fn simulation(num_nodes: usize) -> Result<(), String> {
if num_nodes < 1 {
return Err("Must have at least one node".into());
}
let mut env = EnvironmentBuilder::minimal()
.async_logger("debug")?
.multi_threaded_tokio_runtime()?
.build()?;
let base_config = testing_client_config();
let boot_node =
BeaconNode::production(env.service_context("boot_node".into()), base_config.clone());
let nodes = (1..num_nodes)
.map(|i| {
let context = env.service_context(format!("node_{}", i));
new_with_bootnode_via_enr(context, &boot_node, base_config.clone())
})
.collect::<Vec<_>>();
env.block_until_ctrl_c()?;
Ok(())
}
// TODO: this function does not result in nodes connecting to each other. Age to investigate?
fn new_with_bootnode_via_enr<E: EthSpec>(
context: RuntimeContext<E>,
boot_node: &BeaconNode<E>,
base_config: ClientConfig,
) -> BeaconNode<E> {
let mut config = base_config;
config.network.boot_nodes.push(
boot_node
.client
.enr()
.expect("bootnode must have a network"),
);
BeaconNode::production(context, config)
}
fn new_with_bootnode_via_multiaddr<E: EthSpec>(
context: RuntimeContext<E>,
boot_node: &BeaconNode<E>,
base_config: ClientConfig,
) -> BeaconNode<E> {
let mut config = base_config;
config.network.libp2p_nodes.push(
boot_node
.client
.libp2p_listen_addresses()
.expect("bootnode must have a network")
.first()
.expect("bootnode must have at least one listen addr")
.clone(),
);
BeaconNode::production(context, config)
}

View File

@@ -1,13 +1,12 @@
use beacon_node::{
beacon_chain::BeaconChainTypes, Client, ClientConfig, ClientGenesis, ProductionBeaconNode,
ProductionClient,
};
use beacon_node::{beacon_chain::BeaconChainTypes, Client, ClientGenesis, ProductionBeaconNode};
use environment::RuntimeContext;
use futures::Future;
use remote_beacon_node::RemoteBeaconNode;
use std::path::PathBuf;
use tempdir::TempDir;
use types::EthSpec;
pub use beacon_node::{ClientConfig, ProductionClient};
pub use environment;
/// Provides a beacon node that is running in the current process. Useful for testing purposes.
@@ -18,8 +17,13 @@ pub struct LocalBeaconNode<T> {
impl<E: EthSpec> LocalBeaconNode<ProductionClient<E>> {
/// Starts a new, production beacon node.
pub fn production(context: RuntimeContext<E>) -> Self {
let (client_config, datadir) = testing_client_config();
pub fn production(context: RuntimeContext<E>, mut client_config: ClientConfig) -> Self {
// Creates a temporary directory that will be deleted once this `TempDir` is dropped.
let datadir = TempDir::new("lighthouse_node_test_rig")
.expect("should create temp directory for client datadir");
client_config.data_dir = datadir.path().into();
client_config.network.network_dir = PathBuf::from(datadir.path()).join("network");
let client = ProductionBeaconNode::new(context, client_config)
.wait()
@@ -42,15 +46,9 @@ impl<T: BeaconChainTypes> LocalBeaconNode<Client<T>> {
}
}
fn testing_client_config() -> (ClientConfig, TempDir) {
// Creates a temporary directory that will be deleted once this `TempDir` is dropped.
let tempdir = TempDir::new("lighthouse_node_test_rig")
.expect("should create temp directory for client datadir");
pub fn testing_client_config() -> ClientConfig {
let mut client_config = ClientConfig::default();
client_config.data_dir = tempdir.path().into();
// Setting ports to `0` means that the OS will choose some available port.
client_config.network.libp2p_port = 0;
client_config.network.discovery_port = 0;
@@ -63,5 +61,5 @@ fn testing_client_config() -> (ClientConfig, TempDir) {
genesis_time: 13_371_337,
};
(client_config, tempdir)
client_config
}