Skip to content

Commit

Permalink
[aptos-cli] Consolidate Genesis process
Browse files Browse the repository at this point in the history
Combine all genesis keys into one file, and output waypoint and
genesis blob in one command.

Closes: aptos-labs#892
  • Loading branch information
gregnazario authored and aptos-bot committed May 10, 2022
1 parent ee34e56 commit 982ff5f
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 86 deletions.
26 changes: 13 additions & 13 deletions crates/aptos/src/common/types.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use crate::common::{
init::DEFAULT_REST_URL,
utils::{check_if_file_exists, to_common_result, to_common_success_result, write_to_file},
use crate::{
common::{
init::DEFAULT_REST_URL,
utils::{
check_if_file_exists, read_from_file, to_common_result, to_common_success_result,
write_to_file,
},
},
genesis::git::from_yaml,
};
use aptos_crypto::{
ed25519::{Ed25519PrivateKey, Ed25519PublicKey},
Expand Down Expand Up @@ -152,11 +158,9 @@ impl CliConfig {
return Err(CliError::ConfigNotFoundError(format!("{:?}", config_file)));
}

let bytes = std::fs::read(&config_file).map_err(|err| {
CliError::ConfigLoadError(format!("{:?}", config_file), err.to_string())
})?;
serde_yaml::from_slice(&bytes)
.map_err(|err| CliError::ConfigLoadError(format!("{:?}", config_file), err.to_string()))
from_yaml(
&String::from_utf8(read_from_file(config_file.as_path())?).map_err(CliError::from)?,
)
}

pub fn load_profile(profile: &str) -> CliTypedResult<Option<ProfileConfig>> {
Expand Down Expand Up @@ -267,11 +271,7 @@ impl EncodingType {
name: &'static str,
path: &Path,
) -> CliTypedResult<Key> {
let data = std::fs::read(&path).map_err(|err| {
CliError::UnableToReadFile(path.to_str().unwrap().to_string(), err.to_string())
})?;

self.decode_key(name, data)
self.decode_key(name, read_from_file(path)?)
}

/// Decodes an encoded key given the known encoding
Expand Down
5 changes: 5 additions & 0 deletions crates/aptos/src/common/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,11 @@ pub fn prompt_yes_with_override(prompt: &str, prompt_options: PromptOptions) ->
}
}

pub fn read_from_file(path: &Path) -> CliTypedResult<Vec<u8>> {
std::fs::read(path)
.map_err(|e| CliError::UnableToReadFile(format!("{}", path.display()), e.to_string()))
}

