Externalise Grin command line definition to .yaml file (#2089)

* move command line definition to .yaml file

* rustfmt
This commit is contained in:
Yeastplume
2018-12-06 15:25:05 +00:00
committed by GitHub
parent b8c8840cec
commit 40ccb32be2
9 changed files with 327 additions and 326 deletions
-1
View File
@@ -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
View File
@@ -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()),
-393
View File
@@ -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
View File
@@ -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;
+287
View File
@@ -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