2022-02-11 04:33:35 +03:00
|
|
|
use config::ServerConfig;
|
2022-04-27 06:13:44 +03:00
|
|
|
use node::HttpGrinNode;
|
2022-08-28 08:39:58 +03:00
|
|
|
use store::SwapStore;
|
2022-04-27 06:13:44 +03:00
|
|
|
use wallet::HttpWallet;
|
2022-02-11 04:33:35 +03:00
|
|
|
|
2022-08-28 08:39:58 +03:00
|
|
|
use crate::store::StoreError;
|
2022-02-11 04:33:35 +03:00
|
|
|
use clap::App;
|
2022-08-20 20:31:09 +03:00
|
|
|
use grin_core::global::ChainTypes;
|
2022-04-27 06:13:44 +03:00
|
|
|
use grin_util::{StopState, ZeroingString};
|
2022-07-01 12:33:34 +03:00
|
|
|
use rpassword;
|
2022-02-11 04:33:35 +03:00
|
|
|
use std::path::PathBuf;
|
2022-04-27 06:13:44 +03:00
|
|
|
use std::sync::Arc;
|
2022-07-01 12:33:34 +03:00
|
|
|
use tokio::runtime::Runtime;
|
2021-11-12 19:09:11 +03:00
|
|
|
|
2022-02-11 04:33:35 +03:00
|
|
|
#[macro_use]
|
|
|
|
extern crate clap;
|
|
|
|
|
|
|
|
mod config;
|
|
|
|
mod node;
|
2021-11-12 19:09:11 +03:00
|
|
|
mod onion;
|
2022-08-01 06:17:08 +03:00
|
|
|
mod rpc;
|
2021-11-12 19:09:11 +03:00
|
|
|
mod secp;
|
|
|
|
mod server;
|
2022-08-26 00:16:29 +03:00
|
|
|
mod store;
|
2021-11-12 19:09:11 +03:00
|
|
|
mod types;
|
2022-02-11 04:33:35 +03:00
|
|
|
mod wallet;
|
2021-11-12 19:09:11 +03:00
|
|
|
|
2022-04-27 06:13:44 +03:00
|
|
|
const DEFAULT_INTERVAL: u32 = 12 * 60 * 60;
|
|
|
|
|
2022-04-27 22:11:20 +03:00
|
|
|
fn main() {
|
2022-07-01 12:33:34 +03:00
|
|
|
real_main().unwrap();
|
2022-04-27 22:11:20 +03:00
|
|
|
std::process::exit(0);
|
|
|
|
}
|
|
|
|
|
2022-07-01 12:33:34 +03:00
|
|
|
fn real_main() -> Result<(), Box<dyn std::error::Error>> {
|
2022-02-11 04:33:35 +03:00
|
|
|
let yml = load_yaml!("../mwixnet.yml");
|
|
|
|
let args = App::from_yaml(yml).get_matches();
|
2022-08-20 20:31:09 +03:00
|
|
|
let chain_type = if args.is_present("testnet") {
|
|
|
|
ChainTypes::Testnet
|
|
|
|
} else {
|
|
|
|
ChainTypes::Mainnet
|
|
|
|
};
|
2022-07-01 12:33:34 +03:00
|
|
|
|
|
|
|
let config_path = match args.value_of("config_file") {
|
|
|
|
Some(path) => PathBuf::from(path),
|
|
|
|
None => {
|
2022-08-20 20:31:09 +03:00
|
|
|
let mut grin_path = config::get_grin_path(&chain_type);
|
2022-07-22 17:47:04 +03:00
|
|
|
grin_path.push("mwixnet-config.toml");
|
|
|
|
grin_path
|
2022-07-01 12:33:34 +03:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let round_time = args
|
|
|
|
.value_of("round_time")
|
|
|
|
.map(|t| t.parse::<u32>().unwrap());
|
|
|
|
let bind_addr = args.value_of("bind_addr");
|
|
|
|
let grin_node_url = args.value_of("grin_node_url");
|
2022-07-22 17:47:04 +03:00
|
|
|
let grin_node_secret_path = args.value_of("grin_node_secret_path");
|
2022-07-01 12:33:34 +03:00
|
|
|
let wallet_owner_url = args.value_of("wallet_owner_url");
|
2022-07-22 17:47:04 +03:00
|
|
|
let wallet_owner_secret_path = args.value_of("wallet_owner_secret_path");
|
2022-07-01 12:33:34 +03:00
|
|
|
|
|
|
|
// Write a new config file if init-config command is supplied
|
|
|
|
if let ("init-config", Some(_)) = args.subcommand() {
|
|
|
|
if config_path.exists() {
|
|
|
|
panic!(
|
|
|
|
"Config file already exists at {}",
|
|
|
|
config_path.to_string_lossy()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
let server_config = ServerConfig {
|
|
|
|
key: secp::random_secret(),
|
|
|
|
interval_s: round_time.unwrap_or(DEFAULT_INTERVAL),
|
|
|
|
addr: bind_addr.unwrap_or("0.0.0.0:3000").parse()?,
|
2022-08-20 20:45:51 +03:00
|
|
|
grin_node_url: match grin_node_url {
|
|
|
|
Some(u) => u.parse()?,
|
|
|
|
None => config::grin_node_url(&chain_type),
|
|
|
|
},
|
2022-07-22 17:47:04 +03:00
|
|
|
grin_node_secret_path: match grin_node_secret_path {
|
|
|
|
Some(p) => Some(p.to_owned()),
|
2022-08-20 20:31:09 +03:00
|
|
|
None => config::node_secret_path(&chain_type)
|
|
|
|
.to_str()
|
|
|
|
.map(|p| p.to_owned()),
|
2022-07-22 17:47:04 +03:00
|
|
|
},
|
2022-08-20 20:45:51 +03:00
|
|
|
wallet_owner_url: match wallet_owner_url {
|
|
|
|
Some(u) => u.parse()?,
|
|
|
|
None => config::wallet_owner_url(&chain_type),
|
|
|
|
},
|
2022-07-22 17:47:04 +03:00
|
|
|
wallet_owner_secret_path: match wallet_owner_secret_path {
|
|
|
|
Some(p) => Some(p.to_owned()),
|
2022-08-20 20:31:09 +03:00
|
|
|
None => config::wallet_owner_secret_path(&chain_type)
|
2022-07-22 17:47:04 +03:00
|
|
|
.to_str()
|
|
|
|
.map(|p| p.to_owned()),
|
|
|
|
},
|
2022-07-01 12:33:34 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
let password = prompt_password_confirm();
|
|
|
|
config::write_config(&config_path, &server_config, &password)?;
|
|
|
|
println!(
|
|
|
|
"Config file written to {:?}. Please back this file up in a safe place.",
|
|
|
|
config_path
|
|
|
|
);
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
|
|
|
|
let password = prompt_password();
|
|
|
|
let mut server_config = config::load_config(&config_path, &password)?;
|
|
|
|
|
|
|
|
// Override bind_addr, if supplied
|
|
|
|
if let Some(bind_addr) = bind_addr {
|
|
|
|
server_config.addr = bind_addr.parse()?;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Override grin_node_url, if supplied
|
|
|
|
if let Some(grin_node_url) = grin_node_url {
|
|
|
|
server_config.grin_node_url = grin_node_url.parse()?;
|
|
|
|
}
|
|
|
|
|
2022-07-22 17:47:04 +03:00
|
|
|
// Override grin_node_secret_path, if supplied
|
|
|
|
if let Some(grin_node_secret_path) = grin_node_secret_path {
|
|
|
|
server_config.grin_node_secret_path = Some(grin_node_secret_path.to_owned());
|
|
|
|
}
|
|
|
|
|
2022-07-01 12:33:34 +03:00
|
|
|
// Override wallet_owner_url, if supplied
|
|
|
|
if let Some(wallet_owner_url) = wallet_owner_url {
|
|
|
|
server_config.wallet_owner_url = wallet_owner_url.parse()?;
|
|
|
|
}
|
|
|
|
|
2022-07-22 17:47:04 +03:00
|
|
|
// Override wallet_owner_secret_path, if supplied
|
|
|
|
if let Some(wallet_owner_secret_path) = wallet_owner_secret_path {
|
|
|
|
server_config.wallet_owner_secret_path = Some(wallet_owner_secret_path.to_owned());
|
|
|
|
}
|
|
|
|
|
2022-07-01 12:33:34 +03:00
|
|
|
// Open wallet
|
|
|
|
let wallet_pass = prompt_wallet_password(&args.value_of("wallet_pass"));
|
2022-07-22 17:47:04 +03:00
|
|
|
let wallet = HttpWallet::open_wallet(
|
|
|
|
&server_config.wallet_owner_url,
|
|
|
|
&server_config.wallet_owner_api_secret(),
|
|
|
|
&wallet_pass,
|
|
|
|
)?;
|
2022-07-01 12:33:34 +03:00
|
|
|
|
|
|
|
// Create GrinNode
|
2022-07-22 17:47:04 +03:00
|
|
|
let node = HttpGrinNode::new(
|
|
|
|
&server_config.grin_node_url,
|
|
|
|
&server_config.node_api_secret(),
|
|
|
|
);
|
2022-07-01 12:33:34 +03:00
|
|
|
|
2022-08-28 08:39:58 +03:00
|
|
|
// Open SwapStore
|
|
|
|
let store = SwapStore::new(
|
|
|
|
config::get_grin_path(&chain_type) // todo: load from config
|
|
|
|
.join("db")
|
|
|
|
.to_str()
|
|
|
|
.ok_or(StoreError::OpenError(grin_store::lmdb::Error::FileErr(
|
|
|
|
"db_root path error".to_string(),
|
|
|
|
)))?,
|
|
|
|
)?;
|
|
|
|
|
2022-07-01 12:33:34 +03:00
|
|
|
let stop_state = Arc::new(StopState::new());
|
|
|
|
let stop_state_clone = stop_state.clone();
|
|
|
|
|
|
|
|
let rt = Runtime::new()?;
|
|
|
|
rt.spawn(async move {
|
2022-07-22 17:47:04 +03:00
|
|
|
futures::executor::block_on(build_signals_fut());
|
2022-07-01 12:33:34 +03:00
|
|
|
stop_state_clone.stop();
|
|
|
|
});
|
|
|
|
|
2022-08-01 06:17:08 +03:00
|
|
|
// Start the mwixnet JSON-RPC HTTP server
|
2022-08-28 08:39:58 +03:00
|
|
|
rpc::listen(
|
|
|
|
server_config,
|
|
|
|
Arc::new(wallet),
|
|
|
|
Arc::new(node),
|
|
|
|
store,
|
|
|
|
stop_state,
|
|
|
|
)
|
2022-07-01 12:33:34 +03:00
|
|
|
}
|
|
|
|
|
2022-07-22 17:47:04 +03:00
|
|
|
async fn build_signals_fut() {
|
|
|
|
if cfg!(unix) {
|
|
|
|
use tokio::signal::unix::{signal, SignalKind};
|
|
|
|
|
|
|
|
// Listen for SIGINT, SIGQUIT, and SIGTERM
|
|
|
|
let mut terminate_signal =
|
|
|
|
signal(SignalKind::terminate()).expect("failed to create terminate signal");
|
|
|
|
let mut quit_signal = signal(SignalKind::quit()).expect("failed to create quit signal");
|
|
|
|
let mut interrupt_signal =
|
|
|
|
signal(SignalKind::interrupt()).expect("failed to create interrupt signal");
|
|
|
|
|
|
|
|
futures::future::select_all(vec![
|
|
|
|
Box::pin(terminate_signal.recv()),
|
|
|
|
Box::pin(quit_signal.recv()),
|
|
|
|
Box::pin(interrupt_signal.recv()),
|
|
|
|
])
|
|
|
|
.await;
|
|
|
|
} else {
|
|
|
|
tokio::signal::ctrl_c()
|
|
|
|
.await
|
|
|
|
.expect("failed to install CTRL+C signal handler");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-01 12:33:34 +03:00
|
|
|
fn prompt_password() -> ZeroingString {
|
|
|
|
ZeroingString::from(rpassword::prompt_password_stdout("Server password: ").unwrap())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn prompt_password_confirm() -> ZeroingString {
|
|
|
|
let mut first = "first".to_string();
|
|
|
|
let mut second = "second".to_string();
|
|
|
|
while first != second {
|
|
|
|
first = rpassword::prompt_password_stdout("Server password: ").unwrap();
|
|
|
|
second = rpassword::prompt_password_stdout("Confirm server password: ").unwrap();
|
|
|
|
}
|
|
|
|
ZeroingString::from(first)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn prompt_wallet_password(wallet_pass: &Option<&str>) -> ZeroingString {
|
|
|
|
match *wallet_pass {
|
|
|
|
Some(wallet_pass) => ZeroingString::from(wallet_pass),
|
|
|
|
None => {
|
|
|
|
ZeroingString::from(rpassword::prompt_password_stdout("Wallet password: ").unwrap())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|