Fix local testnet scripts (#2229)
## Issue Addressed Resolves #2094 ## Proposed Changes Fixes scripts for creating local testnets. Adds an option in `lighthouse boot_node` to run with a previously generated enr.
This commit is contained in:
parent
9eb1945136
commit
95a362213d
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -3345,6 +3345,7 @@ dependencies = [
|
|||||||
"directory",
|
"directory",
|
||||||
"dirs 3.0.1",
|
"dirs 3.0.1",
|
||||||
"environment",
|
"environment",
|
||||||
|
"eth1_test_rig",
|
||||||
"eth2_keystore",
|
"eth2_keystore",
|
||||||
"eth2_libp2p",
|
"eth2_libp2p",
|
||||||
"eth2_network_config",
|
"eth2_network_config",
|
||||||
@ -3365,6 +3366,7 @@ dependencies = [
|
|||||||
"tree_hash",
|
"tree_hash",
|
||||||
"types",
|
"types",
|
||||||
"validator_dir",
|
"validator_dir",
|
||||||
|
"web3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -174,6 +174,21 @@ fn compare_enr(local_enr: &Enr, disk_enr: &Enr) -> bool {
|
|||||||
&& local_enr.get(BITFIELD_ENR_KEY) == disk_enr.get(BITFIELD_ENR_KEY)
|
&& local_enr.get(BITFIELD_ENR_KEY) == disk_enr.get(BITFIELD_ENR_KEY)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Loads enr from the given directory
|
||||||
|
pub fn load_enr_from_disk(dir: &Path) -> Result<Enr, String> {
|
||||||
|
let enr_f = dir.join(ENR_FILENAME);
|
||||||
|
let mut enr_file =
|
||||||
|
File::open(enr_f).map_err(|e| format!("Failed to open enr file: {:?}", e))?;
|
||||||
|
let mut enr_string = String::new();
|
||||||
|
match enr_file.read_to_string(&mut enr_string) {
|
||||||
|
Err(_) => Err("Could not read ENR from file".to_string()),
|
||||||
|
Ok(_) => match Enr::from_str(&enr_string) {
|
||||||
|
Ok(disk_enr) => Ok(disk_enr),
|
||||||
|
Err(e) => Err(format!("ENR from file could not be decoded: {:?}", e)),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Saves an ENR to disk
|
/// Saves an ENR to disk
|
||||||
pub fn save_enr_to_disk(dir: &Path, enr: &Enr, log: &slog::Logger) {
|
pub fn save_enr_to_disk(dir: &Path, enr: &Enr, log: &slog::Logger) {
|
||||||
let _ = std::fs::create_dir_all(dir);
|
let _ = std::fs::create_dir_all(dir);
|
||||||
|
@ -3,7 +3,10 @@ pub(crate) mod enr;
|
|||||||
pub mod enr_ext;
|
pub mod enr_ext;
|
||||||
|
|
||||||
// Allow external use of the lighthouse ENR builder
|
// Allow external use of the lighthouse ENR builder
|
||||||
pub use enr::{build_enr, create_enr_builder_from_config, use_or_load_enr, CombinedKey, Eth2Enr};
|
pub use enr::{
|
||||||
|
build_enr, create_enr_builder_from_config, load_enr_from_disk, use_or_load_enr, CombinedKey,
|
||||||
|
Eth2Enr,
|
||||||
|
};
|
||||||
pub use enr_ext::{peer_id_to_node_id, CombinedKeyExt, EnrExt};
|
pub use enr_ext::{peer_id_to_node_id, CombinedKeyExt, EnrExt};
|
||||||
pub use libp2p::core::identity::{Keypair, PublicKey};
|
pub use libp2p::core::identity::{Keypair, PublicKey};
|
||||||
|
|
||||||
|
@ -18,14 +18,16 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
|
|||||||
If a DNS address is provided, the enr-address is set to the IP address it resolves to and \
|
If a DNS address is provided, the enr-address is set to the IP address it resolves to and \
|
||||||
does not auto-update based on PONG responses in discovery.")
|
does not auto-update based on PONG responses in discovery.")
|
||||||
.required(true)
|
.required(true)
|
||||||
.takes_value(true),
|
.takes_value(true)
|
||||||
|
.conflicts_with("network-dir")
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("port")
|
Arg::with_name("port")
|
||||||
|
.long("port")
|
||||||
.value_name("PORT")
|
.value_name("PORT")
|
||||||
.help("The UDP port to listen on.")
|
.help("The UDP port to listen on.")
|
||||||
.default_value("9000")
|
.default_value("9000")
|
||||||
.takes_value(true),
|
.takes_value(true)
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("listen-address")
|
Arg::with_name("listen-address")
|
||||||
@ -48,7 +50,8 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
|
|||||||
.long("enr-port")
|
.long("enr-port")
|
||||||
.value_name("PORT")
|
.value_name("PORT")
|
||||||
.help("The UDP port of the boot node's ENR. This is the port that external peers will dial to reach this boot node. Set this only if the external port differs from the listening port.")
|
.help("The UDP port of the boot node's ENR. This is the port that external peers will dial to reach this boot node. Set this only if the external port differs from the listening port.")
|
||||||
.takes_value(true),
|
.takes_value(true)
|
||||||
|
.conflicts_with("network-dir")
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("enable-enr-auto-update")
|
Arg::with_name("enable-enr-auto-update")
|
||||||
@ -57,4 +60,11 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
|
|||||||
.help("Discovery can automatically update the node's local ENR with an external IP address and port as seen by other peers on the network. \
|
.help("Discovery can automatically update the node's local ENR with an external IP address and port as seen by other peers on the network. \
|
||||||
This enables this feature.")
|
This enables this feature.")
|
||||||
)
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("network-dir")
|
||||||
|
.value_name("NETWORK_DIR")
|
||||||
|
.long("network-dir")
|
||||||
|
.help("The directory which contains the enr and it's assoicated private key")
|
||||||
|
.takes_value(true)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
@ -2,13 +2,13 @@ use beacon_node::{get_data_dir, get_eth2_network_config, set_network_config};
|
|||||||
use clap::ArgMatches;
|
use clap::ArgMatches;
|
||||||
use eth2_libp2p::discv5::{enr::CombinedKey, Enr};
|
use eth2_libp2p::discv5::{enr::CombinedKey, Enr};
|
||||||
use eth2_libp2p::{
|
use eth2_libp2p::{
|
||||||
discovery::{create_enr_builder_from_config, use_or_load_enr},
|
discovery::{create_enr_builder_from_config, load_enr_from_disk, use_or_load_enr},
|
||||||
load_private_key, CombinedKeyExt, NetworkConfig,
|
load_private_key, CombinedKeyExt, NetworkConfig,
|
||||||
};
|
};
|
||||||
use ssz::Encode;
|
use ssz::Encode;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::marker::PhantomData;
|
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
|
use std::{marker::PhantomData, path::PathBuf};
|
||||||
use types::EthSpec;
|
use types::EthSpec;
|
||||||
|
|
||||||
/// A set of configuration parameters for the bootnode, established from CLI arguments.
|
/// A set of configuration parameters for the bootnode, established from CLI arguments.
|
||||||
@ -68,59 +68,65 @@ impl<T: EthSpec> TryFrom<&ArgMatches<'_>> for BootNodeConfig<T> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let private_key = load_private_key(&network_config, &logger);
|
|
||||||
let local_key = CombinedKey::from_libp2p(&private_key)?;
|
|
||||||
|
|
||||||
// build the enr_fork_id and add it to the local_enr if it exists
|
|
||||||
let enr_fork = {
|
|
||||||
let spec = eth2_network_config
|
|
||||||
.yaml_config
|
|
||||||
.as_ref()
|
|
||||||
.ok_or("The network directory must contain a spec config")?
|
|
||||||
.apply_to_chain_spec::<T>(&T::default_spec())
|
|
||||||
.ok_or("The loaded config is not compatible with the current spec")?;
|
|
||||||
|
|
||||||
if eth2_network_config.beacon_state_is_known() {
|
|
||||||
let genesis_state = eth2_network_config.beacon_state::<T>()?;
|
|
||||||
|
|
||||||
slog::info!(logger, "Genesis state found"; "root" => genesis_state.canonical_root().to_string());
|
|
||||||
let enr_fork = spec.enr_fork_id(
|
|
||||||
types::Slot::from(0u64),
|
|
||||||
genesis_state.genesis_validators_root,
|
|
||||||
);
|
|
||||||
|
|
||||||
Some(enr_fork.as_ssz_bytes())
|
|
||||||
} else {
|
|
||||||
slog::warn!(
|
|
||||||
logger,
|
|
||||||
"No genesis state provided. No Eth2 field added to the ENR"
|
|
||||||
);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Build the local ENR
|
|
||||||
|
|
||||||
let mut local_enr = {
|
|
||||||
let mut builder = create_enr_builder_from_config(&network_config, false);
|
|
||||||
|
|
||||||
// If we know of the ENR field, add it to the initial construction
|
|
||||||
if let Some(enr_fork_bytes) = enr_fork {
|
|
||||||
builder.add_value("eth2", &enr_fork_bytes);
|
|
||||||
}
|
|
||||||
builder
|
|
||||||
.build(&local_key)
|
|
||||||
.map_err(|e| format!("Failed to build ENR: {:?}", e))?
|
|
||||||
};
|
|
||||||
|
|
||||||
use_or_load_enr(&local_key, &mut local_enr, &network_config, &logger)?;
|
|
||||||
|
|
||||||
let auto_update = matches.is_present("enable-enr_auto_update");
|
let auto_update = matches.is_present("enable-enr_auto_update");
|
||||||
|
|
||||||
// the address to listen on
|
// the address to listen on
|
||||||
let listen_socket =
|
let listen_socket =
|
||||||
SocketAddr::new(network_config.listen_address, network_config.discovery_port);
|
SocketAddr::new(network_config.listen_address, network_config.discovery_port);
|
||||||
|
|
||||||
|
let private_key = load_private_key(&network_config, &logger);
|
||||||
|
let local_key = CombinedKey::from_libp2p(&private_key)?;
|
||||||
|
|
||||||
|
let local_enr = if let Some(dir) = matches.value_of("network-dir") {
|
||||||
|
let network_dir: PathBuf = dir.into();
|
||||||
|
load_enr_from_disk(&network_dir)?
|
||||||
|
} else {
|
||||||
|
// build the enr_fork_id and add it to the local_enr if it exists
|
||||||
|
let enr_fork = {
|
||||||
|
let spec = eth2_network_config
|
||||||
|
.yaml_config
|
||||||
|
.as_ref()
|
||||||
|
.ok_or("The network directory must contain a spec config")?
|
||||||
|
.apply_to_chain_spec::<T>(&T::default_spec())
|
||||||
|
.ok_or("The loaded config is not compatible with the current spec")?;
|
||||||
|
|
||||||
|
if eth2_network_config.beacon_state_is_known() {
|
||||||
|
let genesis_state = eth2_network_config.beacon_state::<T>()?;
|
||||||
|
|
||||||
|
slog::info!(logger, "Genesis state found"; "root" => genesis_state.canonical_root().to_string());
|
||||||
|
let enr_fork = spec.enr_fork_id(
|
||||||
|
types::Slot::from(0u64),
|
||||||
|
genesis_state.genesis_validators_root,
|
||||||
|
);
|
||||||
|
|
||||||
|
Some(enr_fork.as_ssz_bytes())
|
||||||
|
} else {
|
||||||
|
slog::warn!(
|
||||||
|
logger,
|
||||||
|
"No genesis state provided. No Eth2 field added to the ENR"
|
||||||
|
);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Build the local ENR
|
||||||
|
|
||||||
|
let mut local_enr = {
|
||||||
|
let mut builder = create_enr_builder_from_config(&network_config, false);
|
||||||
|
|
||||||
|
// If we know of the ENR field, add it to the initial construction
|
||||||
|
if let Some(enr_fork_bytes) = enr_fork {
|
||||||
|
builder.add_value("eth2", &enr_fork_bytes);
|
||||||
|
}
|
||||||
|
builder
|
||||||
|
.build(&local_key)
|
||||||
|
.map_err(|e| format!("Failed to build ENR: {:?}", e))?
|
||||||
|
};
|
||||||
|
|
||||||
|
use_or_load_enr(&local_key, &mut local_enr, &network_config, &logger)?;
|
||||||
|
local_enr
|
||||||
|
};
|
||||||
|
|
||||||
Ok(BootNodeConfig {
|
Ok(BootNodeConfig {
|
||||||
listen_socket,
|
listen_socket,
|
||||||
boot_nodes,
|
boot_nodes,
|
||||||
|
@ -37,3 +37,5 @@ lighthouse_version = { path = "../common/lighthouse_version" }
|
|||||||
directory = { path = "../common/directory" }
|
directory = { path = "../common/directory" }
|
||||||
account_utils = { path = "../common/account_utils" }
|
account_utils = { path = "../common/account_utils" }
|
||||||
eth2_wallet = { path = "../crypto/eth2_wallet" }
|
eth2_wallet = { path = "../crypto/eth2_wallet" }
|
||||||
|
web3 = "0.14.0"
|
||||||
|
eth1_test_rig = { path = "../testing/eth1_test_rig" }
|
||||||
|
33
lcli/src/deploy_deposit_contract.rs
Normal file
33
lcli/src/deploy_deposit_contract.rs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
use clap::ArgMatches;
|
||||||
|
use environment::Environment;
|
||||||
|
use types::EthSpec;
|
||||||
|
|
||||||
|
use web3::{transports::Http, Web3};
|
||||||
|
|
||||||
|
pub fn run<T: EthSpec>(env: Environment<T>, matches: &ArgMatches<'_>) -> Result<(), String> {
|
||||||
|
let eth1_http: String = clap_utils::parse_required(matches, "eth1-http")?;
|
||||||
|
let confirmations: usize = clap_utils::parse_required(matches, "confirmations")?;
|
||||||
|
let validator_count: Option<usize> = clap_utils::parse_optional(matches, "validator-count")?;
|
||||||
|
|
||||||
|
let transport =
|
||||||
|
Http::new(ð1_http).map_err(|e| format!("Unable to connect to eth1 HTTP: {:?}", e))?;
|
||||||
|
let web3 = Web3::new(transport);
|
||||||
|
|
||||||
|
env.runtime().block_on(async {
|
||||||
|
let contract = eth1_test_rig::DepositContract::deploy(web3, confirmations, None)
|
||||||
|
.await
|
||||||
|
.map_err(|e| format!("Failed to deploy deposit contract: {:?}", e))?;
|
||||||
|
|
||||||
|
println!("Deposit contract address: {:?}", contract.address());
|
||||||
|
|
||||||
|
// Deposit insecure validators to the deposit contract created
|
||||||
|
if let Some(validator_count) = validator_count {
|
||||||
|
let amount = env.eth2_config.spec.max_effective_balance;
|
||||||
|
for i in 0..validator_count {
|
||||||
|
println!("Submitting deposit for validator {}...", i);
|
||||||
|
contract.deposit_deterministic_async::<T>(i, amount).await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
@ -3,11 +3,13 @@ use std::fs;
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use validator_dir::Builder as ValidatorBuilder;
|
use validator_dir::Builder as ValidatorBuilder;
|
||||||
|
|
||||||
pub fn run(matches: &ArgMatches) -> Result<(), String> {
|
/// Generates validator directories with INSECURE, deterministic keypairs given the range
|
||||||
let validator_count: usize = clap_utils::parse_required(matches, "count")?;
|
/// of indices, validator and secret directories.
|
||||||
let validators_dir: PathBuf = clap_utils::parse_required(matches, "validators-dir")?;
|
pub fn generate_validator_dirs(
|
||||||
let secrets_dir: PathBuf = clap_utils::parse_required(matches, "secrets-dir")?;
|
indices: &[usize],
|
||||||
|
validators_dir: PathBuf,
|
||||||
|
secrets_dir: PathBuf,
|
||||||
|
) -> Result<(), String> {
|
||||||
if !validators_dir.exists() {
|
if !validators_dir.exists() {
|
||||||
fs::create_dir_all(&validators_dir)
|
fs::create_dir_all(&validators_dir)
|
||||||
.map_err(|e| format!("Unable to create validators dir: {:?}", e))?;
|
.map_err(|e| format!("Unable to create validators dir: {:?}", e))?;
|
||||||
@ -18,13 +20,13 @@ pub fn run(matches: &ArgMatches) -> Result<(), String> {
|
|||||||
.map_err(|e| format!("Unable to create secrets dir: {:?}", e))?;
|
.map_err(|e| format!("Unable to create secrets dir: {:?}", e))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
for i in 0..validator_count {
|
for i in indices {
|
||||||
println!("Validator {}/{}", i + 1, validator_count);
|
println!("Validator {}", i + 1);
|
||||||
|
|
||||||
ValidatorBuilder::new(validators_dir.clone())
|
ValidatorBuilder::new(validators_dir.clone())
|
||||||
.password_dir(secrets_dir.clone())
|
.password_dir(secrets_dir.clone())
|
||||||
.store_withdrawal_keystore(false)
|
.store_withdrawal_keystore(false)
|
||||||
.insecure_voting_keypair(i)
|
.insecure_voting_keypair(*i)
|
||||||
.map_err(|e| format!("Unable to generate keys: {:?}", e))?
|
.map_err(|e| format!("Unable to generate keys: {:?}", e))?
|
||||||
.build()
|
.build()
|
||||||
.map_err(|e| format!("Unable to build validator: {:?}", e))?;
|
.map_err(|e| format!("Unable to build validator: {:?}", e))?;
|
||||||
@ -32,3 +34,31 @@ pub fn run(matches: &ArgMatches) -> Result<(), String> {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn run(matches: &ArgMatches) -> Result<(), String> {
|
||||||
|
let validator_count: usize = clap_utils::parse_required(matches, "count")?;
|
||||||
|
let base_dir: PathBuf = clap_utils::parse_required(matches, "base-dir")?;
|
||||||
|
let node_count: Option<usize> = clap_utils::parse_optional(matches, "node-count")?;
|
||||||
|
if let Some(node_count) = node_count {
|
||||||
|
let validators_per_node = validator_count / node_count;
|
||||||
|
let validator_range = (0..validator_count).collect::<Vec<_>>();
|
||||||
|
let indices_range = validator_range
|
||||||
|
.chunks(validators_per_node)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
for (i, indices) in indices_range.iter().enumerate() {
|
||||||
|
let validators_dir = base_dir.join(format!("node_{}", i + 1)).join("validators");
|
||||||
|
let secrets_dir = base_dir.join(format!("node_{}", i + 1)).join("secrets");
|
||||||
|
generate_validator_dirs(indices, validators_dir, secrets_dir)?;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let validators_dir = base_dir.join("validators");
|
||||||
|
let secrets_dir = base_dir.join("secrets");
|
||||||
|
generate_validator_dirs(
|
||||||
|
(0..validator_count).collect::<Vec<_>>().as_slice(),
|
||||||
|
validators_dir,
|
||||||
|
secrets_dir,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
extern crate log;
|
extern crate log;
|
||||||
mod change_genesis_time;
|
mod change_genesis_time;
|
||||||
mod check_deposit_data;
|
mod check_deposit_data;
|
||||||
|
mod deploy_deposit_contract;
|
||||||
mod eth1_genesis;
|
mod eth1_genesis;
|
||||||
mod generate_bootnode_enr;
|
mod generate_bootnode_enr;
|
||||||
mod insecure_validators;
|
mod insecure_validators;
|
||||||
@ -155,6 +156,38 @@ fn main() {
|
|||||||
.help("SSZ encoded as 0x-prefixed hex"),
|
.help("SSZ encoded as 0x-prefixed hex"),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
.subcommand(
|
||||||
|
SubCommand::with_name("deploy-deposit-contract")
|
||||||
|
.about(
|
||||||
|
"Deploy a testing eth1 deposit contract.",
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("eth1-http")
|
||||||
|
.long("eth1-http")
|
||||||
|
.short("e")
|
||||||
|
.value_name("ETH1_HTTP_PATH")
|
||||||
|
.help("Path to an Eth1 JSON-RPC IPC endpoint")
|
||||||
|
.takes_value(true)
|
||||||
|
.required(true)
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("confirmations")
|
||||||
|
.value_name("INTEGER")
|
||||||
|
.long("confirmations")
|
||||||
|
.takes_value(true)
|
||||||
|
.default_value("3")
|
||||||
|
.help("The number of block confirmations before declaring the contract deployed."),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("validator-count")
|
||||||
|
.value_name("VALIDATOR_COUNT")
|
||||||
|
.long("validator-count")
|
||||||
|
.takes_value(true)
|
||||||
|
.help("If present, makes `validator_count` number of INSECURE deterministic deposits after \
|
||||||
|
deploying the deposit contract."
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
SubCommand::with_name("eth1-genesis")
|
SubCommand::with_name("eth1-genesis")
|
||||||
.about("Listens to the eth1 chain and finds the genesis beacon state")
|
.about("Listens to the eth1 chain and finds the genesis beacon state")
|
||||||
@ -343,6 +376,20 @@ fn main() {
|
|||||||
non-default.",
|
non-default.",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("seconds-per-eth1-block")
|
||||||
|
.long("seconds-per-eth1-block")
|
||||||
|
.value_name("SECONDS")
|
||||||
|
.takes_value(true)
|
||||||
|
.help("Eth1 block time"),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("eth1-id")
|
||||||
|
.long("eth1-id")
|
||||||
|
.value_name("ETH1_ID")
|
||||||
|
.takes_value(true)
|
||||||
|
.help("The chain id and network id for the eth1 testnet."),
|
||||||
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("deposit-contract-address")
|
Arg::with_name("deposit-contract-address")
|
||||||
.long("deposit-contract-address")
|
.long("deposit-contract-address")
|
||||||
@ -446,19 +493,19 @@ fn main() {
|
|||||||
.help("Produces validators in the range of 0..count."),
|
.help("Produces validators in the range of 0..count."),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("validators-dir")
|
Arg::with_name("base-dir")
|
||||||
.long("validators-dir")
|
.long("base-dir")
|
||||||
.value_name("VALIDATOR_DIR")
|
.value_name("BASE_DIR")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.help("The directory for storing validators."),
|
.help("The base directory where validator keypairs and secrets are stored"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("secrets-dir")
|
Arg::with_name("node-count")
|
||||||
.long("secrets-dir")
|
.long("node-count")
|
||||||
.value_name("SECRETS_DIR")
|
.value_name("NODE_COUNT")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.help("The directory for storing secrets."),
|
.help("The number of nodes to divide the validator keys to"),
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.get_matches();
|
.get_matches();
|
||||||
|
|
||||||
@ -540,6 +587,10 @@ fn run<T: EthSpec>(
|
|||||||
("pretty-hex", Some(matches)) => {
|
("pretty-hex", Some(matches)) => {
|
||||||
run_parse_hex::<T>(matches).map_err(|e| format!("Failed to pretty print hex: {}", e))
|
run_parse_hex::<T>(matches).map_err(|e| format!("Failed to pretty print hex: {}", e))
|
||||||
}
|
}
|
||||||
|
("deploy-deposit-contract", Some(matches)) => {
|
||||||
|
deploy_deposit_contract::run::<T>(env, matches)
|
||||||
|
.map_err(|e| format!("Failed to run deploy-deposit-contract command: {}", e))
|
||||||
|
}
|
||||||
("eth1-genesis", Some(matches)) => eth1_genesis::run::<T>(env, matches)
|
("eth1-genesis", Some(matches)) => eth1_genesis::run::<T>(env, matches)
|
||||||
.map_err(|e| format!("Failed to run eth1-genesis command: {}", e)),
|
.map_err(|e| format!("Failed to run eth1-genesis command: {}", e)),
|
||||||
("interop-genesis", Some(matches)) => interop_genesis::run::<T>(env, matches)
|
("interop-genesis", Some(matches)) => interop_genesis::run::<T>(env, matches)
|
||||||
|
@ -48,6 +48,9 @@ pub fn run<T: EthSpec>(matches: &ArgMatches) -> Result<(), String> {
|
|||||||
maybe_update!("ejection-balance", ejection_balance);
|
maybe_update!("ejection-balance", ejection_balance);
|
||||||
maybe_update!("eth1-follow-distance", eth1_follow_distance);
|
maybe_update!("eth1-follow-distance", eth1_follow_distance);
|
||||||
maybe_update!("genesis-delay", genesis_delay);
|
maybe_update!("genesis-delay", genesis_delay);
|
||||||
|
maybe_update!("eth1-id", deposit_chain_id);
|
||||||
|
maybe_update!("eth1-id", deposit_network_id);
|
||||||
|
maybe_update!("seconds-per-eth1-block", seconds_per_eth1_block);
|
||||||
|
|
||||||
if let Some(v) = parse_ssz_optional(matches, "genesis-fork-version")? {
|
if let Some(v) = parse_ssz_optional(matches, "genesis-fork-version")? {
|
||||||
spec.genesis_fork_version = v;
|
spec.genesis_fork_version = v;
|
||||||
|
@ -1,58 +1,67 @@
|
|||||||
# Simple Local Testnet
|
# Simple Local Testnet
|
||||||
|
|
||||||
These scripts allow for running a small local testnet with two beacon nodes and
|
These scripts allow for running a small local testnet with multiple beacon nodes and validator clients.
|
||||||
one validator client. This setup can be useful for testing and development.
|
This setup can be useful for testing and development.
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
The scripts require `lci` and `lighthouse` to be installed on `PATH`. From the
|
The scripts require `lcli` and `lighthouse` to be installed on `PATH`. From the
|
||||||
root of this repository, run:
|
root of this repository, run:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cargo install --path lighthouse --force --locked
|
make
|
||||||
cargo install --path lcli --force --locked
|
make install-lcli
|
||||||
```
|
```
|
||||||
|
|
||||||
## Starting the testnet
|
## Starting the testnet
|
||||||
|
|
||||||
Assuming you are happy with the configuration in `var.env`, create the testnet
|
Start a local eth1 ganache server
|
||||||
directory, genesis state and validator keys with:
|
```bash
|
||||||
|
./ganache_test_node.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Assuming you are happy with the configuration in `var.env`, deploy the deposit contract, make deposits,
|
||||||
|
create the testnet directory, genesis state and validator keys with:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./setup.sh
|
./setup.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
Start the first beacon node:
|
Generate bootnode enr and start a discv5 bootnode so that multiple beacon nodes can find each other
|
||||||
|
```bash
|
||||||
|
./bootnode.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Start a beacon node:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./beacon_node.sh
|
./beacon_node.sh <DATADIR> <NETWORK-PORT> <HTTP-PORT> <OPTIONAL-DEBUG-LEVEL>
|
||||||
|
```
|
||||||
|
e.g.
|
||||||
|
```bash
|
||||||
|
./beacon_node.sh $HOME/.lighthouse/local-testnet/node_1 9000 8000
|
||||||
```
|
```
|
||||||
|
|
||||||
In a new terminal, start the validator client which will attach to the first
|
In a new terminal, start the validator client which will attach to the first
|
||||||
beacon node:
|
beacon node:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./validator_client.sh
|
./validator_client.sh <DATADIR> <BEACON-NODE-HTTP> <OPTIONAL-DEBUG-LEVEL>
|
||||||
```
|
```
|
||||||
|
e.g. to attach to the above created beacon node
|
||||||
In a new terminal, start the second beacon node which will peer with the first:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./second_beacon_node.sh
|
./validator_client.sh $HOME/.lighthouse/local-testnet/node_1 http://localhost:8000
|
||||||
```
|
```
|
||||||
|
|
||||||
|
You can create additional beacon node and validator client instances with appropriate parameters.
|
||||||
|
|
||||||
## Additional Info
|
## Additional Info
|
||||||
|
|
||||||
### Debug level
|
### Adjusting number and distribution of validators
|
||||||
|
The `VALIDATOR_COUNT` parameter is used to specify the number of insecure validator keystores to generate and make deposits for.
|
||||||
The beacon nodes and validator client have their `--debug-level` set to `info`.
|
The `NODE_COUNT` parameter is used to adjust the division of these generated keys among separate validator client instances.
|
||||||
Specify a different debug level like this:
|
For e.g. for `VALIDATOR_COUNT=80` and `NODE_COUNT=4`, the validator keys are distributed over 4 datadirs with 20 keystores per datadir. The datadirs are located in `$DATADIR/node_{i}` which can be passed to separate validator client
|
||||||
|
instances using the `--datadir` parameter.
|
||||||
```bash
|
|
||||||
./validator_client.sh debug
|
|
||||||
./beacon_node.sh trace
|
|
||||||
./second_beacon_node.sh warn
|
|
||||||
```
|
|
||||||
|
|
||||||
### Starting fresh
|
### Starting fresh
|
||||||
|
|
||||||
@ -62,7 +71,6 @@ Delete the current testnet and all related files using:
|
|||||||
./clean.sh
|
./clean.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### Updating the genesis time of the beacon state
|
### Updating the genesis time of the beacon state
|
||||||
|
|
||||||
If it's been a while since you ran `./setup` then the genesis time of the
|
If it's been a while since you ran `./setup` then the genesis time of the
|
||||||
|
@ -2,20 +2,22 @@
|
|||||||
|
|
||||||
#
|
#
|
||||||
# Starts a beacon node based upon a genesis state created by
|
# Starts a beacon node based upon a genesis state created by
|
||||||
# `./local_testnet_genesis_state`.
|
# `./setup.sh`.
|
||||||
#
|
#
|
||||||
|
# Usage: ./beacon_node.sh <DATADIR> <NETWORK-PORT> <HTTP-PORT> <OPTIONAL-DEBUG-LEVEL>
|
||||||
|
|
||||||
source ./vars.env
|
source ./vars.env
|
||||||
|
|
||||||
DEBUG_LEVEL=${1:-info}
|
DEBUG_LEVEL=${4:-info}
|
||||||
|
|
||||||
exec lighthouse \
|
exec lighthouse \
|
||||||
--debug-level $DEBUG_LEVEL \
|
--debug-level $DEBUG_LEVEL \
|
||||||
bn \
|
bn \
|
||||||
--datadir $BEACON_DIR \
|
--datadir $1 \
|
||||||
--testnet-dir $TESTNET_DIR \
|
--testnet-dir $TESTNET_DIR \
|
||||||
--dummy-eth1 \
|
--staking \
|
||||||
--http \
|
|
||||||
--enr-address 127.0.0.1 \
|
--enr-address 127.0.0.1 \
|
||||||
--enr-udp-port 9000 \
|
--enr-udp-port $2 \
|
||||||
--enr-tcp-port 9000 \
|
--enr-tcp-port $2 \
|
||||||
|
--port $2 \
|
||||||
|
--http-port $3
|
||||||
|
33
scripts/local_testnet/bootnode.sh
Executable file
33
scripts/local_testnet/bootnode.sh
Executable file
@ -0,0 +1,33 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
#
|
||||||
|
# Generates a bootnode enr and saves it in $TESTNET/boot_enr.yaml
|
||||||
|
# Starts a bootnode from the generated enr.
|
||||||
|
#
|
||||||
|
|
||||||
|
source ./vars.env
|
||||||
|
|
||||||
|
echo "Generating bootnode enr"
|
||||||
|
|
||||||
|
lcli \
|
||||||
|
generate-bootnode-enr \
|
||||||
|
--ip 127.0.0.1 \
|
||||||
|
--udp-port $BOOTNODE_PORT \
|
||||||
|
--tcp-port $BOOTNODE_PORT \
|
||||||
|
--genesis-fork-version $GENESIS_FORK_VERSION \
|
||||||
|
--output-dir $DATADIR/bootnode
|
||||||
|
|
||||||
|
bootnode_enr=`cat $DATADIR/bootnode/enr.dat`
|
||||||
|
echo "- $bootnode_enr" > $TESTNET_DIR/boot_enr.yaml
|
||||||
|
|
||||||
|
echo "Generated bootnode enr and written to $TESTNET_DIR/boot_enr.yaml"
|
||||||
|
|
||||||
|
DEBUG_LEVEL=${1:-info}
|
||||||
|
|
||||||
|
echo "Starting bootnode"
|
||||||
|
|
||||||
|
exec lighthouse boot_node \
|
||||||
|
--testnet-dir $TESTNET_DIR \
|
||||||
|
--port $BOOTNODE_PORT \
|
||||||
|
--listen-address 127.0.0.1 \
|
||||||
|
--network-dir $DATADIR/bootnode \
|
@ -1,8 +1,13 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
source ./vars.env
|
||||||
|
|
||||||
ganache-cli \
|
ganache-cli \
|
||||||
--defaultBalanceEther 1000000000 \
|
--defaultBalanceEther 1000000000 \
|
||||||
--gasLimit 1000000000 \
|
--gasLimit 1000000000 \
|
||||||
--accounts 10 \
|
--accounts 10 \
|
||||||
--mnemonic "vast thought differ pull jewel broom cook wrist tribe word before omit" \
|
--mnemonic "$ETH1_NETWORK_MNEMONIC" \
|
||||||
--port 8545 \
|
--port 8545 \
|
||||||
|
--blockTime 3 \
|
||||||
|
--networkId 4242 \
|
||||||
|
--chainId 4242
|
@ -1,21 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
#
|
|
||||||
# Starts a beacon node based upon a genesis state created by
|
|
||||||
# `./local_testnet_genesis_state`.
|
|
||||||
#
|
|
||||||
|
|
||||||
source ./vars.env
|
|
||||||
|
|
||||||
DEBUG_LEVEL=${1:-info}
|
|
||||||
|
|
||||||
exec lighthouse \
|
|
||||||
--debug-level $DEBUG_LEVEL \
|
|
||||||
bn \
|
|
||||||
--datadir $BEACON_DIR-2 \
|
|
||||||
--testnet-dir $TESTNET_DIR \
|
|
||||||
--dummy-eth1 \
|
|
||||||
--http \
|
|
||||||
--port 9902 \
|
|
||||||
--http-port 6052 \
|
|
||||||
--boot-nodes $(cat $BEACON_DIR/beacon/network/enr.dat)
|
|
@ -1,18 +1,38 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
#
|
#
|
||||||
|
# Deploys the deposit contract and makes deposits for $VALIDATOR_COUNT insecure deterministic validators.
|
||||||
# Produces a testnet specification and a genesis state where the genesis time
|
# Produces a testnet specification and a genesis state where the genesis time
|
||||||
# is now.
|
# is now + $GENESIS_DELAY.
|
||||||
|
#
|
||||||
|
# Generates datadirs for multiple validator keys according to the
|
||||||
|
# $VALIDATOR_COUNT and $NODE_COUNT variables.
|
||||||
#
|
#
|
||||||
|
|
||||||
source ./vars.env
|
source ./vars.env
|
||||||
|
|
||||||
|
lcli \
|
||||||
|
deploy-deposit-contract \
|
||||||
|
--eth1-http http://localhost:8545 \
|
||||||
|
--confirmations 1 \
|
||||||
|
--validator-count $VALIDATOR_COUNT
|
||||||
|
|
||||||
|
NOW=`date +%s`
|
||||||
|
GENESIS_TIME=`expr $NOW + $GENESIS_DELAY`
|
||||||
|
|
||||||
|
|
||||||
lcli \
|
lcli \
|
||||||
--spec mainnet \
|
--spec mainnet \
|
||||||
new-testnet \
|
new-testnet \
|
||||||
--deposit-contract-address 1234567890123456789012345678901234567890 \
|
--deposit-contract-address $DEPOSIT_CONTRACT_ADDRESS \
|
||||||
--testnet-dir $TESTNET_DIR \
|
--testnet-dir $TESTNET_DIR \
|
||||||
--min-genesis-active-validator-count $VALIDATOR_COUNT \
|
--min-genesis-active-validator-count $GENESIS_VALIDATOR_COUNT \
|
||||||
|
--min-genesis-time $GENESIS_TIME \
|
||||||
|
--genesis-delay $GENESIS_DELAY \
|
||||||
|
--genesis-fork-version $GENESIS_FORK_VERSION \
|
||||||
|
--eth1-id $BOOTNODE_PORT \
|
||||||
|
--eth1-follow-distance 1 \
|
||||||
|
--seconds-per-eth1-block 1 \
|
||||||
--force
|
--force
|
||||||
|
|
||||||
echo Specification generated at $TESTNET_DIR.
|
echo Specification generated at $TESTNET_DIR.
|
||||||
@ -21,16 +41,17 @@ echo "Generating $VALIDATOR_COUNT validators concurrently... (this may take a wh
|
|||||||
lcli \
|
lcli \
|
||||||
insecure-validators \
|
insecure-validators \
|
||||||
--count $VALIDATOR_COUNT \
|
--count $VALIDATOR_COUNT \
|
||||||
--validators-dir $VALIDATORS_DIR \
|
--base-dir $DATADIR \
|
||||||
--secrets-dir $SECRETS_DIR
|
--node-count $NODE_COUNT
|
||||||
|
|
||||||
echo Validators generated at $VALIDATORS_DIR with keystore passwords at $SECRETS_DIR.
|
echo Validators generated with keystore passwords at $DATADIR.
|
||||||
echo "Building genesis state... (this might take a while)"
|
echo "Building genesis state... (this might take a while)"
|
||||||
|
|
||||||
lcli \
|
lcli \
|
||||||
--spec mainnet \
|
--spec mainnet \
|
||||||
interop-genesis \
|
interop-genesis \
|
||||||
|
--genesis-time $GENESIS_TIME \
|
||||||
--testnet-dir $TESTNET_DIR \
|
--testnet-dir $TESTNET_DIR \
|
||||||
$VALIDATOR_COUNT
|
$GENESIS_VALIDATOR_COUNT
|
||||||
|
|
||||||
echo Created genesis state in $TESTNET_DIR
|
echo Created genesis state in $TESTNET_DIR
|
@ -2,17 +2,18 @@
|
|||||||
|
|
||||||
#
|
#
|
||||||
# Starts a validator client based upon a genesis state created by
|
# Starts a validator client based upon a genesis state created by
|
||||||
# `./local_testnet_genesis_state`.
|
# `./setup.sh`.
|
||||||
#
|
#
|
||||||
|
# Usage: ./validator_client.sh <DATADIR> <BEACON-NODE-HTTP> <OPTIONAL-DEBUG-LEVEL>
|
||||||
|
|
||||||
source ./vars.env
|
source ./vars.env
|
||||||
|
|
||||||
DEBUG_LEVEL=${1:-info}
|
DEBUG_LEVEL=${3:-info}
|
||||||
|
|
||||||
exec lighthouse \
|
exec lighthouse \
|
||||||
--debug-level $DEBUG_LEVEL \
|
--debug-level $DEBUG_LEVEL \
|
||||||
vc \
|
vc \
|
||||||
--datadir $DATADIR \
|
--datadir $1 \
|
||||||
--testnet-dir $TESTNET_DIR \
|
--testnet-dir $TESTNET_DIR \
|
||||||
--init-slashing-protection \
|
--init-slashing-protection \
|
||||||
--allow-unsynced
|
--beacon-nodes $2
|
||||||
|
@ -1,7 +1,22 @@
|
|||||||
|
# Base directories for the validator keys and secrets
|
||||||
DATADIR=~/.lighthouse/local-testnet
|
DATADIR=~/.lighthouse/local-testnet
|
||||||
TESTNET_DIR=$DATADIR/testnet
|
|
||||||
BEACON_DIR=$DATADIR/beacon
|
|
||||||
VALIDATORS_DIR=$DATADIR/validators
|
|
||||||
SECRETS_DIR=$DATADIR/secrets
|
|
||||||
|
|
||||||
VALIDATOR_COUNT=1024
|
# Directory for the eth2 config
|
||||||
|
TESTNET_DIR=$DATADIR/testnet
|
||||||
|
|
||||||
|
# Mnemonic for the ganache test network
|
||||||
|
ETH1_NETWORK_MNEMONIC="vast thought differ pull jewel broom cook wrist tribe word before omit"
|
||||||
|
|
||||||
|
# Hardcoded deposit contract based on ETH1_NETWORK_MNEMONIC
|
||||||
|
DEPOSIT_CONTRACT_ADDRESS=8c594691c0e592ffa21f153a16ae41db5befcaaa
|
||||||
|
|
||||||
|
GENESIS_FORK_VERSION=0x42424242
|
||||||
|
|
||||||
|
VALIDATOR_COUNT=80
|
||||||
|
GENESIS_VALIDATOR_COUNT=80
|
||||||
|
|
||||||
|
# Number of validator client instances that you intend to run
|
||||||
|
NODE_COUNT=4
|
||||||
|
|
||||||
|
GENESIS_DELAY=180
|
||||||
|
BOOTNODE_PORT=4242
|
||||||
|
Loading…
Reference in New Issue
Block a user