Improve and extend CLI interface

This commit is contained in:
Paul Hauner 2019-08-31 12:34:27 +10:00
parent 6ba093d14f
commit 5f0509be50
No known key found for this signature in database
GPG Key ID: 303E4494BB28068C
5 changed files with 141 additions and 49 deletions

View File

@ -158,12 +158,6 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
genesis_state_root,
));
info!(log, "BeaconChain init";
"genesis_validator_count" => genesis_state.validators.len(),
"genesis_state_root" => format!("{}", genesis_state_root),
"genesis_block_root" => format!("{}", genesis_block_root),
);
// Slot clock
let slot_clock = T::SlotClock::from_eth2_genesis(
spec.genesis_slot,
@ -172,6 +166,12 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
)
.ok_or_else(|| Error::SlotClockDidNotStart)?;
info!(log, "Beacon chain initialized from genesis";
"validator_count" => genesis_state.validators.len(),
"state_root" => format!("{}", genesis_state_root),
"block_root" => format!("{}", genesis_block_root),
);
Ok(Self {
spec,
slot_clock,
@ -211,6 +211,13 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
let op_pool = p.op_pool.into_operation_pool(state, &spec);
info!(log, "Beacon chain initialized from store";
"head_root" => format!("{}", p.canonical_head.beacon_block_root),
"head_epoch" => format!("{}", p.canonical_head.beacon_block.slot.epoch(T::EthSpec::slots_per_epoch())),
"finalized_root" => format!("{}", last_finalized_root),
"finalized_epoch" => format!("{}", last_finalized_block.slot.epoch(T::EthSpec::slots_per_epoch())),
);
Ok(Some(BeaconChain {
spec,
slot_clock,

View File

@ -82,34 +82,70 @@ where
let beacon_chain_builder = match &client_config.beacon_chain_start_method {
BeaconChainStartMethod::Resume => {
info!(
log,
"Starting beacon chain";
"method" => "resume"
);
BeaconChainBuilder::from_store(spec.clone(), log.clone())
}
BeaconChainStartMethod::Mainnet => {
crit!(log, "No mainnet beacon chain startup specification.");
return Err("Mainnet is not yet specified. We're working on it.".into());
return Err("Mainnet launch is not yet announced.".into());
}
BeaconChainStartMethod::RecentGenesis {
validator_count,
minutes,
} => BeaconChainBuilder::recent_genesis(
} => {
info!(
log,
"Starting beacon chain";
"validator_count" => validator_count,
"minutes" => minutes,
"method" => "recent"
);
BeaconChainBuilder::recent_genesis(
*validator_count,
*minutes,
spec.clone(),
log.clone(),
)?,
)?
}
BeaconChainStartMethod::Generated {
validator_count,
genesis_time,
} => BeaconChainBuilder::quick_start(
} => {
info!(
log,
"Starting beacon chain";
"validator_count" => validator_count,
"genesis_time" => genesis_time,
"method" => "quick"
);
BeaconChainBuilder::quick_start(
*genesis_time,
*validator_count,
spec.clone(),
log.clone(),
)?,
)?
}
BeaconChainStartMethod::Yaml { file } => {
info!(
log,
"Starting beacon chain";
"file" => format!("{:?}", file),
"method" => "yaml"
);
BeaconChainBuilder::yaml_state(file, spec.clone(), log.clone())?
}
BeaconChainStartMethod::HttpBootstrap { server, .. } => {
BeaconChainStartMethod::HttpBootstrap { server, port } => {
info!(
log,
"Starting beacon chain";
"port" => port,
"server" => server,
"method" => "bootstrap"
);
BeaconChainBuilder::http_bootstrap(server, spec.clone(), log.clone())?
}
};
@ -124,26 +160,6 @@ where
panic!("Cannot start client before genesis!")
}
// Block starting the client until we have caught the state up to the current slot.
//
// If we don't block here we create an initial scenario where we're unable to process any
// blocks and we're basically useless.
{
let state_slot = beacon_chain.head().beacon_state.slot;
let wall_clock_slot = beacon_chain
.slot()
.expect("Cannot start client before genesis");
let slots_since_genesis = beacon_chain.slots_since_genesis().unwrap();
info!(
log,
"BeaconState cache init";
"state_slot" => state_slot,
"wall_clock_slot" => wall_clock_slot,
"slots_since_genesis" => slots_since_genesis,
"catchup_distance" => wall_clock_slot - state_slot,
);
}
let network_config = &client_config.network;
let (network, network_send) =
NetworkService::new(beacon_chain.clone(), network_config, executor, log.clone())?;

View File

@ -15,6 +15,12 @@ type Result<T> = std::result::Result<T, String>;
type Config = (ClientConfig, Eth2Config);
/// Gets the fully-initialized global client and eth2 configuration objects.
///
/// The top-level `clap` arguments should be provied as `cli_args`.
///
/// The output of this function depends primarily upon the given `cli_args`, however it's behaviour
/// may be influenced by other external services like the contents of the file system or the
/// response of some remote server.
pub fn get_configs(cli_args: &ArgMatches, log: &Logger) -> Result<Config> {
let mut builder = ConfigBuilder::new(cli_args, log)?;
@ -95,7 +101,7 @@ fn process_testnet_subcommand(
"path" => format!("{:?}", builder.data_dir)
);
// Start matching on the second subcommand (e.g., `testnet bootstrap ...`)
// Start matching on the second subcommand (e.g., `testnet bootstrap ...`).
match cli_args.subcommand() {
("bootstrap", Some(cli_args)) => {
let server = cli_args
@ -131,6 +137,24 @@ fn process_testnet_subcommand(
minutes,
})
}
("quick", Some(cli_args)) => {
let validator_count = cli_args
.value_of("validator_count")
.ok_or_else(|| "No validator_count specified")?
.parse::<usize>()
.map_err(|e| format!("Unable to parse validator_count: {:?}", e))?;
let genesis_time = cli_args
.value_of("genesis_time")
.ok_or_else(|| "No genesis time supplied")?
.parse::<u64>()
.map_err(|e| format!("Unable to parse genesis time: {:?}", e))?;
builder.set_beacon_chain_start_method(BeaconChainStartMethod::Generated {
validator_count,
genesis_time,
})
}
_ => return Err("No testnet method specified. See 'testnet --help'.".into()),
};
@ -420,6 +444,18 @@ impl<'a> ConfigBuilder<'a> {
self.client_config
.apply_cli_args(cli_args, &mut self.log.clone())?;
if let Some(bump) = cli_args.value_of("port-bump") {
let bump = bump
.parse::<u16>()
.map_err(|e| format!("Unable to parse port bump: {}", e))?;
self.client_config.network.libp2p_port += bump;
self.client_config.network.discovery_port += bump;
self.client_config.rpc.port += bump;
self.client_config.rpc.port += bump;
self.client_config.rest_api.port += bump;
}
if self.eth2_config.spec_constants != self.client_config.spec_constants {
crit!(self.log, "Specification constants do not match.";
"client_config" => format!("{}", self.client_config.spec_constants),

View File

@ -48,18 +48,29 @@ fn main() {
/*
* Network parameters.
*/
.arg(
Arg::with_name("port-bump")
.long("port-bump")
.short("b")
.value_name("INCREMENT")
.help("Sets all listening TCP/UDP ports to default values, but with each port increased by \
INCREMENT. Useful when starting multiple nodes on a single machine. Using increments \
in multiples of 10 is recommended.")
.takes_value(true),
)
.arg(
Arg::with_name("listen-address")
.long("listen-address")
.value_name("ADDRESS")
.help("The address lighthouse will listen for UDP and TCP connections. (default 127.0.0.1).")
.takes_value(true),
.takes_value(true)
)
.arg(
Arg::with_name("port")
.long("port")
.value_name("PORT")
.help("The TCP/UDP port to listen on. The UDP port can be modified by the --discovery-port flag.")
.conflicts_with("port-bump")
.takes_value(true),
)
.arg(
@ -81,6 +92,7 @@ fn main() {
.long("disc-port")
.value_name("PORT")
.help("The discovery UDP port.")
.conflicts_with("port-bump")
.takes_value(true),
)
.arg(
@ -125,6 +137,7 @@ fn main() {
Arg::with_name("rpc-port")
.long("rpc-port")
.help("Listen port for RPC endpoint.")
.conflicts_with("port-bump")
.takes_value(true),
)
/* Client related arguments */
@ -147,6 +160,7 @@ fn main() {
.long("api-port")
.value_name("APIPORT")
.help("Set the listen TCP port for the RESTful HTTP API server.")
.conflicts_with("port-bump")
.takes_value(true),
)
@ -230,8 +244,6 @@ fn main() {
.conflicts_with("random-datadir")
)
/*
* Testnet sub-commands.
*
* `boostrap`
*
* Start a new node by downloading genesis and network info from another node via the
@ -272,7 +284,29 @@ fn main() {
.default_value("15")
.help("The maximum number of minutes that will have elapsed before genesis"))
)
.subcommand(SubCommand::with_name("yaml-genesis-state")
/*
* `quick`
*
* Start a new node, specifying the number of validators and genesis time
*/
.subcommand(SubCommand::with_name("quick")
.about("Creates a new genesis state from the specified validator count and genesis time. \
Compatible with the `quick-start genesis` defined in the eth2.0-pm repo.")
.arg(Arg::with_name("validator_count")
.value_name("VALIDATOR_COUNT")
.required(true)
.help("The number of validators in the genesis state"))
.arg(Arg::with_name("genesis_time")
.value_name("UNIX_EPOCH_SECONDS")
.required(true)
.help("The genesis time for the given state."))
)
/*
* `yaml`
*
* Start a new node, using a genesis state loaded from a YAML file
*/
.subcommand(SubCommand::with_name("yaml")
.about("Creates a new datadir where the genesis state is read from YAML. Will fail to parse \
a YAML state that was generated to a different spec than that specified by --spec.")
.arg(Arg::with_name("file")

View File

@ -41,11 +41,10 @@ pub fn run_beacon_node(
info!(
log,
"BeaconNode init";
"p2p_listen_address" => format!("{:?}", &other_client_config.network.listen_address),
"network_dir" => format!("{:?}", other_client_config.network.network_dir),
"spec_constants" => &spec_constants,
"Starting beacon node";
"p2p_listen_address" => format!("{}", &other_client_config.network.listen_address),
"db_type" => &other_client_config.db_type,
"spec_constants" => &spec_constants,
);
match (db_type.as_str(), spec_constants.as_str()) {