2018-03-05 22:33:44 +03:00
|
|
|
// Copyright 2018 The Grin Developers
|
2017-04-06 09:41:49 +03:00
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
|
|
|
|
//! Main for building the binary of a Grin peer-to-peer node.
|
|
|
|
|
2017-11-01 02:32:33 +03:00
|
|
|
extern crate blake2_rfc as blake2;
|
2017-04-28 08:07:25 +03:00
|
|
|
extern crate clap;
|
|
|
|
extern crate daemonize;
|
2017-04-25 04:55:01 +03:00
|
|
|
extern crate serde;
|
|
|
|
extern crate serde_json;
|
2017-11-01 02:32:33 +03:00
|
|
|
#[macro_use]
|
|
|
|
extern crate slog;
|
2017-04-25 04:55:01 +03:00
|
|
|
|
2017-05-25 02:08:39 +03:00
|
|
|
extern crate grin_api as api;
|
2017-07-13 20:30:33 +03:00
|
|
|
extern crate grin_config as config;
|
2017-08-09 19:40:23 +03:00
|
|
|
extern crate grin_core as core;
|
2017-11-01 02:32:33 +03:00
|
|
|
extern crate grin_grin as grin;
|
|
|
|
extern crate grin_keychain as keychain;
|
2018-02-03 03:37:35 +03:00
|
|
|
extern crate grin_p2p as p2p;
|
2017-10-12 19:56:44 +03:00
|
|
|
extern crate grin_util as util;
|
2017-11-01 02:32:33 +03:00
|
|
|
extern crate grin_wallet as wallet;
|
2017-04-25 04:55:01 +03:00
|
|
|
|
2017-12-22 21:46:28 +03:00
|
|
|
mod client;
|
|
|
|
|
2017-04-25 04:55:01 +03:00
|
|
|
use std::thread;
|
|
|
|
use std::time::Duration;
|
2017-11-17 14:55:49 +03:00
|
|
|
use std::env::current_dir;
|
2017-04-25 04:55:01 +03:00
|
|
|
|
2017-11-01 02:32:33 +03:00
|
|
|
use clap::{App, Arg, ArgMatches, SubCommand};
|
2017-04-28 08:07:25 +03:00
|
|
|
use daemonize::Daemonize;
|
|
|
|
|
2017-07-26 04:43:17 +03:00
|
|
|
use config::GlobalConfig;
|
2017-08-09 19:40:23 +03:00
|
|
|
use core::global;
|
2017-11-20 22:12:52 +03:00
|
|
|
use core::core::amount_to_hr_string;
|
2017-11-01 02:32:33 +03:00
|
|
|
use util::{init_logger, LoggingConfig, LOGGER};
|
2017-06-16 19:47:29 +03:00
|
|
|
|
2017-07-26 04:43:17 +03:00
|
|
|
fn start_from_config_file(mut global_config: GlobalConfig) {
|
|
|
|
info!(
|
2017-10-12 19:56:44 +03:00
|
|
|
LOGGER,
|
2017-07-26 04:43:17 +03:00
|
|
|
"Starting the Grin server from configuration file at {}",
|
|
|
|
global_config.config_file_path.unwrap().to_str().unwrap()
|
|
|
|
);
|
2017-08-09 19:40:23 +03:00
|
|
|
|
2017-09-05 04:34:24 +03:00
|
|
|
global::set_mining_mode(
|
|
|
|
global_config
|
|
|
|
.members
|
|
|
|
.as_mut()
|
|
|
|
.unwrap()
|
|
|
|
.server
|
|
|
|
.clone()
|
2017-11-16 01:30:48 +03:00
|
|
|
.chain_type,
|
2017-09-05 04:34:24 +03:00
|
|
|
);
|
2017-08-09 19:40:23 +03:00
|
|
|
|
2017-07-13 20:30:33 +03:00
|
|
|
grin::Server::start(global_config.members.as_mut().unwrap().server.clone()).unwrap();
|
|
|
|
loop {
|
|
|
|
thread::sleep(Duration::from_secs(60));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-06 09:41:49 +03:00
|
|
|
fn main() {
|
2017-09-05 04:34:24 +03:00
|
|
|
// First, load a global config object,
|
2017-12-21 01:16:40 +03:00
|
|
|
// then modify that object with any switches
|
|
|
|
// found so that the switches override the
|
|
|
|
// global config file
|
2017-09-05 04:34:24 +03:00
|
|
|
|
|
|
|
// This will return a global config object,
|
2017-12-21 01:16:40 +03:00
|
|
|
// which will either contain defaults for all // of the config structures or a
|
|
|
|
// configuration
|
|
|
|
// read from a config file
|
2017-09-05 04:34:24 +03:00
|
|
|
|
|
|
|
let mut global_config = GlobalConfig::new(None).unwrap_or_else(|e| {
|
|
|
|
panic!("Error parsing config file: {}", e);
|
|
|
|
});
|
|
|
|
|
|
|
|
if global_config.using_config_file {
|
2017-10-13 07:45:07 +03:00
|
|
|
// initialise the logger
|
2017-10-12 19:56:44 +03:00
|
|
|
init_logger(global_config.members.as_mut().unwrap().logging.clone());
|
2017-09-05 04:34:24 +03:00
|
|
|
info!(
|
2017-10-12 19:56:44 +03:00
|
|
|
LOGGER,
|
2017-09-05 04:34:24 +03:00
|
|
|
"Using configuration file at: {}",
|
|
|
|
global_config
|
|
|
|
.config_file_path
|
|
|
|
.clone()
|
|
|
|
.unwrap()
|
|
|
|
.to_str()
|
|
|
|
.unwrap()
|
|
|
|
);
|
|
|
|
global::set_mining_mode(
|
|
|
|
global_config
|
|
|
|
.members
|
|
|
|
.as_mut()
|
|
|
|
.unwrap()
|
|
|
|
.server
|
|
|
|
.clone()
|
2017-11-16 01:30:48 +03:00
|
|
|
.chain_type,
|
2017-09-05 04:34:24 +03:00
|
|
|
);
|
2017-10-17 00:23:10 +03:00
|
|
|
} else {
|
|
|
|
init_logger(Some(LoggingConfig::default()));
|
2017-09-05 04:34:24 +03:00
|
|
|
}
|
|
|
|
|
2017-06-01 00:44:44 +03:00
|
|
|
let args = App::new("Grin")
|
2017-09-24 07:40:31 +03:00
|
|
|
.version("0.1")
|
|
|
|
.author("The Grin Team")
|
|
|
|
.about("Lightweight implementation of the MimbleWimble protocol.")
|
2017-04-25 04:55:01 +03:00
|
|
|
|
2017-04-28 08:07:25 +03:00
|
|
|
// specification of all the server commands and options
|
|
|
|
.subcommand(SubCommand::with_name("server")
|
|
|
|
.about("Control the Grin server")
|
|
|
|
.arg(Arg::with_name("port")
|
|
|
|
.short("p")
|
|
|
|
.long("port")
|
2017-06-27 05:09:01 +03:00
|
|
|
.help("Port to start the P2P server on")
|
|
|
|
.takes_value(true))
|
2017-09-05 04:34:24 +03:00
|
|
|
.arg(Arg::with_name("api_port")
|
2017-06-27 05:09:01 +03:00
|
|
|
.short("a")
|
|
|
|
.long("api_port")
|
|
|
|
.help("Port on which to start the api server (e.g. transaction pool api)")
|
2017-04-28 08:07:25 +03:00
|
|
|
.takes_value(true))
|
|
|
|
.arg(Arg::with_name("seed")
|
|
|
|
.short("s")
|
|
|
|
.long("seed")
|
|
|
|
.help("Override seed node(s) to connect to")
|
2017-11-02 02:00:28 +03:00
|
|
|
.takes_value(true))
|
2017-04-28 08:07:25 +03:00
|
|
|
.arg(Arg::with_name("mine")
|
|
|
|
.short("m")
|
|
|
|
.long("mine")
|
|
|
|
.help("Starts the debugging mining loop"))
|
2017-09-05 04:34:24 +03:00
|
|
|
.arg(Arg::with_name("wallet_url")
|
2017-06-16 19:47:29 +03:00
|
|
|
.short("w")
|
|
|
|
.long("wallet_url")
|
2017-11-19 09:50:01 +03:00
|
|
|
.help("The wallet listener to which mining rewards will be sent")
|
2018-01-16 04:44:03 +03:00
|
|
|
.takes_value(true))
|
2017-04-28 08:07:25 +03:00
|
|
|
.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")
|
2018-02-03 03:37:35 +03:00
|
|
|
.about("Current status of the Grin chain"))
|
|
|
|
.subcommand(SubCommand::with_name("listconnectedpeers")
|
|
|
|
.about("Print a list of currently connected peers"))
|
2018-01-16 04:44:03 +03:00
|
|
|
.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)")
|
|
|
|
.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)")
|
|
|
|
.takes_value(true))))
|
|
|
|
|
2017-05-25 02:08:39 +03:00
|
|
|
|
2017-09-24 07:40:31 +03:00
|
|
|
// 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 generate the private key seed")
|
2017-10-24 20:34:34 +03:00
|
|
|
.takes_value(true)
|
|
|
|
.default_value("mimblewimble"))
|
2017-09-24 07:40:31 +03:00
|
|
|
.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))
|
2017-11-02 23:19:22 +03:00
|
|
|
.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))
|
2017-11-14 19:13:58 +03:00
|
|
|
.arg(Arg::with_name("show_spent")
|
|
|
|
.short("s")
|
|
|
|
.long("show_spent")
|
|
|
|
.help("Show spent outputs on wallet output command")
|
|
|
|
.takes_value(false))
|
2017-09-24 07:40:31 +03:00
|
|
|
.arg(Arg::with_name("api_server_address")
|
|
|
|
.short("a")
|
|
|
|
.long("api_server_address")
|
|
|
|
.help("Api address of running node on which to check inputs and post transactions")
|
|
|
|
.takes_value(true))
|
2017-11-20 03:50:09 +03:00
|
|
|
.arg(Arg::with_name("key_derivations")
|
|
|
|
.help("The number of keys possiblities to search for each output. \
|
|
|
|
Ideally, set this to a number greater than the number of outputs \
|
2018-01-23 21:37:56 +03:00
|
|
|
you believe should belong to this seed/password.")
|
2017-11-20 03:50:09 +03:00
|
|
|
.short("k")
|
|
|
|
.long("key_derivations")
|
|
|
|
.default_value("1000")
|
|
|
|
.takes_value(true))
|
2017-12-19 04:33:27 +03:00
|
|
|
|
2017-11-19 09:50:01 +03:00
|
|
|
.subcommand(SubCommand::with_name("listen")
|
2017-11-29 05:26:53 +03:00
|
|
|
.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)))
|
2017-12-19 04:33:27 +03:00
|
|
|
|
2017-11-29 05:26:53 +03:00
|
|
|
.subcommand(SubCommand::with_name("receive")
|
|
|
|
.about("Processes a JSON transaction file.")
|
2017-09-24 07:40:31 +03:00
|
|
|
.arg(Arg::with_name("input")
|
2017-11-29 05:26:53 +03:00
|
|
|
.help("Partial transaction to process, expects a JSON file.")
|
2017-09-24 07:40:31 +03:00
|
|
|
.short("i")
|
|
|
|
.long("input")
|
|
|
|
.takes_value(true)))
|
2017-12-19 04:33:27 +03:00
|
|
|
|
2017-09-24 07:40:31 +03:00
|
|
|
.subcommand(SubCommand::with_name("send")
|
2018-01-10 22:36:27 +03:00
|
|
|
.about("Builds a transaction to send coins and sends it to the specified \
|
|
|
|
listener directly.")
|
2017-09-24 07:40:31 +03:00
|
|
|
.arg(Arg::with_name("amount")
|
2017-11-08 00:20:36 +03:00
|
|
|
.help("Number of coins to send with optional fraction, e.g. 12.423")
|
2017-09-24 07:40:31 +03:00
|
|
|
.index(1))
|
2017-10-18 23:47:37 +03:00
|
|
|
.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("1")
|
|
|
|
.takes_value(true))
|
2017-11-10 22:33:36 +03:00
|
|
|
.arg(Arg::with_name("selection_strategy")
|
|
|
|
.help("Coin/Output selection strategy.")
|
|
|
|
.short("s")
|
|
|
|
.long("selection")
|
2017-11-15 02:54:28 +03:00
|
|
|
.possible_values(&["all", "smallest"])
|
|
|
|
.default_value("all")
|
2017-11-10 22:33:36 +03:00
|
|
|
.takes_value(true))
|
2017-09-24 07:40:31 +03:00
|
|
|
.arg(Arg::with_name("dest")
|
|
|
|
.help("Send the transaction to the provided server")
|
|
|
|
.short("d")
|
|
|
|
.long("dest")
|
|
|
|
.takes_value(true)))
|
|
|
|
|
2017-10-12 06:35:40 +03:00
|
|
|
.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")
|
2017-11-08 00:20:36 +03:00
|
|
|
.help("Number of coins to burn")
|
2017-10-18 23:47:37 +03:00
|
|
|
.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("1")
|
|
|
|
.takes_value(true)))
|
2017-10-12 06:35:40 +03:00
|
|
|
|
2017-11-10 17:03:31 +03:00
|
|
|
.subcommand(SubCommand::with_name("outputs")
|
|
|
|
.about("raw wallet info (list of outputs)"))
|
|
|
|
|
2017-09-24 07:40:31 +03:00
|
|
|
.subcommand(SubCommand::with_name("info")
|
2017-11-10 17:03:31 +03:00
|
|
|
.about("basic wallet contents summary"))
|
2017-10-24 20:34:34 +03:00
|
|
|
|
|
|
|
.subcommand(SubCommand::with_name("init")
|
2017-11-20 03:50:09 +03:00
|
|
|
.about("Initialize a new wallet seed file."))
|
2017-09-24 07:40:31 +03:00
|
|
|
|
2017-11-20 03:50:09 +03:00
|
|
|
.subcommand(SubCommand::with_name("restore")
|
2018-01-12 23:08:18 +03:00
|
|
|
.about("Attempt to restore wallet contents from the chain using seed and password. \
|
|
|
|
NOTE: Backup wallet.* and run `wallet listen` before running restore.")))
|
2017-11-20 22:12:52 +03:00
|
|
|
|
2017-09-24 07:40:31 +03:00
|
|
|
.get_matches();
|
2017-04-28 08:07:25 +03:00
|
|
|
|
2017-06-01 00:44:44 +03:00
|
|
|
match args.subcommand() {
|
|
|
|
// server commands and options
|
|
|
|
("server", Some(server_args)) => {
|
2017-09-05 04:34:24 +03:00
|
|
|
server_command(server_args, global_config);
|
2017-06-01 00:44:44 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// client commands and options
|
2017-12-21 01:16:40 +03:00
|
|
|
("client", Some(client_args)) => {
|
2017-12-22 21:46:28 +03:00
|
|
|
client_command(client_args, global_config);
|
2017-12-21 01:16:40 +03:00
|
|
|
}
|
2017-06-01 00:44:44 +03:00
|
|
|
|
|
|
|
// client commands and options
|
|
|
|
("wallet", Some(wallet_args)) => {
|
2017-12-07 22:04:17 +03:00
|
|
|
wallet_command(wallet_args, global_config);
|
2017-06-01 00:44:44 +03:00
|
|
|
}
|
|
|
|
|
2017-09-05 04:34:24 +03:00
|
|
|
// If nothing is specified, try to just use the config file instead
|
|
|
|
// this could possibly become the way to configure most things
|
2017-07-26 04:43:17 +03:00
|
|
|
// with most command line options being phased out
|
2017-07-13 20:30:33 +03:00
|
|
|
_ => {
|
2017-09-05 04:34:24 +03:00
|
|
|
if global_config.using_config_file {
|
|
|
|
start_from_config_file(global_config);
|
|
|
|
} else {
|
|
|
|
// won't attempt to just start with defaults,
|
2017-12-21 01:16:40 +03:00
|
|
|
// and will reject
|
2017-09-05 04:34:24 +03:00
|
|
|
println!("Unknown command, and no configuration file was found.");
|
|
|
|
println!("Use 'grin help' for a list of all commands.");
|
2017-07-26 04:43:17 +03:00
|
|
|
}
|
2017-07-13 20:30:33 +03:00
|
|
|
}
|
2017-06-01 00:44:44 +03:00
|
|
|
}
|
2017-04-28 08:07:25 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Handles the server part of the command line, mostly running, starting and
|
2017-06-01 00:44:44 +03:00
|
|
|
/// stopping the Grin blockchain server. Processes all the command line
|
|
|
|
/// arguments
|
2017-04-28 08:07:25 +03:00
|
|
|
/// to build a proper configuration and runs Grin with that configuration.
|
2017-09-05 04:34:24 +03:00
|
|
|
fn server_command(server_args: &ArgMatches, global_config: GlobalConfig) {
|
2017-10-12 19:56:44 +03:00
|
|
|
info!(LOGGER, "Starting the Grin server...");
|
2017-06-01 00:44:44 +03:00
|
|
|
|
2017-07-13 20:30:33 +03:00
|
|
|
// just get defaults from the global config
|
2017-09-05 04:34:24 +03:00
|
|
|
let mut server_config = global_config.members.unwrap().server;
|
2017-07-13 20:30:33 +03:00
|
|
|
|
2017-06-01 00:44:44 +03:00
|
|
|
if let Some(port) = server_args.value_of("port") {
|
2018-01-31 00:44:13 +03:00
|
|
|
server_config.p2p_config.port = port.parse().unwrap();
|
2017-06-01 00:44:44 +03:00
|
|
|
}
|
2017-07-26 04:43:17 +03:00
|
|
|
|
2017-06-27 05:09:01 +03:00
|
|
|
if let Some(api_port) = server_args.value_of("api_port") {
|
2017-10-23 19:34:43 +03:00
|
|
|
let default_ip = "0.0.0.0";
|
2017-06-27 05:09:01 +03:00
|
|
|
server_config.api_http_addr = format!("{}:{}", default_ip, api_port);
|
|
|
|
}
|
|
|
|
|
2017-06-01 00:44:44 +03:00
|
|
|
if server_args.is_present("mine") {
|
2017-07-13 20:30:33 +03:00
|
|
|
server_config.mining_config.as_mut().unwrap().enable_mining = true;
|
2017-06-01 00:44:44 +03:00
|
|
|
}
|
2017-07-26 04:43:17 +03:00
|
|
|
|
2017-06-16 19:47:29 +03:00
|
|
|
if let Some(wallet_url) = server_args.value_of("wallet_url") {
|
2017-07-26 04:43:17 +03:00
|
|
|
server_config
|
|
|
|
.mining_config
|
|
|
|
.as_mut()
|
|
|
|
.unwrap()
|
2017-11-19 09:50:01 +03:00
|
|
|
.wallet_listener_url = wallet_url.to_string();
|
2017-06-16 19:47:29 +03:00
|
|
|
}
|
|
|
|
|
2017-06-01 00:44:44 +03:00
|
|
|
if let Some(seeds) = server_args.values_of("seed") {
|
2017-07-13 20:30:33 +03:00
|
|
|
server_config.seeding_type = grin::Seeding::List;
|
|
|
|
server_config.seeds = Some(seeds.map(|s| s.to_string()).collect());
|
2017-06-01 00:44:44 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// start the server in the different run modes (interactive or daemon)
|
|
|
|
match server_args.subcommand() {
|
|
|
|
("run", _) => {
|
|
|
|
grin::Server::start(server_config).unwrap();
|
|
|
|
}
|
|
|
|
("start", _) => {
|
|
|
|
let daemonize = Daemonize::new()
|
|
|
|
.pid_file("/tmp/grin.pid")
|
|
|
|
.chown_pid_file(true)
|
2017-11-17 14:55:49 +03:00
|
|
|
.working_directory(current_dir().unwrap())
|
2017-06-01 00:44:44 +03:00
|
|
|
.privileged_action(move || {
|
|
|
|
grin::Server::start(server_config.clone()).unwrap();
|
|
|
|
loop {
|
|
|
|
thread::sleep(Duration::from_secs(60));
|
|
|
|
}
|
|
|
|
});
|
|
|
|
match daemonize.start() {
|
2017-12-12 07:56:48 +03:00
|
|
|
Ok(_) => info!(LOGGER, "Grin server successfully started."),
|
2017-10-12 19:56:44 +03:00
|
|
|
Err(e) => error!(LOGGER, "Error starting: {}", e),
|
2017-06-01 00:44:44 +03:00
|
|
|
}
|
|
|
|
}
|
2017-12-12 07:56:48 +03:00
|
|
|
("stop", _) => println!("TODO. Just 'kill $pid' for now. Maybe /tmp/grin.pid is $pid"),
|
2017-11-02 02:00:28 +03:00
|
|
|
(cmd, _) => {
|
2017-12-12 07:56:48 +03:00
|
|
|
println!(":: {:?}", server_args);
|
|
|
|
panic!(
|
|
|
|
"Unknown server command '{}', use 'grin help server' for details",
|
|
|
|
cmd
|
|
|
|
);
|
|
|
|
}
|
2017-06-01 00:44:44 +03:00
|
|
|
}
|
2017-04-25 04:55:01 +03:00
|
|
|
}
|
|
|
|
|
2017-12-22 21:46:28 +03:00
|
|
|
fn client_command(client_args: &ArgMatches, global_config: GlobalConfig) {
|
|
|
|
// just get defaults from the global config
|
|
|
|
let server_config = global_config.members.unwrap().server;
|
|
|
|
|
|
|
|
match client_args.subcommand() {
|
|
|
|
("status", Some(_)) => {
|
|
|
|
client::show_status(&server_config);
|
|
|
|
}
|
2018-02-03 03:37:35 +03:00
|
|
|
("listconnectedpeers", Some(_)) => {
|
|
|
|
client::list_connected_peers(&server_config);
|
|
|
|
}
|
2018-01-16 04:44:03 +03:00
|
|
|
("ban", Some(peer_args)) => {
|
|
|
|
if let Some(peer) = peer_args.value_of("peer") {
|
|
|
|
if let Ok(addr) = peer.parse() {
|
|
|
|
client::ban_peer(&server_config, &addr);
|
|
|
|
} else {
|
|
|
|
panic!("Invalid peer address format");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
("unban", Some(peer_args)) => {
|
|
|
|
if let Some(peer) = peer_args.value_of("peer") {
|
|
|
|
if let Ok(addr) = peer.parse() {
|
|
|
|
client::unban_peer(&server_config, &addr);
|
|
|
|
} else {
|
|
|
|
panic!("Invalid peer address format");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-12-22 21:46:28 +03:00
|
|
|
_ => panic!("Unknown client command, use 'grin help client' for details"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-07 22:04:17 +03:00
|
|
|
fn wallet_command(wallet_args: &ArgMatches, global_config: GlobalConfig) {
|
|
|
|
// just get defaults from the global config
|
|
|
|
let mut wallet_config = global_config.members.unwrap().wallet;
|
2017-10-24 20:34:34 +03:00
|
|
|
|
2017-11-02 23:19:22 +03:00
|
|
|
if wallet_args.is_present("external") {
|
|
|
|
wallet_config.api_listen_interface = "0.0.0.0".to_string();
|
2017-06-16 19:47:29 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(dir) = wallet_args.value_of("dir") {
|
|
|
|
wallet_config.data_file_dir = dir.to_string().clone();
|
|
|
|
}
|
2017-06-27 05:09:01 +03:00
|
|
|
|
|
|
|
if let Some(sa) = wallet_args.value_of("api_server_address") {
|
|
|
|
wallet_config.check_node_api_http_addr = sa.to_string().clone();
|
|
|
|
}
|
|
|
|
|
2018-03-04 03:19:54 +03:00
|
|
|
let key_derivations: u32 = wallet_args
|
|
|
|
.value_of("key_derivations")
|
|
|
|
.unwrap()
|
|
|
|
.parse()
|
|
|
|
.unwrap();
|
2017-11-20 03:50:09 +03:00
|
|
|
|
2017-12-21 01:16:40 +03:00
|
|
|
let mut show_spent = false;
|
2017-11-14 19:13:58 +03:00
|
|
|
if wallet_args.is_present("show_spent") {
|
2017-12-21 01:16:40 +03:00
|
|
|
show_spent = true;
|
2017-11-14 19:13:58 +03:00
|
|
|
}
|
|
|
|
|
2017-10-24 20:34:34 +03:00
|
|
|
// Derive the keychain based on seed from seed file and specified passphrase.
|
2017-11-02 23:19:22 +03:00
|
|
|
// Generate the initial wallet seed if we are running "wallet init".
|
2017-10-24 20:34:34 +03:00
|
|
|
if let ("init", Some(_)) = wallet_args.subcommand() {
|
2017-11-01 02:32:33 +03:00
|
|
|
wallet::WalletSeed::init_file(&wallet_config).expect("Failed to init wallet seed file.");
|
2017-10-24 20:34:34 +03:00
|
|
|
|
|
|
|
// we are done here with creating the wallet, so just return
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-11-01 02:32:33 +03:00
|
|
|
let wallet_seed =
|
|
|
|
wallet::WalletSeed::from_file(&wallet_config).expect("Failed to read wallet seed file.");
|
2018-01-16 04:44:03 +03:00
|
|
|
let passphrase = wallet_args
|
|
|
|
.value_of("pass")
|
|
|
|
.expect("Failed to read passphrase.");
|
|
|
|
let mut keychain = wallet_seed
|
|
|
|
.derive_keychain(&passphrase)
|
|
|
|
.expect("Failed to derive keychain from seed file and passphrase.");
|
2017-07-04 02:46:25 +03:00
|
|
|
|
2017-10-24 20:34:34 +03:00
|
|
|
match wallet_args.subcommand() {
|
2017-11-29 05:26:53 +03:00
|
|
|
("listen", Some(listen_args)) => {
|
|
|
|
if let Some(port) = listen_args.value_of("port") {
|
|
|
|
wallet_config.api_listen_port = port.to_string();
|
|
|
|
}
|
|
|
|
wallet::server::start_rest_apis(wallet_config, keychain);
|
2017-12-21 01:16:40 +03:00
|
|
|
}
|
2018-01-10 22:36:27 +03:00
|
|
|
// The following is gone for now, as a result of aggsig transactions
|
|
|
|
// being implemented
|
|
|
|
/*("receive", Some(receive_args)) => {
|
2017-12-21 01:16:40 +03:00
|
|
|
let input = receive_args.value_of("input").expect("Input file required");
|
|
|
|
let mut file = File::open(input).expect("Unable to open transaction file.");
|
2017-11-01 02:32:33 +03:00
|
|
|
let mut contents = String::new();
|
2017-12-21 01:16:40 +03:00
|
|
|
file.read_to_string(&mut contents).expect(
|
|
|
|
"Unable to read transaction file.",
|
|
|
|
);
|
2018-01-07 02:27:21 +03:00
|
|
|
if let Err(e) =
|
|
|
|
wallet::receive_json_tx_str(
|
|
|
|
&wallet_config, &keychain, contents.as_str()) {
|
|
|
|
|
|
|
|
println!("Error receiving transaction, the most likely reasons are:");
|
|
|
|
println!(" * the transaction has already been sent");
|
|
|
|
println!(" * your node isn't running or can't be reached");
|
|
|
|
println!("\nDetailed error: {:?}", e);
|
|
|
|
}
|
2018-01-10 22:36:27 +03:00
|
|
|
}*/
|
2017-06-01 00:44:44 +03:00
|
|
|
("send", Some(send_args)) => {
|
2018-01-16 04:44:03 +03:00
|
|
|
let amount = send_args
|
|
|
|
.value_of("amount")
|
|
|
|
.expect("Amount to send required");
|
|
|
|
let amount = core::core::amount_from_hr_string(amount)
|
|
|
|
.expect("Could not parse amount as a number with optional decimal point.");
|
|
|
|
let minimum_confirmations: u64 = send_args
|
|
|
|
.value_of("minimum_confirmations")
|
|
|
|
.unwrap()
|
|
|
|
.parse()
|
|
|
|
.expect("Could not parse minimum_confirmations as a whole number.");
|
|
|
|
let selection_strategy = send_args
|
|
|
|
.value_of("selection_strategy")
|
|
|
|
.expect("Selection strategy required");
|
|
|
|
let dest = send_args
|
|
|
|
.value_of("dest")
|
|
|
|
.expect("Destination wallet address required");
|
2017-11-15 21:56:35 +03:00
|
|
|
let max_outputs = 500;
|
2017-12-21 01:16:40 +03:00
|
|
|
let result = wallet::issue_send_tx(
|
2017-10-18 23:47:37 +03:00
|
|
|
&wallet_config,
|
2018-01-10 22:36:27 +03:00
|
|
|
&mut keychain,
|
2017-10-18 23:47:37 +03:00
|
|
|
amount,
|
|
|
|
minimum_confirmations,
|
2017-10-22 10:11:45 +03:00
|
|
|
dest.to_string(),
|
2017-11-15 21:56:35 +03:00
|
|
|
max_outputs,
|
2018-01-28 09:12:33 +03:00
|
|
|
selection_strategy == "all",
|
2017-11-08 00:20:36 +03:00
|
|
|
);
|
|
|
|
match result {
|
2018-01-16 04:44:03 +03:00
|
|
|
Ok(_) => info!(
|
|
|
|
LOGGER,
|
|
|
|
"Tx sent: {} grin to {} (strategy '{}')",
|
|
|
|
amount_to_hr_string(amount),
|
|
|
|
dest,
|
|
|
|
selection_strategy,
|
|
|
|
),
|
2018-03-04 03:19:54 +03:00
|
|
|
Err(e) => match e.kind() {
|
|
|
|
wallet::ErrorKind::NotEnoughFunds(available) => {
|
|
|
|
error!(
|
|
|
|
LOGGER,
|
|
|
|
"Tx not sent: insufficient funds (max: {})",
|
|
|
|
amount_to_hr_string(available),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
wallet::ErrorKind::FeeExceedsAmount {
|
|
|
|
sender_amount,
|
|
|
|
recipient_fee,
|
|
|
|
} => {
|
|
|
|
error!(
|
2018-02-28 20:56:09 +03:00
|
|
|
LOGGER,
|
|
|
|
"Recipient rejected the transfer because transaction fee ({}) exceeded amount ({}).",
|
|
|
|
amount_to_hr_string(recipient_fee),
|
|
|
|
amount_to_hr_string(sender_amount)
|
|
|
|
);
|
2018-03-04 03:19:54 +03:00
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
error!(LOGGER, "Tx not sent: {:?}", e);
|
|
|
|
}
|
|
|
|
},
|
2017-11-08 00:20:36 +03:00
|
|
|
};
|
2017-09-29 21:44:25 +03:00
|
|
|
}
|
2017-10-12 06:35:40 +03:00
|
|
|
("burn", Some(send_args)) => {
|
2018-01-16 04:44:03 +03:00
|
|
|
let amount = send_args
|
|
|
|
.value_of("amount")
|
|
|
|
.expect("Amount to burn required");
|
|
|
|
let amount = core::core::amount_from_hr_string(amount)
|
|
|
|
.expect("Could not parse amount as number with optional decimal point.");
|
|
|
|
let minimum_confirmations: u64 = send_args
|
|
|
|
.value_of("minimum_confirmations")
|
|
|
|
.unwrap()
|
|
|
|
.parse()
|
|
|
|
.expect("Could not parse minimum_confirmations as a whole number.");
|
2017-11-15 21:56:35 +03:00
|
|
|
let max_outputs = 500;
|
|
|
|
wallet::issue_burn_tx(
|
|
|
|
&wallet_config,
|
|
|
|
&keychain,
|
|
|
|
amount,
|
|
|
|
minimum_confirmations,
|
|
|
|
max_outputs,
|
|
|
|
).unwrap();
|
2017-10-12 06:35:40 +03:00
|
|
|
}
|
2017-09-24 07:40:31 +03:00
|
|
|
("info", Some(_)) => {
|
2017-10-03 03:02:31 +03:00
|
|
|
wallet::show_info(&wallet_config, &keychain);
|
2017-09-29 21:44:25 +03:00
|
|
|
}
|
2017-11-10 17:03:31 +03:00
|
|
|
("outputs", Some(_)) => {
|
2017-11-14 19:13:58 +03:00
|
|
|
wallet::show_outputs(&wallet_config, &keychain, show_spent);
|
2017-11-10 17:03:31 +03:00
|
|
|
}
|
2017-11-20 03:50:09 +03:00
|
|
|
("restore", Some(_)) => {
|
2017-12-21 01:16:40 +03:00
|
|
|
let _ = wallet::restore(&wallet_config, &keychain, key_derivations);
|
2017-11-20 03:50:09 +03:00
|
|
|
}
|
2017-06-01 00:44:44 +03:00
|
|
|
_ => panic!("Unknown wallet command, use 'grin help wallet' for details"),
|
|
|
|
}
|
2017-05-25 02:08:39 +03:00
|
|
|
}
|