2016-01-18 15:33:29 +00:00
|
|
|
// Copyright (c) 2011-2016 The Cryptonote developers
|
2015-09-18 11:55:31 +00:00
|
|
|
// Distributed under the MIT/X11 software license, see the accompanying
|
|
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
2014-03-03 22:07:58 +00:00
|
|
|
|
|
|
|
#include "version.h"
|
|
|
|
|
2015-07-15 12:23:00 +00:00
|
|
|
#include <boost/filesystem.hpp>
|
2014-03-03 22:07:58 +00:00
|
|
|
#include <boost/program_options.hpp>
|
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
#include "DaemonCommandsHandler.h"
|
2014-08-13 10:51:37 +00:00
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
#include "Common/SignalHandler.h"
|
|
|
|
#include "Common/PathTools.h"
|
2014-08-13 10:51:37 +00:00
|
|
|
#include "crypto/hash.h"
|
2015-07-30 15:22:07 +00:00
|
|
|
#include "CryptoNoteCore/Core.h"
|
|
|
|
#include "CryptoNoteCore/CoreConfig.h"
|
2015-09-18 11:55:31 +00:00
|
|
|
#include "CryptoNoteCore/CryptoNoteTools.h"
|
2015-07-30 15:22:07 +00:00
|
|
|
#include "CryptoNoteCore/Currency.h"
|
|
|
|
#include "CryptoNoteCore/MinerConfig.h"
|
|
|
|
#include "CryptoNoteProtocol/CryptoNoteProtocolHandler.h"
|
|
|
|
#include "P2p/NetNode.h"
|
|
|
|
#include "P2p/NetNodeConfig.h"
|
|
|
|
#include "Rpc/RpcServer.h"
|
|
|
|
#include "Rpc/RpcServerConfig.h"
|
2014-03-03 22:07:58 +00:00
|
|
|
#include "version.h"
|
|
|
|
|
2015-09-18 11:55:31 +00:00
|
|
|
#include "Logging/ConsoleLogger.h"
|
2015-05-27 12:08:46 +00:00
|
|
|
#include <Logging/LoggerManager.h>
|
|
|
|
|
2014-03-03 22:07:58 +00:00
|
|
|
#if defined(WIN32)
|
|
|
|
#include <crtdbg.h>
|
|
|
|
#endif
|
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
using Common::JsonValue;
|
|
|
|
using namespace CryptoNote;
|
|
|
|
using namespace Logging;
|
|
|
|
|
2014-03-03 22:07:58 +00:00
|
|
|
namespace po = boost::program_options;
|
|
|
|
|
|
|
|
namespace
|
|
|
|
{
|
2015-05-27 12:08:46 +00:00
|
|
|
const command_line::arg_descriptor<std::string> arg_config_file = {"config-file", "Specify configuration file", std::string(CryptoNote::CRYPTONOTE_NAME) + ".conf"};
|
2014-03-03 22:07:58 +00:00
|
|
|
const command_line::arg_descriptor<bool> arg_os_version = {"os-version", ""};
|
|
|
|
const command_line::arg_descriptor<std::string> arg_log_file = {"log-file", "", ""};
|
2015-05-27 12:08:46 +00:00
|
|
|
const command_line::arg_descriptor<int> arg_log_level = {"log-level", "", 2}; // info level
|
2014-03-20 11:46:11 +00:00
|
|
|
const command_line::arg_descriptor<bool> arg_console = {"no-console", "Disable daemon console commands"};
|
2014-08-13 10:51:37 +00:00
|
|
|
const command_line::arg_descriptor<bool> arg_testnet_on = {"testnet", "Used to deploy test nets. Checkpoints and hardcoded seeds are ignored, "
|
|
|
|
"network id is changed. Use it with --data-dir flag. The wallet must be launched with --testnet flag.", false};
|
2015-09-18 11:55:31 +00:00
|
|
|
const command_line::arg_descriptor<bool> arg_print_genesis_tx = { "print-genesis-tx", "Prints genesis' block tx hex to insert it to config and exits" };
|
2014-03-03 22:07:58 +00:00
|
|
|
}
|
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
bool command_line_preprocessor(const boost::program_options::variables_map& vm, LoggerRef& logger);
|
|
|
|
|
2015-09-18 11:55:31 +00:00
|
|
|
void print_genesis_tx_hex() {
|
|
|
|
Logging::ConsoleLogger logger;
|
|
|
|
CryptoNote::Transaction tx = CryptoNote::CurrencyBuilder(logger).generateGenesisTransaction();
|
|
|
|
CryptoNote::BinaryArray txb = CryptoNote::toBinaryArray(tx);
|
|
|
|
std::string tx_hex = Common::toHex(txb);
|
|
|
|
|
|
|
|
std::cout << "Insert this line into your coin configuration file as is: " << std::endl;
|
|
|
|
std::cout << "const char GENESIS_COINBASE_TX_HEX[] = \"" << tx_hex << "\";" << std::endl;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
JsonValue buildLoggerConfiguration(Level level, const std::string& logfile) {
|
|
|
|
JsonValue loggerConfiguration(JsonValue::OBJECT);
|
|
|
|
loggerConfiguration.insert("globalLevel", static_cast<int64_t>(level));
|
|
|
|
|
|
|
|
JsonValue& cfgLoggers = loggerConfiguration.insert("loggers", JsonValue::ARRAY);
|
|
|
|
|
|
|
|
JsonValue& fileLogger = cfgLoggers.pushBack(JsonValue::OBJECT);
|
|
|
|
fileLogger.insert("type", "file");
|
|
|
|
fileLogger.insert("filename", logfile);
|
|
|
|
fileLogger.insert("level", static_cast<int64_t>(TRACE));
|
|
|
|
|
|
|
|
JsonValue& consoleLogger = cfgLoggers.pushBack(JsonValue::OBJECT);
|
|
|
|
consoleLogger.insert("type", "console");
|
|
|
|
consoleLogger.insert("level", static_cast<int64_t>(TRACE));
|
|
|
|
consoleLogger.insert("pattern", "%T %L ");
|
|
|
|
|
|
|
|
return loggerConfiguration;
|
|
|
|
}
|
|
|
|
|
2014-03-03 22:07:58 +00:00
|
|
|
|
|
|
|
int main(int argc, char* argv[])
|
|
|
|
{
|
|
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
|
|
|
|
#endif
|
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
LoggerManager logManager;
|
|
|
|
LoggerRef logger(logManager, "daemon");
|
2014-03-03 22:07:58 +00:00
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
try {
|
2014-03-03 22:07:58 +00:00
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
po::options_description desc_cmd_only("Command line options");
|
|
|
|
po::options_description desc_cmd_sett("Command line options and settings options");
|
2014-03-03 22:07:58 +00:00
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
command_line::add_arg(desc_cmd_only, command_line::arg_help);
|
|
|
|
command_line::add_arg(desc_cmd_only, command_line::arg_version);
|
|
|
|
command_line::add_arg(desc_cmd_only, arg_os_version);
|
|
|
|
// tools::get_default_data_dir() can't be called during static initialization
|
2015-07-30 15:22:07 +00:00
|
|
|
command_line::add_arg(desc_cmd_only, command_line::arg_data_dir, Tools::getDefaultDataDirectory());
|
2015-05-27 12:08:46 +00:00
|
|
|
command_line::add_arg(desc_cmd_only, arg_config_file);
|
2015-04-06 16:13:07 +00:00
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
command_line::add_arg(desc_cmd_sett, arg_log_file);
|
|
|
|
command_line::add_arg(desc_cmd_sett, arg_log_level);
|
|
|
|
command_line::add_arg(desc_cmd_sett, arg_console);
|
|
|
|
command_line::add_arg(desc_cmd_sett, arg_testnet_on);
|
2015-09-18 11:55:31 +00:00
|
|
|
command_line::add_arg(desc_cmd_sett, arg_print_genesis_tx);
|
2014-03-03 22:07:58 +00:00
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
RpcServerConfig::initOptions(desc_cmd_sett);
|
|
|
|
CoreConfig::initOptions(desc_cmd_sett);
|
|
|
|
NetNodeConfig::initOptions(desc_cmd_sett);
|
|
|
|
MinerConfig::initOptions(desc_cmd_sett);
|
2014-03-03 22:07:58 +00:00
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
po::options_description desc_options("Allowed options");
|
|
|
|
desc_options.add(desc_cmd_only).add(desc_cmd_sett);
|
2014-03-03 22:07:58 +00:00
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
po::variables_map vm;
|
|
|
|
bool r = command_line::handle_error_helper(desc_options, [&]()
|
2014-03-03 22:07:58 +00:00
|
|
|
{
|
2015-05-27 12:08:46 +00:00
|
|
|
po::store(po::parse_command_line(argc, argv, desc_options), vm);
|
|
|
|
|
|
|
|
if (command_line::get_arg(vm, command_line::arg_help))
|
|
|
|
{
|
|
|
|
std::cout << CryptoNote::CRYPTONOTE_NAME << " v" << PROJECT_VERSION_LONG << ENDL << ENDL;
|
|
|
|
std::cout << desc_options << std::endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-09-18 11:55:31 +00:00
|
|
|
if (command_line::get_arg(vm, arg_print_genesis_tx)) {
|
|
|
|
print_genesis_tx_hex();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
std::string data_dir = command_line::get_arg(vm, command_line::arg_data_dir);
|
|
|
|
std::string config = command_line::get_arg(vm, arg_config_file);
|
|
|
|
|
|
|
|
boost::filesystem::path data_dir_path(data_dir);
|
|
|
|
boost::filesystem::path config_path(config);
|
|
|
|
if (!config_path.has_parent_path()) {
|
|
|
|
config_path = data_dir_path / config_path;
|
|
|
|
}
|
|
|
|
|
|
|
|
boost::system::error_code ec;
|
|
|
|
if (boost::filesystem::exists(config_path, ec)) {
|
|
|
|
po::store(po::parse_config_file<char>(config_path.string<std::string>().c_str(), desc_cmd_sett), vm);
|
|
|
|
}
|
|
|
|
po::notify(vm);
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
|
|
|
|
if (!r)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
auto modulePath = Common::NativePathToGeneric(argv[0]);
|
|
|
|
auto cfgLogFile = Common::NativePathToGeneric(command_line::get_arg(vm, arg_log_file));
|
|
|
|
|
|
|
|
if (cfgLogFile.empty()) {
|
|
|
|
cfgLogFile = Common::ReplaceExtenstion(modulePath, ".log");
|
|
|
|
} else {
|
|
|
|
if (!Common::HasParentPath(cfgLogFile)) {
|
|
|
|
cfgLogFile = Common::CombinePath(Common::GetPathDirectory(modulePath), cfgLogFile);
|
|
|
|
}
|
2014-03-03 22:07:58 +00:00
|
|
|
}
|
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
Level cfgLogLevel = static_cast<Level>(static_cast<int>(Logging::ERROR) + command_line::get_arg(vm, arg_log_level));
|
2014-03-03 22:07:58 +00:00
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
// configure logging
|
|
|
|
logManager.configure(buildLoggerConfiguration(cfgLogLevel, cfgLogFile));
|
2014-03-03 22:07:58 +00:00
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
logger(INFO) << CryptoNote::CRYPTONOTE_NAME << " v" << PROJECT_VERSION_LONG;
|
2014-03-03 22:07:58 +00:00
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
if (command_line_preprocessor(vm, logger)) {
|
|
|
|
return 0;
|
|
|
|
}
|
2014-03-03 22:07:58 +00:00
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
logger(INFO) << "Module folder: " << argv[0];
|
2014-03-03 22:07:58 +00:00
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
bool testnet_mode = command_line::get_arg(vm, arg_testnet_on);
|
|
|
|
if (testnet_mode) {
|
|
|
|
logger(INFO) << "Starting in testnet mode!";
|
|
|
|
}
|
2014-03-03 22:07:58 +00:00
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
//create objects and link them
|
|
|
|
CryptoNote::CurrencyBuilder currencyBuilder(logManager);
|
|
|
|
currencyBuilder.testnet(testnet_mode);
|
2015-09-18 11:55:31 +00:00
|
|
|
|
|
|
|
try {
|
|
|
|
currencyBuilder.currency();
|
|
|
|
} catch (std::exception&) {
|
|
|
|
std::cout << "GENESIS_COINBASE_TX_HEX constant has an incorrect value. Please launch: " << CryptoNote::CRYPTONOTE_NAME << "d --" << arg_print_genesis_tx.name;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
CryptoNote::Currency currency = currencyBuilder.currency();
|
|
|
|
CryptoNote::core ccore(currency, nullptr, logManager);
|
2014-03-03 22:07:58 +00:00
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
CryptoNote::Checkpoints checkpoints(logManager);
|
2015-05-27 12:08:46 +00:00
|
|
|
for (const auto& cp : CryptoNote::CHECKPOINTS) {
|
|
|
|
checkpoints.add_checkpoint(cp.height, cp.blockId);
|
|
|
|
}
|
2014-03-03 22:07:58 +00:00
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
if (!testnet_mode) {
|
|
|
|
ccore.set_checkpoints(std::move(checkpoints));
|
|
|
|
}
|
2014-03-03 22:07:58 +00:00
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
CoreConfig coreConfig;
|
|
|
|
coreConfig.init(vm);
|
|
|
|
NetNodeConfig netNodeConfig;
|
|
|
|
netNodeConfig.init(vm);
|
2015-07-30 15:22:07 +00:00
|
|
|
netNodeConfig.setTestnet(testnet_mode);
|
2015-05-27 12:08:46 +00:00
|
|
|
MinerConfig minerConfig;
|
|
|
|
minerConfig.init(vm);
|
|
|
|
RpcServerConfig rpcConfig;
|
|
|
|
rpcConfig.init(vm);
|
|
|
|
|
2015-12-09 13:19:03 +00:00
|
|
|
if (!coreConfig.configFolderDefaulted) {
|
|
|
|
if (!Tools::directoryExists(coreConfig.configFolder)) {
|
|
|
|
throw std::runtime_error("Directory does not exist: " + coreConfig.configFolder);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!Tools::create_directories_if_necessary(coreConfig.configFolder)) {
|
|
|
|
throw std::runtime_error("Can't create directory: " + coreConfig.configFolder);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
System::Dispatcher dispatcher;
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
CryptoNote::CryptoNoteProtocolHandler cprotocol(currency, dispatcher, ccore, nullptr, logManager);
|
|
|
|
CryptoNote::NodeServer p2psrv(dispatcher, cprotocol, logManager);
|
2015-12-09 13:19:03 +00:00
|
|
|
CryptoNote::RpcServer rpcServer(dispatcher, logManager, ccore, p2psrv, cprotocol);
|
2015-05-27 12:08:46 +00:00
|
|
|
|
|
|
|
cprotocol.set_p2p_endpoint(&p2psrv);
|
|
|
|
ccore.set_cryptonote_protocol(&cprotocol);
|
|
|
|
DaemonCommandsHandler dch(ccore, p2psrv, logManager);
|
|
|
|
|
|
|
|
// initialize objects
|
|
|
|
logger(INFO) << "Initializing p2p server...";
|
2015-07-30 15:22:07 +00:00
|
|
|
if (!p2psrv.init(netNodeConfig)) {
|
2015-05-27 12:08:46 +00:00
|
|
|
logger(ERROR, BRIGHT_RED) << "Failed to initialize p2p server.";
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
logger(INFO) << "P2p server initialized OK";
|
|
|
|
|
|
|
|
//logger(INFO) << "Initializing core rpc server...";
|
|
|
|
//if (!rpc_server.init(vm)) {
|
|
|
|
// logger(ERROR, BRIGHT_RED) << "Failed to initialize core rpc server.";
|
|
|
|
// return 1;
|
|
|
|
//}
|
|
|
|
// logger(INFO, BRIGHT_GREEN) << "Core rpc server initialized OK on port: " << rpc_server.get_binded_port();
|
|
|
|
|
|
|
|
// initialize core here
|
|
|
|
logger(INFO) << "Initializing core...";
|
|
|
|
if (!ccore.init(coreConfig, minerConfig, true)) {
|
|
|
|
logger(ERROR, BRIGHT_RED) << "Failed to initialize core";
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
logger(INFO) << "Core initialized OK";
|
2014-08-13 10:51:37 +00:00
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
// start components
|
|
|
|
if (!command_line::has_arg(vm, arg_console)) {
|
|
|
|
dch.start_handling();
|
|
|
|
}
|
2014-08-13 10:51:37 +00:00
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
logger(INFO) << "Starting core rpc server on address " << rpcConfig.getBindAddress();
|
|
|
|
rpcServer.start(rpcConfig.bindIp, rpcConfig.bindPort);
|
|
|
|
logger(INFO) << "Core rpc server started ok";
|
2014-08-13 10:51:37 +00:00
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
Tools::SignalHandler::install([&dch, &p2psrv] {
|
2015-05-27 12:08:46 +00:00
|
|
|
dch.stop_handling();
|
2015-07-30 15:22:07 +00:00
|
|
|
p2psrv.sendStopSignal();
|
2015-05-27 12:08:46 +00:00
|
|
|
});
|
2014-03-03 22:07:58 +00:00
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
logger(INFO) << "Starting p2p net loop...";
|
|
|
|
p2psrv.run();
|
|
|
|
logger(INFO) << "p2p net loop stopped";
|
2014-03-03 22:07:58 +00:00
|
|
|
|
2014-03-20 11:46:11 +00:00
|
|
|
dch.stop_handling();
|
2014-03-03 22:07:58 +00:00
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
//stop components
|
|
|
|
logger(INFO) << "Stopping core rpc server...";
|
|
|
|
rpcServer.stop();
|
2014-03-03 22:07:58 +00:00
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
//deinitialize components
|
|
|
|
logger(INFO) << "Deinitializing core...";
|
|
|
|
ccore.deinit();
|
|
|
|
logger(INFO) << "Deinitializing p2p...";
|
|
|
|
p2psrv.deinit();
|
2014-03-03 22:07:58 +00:00
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
ccore.set_cryptonote_protocol(NULL);
|
|
|
|
cprotocol.set_p2p_endpoint(NULL);
|
2014-03-03 22:07:58 +00:00
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
} catch (const std::exception& e) {
|
|
|
|
logger(ERROR, BRIGHT_RED) << "Exception: " << e.what();
|
|
|
|
return 1;
|
|
|
|
}
|
2014-03-03 22:07:58 +00:00
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
logger(INFO) << "Node stopped.";
|
2014-03-03 22:07:58 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
bool command_line_preprocessor(const boost::program_options::variables_map &vm, LoggerRef &logger) {
|
2014-03-03 22:07:58 +00:00
|
|
|
bool exit = false;
|
2015-05-27 12:08:46 +00:00
|
|
|
|
|
|
|
if (command_line::get_arg(vm, command_line::arg_version)) {
|
|
|
|
std::cout << CryptoNote::CRYPTONOTE_NAME << " v" << PROJECT_VERSION_LONG << ENDL;
|
2014-03-03 22:07:58 +00:00
|
|
|
exit = true;
|
|
|
|
}
|
2015-05-27 12:08:46 +00:00
|
|
|
if (command_line::get_arg(vm, arg_os_version)) {
|
2015-07-30 15:22:07 +00:00
|
|
|
std::cout << "OS: " << Tools::get_os_version_string() << ENDL;
|
2014-03-03 22:07:58 +00:00
|
|
|
exit = true;
|
|
|
|
}
|
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
if (exit) {
|
2014-03-03 22:07:58 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|