2021-02-19 21:04:58 +00:00
|
|
|
// With the default subsystem, 'console', windows creates an additional console window for the program.
|
|
|
|
// This is silently ignored on non-windows systems.
|
|
|
|
// See https://msdn.microsoft.com/en-us/library/4cc7ya5b.aspx for more details.
|
2019-12-08 11:32:51 +00:00
|
|
|
#![windows_subsystem = "windows"]
|
|
|
|
|
2021-02-19 15:41:43 +00:00
|
|
|
use std::env;
|
2021-01-30 13:18:37 +00:00
|
|
|
use std::sync::{Arc, Mutex};
|
|
|
|
use std::thread;
|
2021-03-10 21:21:50 +00:00
|
|
|
use std::time::Duration;
|
2021-01-30 13:18:37 +00:00
|
|
|
|
2021-02-19 15:41:43 +00:00
|
|
|
use getopts::Options;
|
2021-02-21 20:56:56 +00:00
|
|
|
#[allow(unused_imports)]
|
2021-03-10 21:21:50 +00:00
|
|
|
use log::{debug, error, info, LevelFilter, trace, warn};
|
|
|
|
use simple_logger::SimpleLogger;
|
|
|
|
#[cfg(windows)]
|
|
|
|
use winapi::um::wincon::{ATTACH_PARENT_PROCESS, AttachConsole, FreeConsole};
|
|
|
|
|
|
|
|
use alfis::{Block, Bytes, Chain, Miner, Context, Network, Settings, dns_utils, Keystore};
|
2021-03-17 13:55:05 +00:00
|
|
|
use alfis::blockchain::BLOCK_DIFFICULTY;
|
2019-12-01 21:45:25 +00:00
|
|
|
|
2021-03-19 14:20:18 +00:00
|
|
|
#[cfg(feature = "webgui")]
|
2021-03-10 21:21:50 +00:00
|
|
|
mod web_ui;
|
2021-01-30 13:18:37 +00:00
|
|
|
|
2021-03-06 21:40:19 +00:00
|
|
|
const SETTINGS_FILENAME: &str = "alfis.toml";
|
2021-03-06 20:28:06 +00:00
|
|
|
const LOG_TARGET_MAIN: &str = "alfis::Main";
|
2021-01-14 17:34:43 +00:00
|
|
|
|
2019-12-01 21:45:25 +00:00
|
|
|
fn main() {
|
2021-02-19 21:04:58 +00:00
|
|
|
// When linked with the windows subsystem windows won't automatically attach
|
|
|
|
// to the console of the parent process, so we do it explicitly. This fails silently if the parent has no console.
|
|
|
|
#[cfg(windows)]
|
|
|
|
unsafe {
|
|
|
|
AttachConsole(ATTACH_PARENT_PROCESS);
|
2021-03-18 14:09:26 +00:00
|
|
|
winapi::um::shellscalingapi::SetProcessDpiAwareness(2);
|
2021-02-19 21:04:58 +00:00
|
|
|
}
|
|
|
|
|
2021-02-19 15:41:43 +00:00
|
|
|
let args: Vec<String> = env::args().collect();
|
|
|
|
let program = args[0].clone();
|
|
|
|
|
|
|
|
let mut opts = Options::new();
|
2021-02-27 17:57:15 +00:00
|
|
|
opts.optflag("h", "help", "Print this help menu");
|
2021-03-19 14:20:18 +00:00
|
|
|
opts.optflag("n", "nogui", "Run without graphic user interface (default for no gui builds)");
|
2021-02-27 17:57:15 +00:00
|
|
|
opts.optflag("v", "verbose", "Show more debug messages");
|
|
|
|
opts.optflag("d", "debug", "Show trace messages, more than debug");
|
2021-03-06 20:28:06 +00:00
|
|
|
opts.optflag("l", "list", "List blocks from DB and exit");
|
2021-02-27 17:57:15 +00:00
|
|
|
opts.optopt("c", "config", "Path to config file", "");
|
2021-02-19 15:41:43 +00:00
|
|
|
|
|
|
|
let opt_matches = match opts.parse(&args[1..]) {
|
|
|
|
Ok(m) => m,
|
|
|
|
Err(f) => panic!(f.to_string()),
|
|
|
|
};
|
|
|
|
|
|
|
|
if opt_matches.opt_present("h") {
|
|
|
|
let brief = format!("Usage: {} [options]", program);
|
|
|
|
print!("{}", opts.usage(&brief));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-03-19 14:20:18 +00:00
|
|
|
#[cfg(feature = "webgui")]
|
2021-02-19 15:41:43 +00:00
|
|
|
let no_gui = opt_matches.opt_present("n");
|
2021-03-19 14:20:18 +00:00
|
|
|
#[cfg(not(feature = "webgui"))]
|
2021-03-19 10:37:49 +00:00
|
|
|
let no_gui = true;
|
2021-02-19 15:41:43 +00:00
|
|
|
|
2021-02-20 15:28:10 +00:00
|
|
|
let mut level = LevelFilter::Info;
|
|
|
|
if opt_matches.opt_present("v") {
|
|
|
|
level = LevelFilter::Debug;
|
|
|
|
}
|
|
|
|
if opt_matches.opt_present("d") {
|
|
|
|
level = LevelFilter::Trace;
|
|
|
|
}
|
2021-02-22 09:11:22 +00:00
|
|
|
let config_name = match opt_matches.opt_str("c") {
|
|
|
|
None => { SETTINGS_FILENAME.to_owned() }
|
|
|
|
Some(path) => { path }
|
|
|
|
};
|
2021-03-20 23:19:09 +00:00
|
|
|
SimpleLogger::new().with_level(level).with_module_level("mio::poll", LevelFilter::Warn).init().unwrap();
|
2021-03-06 20:28:06 +00:00
|
|
|
info!(target: LOG_TARGET_MAIN, "Starting ALFIS {}", env!("CARGO_PKG_VERSION"));
|
2021-02-20 15:28:10 +00:00
|
|
|
|
2021-03-16 13:00:14 +00:00
|
|
|
let settings = Settings::load(&config_name);
|
2021-03-16 17:16:31 +00:00
|
|
|
info!(target: LOG_TARGET_MAIN, "Loaded settings: {:?}", &settings);
|
2021-01-17 23:18:35 +00:00
|
|
|
let keystore: Keystore = match Keystore::from_file(&settings.key_file, "") {
|
2021-02-15 22:09:30 +00:00
|
|
|
None => {
|
2021-03-06 20:28:06 +00:00
|
|
|
warn!(target: LOG_TARGET_MAIN, "Generated temporary keystore. Please, generate full-privileged keys.");
|
2021-02-15 22:09:30 +00:00
|
|
|
Keystore::new()
|
|
|
|
}
|
2021-01-17 23:18:35 +00:00
|
|
|
Some(keystore) => { keystore }
|
|
|
|
};
|
2021-03-10 21:21:50 +00:00
|
|
|
let chain: Chain = Chain::new(&settings);
|
2021-03-06 20:28:06 +00:00
|
|
|
if opt_matches.opt_present("l") {
|
2021-03-10 21:21:50 +00:00
|
|
|
for i in 1..(chain.height() + 1) {
|
|
|
|
if let Some(block) = chain.get_block(i) {
|
2021-03-06 20:28:06 +00:00
|
|
|
info!(target: LOG_TARGET_MAIN, "{:?}", &block);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-03-10 21:21:50 +00:00
|
|
|
match chain.get_block(1) {
|
2021-03-06 20:28:06 +00:00
|
|
|
None => { info!(target: LOG_TARGET_MAIN, "No blocks found in DB"); }
|
|
|
|
Some(block) => { trace!(target: LOG_TARGET_MAIN, "Loaded DB with origin {:?}", &block.hash); }
|
2021-02-14 23:29:30 +00:00
|
|
|
}
|
2021-02-19 15:41:43 +00:00
|
|
|
let settings_copy = settings.clone();
|
2021-03-10 21:21:50 +00:00
|
|
|
let context: Arc<Mutex<Context>> = Arc::new(Mutex::new(Context::new(settings, keystore, chain)));
|
|
|
|
dns_utils::start_dns_server(&context, &settings_copy);
|
2020-04-18 19:31:40 +00:00
|
|
|
|
2021-01-14 17:34:43 +00:00
|
|
|
let mut miner_obj = Miner::new(context.clone());
|
|
|
|
miner_obj.start_mining_thread();
|
|
|
|
let miner: Arc<Mutex<Miner>> = Arc::new(Mutex::new(miner_obj));
|
2020-04-18 19:31:40 +00:00
|
|
|
|
2021-02-05 21:24:28 +00:00
|
|
|
let mut network = Network::new(context.clone());
|
2021-02-14 17:20:30 +00:00
|
|
|
network.start().expect("Error starting network component");
|
2021-02-05 21:24:28 +00:00
|
|
|
|
2021-01-14 17:34:43 +00:00
|
|
|
create_genesis_if_needed(&context, &miner);
|
2021-02-19 15:41:43 +00:00
|
|
|
if no_gui {
|
|
|
|
let sleep = Duration::from_millis(1000);
|
|
|
|
loop {
|
|
|
|
thread::sleep(sleep);
|
|
|
|
}
|
|
|
|
} else {
|
2021-03-19 14:20:18 +00:00
|
|
|
#[cfg(feature = "webgui")]
|
2021-03-10 21:21:50 +00:00
|
|
|
web_ui::run_interface(context.clone(), miner.clone());
|
2021-02-19 15:41:43 +00:00
|
|
|
}
|
2021-02-19 21:04:58 +00:00
|
|
|
|
|
|
|
// Without explicitly detaching the console cmd won't redraw it's prompt.
|
|
|
|
#[cfg(windows)]
|
|
|
|
unsafe {
|
|
|
|
FreeConsole();
|
|
|
|
}
|
2021-02-19 15:41:43 +00:00
|
|
|
}
|
|
|
|
|
2021-01-14 17:34:43 +00:00
|
|
|
fn create_genesis_if_needed(context: &Arc<Mutex<Context>>, miner: &Arc<Mutex<Miner>>) {
|
2021-02-13 22:37:44 +00:00
|
|
|
// If there is no origin in settings and no blockchain in DB, generate genesis block
|
|
|
|
let context = context.lock().unwrap();
|
2021-03-10 21:21:50 +00:00
|
|
|
let last_block = context.get_chain().last_block();
|
2021-02-13 22:37:44 +00:00
|
|
|
let origin = context.settings.origin.clone();
|
|
|
|
if origin.eq("") && last_block.is_none() {
|
2021-01-20 18:23:41 +00:00
|
|
|
// If blockchain is empty, we are going to mine a Genesis block
|
2021-03-17 13:55:05 +00:00
|
|
|
let block = Block::new(None, context.get_keystore().get_public(), Bytes::default(), BLOCK_DIFFICULTY);
|
2021-03-10 21:21:50 +00:00
|
|
|
miner.lock().unwrap().add_block(block);
|
2021-01-17 23:18:35 +00:00
|
|
|
}
|
|
|
|
}
|
2021-01-14 17:34:43 +00:00
|
|
|
|
2021-02-19 15:41:43 +00:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use alfis::dns::protocol::{DnsRecord, TransientTtl};
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn record_to_string() {
|
|
|
|
let record = DnsRecord::A {
|
|
|
|
domain: "google.com".to_string(),
|
|
|
|
addr: "127.0.0.1".parse().unwrap(),
|
|
|
|
ttl: TransientTtl(300)
|
|
|
|
};
|
|
|
|
println!("Record is {:?}", &record);
|
|
|
|
println!("Record in JSON is {}", serde_json::to_string(&record).unwrap());
|
|
|
|
}
|
|
|
|
}
|