Skip to content

Commit

Permalink
[aptos-cli] Build genesis transaction
Browse files Browse the repository at this point in the history
  • Loading branch information
gregnazario authored and aptos-bot committed May 5, 2022
1 parent d89edb5 commit cfd2320
Show file tree
Hide file tree
Showing 6 changed files with 169 additions and 23 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/aptos/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ move-stdlib = { git = "https://github.com/move-language/move", rev = "f2e7585b1e
move-vm-runtime = { git = "https://github.com/move-language/move", rev = "f2e7585b1ed5bd2810163d6bdebafe5a388881d3", features=["testing"] }
framework = { path = '../../aptos-move/framework' }
move-table-extension = { git = "https://github.com/move-language/move", rev = "f2e7585b1ed5bd2810163d6bdebafe5a388881d3" }
vm-genesis = { path = "../../aptos-move/vm-genesis" }

[build-dependencies]
shadow-rs = "0.11.0"
76 changes: 72 additions & 4 deletions crates/aptos/src/genesis/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,23 @@ use crate::{
common::types::{CliError, CliTypedResult},
genesis::git::from_yaml,
};
use aptos_config::config::HANDSHAKE_VERSION;
use aptos_crypto::{ed25519::Ed25519PublicKey, x25519};
use aptos_types::{chain_id::ChainId, network_address::DnsName};
use aptos_types::{
chain_id::ChainId,
network_address::{DnsName, NetworkAddress, Protocol},
transaction::authenticator::AuthenticationKey,
};
use serde::{Deserialize, Serialize};
use std::{fs::File, io::Read, path::PathBuf, str::FromStr};
use std::{
convert::TryFrom,
fs::File,
io::Read,
net::{Ipv4Addr, Ipv6Addr},
path::PathBuf,
str::FromStr,
};
use vm_genesis::Validator;

/// Template for setting up Github for Genesis
///
Expand Down Expand Up @@ -39,7 +52,7 @@ impl Layout {

/// A set of configuration needed to add a Validator to genesis
///
#[derive(Debug, Serialize, Deserialize)]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ValidatorConfiguration {
/// Key used for signing in consensus
pub consensus_key: Ed25519PublicKey,
Expand All @@ -53,13 +66,68 @@ pub struct ValidatorConfiguration {
pub full_node_host: Option<HostAndPort>,
}

impl From<ValidatorConfiguration> for Validator {
fn from(config: ValidatorConfiguration) -> Self {
let auth_key = AuthenticationKey::ed25519(&config.account_key);
let validator_addresses = vec![config
.validator_host
.as_network_address(config.network_key)
.unwrap()];
let full_node_addresses = if let Some(full_node_host) = config.full_node_host {
vec![full_node_host
.as_network_address(config.network_key)
.unwrap()]
} else {
vec![]
};

Validator {
address: auth_key.derived_address(),
name: vec![], // TODO: To remove
consensus_pubkey: bcs::to_bytes(&config.consensus_key).unwrap(),
operator_address: auth_key.derived_address(),
operator_name: vec![], // TODO: To remove
network_address: bcs::to_bytes(&validator_addresses).unwrap(),
full_node_network_address: bcs::to_bytes(&full_node_addresses).unwrap(),
operator_auth_key: auth_key,
auth_key,
}
}
}

/// Combined Host (DnsName or IP) and port
#[derive(Debug, Serialize, Deserialize)]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct HostAndPort {
pub host: DnsName,
pub port: u16,
}

impl HostAndPort {
pub fn as_network_address(&self, key: x25519::PublicKey) -> CliTypedResult<NetworkAddress> {
let host = self.host.to_string();

// Since DnsName supports IPs as well, let's properly fix what the type is
let host_protocol = if let Ok(ip) = Ipv4Addr::from_str(&host) {
Protocol::Ip4(ip)
} else if let Ok(ip) = Ipv6Addr::from_str(&host) {
Protocol::Ip6(ip)
} else {
Protocol::Dns(self.host.clone())
};
let port_protocol = Protocol::Tcp(self.port);
let noise_protocol = Protocol::NoiseIK(key);
let handshake_protocol = Protocol::Handshake(HANDSHAKE_VERSION);

NetworkAddress::try_from(vec![
host_protocol,
port_protocol,
noise_protocol,
handshake_protocol,
])
.map_err(|e| CliError::UnexpectedError(e.to_string()))
}
}

impl FromStr for HostAndPort {
type Err = CliError;

Expand Down
54 changes: 50 additions & 4 deletions crates/aptos/src/genesis/git.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ impl GitClient {
match self {
GitClient::Local(local_repository_path) => {
let path = local_repository_path.join(format!("{}.yml", name));
let mut file = std::fs::File::open(path.clone())
let mut file = std::fs::File::open(path.as_path())
.map_err(|e| CliError::IO(path.display().to_string(), e))?;
let mut contents = String::new();
file.read_to_string(&mut contents)
Expand All @@ -161,10 +161,10 @@ impl GitClient {
GitClient::Local(local_repository_path) => {
let path = local_repository_path.join(format!("{}.yml", name));
let mut file = if path.exists() {
std::fs::File::open(path.clone())
std::fs::File::open(path.as_path())
.map_err(|e| CliError::IO(path.display().to_string(), e))?
} else {
std::fs::File::create(path.clone())
std::fs::File::create(path.as_path())
.map_err(|e| CliError::IO(path.display().to_string(), e))?
};

Expand All @@ -186,7 +186,7 @@ impl GitClient {
if path.exists() && path.is_dir() {
// Do nothing
} else {
std::fs::create_dir(path.clone())
std::fs::create_dir(path.as_path())
.map_err(|e| CliError::IO(path.display().to_string(), e))?
};
}
Expand All @@ -197,6 +197,52 @@ impl GitClient {

Ok(())
}

/// Retrieve bytecode Move modules from a module folder
pub fn get_modules(&self, name: &str) -> CliTypedResult<Vec<Vec<u8>>> {
let mut modules = Vec::new();

match self {
GitClient::Local(local_repository_path) => {
let module_folder = local_repository_path.join(name);
if !module_folder.is_dir() {
return Err(CliError::UnexpectedError(format!(
"{} is not a directory!",
module_folder.display()
)));
}

let files = std::fs::read_dir(module_folder.as_path())
.map_err(|e| CliError::IO(module_folder.display().to_string(), e))?;

for maybe_file in files {
let file = maybe_file
.map_err(|e| CliError::UnexpectedError(e.to_string()))?
.path();
let extension = file.extension();

// Only collect move files
if file.is_file() && extension.is_some() && extension.unwrap() == "mv" {
modules.push(
std::fs::read(file.as_path())
.map_err(|e| CliError::IO(file.display().to_string(), e))?,
);
}
}
}
GitClient::Github(client) => {
let files = client.get_directory(name)?;

for file in files {
// Only collect .mv files
if file.ends_with(".mv") {
modules.push(base64::decode(client.get_file(&file)?)?)
}
}
}
}
Ok(modules)
}
}

pub fn to_yaml<T: Serialize + ?Sized>(input: &T) -> CliTypedResult<String> {
Expand Down
7 changes: 4 additions & 3 deletions crates/aptos/src/genesis/keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ const NETWORK_KEY_FILE: &str = "network.key";
/// Generate account key, consensus key, and network key for a validator
#[derive(Parser)]
pub struct GenerateKeys {
#[clap(long, parse(from_os_str))]
/// Output path for the three keys
#[clap(long, parse(from_os_str), default_value = ".")]
output_path: PathBuf,
}

Expand All @@ -43,7 +44,7 @@ impl CliCommand<Vec<PathBuf>> for GenerateKeys {
}
}

/// Upload ValidatorCredentials
/// Set ValidatorConfiguration for a single validator in the git repository
#[derive(Parser)]
pub struct SetValidatorConfiguration {
/// Username
Expand All @@ -52,7 +53,7 @@ pub struct SetValidatorConfiguration {
#[clap(flatten)]
git_options: GitOptions,
/// Path to credentials
#[clap(long, parse(from_os_str), default_value = ".aptos/")]
#[clap(long, parse(from_os_str), default_value = ".")]
credentials_path: PathBuf,
/// Host and port pair for the validator e.g. 127.0.0.1:6180
#[clap(long)]
Expand Down
53 changes: 41 additions & 12 deletions crates/aptos/src/genesis/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,15 @@ use crate::{
CliCommand, CliResult,
};
use aptos_crypto::ed25519::Ed25519PublicKey;
use aptos_types::chain_id::ChainId;
use aptos_types::{
chain_id::ChainId,
on_chain_config::{ConsensusConfigV2, OnChainConsensusConfig, VMPublishingOption},
};
use async_trait::async_trait;
use clap::Parser;
use serde::Serialize;
use vm_genesis::Validator;

const MIN_PRICE_PER_GAS_UNIT: u64 = 1;

/// Tool for setting up and building the Genesis transaction
///
Expand All @@ -40,44 +45,68 @@ impl GenesisTool {
}
}

/// Generate genesis from a git repo
/// Generate genesis from a git repository
#[derive(Parser)]
pub struct GenerateGenesis {
#[clap(flatten)]
github_options: GitOptions,
}

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

async fn execute(self) -> CliTypedResult<GenesisInfo> {
// TODO: Generate genesis, this right now just reads all users
fetch_genesis_info(self.github_options)
async fn execute(self) -> CliTypedResult<()> {
let genesis_info = fetch_genesis_info(self.github_options)?;

let consensus_config = OnChainConsensusConfig::V2(ConsensusConfigV2 {
two_chain: true,
decoupled_execution: true,
back_pressure_limit: 10,
exclude_round: 20,
});

vm_genesis::encode_genesis_transaction(
genesis_info.root_key.clone(),
&genesis_info.validators,
&genesis_info.modules,
Some(VMPublishingOption::open()), // TODO: Remove
consensus_config, // TODO: Remove
genesis_info.chain_id,
MIN_PRICE_PER_GAS_UNIT,
);

Ok(())
}
}

/// Retrieves all information for genesis from the Git repository
pub fn fetch_genesis_info(git_options: GitOptions) -> CliTypedResult<GenesisInfo> {
let client = git_options.get_client()?;
let layout: Layout = client.get(LAYOUT_NAME)?;

let mut configs = Vec::new();
let mut validators = Vec::new();
for user in &layout.users {
configs.push(client.get(user)?);
validators.push(client.get::<ValidatorConfiguration>(user)?.into());
}

let modules = client.get_modules(&layout.modules_folder)?;

Ok(GenesisInfo {
chain_id: layout.chain_id,
root_key: layout.root_key,
participants: configs,
validators,
modules,
})
}

#[derive(Debug, Serialize)]
/// Holder object for all pieces needed to generate a genesis transaction
#[derive(Clone)]
pub struct GenesisInfo {
chain_id: ChainId,
root_key: Ed25519PublicKey,
participants: Vec<ValidatorConfiguration>,
validators: Vec<Validator>,
modules: Vec<Vec<u8>>,
}

0 comments on commit cfd2320

Please sign in to comment.