Add lcli indexed-attestations (#3221)

## Proposed Changes

It's reasonably often that we want to manually convert an attestation to indexed form. This PR adds an `lcli` command for doing this, using an SSZ state and a list of JSON attestations (as extracted from a JSON block) as input.
This commit is contained in:
Michael Sproul 2022-05-31 06:09:08 +00:00
parent af5da1244e
commit ee18f6a9f7
2 changed files with 71 additions and 0 deletions

View File

@ -0,0 +1,48 @@
use clap::ArgMatches;
use clap_utils::parse_required;
use state_processing::common::get_indexed_attestation;
use std::fs::File;
use std::io::Read;
use std::path::{Path, PathBuf};
use types::*;
fn read_file_bytes(filename: &Path) -> Result<Vec<u8>, String> {
let mut bytes = vec![];
let mut file = File::open(filename)
.map_err(|e| format!("Unable to open {}: {}", filename.display(), e))?;
file.read_to_end(&mut bytes)
.map_err(|e| format!("Unable to read {}: {}", filename.display(), e))?;
Ok(bytes)
}
pub fn run<T: EthSpec>(matches: &ArgMatches) -> Result<(), String> {
let spec = &T::default_spec();
let state_file: PathBuf = parse_required(matches, "state")?;
let attestations_file: PathBuf = parse_required(matches, "attestations")?;
let mut state = BeaconState::<T>::from_ssz_bytes(&read_file_bytes(&state_file)?, spec)
.map_err(|e| format!("Invalid state: {:?}", e))?;
state
.build_all_committee_caches(spec)
.map_err(|e| format!("{:?}", e))?;
let attestations: Vec<Attestation<T>> =
serde_json::from_slice(&read_file_bytes(&attestations_file)?)
.map_err(|e| format!("Invalid attestation list: {:?}", e))?;
let indexed_attestations = attestations
.into_iter()
.map(|att| {
let committee = state.get_beacon_committee(att.data.slot, att.data.index)?;
get_indexed_attestation(committee.committee, &att)
})
.collect::<Result<Vec<_>, _>>()
.map_err(|e| format!("Error constructing indexed attestation: {:?}", e))?;
let string_output = serde_json::to_string_pretty(&indexed_attestations)
.map_err(|e| format!("Unable to convert to JSON: {:?}", e))?;
println!("{}", string_output);
Ok(())
}

View File

@ -6,6 +6,7 @@ mod create_payload_header;
mod deploy_deposit_contract;
mod eth1_genesis;
mod generate_bootnode_enr;
mod indexed_attestations;
mod insecure_validators;
mod interop_genesis;
mod new_testnet;
@ -598,6 +599,26 @@ fn main() {
.help("The number of nodes to divide the validator keys to"),
)
)
.subcommand(
SubCommand::with_name("indexed-attestations")
.about("Convert attestations to indexed form, using the committees from a state.")
.arg(
Arg::with_name("state")
.long("state")
.value_name("SSZ_STATE")
.takes_value(true)
.required(true)
.help("BeaconState to generate committees from (SSZ)"),
)
.arg(
Arg::with_name("attestations")
.long("attestations")
.value_name("JSON_ATTESTATIONS")
.takes_value(true)
.required(true)
.help("List of Attestations to convert to indexed form (JSON)"),
)
)
.get_matches();
let result = matches
@ -679,6 +700,8 @@ fn run<T: EthSpec>(
.map_err(|e| format!("Failed to run generate-bootnode-enr command: {}", e)),
("insecure-validators", Some(matches)) => insecure_validators::run(matches)
.map_err(|e| format!("Failed to run insecure-validators command: {}", e)),
("indexed-attestations", Some(matches)) => indexed_attestations::run::<T>(matches)
.map_err(|e| format!("Failed to run indexed-attestations command: {}", e)),
(other, _) => Err(format!("Unknown subcommand {}. See --help.", other)),
}
}