diff --git a/beacon_node/beacon_chain/src/builder.rs b/beacon_node/beacon_chain/src/builder.rs index f5df3e4ac4..ce59c91650 100644 --- a/beacon_node/beacon_chain/src/builder.rs +++ b/beacon_node/beacon_chain/src/builder.rs @@ -229,7 +229,7 @@ where .get::(&Hash256::from_slice(&BEACON_CHAIN_DB_KEY)) .map_err(|e| format!("DB error when reading persisted beacon chain: {:?}", e))? .ok_or_else(|| { - "No persisted beacon chain found in store. Try deleting the .lighthouse/beacon dir." + "No persisted beacon chain found in store. Try purging the beacon chain database." .to_string() })?; diff --git a/beacon_node/eth2-libp2p/tests/common/mod.rs b/beacon_node/eth2-libp2p/tests/common/mod.rs index 15918a21a3..3d4df4cf5e 100644 --- a/beacon_node/eth2-libp2p/tests/common/mod.rs +++ b/beacon_node/eth2-libp2p/tests/common/mod.rs @@ -4,6 +4,7 @@ use eth2_libp2p::Multiaddr; use eth2_libp2p::NetworkConfig; use eth2_libp2p::Service as LibP2PService; use slog::{debug, error, o, Drain}; +use std::net::{TcpListener, UdpSocket}; use std::time::Duration; use types::{EnrForkId, MinimalEthSpec}; @@ -22,6 +23,38 @@ pub fn build_log(level: slog::Level, enabled: bool) -> slog::Logger { } } +// A bit of hack to find an unused 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(transport: &str) -> Result { + let local_addr = match transport { + "tcp" => { + let listener = TcpListener::bind("127.0.0.1:0").map_err(|e| { + format!("Failed to create TCP listener to find unused port: {:?}", e) + })?; + listener.local_addr().map_err(|e| { + format!( + "Failed to read TCP listener local_addr to find unused port: {:?}", + e + ) + })? + } + "udp" => { + let socket = UdpSocket::bind("127.0.0.1:0") + .map_err(|e| format!("Failed to create UDP socket to find unused port: {:?}", e))?; + socket.local_addr().map_err(|e| { + format!( + "Failed to read UDP socket local_addr to find unused port: {:?}", + e + ) + })? + } + _ => return Err("Invalid transport to find unused port".into()), + }; + Ok(local_addr.port()) +} + pub fn build_config( port: u16, mut boot_nodes: Vec, diff --git a/beacon_node/eth2-libp2p/tests/gossipsub_tests.rs b/beacon_node/eth2-libp2p/tests/gossipsub_tests.rs index 8268fc5d87..5b63aa9e1c 100644 --- a/beacon_node/eth2-libp2p/tests/gossipsub_tests.rs +++ b/beacon_node/eth2-libp2p/tests/gossipsub_tests.rs @@ -25,7 +25,8 @@ fn test_gossipsub_forward() { let log = common::build_log(Level::Info, false); let num_nodes = 20; - let mut nodes = common::build_linear(log.clone(), num_nodes, Some(19000)); + let base_port = 54236; + let mut nodes = common::build_linear(log.clone(), num_nodes, Some(base_port)); let mut received_count = 0; let spec = E::default_spec(); let empty_block = BeaconBlock::empty(&spec); @@ -98,7 +99,8 @@ fn test_gossipsub_full_mesh_publish() { // as nodes may get pruned out of the mesh before the gossipsub message // is published to them. let num_nodes = 12; - let mut nodes = common::build_full_mesh(log, num_nodes, Some(11320)); + let base_port = 5264; + let mut nodes = common::build_full_mesh(log, num_nodes, Some(base_port)); let mut publishing_node = nodes.pop().unwrap(); let spec = E::default_spec(); let empty_block = BeaconBlock::empty(&spec); diff --git a/beacon_node/eth2-libp2p/tests/noise.rs b/beacon_node/eth2-libp2p/tests/noise.rs index ac29f3959b..236150b632 100644 --- a/beacon_node/eth2-libp2p/tests/noise.rs +++ b/beacon_node/eth2-libp2p/tests/noise.rs @@ -125,12 +125,14 @@ fn test_secio_noise_fallback() { let log = common::build_log(log_level, enable_logging); - let noisy_config = common::build_config(56010, vec![], None); + let port = common::unused_port("tcp").unwrap(); + let noisy_config = common::build_config(port, vec![], None); let mut noisy_node = Service::new(&noisy_config, EnrForkId::default(), log.clone()) .expect("should build a libp2p instance") .1; - let secio_config = common::build_config(56011, vec![common::get_enr(&noisy_node)], None); + let port = common::unused_port("tcp").unwrap(); + let secio_config = common::build_config(port, vec![common::get_enr(&noisy_node)], None); // Building a custom Libp2pService from outside the crate isn't possible because of // private fields in the Libp2pService struct. A swarm is good enough for testing diff --git a/beacon_node/eth2-libp2p/tests/rpc_tests.rs b/beacon_node/eth2-libp2p/tests/rpc_tests.rs index 016e3ab1d4..8447599e17 100644 --- a/beacon_node/eth2-libp2p/tests/rpc_tests.rs +++ b/beacon_node/eth2-libp2p/tests/rpc_tests.rs @@ -25,7 +25,8 @@ fn test_status_rpc() { let log = common::build_log(log_level, enable_logging); // get sender/receiver - let (mut sender, mut receiver) = common::build_node_pair(&log, 10500); + let port = common::unused_port("tcp").unwrap(); + let (mut sender, mut receiver) = common::build_node_pair(&log, port); // Dummy STATUS RPC message let rpc_request = RPCRequest::Status(StatusMessage { @@ -140,7 +141,8 @@ fn test_blocks_by_range_chunked_rpc() { let log = common::build_log(log_level, enable_logging); // get sender/receiver - let (mut sender, mut receiver) = common::build_node_pair(&log, 10505); + let port = common::unused_port("tcp").unwrap(); + let (mut sender, mut receiver) = common::build_node_pair(&log, port); // BlocksByRange Request let rpc_request = RPCRequest::BlocksByRange(BlocksByRangeRequest { @@ -275,7 +277,8 @@ fn test_blocks_by_range_single_empty_rpc() { let log = common::build_log(log_level, enable_logging); // get sender/receiver - let (mut sender, mut receiver) = common::build_node_pair(&log, 10510); + let port = common::unused_port("tcp").unwrap(); + let (mut sender, mut receiver) = common::build_node_pair(&log, port); // BlocksByRange Request let rpc_request = RPCRequest::BlocksByRange(BlocksByRangeRequest { @@ -411,7 +414,8 @@ fn test_blocks_by_root_chunked_rpc() { let spec = E::default_spec(); // get sender/receiver - let (mut sender, mut receiver) = common::build_node_pair(&log, 10515); + let port = common::unused_port("tcp").unwrap(); + let (mut sender, mut receiver) = common::build_node_pair(&log, port); // BlocksByRoot Request let rpc_request = RPCRequest::BlocksByRoot(BlocksByRootRequest { @@ -539,7 +543,8 @@ fn test_goodbye_rpc() { let log = common::build_log(log_level, enable_logging); // get sender/receiver - let (mut sender, mut receiver) = common::build_node_pair(&log, 10520); + let port = common::unused_port("tcp").unwrap(); + let (mut sender, mut receiver) = common::build_node_pair(&log, port); // Goodbye Request let rpc_request = RPCRequest::Goodbye(GoodbyeReason::ClientShutdown); diff --git a/beacon_node/src/cli.rs b/beacon_node/src/cli.rs index 637dc289e0..db976859ff 100644 --- a/beacon_node/src/cli.rs +++ b/beacon_node/src/cli.rs @@ -235,4 +235,12 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> { .help("Specifies how many states the database should cache in memory [default: 5]") .takes_value(true) ) + /* + * Purge. + */ + .arg( + Arg::with_name("purge-db") + .long("purge-db") + .help("If present, the chain database will be deleted. Use with caution.") + ) } diff --git a/beacon_node/src/config.rs b/beacon_node/src/config.rs index a48569e53a..4b8c28b62b 100644 --- a/beacon_node/src/config.rs +++ b/beacon_node/src/config.rs @@ -1,8 +1,9 @@ +use beacon_chain::builder::PUBKEY_CACHE_FILENAME; use clap::ArgMatches; use client::{config::DEFAULT_DATADIR, ClientConfig, ClientGenesis}; use eth2_libp2p::{Enr, Multiaddr}; use eth2_testnet_config::Eth2TestnetConfig; -use slog::{crit, info, Logger}; +use slog::{crit, info, warn, Logger}; use ssz::Encode; use std::fs; use std::fs::File; @@ -33,6 +34,32 @@ pub fn get_config( client_config.data_dir = get_data_dir(cli_args); + // If necessary, remove any existing database and configuration + if client_config.data_dir.exists() && cli_args.is_present("purge-db") { + // Remove the chain_db. + fs::remove_dir_all( + client_config + .get_db_path() + .ok_or("Failed to get db_path".to_string())?, + ) + .map_err(|err| format!("Failed to remove chain_db: {}", err))?; + + // Remove the freezer db. + fs::remove_dir_all( + client_config + .get_freezer_db_path() + .ok_or("Failed to get freezer db path".to_string())?, + ) + .map_err(|err| format!("Failed to remove chain_db: {}", err))?; + + // Remove the pubkey cache file if it exists + let pubkey_cache_file = client_config.data_dir.join(PUBKEY_CACHE_FILENAME); + if pubkey_cache_file.exists() { + fs::remove_file(&pubkey_cache_file) + .map_err(|e| format!("Failed to remove {:?}: {:?}", pubkey_cache_file, e))?; + } + } + // Create `datadir` and any non-existing parent directories. fs::create_dir_all(&client_config.data_dir) .map_err(|e| format!("Failed to create data dir: {}", e))?; @@ -293,24 +320,7 @@ pub fn get_config( } /* - * Load the eth2 testnet dir to obtain some addition config values. - */ - let eth2_testnet_config: Eth2TestnetConfig = - get_eth2_testnet_config(&client_config.testnet_dir)?; - - client_config.eth1.deposit_contract_address = - format!("{:?}", eth2_testnet_config.deposit_contract_address()?); - client_config.eth1.deposit_contract_deploy_block = - eth2_testnet_config.deposit_contract_deploy_block; - client_config.eth1.lowest_cached_block_number = - client_config.eth1.deposit_contract_deploy_block; - - if let Some(mut boot_nodes) = eth2_testnet_config.boot_enr { - client_config.network.boot_nodes.append(&mut boot_nodes) - } - - /* - * Load the eth2 testnet dir to obtain some addition config values. + * Load the eth2 testnet dir to obtain some additional config values. */ let eth2_testnet_config: Eth2TestnetConfig = get_eth2_testnet_config(&client_config.testnet_dir)?; diff --git a/book/src/local-testnets.md b/book/src/local-testnets.md index 387df1dd45..b9b351bab5 100644 --- a/book/src/local-testnets.md +++ b/book/src/local-testnets.md @@ -27,6 +27,7 @@ lighthouse vc --testnet-dir ~/.lighthouse/testnet --allow-unsynced testnet insec Optionally update the genesis time to now: ```bash +<<<<<<< HEAD lcli change-genesis-time ~/.lighthouse/testnet/genesis.ssz $(date +%s) ```