diff --git a/beacon_node/rest_api/src/beacon.rs b/beacon_node/rest_api/src/beacon.rs index 85f20294d..a4660836d 100644 --- a/beacon_node/rest_api/src/beacon.rs +++ b/beacon_node/rest_api/src/beacon.rs @@ -101,6 +101,21 @@ pub fn get_block_root(req: Request) -> ApiR Ok(success_response(Body::from(json))) } +/// HTTP handler to return a `BeaconState` at a given `root` or `slot`. +/// +/// Will not return a state if the request slot is in the future. Will return states higher than +/// the current head by skipping slots. +pub fn get_genesis_state(req: Request) -> ApiResult { + let beacon_chain = req + .extensions() + .get::>>() + .ok_or_else(|| ApiError::ServerError("Beacon chain extension missing".to_string()))?; + + let (_root, state) = state_at_slot(&beacon_chain, Slot::new(0))?; + + ResponseBuilder::new(&req).body(&state) +} + #[derive(Serialize, Encode)] #[serde(bound = "T: EthSpec")] pub struct StateResponse { diff --git a/beacon_node/rest_api/src/lib.rs b/beacon_node/rest_api/src/lib.rs index 1b5a2d6ee..4aab91e69 100644 --- a/beacon_node/rest_api/src/lib.rs +++ b/beacon_node/rest_api/src/lib.rs @@ -147,6 +147,7 @@ pub fn start_server( beacon::get_latest_finalized_checkpoint::(req) } (&Method::GET, "/beacon/state") => beacon::get_state::(req), + (&Method::GET, "/beacon/state/genesis") => beacon::get_genesis_state::(req), (&Method::GET, "/beacon/state_root") => beacon::get_state_root::(req), //TODO: Add aggreggate/filtered state lookups here, e.g. /beacon/validators/balances diff --git a/beacon_node/src/config.rs b/beacon_node/src/config.rs index 949b7277e..ba831c733 100644 --- a/beacon_node/src/config.rs +++ b/beacon_node/src/config.rs @@ -172,6 +172,31 @@ fn process_testnet_subcommand( genesis_time, }) } + ("file", Some(cli_args)) => { + let file = cli_args + .value_of("file") + .ok_or_else(|| "No filename specified")? + .parse::() + .map_err(|e| format!("Unable to parse filename: {:?}", e))?; + + let format = cli_args + .value_of("format") + .ok_or_else(|| "No file format specified")?; + + let start_method = match format { + "yaml" => BeaconChainStartMethod::Yaml { file }, + "ssz" => BeaconChainStartMethod::Ssz { file }, + other => return Err(format!("Unknown genesis file format: {}", other)), + }; + + builder.set_beacon_chain_start_method(start_method) + } + (cmd, Some(_)) => { + return Err(format!( + "Invalid valid method specified: {}. See 'testnet --help'.", + cmd + )) + } _ => return Err("No testnet method specified. See 'testnet --help'.".into()), }; diff --git a/beacon_node/src/main.rs b/beacon_node/src/main.rs index a2a977e85..cf7a7b854 100644 --- a/beacon_node/src/main.rs +++ b/beacon_node/src/main.rs @@ -312,9 +312,14 @@ fn main() { * * 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.") + .subcommand(SubCommand::with_name("file") + .about("Creates a new datadir where the genesis state is read from YAML. May fail to parse \ + a file that was generated to a different spec than that specified by --spec.") + .arg(Arg::with_name("format") + .value_name("FORMAT") + .required(true) + .possible_values(&["yaml", "ssz"]) + .help("The encoding of the state in the file.")) .arg(Arg::with_name("file") .value_name("YAML_FILE") .required(true)