Skip to content

Commit

Permalink
[aptos-tool] Build skeleton for aptos tooling
Browse files Browse the repository at this point in the history
This should be a single tool to replace all other tools and be composable
to add new tools easily.

Closes: aptos-labs#257
  • Loading branch information
gregnazario authored and aptos-bot committed Mar 22, 2022
1 parent f69b231 commit 6028e67
Show file tree
Hide file tree
Showing 11 changed files with 480 additions and 0 deletions.
29 changes: 29 additions & 0 deletions Cargo.lock

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

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ members = [
"consensus",
"consensus/consensus-types",
"consensus/safety-rules",
"crates/aptos",
"crates/aptos-bitvec",
"crates/aptos-crypto",
"crates/aptos-crypto-derive",
Expand Down Expand Up @@ -136,6 +137,7 @@ default-members = [
"config/management/operational",
"config/seed-peer-generator",
"consensus/safety-rules",
"crates/aptos",
"crates/aptos-faucet",
"crates/aptos-rate-limiter",
"aptos-move/framework",
Expand Down
36 changes: 36 additions & 0 deletions crates/aptos/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
[package]
name = "aptos"
version = "0.1.0"
authors = ["Aptos Labs <[email protected]>"]
description = "Aptos tool for management of nodes and interacting with blockchain"
repository = "https://github.com/aptos-labs/aptos-core"
homepage = "https://aptoslabs.com"
license = "Apache-2.0"
publish = false
edition = "2018"

[dependencies]
anyhow = "1.0.52"
base64 = "0.13.0"
futures = "0.3.12"
hex = "0.4.3"
itertools = "0.10.0"
rand = "0.8.3"
serde = "1.0.124"
serde_json = "1.0.64"
serde_yaml = "0.8.17"
structopt = "0.3.21"
thiserror = "1.0.24"
tokio = { version = "1.8.1", features = ["full"] }
tokio-util = { version = "0.6.4", features = ["compat"] }
toml = { version = "0.5.8", default-features = false }
url = "2.2.2"

aptos-config = { path = "../../config" }
aptos-crypto = { path = "../aptos-crypto" }
aptos-secure-storage = { path = "../../secure/storage" }
aptos-temppath = { path = "../aptos-temppath" }
aptos-types = { path = "../../types" }
aptos-workspace-hack = { version = "0.1", path = "../aptos-workspace-hack" }
bcs = "0.1.2"
short-hex-str = { path = "../short-hex-str" }
3 changes: 3 additions & 0 deletions crates/aptos/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
### Aptos Tool

`aptos` is designed to be a single interface tool for debugging, development, and node operation.
5 changes: 5 additions & 0 deletions crates/aptos/src/common/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

pub mod types;
pub mod utils;
101 changes: 101 additions & 0 deletions crates/aptos/src/common/types.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use std::{fmt::Debug, str::FromStr};
use structopt::StructOpt;
use thiserror::Error;

/// A common result to be returned to users
pub type CliResult = Result<String, String>;

/// TODO: Re-evaluate these errors
#[derive(Debug, Error)]
pub enum Error {
#[error("Invalid key value found in backend: {0}")]
BackendInvalidKeyValue(String),
#[error("Backend is missing the backend key")]
BackendMissingBackendKey,
#[error("Backend parsing error: {0}")]
BackendParsingError(String),
#[error("Invalid arguments: {0}")]
CommandArgumentError(String),
#[error("Unable to load config: {0}")]
ConfigError(String),
#[error("Error accessing '{0}': {1}")]
IO(String, #[source] std::io::Error),
#[error("Error (de)serializing '{0}': {1}")]
BCS(String, #[source] bcs::Error),
#[error("Unable to decode network address: {0}")]
NetworkAddressDecodeError(String),
#[error("Unable to parse '{0}': error: {1}")]
UnableToParse(&'static str, String),
#[error("Unable to parse file '{0}', error: {1}")]
UnableToParseFile(String, String),
#[error("Unable to read file '{0}', error: {1}")]
UnableToReadFile(String, String),
#[error("Unexpected command, expected {0}, found {1}")]
UnexpectedCommand(String, String),
#[error("Unexpected error: {0}")]
UnexpectedError(String),
#[error("Aborted command")]
AbortedError,
}

/// Types of Keys used by the blockchain
#[derive(Clone, Copy, Debug, StructOpt)]
pub enum KeyType {
Ed25519,
X25519,
}

impl FromStr for KeyType {
type Err = &'static str;

fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_lowercase().as_str() {
"ed25519" => Ok(KeyType::Ed25519),
"x25519" => Ok(KeyType::X25519),
_ => Err("Invalid key type"),
}
}
}

/// Types of encodings used by the blockchain
#[derive(Clone, Copy, Debug, StructOpt)]
pub enum EncodingType {
/// Binary Canonical Serialization
BCS,
/// Hex encoded e.g. 0xABCDE12345
Hex,
/// Base 64 encoded
Base64,
}

impl FromStr for EncodingType {
type Err = &'static str;

fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_lowercase().as_str() {
"hex" => Ok(EncodingType::Hex),
"bcs" => Ok(EncodingType::BCS),
"base64" => Ok(EncodingType::Base64),
_ => Err("Invalid encoding type"),
}
}
}

/// An insertable option for use with prompts.
#[derive(Debug, StructOpt)]
pub struct PromptOptions {
/// Assume yes for all yes/no prompts
#[structopt(long)]
pub assume_yes: bool,
}

/// An insertable option for use with encodings.
#[derive(Debug, StructOpt)]
pub struct EncodingOptions {
/// Encoding of data as `base64`, `bcs`, or `hex`
#[structopt(long, default_value = "hex")]
pub encoding: EncodingType,
}
72 changes: 72 additions & 0 deletions crates/aptos/src/common/utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use crate::{CliResult, Error};
use serde::Serialize;

/// Prompts for confirmation until a yes or no is given explicitly
/// TODO: Capture interrupts
pub fn prompt_yes(prompt: &str) -> bool {
let mut result: Result<bool, ()> = Err(());

// Read input until a yes or a no is given
while result.is_err() {
println!("{} [yes/no] >", prompt);
let mut input = String::new();
if std::io::stdin().read_line(&mut input).is_err() {
continue;
}
result = match input.trim().to_lowercase().as_str() {
"yes" | "y" => Ok(true),
"no" | "n" => Ok(false),
_ => Err(()),
};
}
result.unwrap()
}

/// Convert an empty response to Success
pub fn to_common_success_result(result: Result<(), Error>) -> CliResult {
to_common_result(result.map(|()| "Success"))
}

/// For pretty printing outputs in JSON
pub fn to_common_result<T: Serialize>(result: Result<T, Error>) -> CliResult {
let is_err = result.is_err();
let result: ResultWrapper<T> = result.into();
let string = serde_json::to_string_pretty(&result).unwrap();
if is_err {
Err(string)
} else {
Ok(string)
}
}

/// A result wrapper for displaying either a correct execution result or an error.
///
/// The purpose of this is to have a pretty easy to recognize JSON output format e.g.
///
/// {
/// "Result":{
/// "encoded":{ ... }
/// }
/// }
///
/// {
/// "Error":"Failed to run command"
/// }
///
#[derive(Debug, Serialize)]
enum ResultWrapper<T> {
Result(T),
Error(String),
}

impl<T> From<Result<T, Error>> for ResultWrapper<T> {
fn from(result: Result<T, Error>) -> Self {
match result {
Ok(inner) => ResultWrapper::Result(inner),
Err(inner) => ResultWrapper::Error(inner.to_string()),
}
}
}
26 changes: 26 additions & 0 deletions crates/aptos/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

#![forbid(unsafe_code)]

pub mod common;
pub mod op;

use crate::common::types::{CliResult, Error};
use structopt::StructOpt;

/// CLI tool for interacting with the Aptos blockchain and nodes
///
#[derive(Debug, StructOpt)]
#[structopt(name = "aptos")]
pub enum Tool {
Op(op::OpTool),
}

impl Tool {
pub async fn execute(self) -> CliResult {
match self {
Tool::Op(op_tool) => op_tool.execute().await,
}
}
}
27 changes: 27 additions & 0 deletions crates/aptos/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

//! Aptos is a one stop tool for operations, debugging, and other operations with the blockchain
//!
//! TODO: Examples
//!
#![forbid(unsafe_code)]

use aptos::Tool;
use std::process::exit;
use structopt::StructOpt;

#[tokio::main]
async fn main() {
// Run the corresponding tools
let result = Tool::from_args().execute().await;

// At this point, we'll want to print and determine whether to exit for an error code
match result {
Ok(inner) => println!("{}", inner),
Err(inner) => {
println!("{}", inner);
exit(1);
}
}
}
Loading

0 comments on commit 6028e67

Please sign in to comment.