Externalise Grin command line definition to .yaml file (#2089)
* move command line definition to .yaml file * rustfmt
This commit is contained in:
@@ -16,7 +16,6 @@ mod client;
|
||||
mod config;
|
||||
mod server;
|
||||
mod wallet;
|
||||
mod wallet_args;
|
||||
|
||||
pub use self::client::client_command;
|
||||
pub use self::config::{config_command_server, config_command_wallet};
|
||||
|
||||
+17
-16
@@ -17,10 +17,9 @@ use std::path::PathBuf;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
use super::wallet_args;
|
||||
use config::GlobalWalletConfig;
|
||||
use core::global;
|
||||
use grin_wallet::{self, command, WalletConfig, WalletSeed};
|
||||
use grin_wallet::{self, command, command_args, WalletConfig, WalletSeed};
|
||||
use servers::start_webwallet_server;
|
||||
|
||||
// define what to do on argument error
|
||||
@@ -74,12 +73,14 @@ pub fn wallet_command(wallet_args: &ArgMatches, config: GlobalWalletConfig) -> i
|
||||
wallet_config.check_node_api_http_addr = sa.to_string().clone();
|
||||
}
|
||||
|
||||
let global_wallet_args =
|
||||
arg_parse!(wallet_args::parse_global_args(&wallet_config, &wallet_args));
|
||||
let global_wallet_args = arg_parse!(command_args::parse_global_args(
|
||||
&wallet_config,
|
||||
&wallet_args
|
||||
));
|
||||
|
||||
// closure to instantiate wallet as needed by each subcommand
|
||||
let inst_wallet = || {
|
||||
let res = wallet_args::instantiate_wallet(wallet_config.clone(), &global_wallet_args);
|
||||
let res = command_args::inst_wallet(wallet_config.clone(), &global_wallet_args);
|
||||
res.unwrap_or_else(|e| {
|
||||
println!("{}", e);
|
||||
std::process::exit(0);
|
||||
@@ -88,17 +89,17 @@ pub fn wallet_command(wallet_args: &ArgMatches, config: GlobalWalletConfig) -> i
|
||||
|
||||
let res = match wallet_args.subcommand() {
|
||||
("init", Some(args)) => {
|
||||
let a = arg_parse!(wallet_args::parse_init_args(&wallet_config, &args));
|
||||
let a = arg_parse!(command_args::parse_init_args(&wallet_config, &args));
|
||||
command::init(&global_wallet_args, a)
|
||||
}
|
||||
("recover", Some(args)) => {
|
||||
let a = arg_parse!(wallet_args::parse_recover_args(&global_wallet_args, &args));
|
||||
let a = arg_parse!(command_args::parse_recover_args(&global_wallet_args, &args));
|
||||
command::recover(&wallet_config, a)
|
||||
}
|
||||
("listen", Some(args)) => {
|
||||
let mut c = wallet_config.clone();
|
||||
let mut g = global_wallet_args.clone();
|
||||
arg_parse!(wallet_args::parse_listen_args(&mut c, &mut g, &args));
|
||||
arg_parse!(command_args::parse_listen_args(&mut c, &mut g, &args));
|
||||
command::listen(&wallet_config, &g)
|
||||
}
|
||||
("owner_api", Some(_)) => {
|
||||
@@ -111,23 +112,23 @@ pub fn wallet_command(wallet_args: &ArgMatches, config: GlobalWalletConfig) -> i
|
||||
command::owner_api(inst_wallet(), &global_wallet_args)
|
||||
}
|
||||
("account", Some(args)) => {
|
||||
let a = arg_parse!(wallet_args::parse_account_args(&args));
|
||||
let a = arg_parse!(command_args::parse_account_args(&args));
|
||||
command::account(inst_wallet(), a)
|
||||
}
|
||||
("send", Some(args)) => {
|
||||
let a = arg_parse!(wallet_args::parse_send_args(&args));
|
||||
let a = arg_parse!(command_args::parse_send_args(&args));
|
||||
command::send(inst_wallet(), a)
|
||||
}
|
||||
("receive", Some(args)) => {
|
||||
let a = arg_parse!(wallet_args::parse_receive_args(&args));
|
||||
let a = arg_parse!(command_args::parse_receive_args(&args));
|
||||
command::receive(inst_wallet(), &global_wallet_args, a)
|
||||
}
|
||||
("finalize", Some(args)) => {
|
||||
let a = arg_parse!(wallet_args::parse_finalize_args(&args));
|
||||
let a = arg_parse!(command_args::parse_finalize_args(&args));
|
||||
command::finalize(inst_wallet(), a)
|
||||
}
|
||||
("info", Some(args)) => {
|
||||
let a = arg_parse!(wallet_args::parse_info_args(&args));
|
||||
let a = arg_parse!(command_args::parse_info_args(&args));
|
||||
command::info(
|
||||
inst_wallet(),
|
||||
&global_wallet_args,
|
||||
@@ -141,7 +142,7 @@ pub fn wallet_command(wallet_args: &ArgMatches, config: GlobalWalletConfig) -> i
|
||||
wallet_config.dark_background_color_scheme.unwrap_or(true),
|
||||
),
|
||||
("txs", Some(args)) => {
|
||||
let a = arg_parse!(wallet_args::parse_txs_args(&args));
|
||||
let a = arg_parse!(command_args::parse_txs_args(&args));
|
||||
command::txs(
|
||||
inst_wallet(),
|
||||
&global_wallet_args,
|
||||
@@ -150,11 +151,11 @@ pub fn wallet_command(wallet_args: &ArgMatches, config: GlobalWalletConfig) -> i
|
||||
)
|
||||
}
|
||||
("repost", Some(args)) => {
|
||||
let a = arg_parse!(wallet_args::parse_repost_args(&args));
|
||||
let a = arg_parse!(command_args::parse_repost_args(&args));
|
||||
command::repost(inst_wallet(), a)
|
||||
}
|
||||
("cancel", Some(args)) => {
|
||||
let a = arg_parse!(wallet_args::parse_cancel_args(&args));
|
||||
let a = arg_parse!(command_args::parse_cancel_args(&args));
|
||||
command::cancel(inst_wallet(), a)
|
||||
}
|
||||
("restore", Some(_)) => command::restore(inst_wallet()),
|
||||
|
||||
@@ -1,393 +0,0 @@
|
||||
// Copyright 2018 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/// Argument parsing and error handling for wallet commands
|
||||
use clap::ArgMatches;
|
||||
use failure::Fail;
|
||||
|
||||
use api::TLSConfig;
|
||||
use core::core;
|
||||
use grin_wallet::{self, command, WalletConfig, WalletSeed};
|
||||
use std::path::Path;
|
||||
use util::file::get_first_line;
|
||||
|
||||
/// Simple error definition, just so we can return errors from all commands
|
||||
/// and let the caller figure out what to do
|
||||
#[derive(Clone, Eq, PartialEq, Debug, Fail)]
|
||||
pub enum Error {
|
||||
#[fail(display = "Invalid Arguments: {}", _0)]
|
||||
ArgumentError(String),
|
||||
}
|
||||
|
||||
pub fn prompt_password(password: &Option<String>) -> String {
|
||||
match password {
|
||||
None => {
|
||||
println!("Temporary note:");
|
||||
println!(
|
||||
"If this is your first time running your wallet since BIP32 (word lists) \
|
||||
were implemented, your seed will be converted to \
|
||||
the new format. Please ensure the provided password is correct."
|
||||
);
|
||||
println!("If this goes wrong, your old 'wallet.seed' file has been saved as 'wallet.seed.bak' \
|
||||
Rename this file to back to `wallet.seed` and try again");
|
||||
rpassword::prompt_password_stdout("Password: ").unwrap()
|
||||
}
|
||||
Some(p) => p.to_owned(),
|
||||
}
|
||||
}
|
||||
|
||||
fn prompt_password_confirm() -> String {
|
||||
let first = rpassword::prompt_password_stdout("Password: ").unwrap();
|
||||
let second = rpassword::prompt_password_stdout("Confirm Password: ").unwrap();
|
||||
if first != second {
|
||||
println!("Passwords do not match");
|
||||
std::process::exit(0);
|
||||
}
|
||||
first
|
||||
}
|
||||
|
||||
// instantiate wallet (needed by most functions)
|
||||
|
||||
pub fn instantiate_wallet(
|
||||
config: WalletConfig,
|
||||
g_args: &command::GlobalArgs,
|
||||
) -> Result<command::WalletRef, Error> {
|
||||
let passphrase = prompt_password(&g_args.password);
|
||||
let res = grin_wallet::instantiate_wallet(
|
||||
config.clone(),
|
||||
&passphrase,
|
||||
&g_args.account,
|
||||
g_args.node_api_secret.clone(),
|
||||
);
|
||||
match res {
|
||||
Ok(p) => Ok(p),
|
||||
Err(e) => {
|
||||
let msg = {
|
||||
match e.kind() {
|
||||
grin_wallet::ErrorKind::Encryption => {
|
||||
format!("Error decrypting wallet seed (check provided password)")
|
||||
}
|
||||
_ => format!("Error instantiating wallet: {}", e),
|
||||
}
|
||||
};
|
||||
Err(Error::ArgumentError(msg))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// parses a required value, or throws error with message otherwise
|
||||
fn parse_required<'a>(args: &'a ArgMatches, name: &str) -> Result<&'a str, Error> {
|
||||
let arg = args.value_of(name);
|
||||
match arg {
|
||||
Some(ar) => Ok(ar),
|
||||
None => {
|
||||
let msg = format!("Value for argument '{}' is required in this context", name,);
|
||||
Err(Error::ArgumentError(msg))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// parses a number, or throws error with message otherwise
|
||||
fn parse_u64(arg: &str, name: &str) -> Result<u64, Error> {
|
||||
let val = arg.parse::<u64>();
|
||||
match val {
|
||||
Ok(v) => Ok(v),
|
||||
Err(e) => {
|
||||
let msg = format!("Could not parse {} as a whole number. e={}", name, e);
|
||||
Err(Error::ArgumentError(msg))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_global_args(
|
||||
config: &WalletConfig,
|
||||
args: &ArgMatches,
|
||||
) -> Result<command::GlobalArgs, Error> {
|
||||
let account = parse_required(args, "account")?;
|
||||
let mut show_spent = false;
|
||||
if args.is_present("show_spent") {
|
||||
show_spent = true;
|
||||
}
|
||||
let node_api_secret = get_first_line(config.node_api_secret_path.clone());
|
||||
let password = match args.value_of("pass") {
|
||||
None => None,
|
||||
Some(p) => Some(p.to_owned()),
|
||||
};
|
||||
|
||||
let tls_conf = match config.tls_certificate_file.clone() {
|
||||
None => None,
|
||||
Some(file) => {
|
||||
let key = match config.tls_certificate_key.clone() {
|
||||
Some(k) => k,
|
||||
None => {
|
||||
let msg = format!("Private key for certificate is not set");
|
||||
return Err(Error::ArgumentError(msg));
|
||||
}
|
||||
};
|
||||
Some(TLSConfig::new(file, key))
|
||||
}
|
||||
};
|
||||
|
||||
Ok(command::GlobalArgs {
|
||||
account: account.to_owned(),
|
||||
show_spent: show_spent,
|
||||
node_api_secret: node_api_secret,
|
||||
password: password,
|
||||
tls_conf: tls_conf,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parse_init_args(
|
||||
config: &WalletConfig,
|
||||
args: &ArgMatches,
|
||||
) -> Result<command::InitArgs, Error> {
|
||||
if let Err(e) = WalletSeed::seed_file_exists(config) {
|
||||
let msg = format!("Not creating wallet - {}", e.inner);
|
||||
return Err(Error::ArgumentError(msg));
|
||||
}
|
||||
let list_length = match args.is_present("short_wordlist") {
|
||||
false => 32,
|
||||
true => 16,
|
||||
};
|
||||
println!("Please enter a password for your new wallet");
|
||||
let password = prompt_password_confirm();
|
||||
Ok(command::InitArgs {
|
||||
list_length: list_length,
|
||||
password: password,
|
||||
config: config.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parse_recover_args(
|
||||
g_args: &command::GlobalArgs,
|
||||
args: &ArgMatches,
|
||||
) -> Result<command::RecoverArgs, Error> {
|
||||
let (passphrase, recovery_phrase) = {
|
||||
match args.value_of("recovery_phrase") {
|
||||
None => (prompt_password(&g_args.password), None),
|
||||
Some(l) => {
|
||||
if WalletSeed::from_mnemonic(l).is_err() {
|
||||
let msg = format!("Recovery word phrase is invalid");
|
||||
return Err(Error::ArgumentError(msg));
|
||||
}
|
||||
println!("Please provide a new password for the recovered wallet");
|
||||
(prompt_password_confirm(), Some(l.to_owned()))
|
||||
}
|
||||
}
|
||||
};
|
||||
Ok(command::RecoverArgs {
|
||||
passphrase: passphrase,
|
||||
recovery_phrase: recovery_phrase,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parse_listen_args(
|
||||
config: &mut WalletConfig,
|
||||
g_args: &mut command::GlobalArgs,
|
||||
args: &ArgMatches,
|
||||
) -> Result<(), Error> {
|
||||
// listen args
|
||||
let pass = match args.value_of("pass") {
|
||||
Some(p) => Some(p.to_owned()),
|
||||
None => Some(prompt_password(&None)),
|
||||
};
|
||||
g_args.password = pass;
|
||||
if let Some(port) = args.value_of("port") {
|
||||
config.api_listen_port = port.parse().unwrap();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn parse_account_args(account_args: &ArgMatches) -> Result<command::AccountArgs, Error> {
|
||||
let create = match account_args.value_of("create") {
|
||||
None => None,
|
||||
Some(s) => Some(s.to_owned()),
|
||||
};
|
||||
Ok(command::AccountArgs { create: create })
|
||||
}
|
||||
|
||||
pub fn parse_send_args(args: &ArgMatches) -> Result<command::SendArgs, Error> {
|
||||
// amount
|
||||
let amount = parse_required(args, "amount")?;
|
||||
let amount = core::amount_from_hr_string(amount);
|
||||
let amount = match amount {
|
||||
Ok(a) => a,
|
||||
Err(e) => {
|
||||
let msg = format!(
|
||||
"Could not parse amount as a number with optional decimal point. e={}",
|
||||
e
|
||||
);
|
||||
return Err(Error::ArgumentError(msg));
|
||||
}
|
||||
};
|
||||
|
||||
// message
|
||||
let message = match args.is_present("message") {
|
||||
true => Some(args.value_of("message").unwrap().to_owned()),
|
||||
false => None,
|
||||
};
|
||||
|
||||
// minimum_confirmations
|
||||
let min_c = parse_required(args, "minimum_confirmations")?;
|
||||
let min_c = parse_u64(min_c, "minimum_confirmations")?;
|
||||
|
||||
// selection_strategy
|
||||
let selection_strategy = parse_required(args, "selection_strategy")?;
|
||||
|
||||
// method
|
||||
let method = parse_required(args, "method")?;
|
||||
|
||||
// dest
|
||||
let dest = {
|
||||
if method == "self" {
|
||||
match args.value_of("dest") {
|
||||
Some(d) => d,
|
||||
None => "default",
|
||||
}
|
||||
} else {
|
||||
parse_required(args, "dest")?
|
||||
}
|
||||
};
|
||||
if method == "http" && !dest.starts_with("http://") && !dest.starts_with("https://") {
|
||||
let msg = format!(
|
||||
"HTTP Destination should start with http://: or https://: {}",
|
||||
dest,
|
||||
);
|
||||
return Err(Error::ArgumentError(msg));
|
||||
}
|
||||
|
||||
// change_outputs
|
||||
let change_outputs = parse_required(args, "change_outputs")?;
|
||||
let change_outputs = parse_u64(change_outputs, "change_outputs")? as usize;
|
||||
|
||||
// fluff
|
||||
let fluff = args.is_present("fluff");
|
||||
|
||||
// max_outputs
|
||||
let max_outputs = 500;
|
||||
|
||||
Ok(command::SendArgs {
|
||||
amount: amount,
|
||||
message: message,
|
||||
minimum_confirmations: min_c,
|
||||
selection_strategy: selection_strategy.to_owned(),
|
||||
method: method.to_owned(),
|
||||
dest: dest.to_owned(),
|
||||
change_outputs: change_outputs,
|
||||
fluff: fluff,
|
||||
max_outputs: max_outputs,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parse_receive_args(receive_args: &ArgMatches) -> Result<command::ReceiveArgs, Error> {
|
||||
// message
|
||||
let message = match receive_args.is_present("message") {
|
||||
true => Some(receive_args.value_of("message").unwrap().to_owned()),
|
||||
false => None,
|
||||
};
|
||||
|
||||
// input
|
||||
let tx_file = parse_required(receive_args, "input")?;
|
||||
|
||||
// validate input
|
||||
if !Path::new(&tx_file).is_file() {
|
||||
let msg = format!("File {} not found.", &tx_file);
|
||||
return Err(Error::ArgumentError(msg));
|
||||
}
|
||||
|
||||
Ok(command::ReceiveArgs {
|
||||
input: tx_file.to_owned(),
|
||||
message: message,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parse_finalize_args(args: &ArgMatches) -> Result<command::FinalizeArgs, Error> {
|
||||
let fluff = args.is_present("fluff");
|
||||
let tx_file = parse_required(args, "input")?;
|
||||
|
||||
if !Path::new(&tx_file).is_file() {
|
||||
let msg = format!("File {} not found.", tx_file);
|
||||
return Err(Error::ArgumentError(msg));
|
||||
}
|
||||
Ok(command::FinalizeArgs {
|
||||
input: tx_file.to_owned(),
|
||||
fluff: fluff,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parse_info_args(args: &ArgMatches) -> Result<command::InfoArgs, Error> {
|
||||
// minimum_confirmations
|
||||
let mc = parse_required(args, "minimum_confirmations")?;
|
||||
let mc = parse_u64(mc, "minimum_confirmations")?;
|
||||
Ok(command::InfoArgs {
|
||||
minimum_confirmations: mc,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parse_txs_args(args: &ArgMatches) -> Result<command::TxsArgs, Error> {
|
||||
let tx_id = match args.value_of("id") {
|
||||
None => None,
|
||||
Some(tx) => Some(parse_u64(tx, "id")? as u32),
|
||||
};
|
||||
Ok(command::TxsArgs { id: tx_id })
|
||||
}
|
||||
|
||||
pub fn parse_repost_args(args: &ArgMatches) -> Result<command::RepostArgs, Error> {
|
||||
let tx_id = match args.value_of("id") {
|
||||
None => None,
|
||||
Some(tx) => Some(parse_u64(tx, "id")? as u32),
|
||||
};
|
||||
|
||||
let fluff = args.is_present("fluff");
|
||||
let dump_file = match args.value_of("dumpfile") {
|
||||
None => None,
|
||||
Some(d) => Some(d.to_owned()),
|
||||
};
|
||||
|
||||
Ok(command::RepostArgs {
|
||||
id: tx_id.unwrap(),
|
||||
dump_file: dump_file,
|
||||
fluff: fluff,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parse_cancel_args(args: &ArgMatches) -> Result<command::CancelArgs, Error> {
|
||||
let mut tx_id_string = "";
|
||||
let tx_id = match args.value_of("id") {
|
||||
None => None,
|
||||
Some(tx) => Some(parse_u64(tx, "id")? as u32),
|
||||
};
|
||||
let tx_slate_id = match args.value_of("txid") {
|
||||
None => None,
|
||||
Some(tx) => match tx.parse() {
|
||||
Ok(t) => {
|
||||
tx_id_string = tx;
|
||||
Some(t)
|
||||
}
|
||||
Err(e) => {
|
||||
let msg = format!("Could not parse txid parameter. e={}", e);
|
||||
return Err(Error::ArgumentError(msg));
|
||||
}
|
||||
},
|
||||
};
|
||||
if (tx_id.is_none() && tx_slate_id.is_none()) || (tx_id.is_some() && tx_slate_id.is_some()) {
|
||||
let msg = format!("'id' (-i) or 'txid' (-t) argument is required.");
|
||||
return Err(Error::ArgumentError(msg));
|
||||
}
|
||||
Ok(command::CancelArgs {
|
||||
tx_id: tx_id,
|
||||
tx_slate_id: tx_slate_id,
|
||||
tx_id_string: tx_id_string.to_owned(),
|
||||
})
|
||||
}
|
||||
+3
-302
@@ -26,10 +26,7 @@ extern crate serde_json;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
extern crate failure;
|
||||
extern crate rpassword;
|
||||
extern crate term;
|
||||
#[macro_use]
|
||||
extern crate failure_derive;
|
||||
|
||||
extern crate grin_api as api;
|
||||
extern crate grin_config as config;
|
||||
@@ -45,7 +42,7 @@ pub mod tui;
|
||||
|
||||
use std::process::exit;
|
||||
|
||||
use clap::{App, Arg, SubCommand};
|
||||
use clap::App;
|
||||
|
||||
use config::config::{SERVER_CONFIG_FILE_NAME, WALLET_CONFIG_FILE_NAME};
|
||||
use core::global;
|
||||
@@ -85,304 +82,8 @@ fn main() {
|
||||
}
|
||||
|
||||
fn real_main() -> i32 {
|
||||
let args = App::new("Grin")
|
||||
.version(crate_version!())
|
||||
.author("The Grin Team")
|
||||
.about("Lightweight implementation of the MimbleWimble protocol.")
|
||||
// specification of all the server commands and options
|
||||
.subcommand(SubCommand::with_name("server")
|
||||
.about("Control the Grin server")
|
||||
.arg(Arg::with_name("config_file")
|
||||
.short("c")
|
||||
.long("config_file")
|
||||
.help("Path to a grin-server.toml configuration file")
|
||||
.takes_value(true))
|
||||
.arg(Arg::with_name("port")
|
||||
.short("p")
|
||||
.long("port")
|
||||
.help("Port to start the P2P server on")
|
||||
.takes_value(true))
|
||||
.arg(Arg::with_name("api_port")
|
||||
.short("api")
|
||||
.long("api_port")
|
||||
.help("Port on which to start the api server (e.g. transaction pool api)")
|
||||
.takes_value(true))
|
||||
.arg(Arg::with_name("seed")
|
||||
.short("s")
|
||||
.long("seed")
|
||||
.help("Override seed node(s) to connect to")
|
||||
.takes_value(true))
|
||||
.arg(Arg::with_name("wallet_url")
|
||||
.short("w")
|
||||
.long("wallet_url")
|
||||
.help("The wallet listener to which mining rewards will be sent")
|
||||
.takes_value(true))
|
||||
.subcommand(SubCommand::with_name("config")
|
||||
.about("Generate a configuration grin-server.toml file in the current directory"))
|
||||
.subcommand(SubCommand::with_name("start")
|
||||
.about("Start the Grin server as a daemon"))
|
||||
.subcommand(SubCommand::with_name("stop")
|
||||
.about("Stop the Grin server daemon"))
|
||||
.subcommand(SubCommand::with_name("run")
|
||||
.about("Run the Grin server in this console")))
|
||||
|
||||
// specification of all the client commands and options
|
||||
.subcommand(SubCommand::with_name("client")
|
||||
.about("Communicates with the Grin server")
|
||||
.subcommand(SubCommand::with_name("status")
|
||||
.about("Current status of the Grin chain"))
|
||||
.subcommand(SubCommand::with_name("listconnectedpeers")
|
||||
.about("Print a list of currently connected peers"))
|
||||
.subcommand(SubCommand::with_name("ban")
|
||||
.about("Ban peer")
|
||||
.arg(Arg::with_name("peer")
|
||||
.short("p")
|
||||
.long("peer")
|
||||
.help("Peer ip and port (e.g. 10.12.12.13:13414)")
|
||||
.required(true)
|
||||
.takes_value(true)))
|
||||
.subcommand(SubCommand::with_name("unban")
|
||||
.about("Unban peer")
|
||||
.arg(Arg::with_name("peer")
|
||||
.short("p")
|
||||
.long("peer")
|
||||
.help("Peer ip and port (e.g. 10.12.12.13:13414)")
|
||||
.required(true)
|
||||
.takes_value(true))))
|
||||
|
||||
|
||||
// specification of the wallet commands and options
|
||||
.subcommand(SubCommand::with_name("wallet")
|
||||
.about("Wallet software for Grin")
|
||||
.arg(Arg::with_name("pass")
|
||||
.short("p")
|
||||
.long("pass")
|
||||
.help("Wallet passphrase used to encrypt wallet seed")
|
||||
.takes_value(true))
|
||||
.arg(Arg::with_name("account")
|
||||
.short("a")
|
||||
.long("account")
|
||||
.help("Wallet account to use for this operation")
|
||||
.takes_value(true)
|
||||
.default_value("default"))
|
||||
.arg(Arg::with_name("data_dir")
|
||||
.short("dd")
|
||||
.long("data_dir")
|
||||
.help("Directory in which to store wallet files (defaults to current \
|
||||
directory)")
|
||||
.takes_value(true))
|
||||
.arg(Arg::with_name("external")
|
||||
.short("e")
|
||||
.long("external")
|
||||
.help("Listen on 0.0.0.0 interface to allow external connections (default is 127.0.0.1)")
|
||||
.takes_value(false))
|
||||
.arg(Arg::with_name("show_spent")
|
||||
.short("s")
|
||||
.long("show_spent")
|
||||
.help("Show spent outputs on wallet output command")
|
||||
.takes_value(false))
|
||||
.arg(Arg::with_name("api_server_address")
|
||||
.short("r")
|
||||
.long("api_server_address")
|
||||
.help("Api address of running node on which to check inputs and post transactions")
|
||||
.takes_value(true))
|
||||
|
||||
.subcommand(SubCommand::with_name("account")
|
||||
.about("List wallet accounts or create a new account")
|
||||
.arg(Arg::with_name("create")
|
||||
.short("c")
|
||||
.long("create")
|
||||
.help("Name of new wallet account")
|
||||
.takes_value(true)))
|
||||
|
||||
.subcommand(SubCommand::with_name("listen")
|
||||
.about("Runs the wallet in listening mode waiting for transactions.")
|
||||
.arg(Arg::with_name("port")
|
||||
.short("l")
|
||||
.long("port")
|
||||
.help("Port on which to run the wallet listener")
|
||||
.takes_value(true))
|
||||
.arg(Arg::with_name("method")
|
||||
.short("m")
|
||||
.long("method")
|
||||
.help("Which method to use for communication")
|
||||
.possible_values(&["http", "keybase"])
|
||||
.default_value("http")
|
||||
.takes_value(true)))
|
||||
|
||||
.subcommand(SubCommand::with_name("owner_api")
|
||||
.about("Runs the wallet's local web API."))
|
||||
|
||||
.subcommand(SubCommand::with_name("web")
|
||||
.about("Runs the local web wallet which can be accessed through a browser"))
|
||||
|
||||
.subcommand(SubCommand::with_name("send")
|
||||
.about("Builds a transaction to send coins and sends it to the specified \
|
||||
listener directly.")
|
||||
.arg(Arg::with_name("amount")
|
||||
.help("Number of coins to send with optional fraction, e.g. 12.423")
|
||||
.index(1))
|
||||
.arg(Arg::with_name("minimum_confirmations")
|
||||
.help("Minimum number of confirmations required for an output to be spendable.")
|
||||
.short("c")
|
||||
.long("min_conf")
|
||||
.default_value("10")
|
||||
.takes_value(true))
|
||||
.arg(Arg::with_name("selection_strategy")
|
||||
.help("Coin/Output selection strategy.")
|
||||
.short("s")
|
||||
.long("selection")
|
||||
.possible_values(&["all", "smallest"])
|
||||
.default_value("all")
|
||||
.takes_value(true))
|
||||
.arg(Arg::with_name("change_outputs")
|
||||
.help("Number of change outputs to generate (mainly for testing).")
|
||||
.short("o")
|
||||
.long("change_outputs")
|
||||
.default_value("1")
|
||||
.takes_value(true))
|
||||
.arg(Arg::with_name("method")
|
||||
.help("Method for sending this transaction.")
|
||||
.short("m")
|
||||
.long("method")
|
||||
.possible_values(&["http", "file", "self", "keybase"])
|
||||
.default_value("http")
|
||||
.takes_value(true))
|
||||
.arg(Arg::with_name("dest")
|
||||
.help("Send the transaction to the provided server (start with http://) or save as file.")
|
||||
.short("d")
|
||||
.long("dest")
|
||||
.takes_value(true))
|
||||
.arg(Arg::with_name("fluff")
|
||||
.help("Fluff the transaction (ignore Dandelion relay protocol)")
|
||||
.short("f")
|
||||
.long("fluff"))
|
||||
.arg(Arg::with_name("message")
|
||||
.help("Optional participant message to include")
|
||||
.short("g")
|
||||
.long("message")
|
||||
.takes_value(true))
|
||||
.arg(Arg::with_name("stored_tx")
|
||||
.help("If present, use the previously stored Unconfirmed transaction with given id.")
|
||||
.short("t")
|
||||
.long("stored_tx")
|
||||
.takes_value(true)))
|
||||
|
||||
.subcommand(SubCommand::with_name("receive")
|
||||
.about("Processes a transaction file to accept a transfer from a sender.")
|
||||
.arg(Arg::with_name("message")
|
||||
.help("Optional participant message to include")
|
||||
.short("g")
|
||||
.long("message")
|
||||
.takes_value(true))
|
||||
.arg(Arg::with_name("input")
|
||||
.help("Partial transaction to process, expects the sender's transaction file.")
|
||||
.short("i")
|
||||
.long("input")
|
||||
.takes_value(true)))
|
||||
|
||||
.subcommand(SubCommand::with_name("finalize")
|
||||
.about("Processes a receiver's transaction file to finalize a transfer.")
|
||||
.arg(Arg::with_name("input")
|
||||
.help("Partial transaction to process, expects the receiver's transaction file.")
|
||||
.short("i")
|
||||
.long("input")
|
||||
.takes_value(true))
|
||||
.arg(Arg::with_name("fluff")
|
||||
.help("Fluff the transaction (ignore Dandelion relay protocol)")
|
||||
.short("f")
|
||||
.long("fluff")))
|
||||
|
||||
.subcommand(SubCommand::with_name("burn")
|
||||
.about("** TESTING ONLY ** Burns the provided amount to a known \
|
||||
key. Similar to send but burns an output to allow single-party \
|
||||
transactions.")
|
||||
.arg(Arg::with_name("amount")
|
||||
.help("Number of coins to burn")
|
||||
.index(1))
|
||||
.arg(Arg::with_name("minimum_confirmations")
|
||||
.help("Minimum number of confirmations required for an output to be spendable.")
|
||||
.short("c")
|
||||
.long("min_conf")
|
||||
.default_value("10")
|
||||
.takes_value(true)))
|
||||
|
||||
.subcommand(SubCommand::with_name("outputs")
|
||||
.about("raw wallet output info (list of outputs)"))
|
||||
|
||||
.subcommand(SubCommand::with_name("txs")
|
||||
.about("Display transaction information")
|
||||
.arg(Arg::with_name("id")
|
||||
.help("If specified, display transaction with given ID and all associated Inputs/Outputs")
|
||||
.short("i")
|
||||
.long("id")
|
||||
.takes_value(true)))
|
||||
|
||||
.subcommand(SubCommand::with_name("repost")
|
||||
.about("Reposts a stored, completed but unconfirmed transaction to the chain, or dumps it to a file")
|
||||
.arg(Arg::with_name("id")
|
||||
.help("Transaction ID Containing the stored completed transaction")
|
||||
.short("i")
|
||||
.long("id")
|
||||
.takes_value(true))
|
||||
.arg(Arg::with_name("dumpfile")
|
||||
.help("File name to duMp the tranaction to instead of posting")
|
||||
.short("m")
|
||||
.long("dumpfile")
|
||||
.takes_value(true))
|
||||
.arg(Arg::with_name("fluff")
|
||||
.help("Fluff the transaction (ignore Dandelion relay protocol)")
|
||||
.short("f")
|
||||
.long("fluff")))
|
||||
|
||||
.subcommand(SubCommand::with_name("cancel")
|
||||
.about("Cancels an previously created transaction, freeing previously locked outputs for use again")
|
||||
.arg(Arg::with_name("id")
|
||||
.help("The ID of the transaction to cancel")
|
||||
.short("i")
|
||||
.long("id")
|
||||
.takes_value(true))
|
||||
.arg(Arg::with_name("txid")
|
||||
.help("The TxID of the transaction to cancel")
|
||||
.short("t")
|
||||
.long("txid")
|
||||
.takes_value(true)))
|
||||
|
||||
.subcommand(SubCommand::with_name("info")
|
||||
.about("basic wallet contents summary")
|
||||
.arg(Arg::with_name("minimum_confirmations")
|
||||
.help("Minimum number of confirmations required for an output to be spendable.")
|
||||
.short("c")
|
||||
.long("min_conf")
|
||||
.default_value("10")
|
||||
.takes_value(true)))
|
||||
|
||||
.subcommand(SubCommand::with_name("init")
|
||||
.about("Initialize a new wallet seed file and database.")
|
||||
.arg(Arg::with_name("here")
|
||||
.short("h")
|
||||
.long("here")
|
||||
.help("Create wallet files in the current directory instead of the default ~/.grin directory")
|
||||
.takes_value(false))
|
||||
.arg(Arg::with_name("short_wordlist")
|
||||
.help("Generate a 12 word recovery phrase/seed instead of default 24.")
|
||||
.short("s")
|
||||
.long("short_wordlist")
|
||||
.takes_value(false)))
|
||||
|
||||
.subcommand(SubCommand::with_name("recover")
|
||||
.about("recover (create a new wallet.seed file) from a recovery phrase")
|
||||
.arg(Arg::with_name("recovery_phrase")
|
||||
.help("12 or 24 word recovery phrase (encased in quotes).")
|
||||
.short("p")
|
||||
.long("recovery_phrase")
|
||||
.takes_value(true)))
|
||||
|
||||
.subcommand(SubCommand::with_name("restore")
|
||||
.about("Attempt to restore wallet contents from the chain using seed. \
|
||||
NOTE: Backup wallet.* and run `wallet listen` before running restore.")))
|
||||
|
||||
.get_matches();
|
||||
let yml = load_yaml!("grin.yml");
|
||||
let args = App::from_yaml(yml).get_matches();
|
||||
let mut wallet_config = None;
|
||||
let mut node_config = None;
|
||||
|
||||
|
||||
@@ -0,0 +1,287 @@
|
||||
name: grin
|
||||
version: "0.4.2"
|
||||
about: Lightweight implementation of the MimbleWimble protocol.
|
||||
author: The Grin Team
|
||||
|
||||
subcommands:
|
||||
- server:
|
||||
about: Control the Grin server
|
||||
args:
|
||||
- config_file:
|
||||
help: Path to a grin-server.toml configuration file
|
||||
short: c
|
||||
long: config_file
|
||||
takes_value: true
|
||||
- port:
|
||||
help: Port to start the P2P server on
|
||||
short: p
|
||||
long: port
|
||||
takes_value: true
|
||||
- api_port:
|
||||
help: Port on which to start the api server (e.g. transaction pool api)
|
||||
short: api
|
||||
long: api_port
|
||||
takes_value: true
|
||||
- seed:
|
||||
help: Override seed node(s) to connect to
|
||||
short: s
|
||||
long: seed
|
||||
takes_value: true
|
||||
- wallet_url:
|
||||
help: The wallet listener to which mining rewards will be sent
|
||||
short: w
|
||||
long: wallet_url
|
||||
takes_value: true
|
||||
subcommands:
|
||||
- config:
|
||||
about: Generate a configuration grin-server.toml file in the current directory
|
||||
- start:
|
||||
about: Start the Grin server as a daemon
|
||||
- stop:
|
||||
about: Stop the Grin server daemon
|
||||
- run:
|
||||
about: Run the Grin server in this console
|
||||
- client:
|
||||
about: Communicates with the Grin server
|
||||
subcommands:
|
||||
- status:
|
||||
about: Current status of the Grin chain
|
||||
- listconnectedpeers:
|
||||
about: Print a list of currently connected peers
|
||||
- ban:
|
||||
about: Ban peer
|
||||
args:
|
||||
- peer:
|
||||
help: Peer ip and port (e.g. 10.12.12.13:13414)
|
||||
short: p
|
||||
long: peer
|
||||
required: true
|
||||
takes_value: true
|
||||
- unban:
|
||||
about: Unban peer
|
||||
args:
|
||||
- peer:
|
||||
help: Peer ip and port (e.g. 10.12.12.13:13414)
|
||||
short: p
|
||||
long: peer
|
||||
required: true
|
||||
takes_value: true
|
||||
- wallet:
|
||||
about: Wallet software for Grin
|
||||
args:
|
||||
- pass:
|
||||
help: Wallet passphrase used to encrypt wallet seed
|
||||
short: p
|
||||
long: pass
|
||||
takes_value: true
|
||||
- account:
|
||||
help: Wallet account to use for this operation
|
||||
short: a
|
||||
long: account
|
||||
takes_value: true
|
||||
default_value: default
|
||||
- data_dir:
|
||||
help: Directory in which to store wallet files
|
||||
short: dd
|
||||
long: data_dir
|
||||
takes_value: true
|
||||
- external:
|
||||
help: Listen on 0.0.0.0 interface to allow external connections (default is 127.0.0.1)
|
||||
short: e
|
||||
long: external
|
||||
takes_value: false
|
||||
- show_spent:
|
||||
help: Show spent outputs on wallet output commands
|
||||
short: s
|
||||
long: show_spent
|
||||
takes_value: false
|
||||
- api_server_address:
|
||||
help: Api address of running node on which to check inputs and post transactions
|
||||
short: r
|
||||
long: api_server_address
|
||||
takes_value: true
|
||||
subcommands:
|
||||
- account:
|
||||
about: List wallet accounts or create a new account
|
||||
args:
|
||||
- create:
|
||||
help: Create a new wallet account with provided name
|
||||
short: c
|
||||
long: create
|
||||
takes_value: true
|
||||
- listen:
|
||||
about: Runs the wallet in listening mode waiting for transactions
|
||||
args:
|
||||
- port:
|
||||
help: Port on which to run the wallet listener
|
||||
short: l
|
||||
long: port
|
||||
takes_value: true
|
||||
- method:
|
||||
help: Which method to use for communication
|
||||
short: m
|
||||
long: method
|
||||
possible_values:
|
||||
- http
|
||||
- keybase
|
||||
default_value: http
|
||||
takes_value: true
|
||||
- owner_api:
|
||||
about: Runs the wallet's local web API
|
||||
- web:
|
||||
about: Runs the local web wallet which can be accessed through a browser
|
||||
- send:
|
||||
about: Builds a transaction to send coins and sends to the specified listener directly
|
||||
args:
|
||||
- amount:
|
||||
help: Number of coins to send with optional fraction, e.g. 12.423
|
||||
index: 1
|
||||
- minimum_confirmations:
|
||||
help: Minimum number of confirmations required for an output to be spendable
|
||||
short: c
|
||||
long: min_conf
|
||||
default_value: "10"
|
||||
takes_value: true
|
||||
- selection_strategy:
|
||||
help: Coin/Output selection strategy.
|
||||
short: s
|
||||
long: selection
|
||||
possible_values:
|
||||
- all
|
||||
- smallest
|
||||
default_value: all
|
||||
takes_value: true
|
||||
- change_outputs:
|
||||
help: Number of change outputs to generate (mainly for testing)
|
||||
short: o
|
||||
long: change_outputs
|
||||
default_value: "1"
|
||||
takes_value: true
|
||||
- method:
|
||||
help: Method for sending this transaction
|
||||
short: m
|
||||
long: method
|
||||
possible_values:
|
||||
- http
|
||||
- file
|
||||
- self
|
||||
- keybase
|
||||
default_value: http
|
||||
takes_value: true
|
||||
- dest:
|
||||
help: Send the transaction to the provided server (start with http://) or save as file.
|
||||
short: d
|
||||
long: dest
|
||||
takes_value: true
|
||||
- fluff:
|
||||
help: Fluff the transaction (ignore Dandelion relay protocol)
|
||||
short: f
|
||||
long: fluff
|
||||
- message:
|
||||
help: Optional participant message to include
|
||||
short: g
|
||||
long: message
|
||||
takes_value: true
|
||||
- stored_tx:
|
||||
help: If present, use the previously stored Unconfirmed transaction with given id
|
||||
short: t
|
||||
long: stored_tx
|
||||
takes_value: true
|
||||
- receive:
|
||||
about: Processes a transaction file to accept a transfer from a sender
|
||||
args:
|
||||
- message:
|
||||
help: Optional participant message to include
|
||||
short: g
|
||||
long: message
|
||||
takes_value: true
|
||||
- input:
|
||||
help: Partial transaction to process, expects the sender's transaction file.
|
||||
short: i
|
||||
long: input
|
||||
takes_value: true
|
||||
- finalize:
|
||||
about: Processes a receiver's transaction file to finalize a transfer.
|
||||
args:
|
||||
- input:
|
||||
help: Partial transaction to process, expects the receiver's transaction file.
|
||||
short: i
|
||||
long: input
|
||||
takes_value: true
|
||||
- fluff:
|
||||
help: Fluff the transaction (ignore Dandelion relay protocol)
|
||||
short: f
|
||||
long: fluff
|
||||
- outputs:
|
||||
about: Raw wallet output info (list of outputs)
|
||||
- txs:
|
||||
about: Display transaction information
|
||||
args:
|
||||
- id:
|
||||
help: If specified, display transaction with given Id and all associated Inputs/Outputs
|
||||
short: i
|
||||
long: id
|
||||
takes_value: true
|
||||
- repost:
|
||||
about: Reposts a stored, completed but unconfirmed transaction to the chain, or dumps it to a file
|
||||
args:
|
||||
- id:
|
||||
help: Transaction ID containing the stored completed transaction
|
||||
short: i
|
||||
long: id
|
||||
takes_value: true
|
||||
- dumpfile:
|
||||
help: File name to duMp the transaction to instead of posting
|
||||
short: m
|
||||
long: dumpfile
|
||||
takes_value: true
|
||||
- fluff:
|
||||
help: Fluff the transaction (ignore Dandelion relay protocol)
|
||||
short: f
|
||||
long: fluff
|
||||
- cancel:
|
||||
about: Cancels an previously created transaction, freeing previously locked outputs for use again
|
||||
args:
|
||||
- id:
|
||||
help: The ID of the transaction to cancel
|
||||
short: i
|
||||
long: id
|
||||
takes_value: true
|
||||
- txid:
|
||||
help: The TxID UUID of the transaction to cancel
|
||||
short: t
|
||||
long: txid
|
||||
takes_value: true
|
||||
- info:
|
||||
about: Basic wallet contents summary
|
||||
args:
|
||||
- minimum_confirmations:
|
||||
help: Minimum number of confirmations required for an output to be spendable
|
||||
short: c
|
||||
long: min_conf
|
||||
default_value: "10"
|
||||
takes_value: true
|
||||
- init:
|
||||
about: Initialize a new wallet seed file and database
|
||||
args:
|
||||
- here:
|
||||
help: Create wallet files in the current directory instead of the default ~/.grin directory
|
||||
short: h
|
||||
long: here
|
||||
takes_value: false
|
||||
- short_wordlist:
|
||||
help: Generate a 12-word recovery phrase/seed instead of default 24
|
||||
short: s
|
||||
long: short_wordlist
|
||||
takes_value: false
|
||||
- recover:
|
||||
about: recover (create a new wallet.seed file) from a recovery phrase
|
||||
args:
|
||||
- recovery_phrase:
|
||||
help: 12 or 24 word recovery phrase (encased in quotes).
|
||||
short: p
|
||||
long: recovery_phrase
|
||||
takes_value: true
|
||||
- restore:
|
||||
about: Initialize a new wallet seed file and database
|
||||
|
||||
Reference in New Issue
Block a user