/// Write a `&[u8]` to a file
pub fn write_to_file(path: &Path, name: &str, bytes: &[u8]) -> CliTypedResult<()> {
let mut file = File::create(path).map_err(|e| CliError::IO(name.to_string(), e))?;
Expand Down
75 changes: 46 additions & 29 deletions crates/aptos/src/genesis/keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@
// SPDX-License-Identifier: Apache-2.0

use crate::{
common::types::{CliTypedResult, EncodingType},
common::{
types::{CliError, CliTypedResult},
utils::{read_from_file, write_to_file},
},
genesis::{
config::{HostAndPort, ValidatorConfiguration},
git::GitOptions,
git::{from_yaml, to_yaml, GitOptions},
},
op::key,
CliCommand,
Expand All @@ -14,11 +17,11 @@ use aptos_crypto::{ed25519::Ed25519PrivateKey, x25519, PrivateKey};
use aptos_types::transaction::authenticator::AuthenticationKey;
use async_trait::async_trait;
use clap::Parser;
use move_core_types::account_address::AccountAddress;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;

const ACCOUNT_KEY_FILE: &str = "account.key";
const CONSENSUS_KEY_FILE: &str = "consensus.key";
const NETWORK_KEY_FILE: &str = "network.key";
const PRIVATE_KEYS_FILE: &str = "private-keys.yml";

/// Generate account key, consensus key, and network key for a validator
#[derive(Parser)]
Expand All @@ -29,22 +32,43 @@ pub struct GenerateKeys {
}

#[async_trait]
impl CliCommand<Vec<PathBuf>> for GenerateKeys {
impl CliCommand<PathBuf> for GenerateKeys {
fn command_name(&self) -> &'static str {
"GenerateKeys"
}

async fn execute(self) -> CliTypedResult<Vec<PathBuf>> {
let account_key_path = self.output_dir.join(ACCOUNT_KEY_FILE);
let consensus_key_path = self.output_dir.join(CONSENSUS_KEY_FILE);
let network_key_path = self.output_dir.join(NETWORK_KEY_FILE);
let _ = key::GenerateKey::generate_ed25519(EncodingType::Hex, &account_key_path).await?;
let _ = key::GenerateKey::generate_ed25519(EncodingType::Hex, &consensus_key_path).await?;
let _ = key::GenerateKey::generate_x25519(EncodingType::Hex, &network_key_path).await?;
Ok(vec![account_key_path, consensus_key_path, network_key_path])
async fn execute(self) -> CliTypedResult<PathBuf> {
let account_key = key::GenerateKey::generate_ed25519_in_memory();
let consensus_key = key::GenerateKey::generate_ed25519_in_memory();
let network_key = key::GenerateKey::generate_x25519_in_memory()?;
let keys_file = self.output_dir.join(PRIVATE_KEYS_FILE);

let account_address =
AuthenticationKey::ed25519(&account_key.public_key()).derived_address();
let config = KeysAndAccount {
account_address,
account_key,
consensus_key,
network_key,
};

write_to_file(
keys_file.as_path(),
"private_keys.yaml",
to_yaml(&config)?.as_bytes(),
)?;
Ok(keys_file)
}
}

#[derive(Deserialize, Serialize)]
pub struct KeysAndAccount {
account_address: AccountAddress,
account_key: Ed25519PrivateKey,
consensus_key: Ed25519PrivateKey,
network_key: x25519::PrivateKey,
}

/// Set ValidatorConfiguration for a single validator in the git repository
#[derive(Parser)]
pub struct SetValidatorConfiguration {
Expand Down Expand Up @@ -74,21 +98,14 @@ impl CliCommand<()> for SetValidatorConfiguration {
}

async fn execute(self) -> CliTypedResult<()> {
let account_key_path = self.keys_dir.join(ACCOUNT_KEY_FILE);
let consensus_key_path = self.keys_dir.join(CONSENSUS_KEY_FILE);
let network_key_path = self.keys_dir.join(NETWORK_KEY_FILE);
let account_key: Ed25519PrivateKey =
EncodingType::Hex.load_key(ACCOUNT_KEY_FILE, &account_key_path)?;
let consensus_key: Ed25519PrivateKey =
EncodingType::Hex.load_key(CONSENSUS_KEY_FILE, &consensus_key_path)?;
let network_key: x25519::PrivateKey =
EncodingType::Hex.load_key(NETWORK_KEY_FILE, &network_key_path)?;

let account_key = account_key.public_key();
let consensus_key = consensus_key.public_key();
let network_key = network_key.public_key();
let auth_key = AuthenticationKey::ed25519(&account_key);
let account_address = auth_key.derived_address();
let private_keys_path = self.keys_dir.join(PRIVATE_KEYS_FILE);
let bytes = read_from_file(private_keys_path.as_path())?;
let key_files: KeysAndAccount =
from_yaml(&String::from_utf8(bytes).map_err(CliError::from)?)?;
let account_address = key_files.account_address;
let account_key = key_files.account_key.public_key();
let consensus_key = key_files.consensus_key.public_key();
let network_key = key_files.network_key.public_key();

let credentials = ValidatorConfiguration {
account_address,
Expand Down
76 changes: 32 additions & 44 deletions crates/aptos/src/genesis/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use crate::{
use aptos_config::config::{RocksdbConfig, NO_OP_STORAGE_PRUNER_CONFIG};
use aptos_crypto::ed25519::Ed25519PublicKey;
use aptos_temppath::TempPath;
use aptos_types::{chain_id::ChainId, transaction::Transaction, waypoint::Waypoint};
use aptos_types::{chain_id::ChainId, transaction::Transaction};
use aptos_vm::AptosVM;
use aptosdb::AptosDB;
use async_trait::async_trait;
Expand All @@ -29,24 +29,24 @@ use storage_interface::DbReaderWriter;
use vm_genesis::Validator;

const MIN_PRICE_PER_GAS_UNIT: u64 = 1;
const WAYPOINT_FILE: &str = "waypoint.txt";
const GENESIS_FILE: &str = "genesis.blob";

/// Tool for setting up and building the Genesis transaction
///
#[derive(Parser)]
pub enum GenesisTool {
GenerateGenesis(GenerateGenesis),
GenerateKeys(keys::GenerateKeys),
GenerateWaypoint(GenerateWaypoint),
SetupGit(git::SetupGit),
SetValidatorConfiguration(keys::SetValidatorConfiguration),
}

impl GenesisTool {
pub async fn execute(self) -> CliResult {
match self {
GenesisTool::GenerateGenesis(tool) => tool.execute_serialized_success().await,
GenesisTool::GenerateGenesis(tool) => tool.execute_serialized().await,
GenesisTool::GenerateKeys(tool) => tool.execute_serialized().await,
GenesisTool::GenerateWaypoint(tool) => tool.execute_serialized().await,
GenesisTool::SetupGit(tool) => tool.execute_serialized_success().await,
GenesisTool::SetValidatorConfiguration(tool) => tool.execute_serialized_success().await,
}
Expand Down Expand Up @@ -79,23 +79,43 @@ impl GenerateGenesis {
}

#[async_trait]
impl CliCommand<()> for GenerateGenesis {
impl CliCommand<Vec<PathBuf>> for GenerateGenesis {
fn command_name(&self) -> &'static str {
"GenerateGenesis"
}

async fn execute(self) -> CliTypedResult<()> {
let genesis_file = self.output_dir.join("genesis.blob");
async fn execute(self) -> CliTypedResult<Vec<PathBuf>> {
let genesis_file = self.output_dir.join(GENESIS_FILE);
let waypoint_file = self.output_dir.join(WAYPOINT_FILE);
check_if_file_exists(genesis_file.as_path(), self.prompt_options)?;
check_if_file_exists(waypoint_file.as_path(), self.prompt_options)?;

let txn = Self::generate_genesis_txn(self.git_options)?;

// Generate genesis file
let genesis = Self::generate_genesis_txn(self.git_options)?;
write_to_file(
genesis_file.as_path(),
"genesis.blob",
&bcs::to_bytes(&txn).map_err(|e| CliError::BCS("genesis.blob", e))?,
GENESIS_FILE,
&bcs::to_bytes(&genesis).map_err(|e| CliError::BCS(GENESIS_FILE, e))?,
)?;
Ok(())

// Generate waypoint file
let path = TempPath::new();
let aptosdb = AptosDB::open(
&path,
false,
NO_OP_STORAGE_PRUNER_CONFIG,
RocksdbConfig::default(),
)
.map_err(|e| CliError::UnexpectedError(e.to_string()))?;
let db_rw = DbReaderWriter::new(aptosdb);
let waypoint = executor::db_bootstrapper::generate_waypoint::<AptosVM>(&db_rw, &genesis)
.map_err(|e| CliError::UnexpectedError(e.to_string()))?;
write_to_file(
waypoint_file.as_path(),
WAYPOINT_FILE,
waypoint.to_string().as_bytes(),
)?;
Ok(vec![genesis_file, waypoint_file])
}
}

Expand Down Expand Up @@ -127,35 +147,3 @@ pub struct GenesisInfo {
validators: Vec<Validator>,
modules: Vec<Vec<u8>>,
}

/// Generate a Waypoint from the Genesis repository
#[derive(Parser)]
pub struct GenerateWaypoint {
#[clap(flatten)]
prompt_options: PromptOptions,
#[clap(flatten)]
git_options: GitOptions,
}

#[async_trait]
impl CliCommand<Waypoint> for GenerateWaypoint {
fn command_name(&self) -> &'static str {
"GenerateWaypoint"
}

async fn execute(self) -> CliTypedResult<Waypoint> {
let path = TempPath::new();
let aptosdb = AptosDB::open(
&path,
false,
NO_OP_STORAGE_PRUNER_CONFIG,
RocksdbConfig::default(),
)
.map_err(|e| CliError::UnexpectedError(e.to_string()))?;
let db_rw = DbReaderWriter::new(aptosdb);

let genesis = GenerateGenesis::generate_genesis_txn(self.git_options)?;
executor::db_bootstrapper::generate_waypoint::<AptosVM>(&db_rw, &genesis)
.map_err(|e| CliError::UnexpectedError(e.to_string()))
}
}

0 comments on commit 982ff5f

Please sign in to comment.