dncurrency/nano/nano_wallet/entry.cpp
cryptocode bab4474274
Network selector (#1729)
* Network selector

* Make sure network option is checked before working path is called (migration). Also remove bool assignment from error.

* Formatting

* Fix merge error

* Use network_params for RPC port config (rebase)

* Formatting

* Rebase

* Rebase (debug_opencl, merge fix)

* Rebase fix

* post-rebase update
2019-03-11 16:10:33 +01:00

409 lines
12 KiB
C++

#include <nano/lib/errors.hpp>
#include <nano/lib/jsonconfig.hpp>
#include <nano/lib/utility.hpp>
#include <nano/nano_wallet/icon.hpp>
#include <nano/node/cli.hpp>
#include <nano/node/ipc.hpp>
#include <nano/node/rpc.hpp>
#include <nano/node/working.hpp>
#include <nano/qt/qt.hpp>
#include <boost/make_shared.hpp>
#include <boost/program_options.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp>
class qt_wallet_config
{
public:
qt_wallet_config (boost::filesystem::path const & application_path_a) :
account (0),
rpc_enable (false),
opencl_enable (false)
{
nano::random_pool::generate_block (wallet.bytes.data (), wallet.bytes.size ());
assert (!wallet.is_zero ());
}
bool upgrade_json (unsigned version_a, nano::jsonconfig & json)
{
json.put ("version", json_version ());
auto upgraded (false);
switch (version_a)
{
case 1:
{
nano::account account;
account.decode_account (json.get<std::string> ("account"));
json.erase ("account");
json.put ("account", account.to_account ());
json.erase ("version");
upgraded = true;
}
case 2:
{
nano::jsonconfig rpc_l;
rpc.serialize_json (rpc_l);
json.put ("rpc_enable", "false");
json.put_child ("rpc", rpc_l);
json.erase ("version");
upgraded = true;
}
case 3:
{
auto opencl_enable_l (json.get_optional<bool> ("opencl_enable"));
if (!opencl_enable_l)
{
json.put ("opencl_enable", "false");
}
auto opencl_l (json.get_optional_child ("opencl"));
if (!opencl_l)
{
nano::jsonconfig opencl_l;
opencl.serialize_json (opencl_l);
json.put_child ("opencl", opencl_l);
}
upgraded = true;
}
case 4:
break;
default:
throw std::runtime_error ("Unknown qt_wallet_config version");
}
return upgraded;
}
nano::error deserialize_json (bool & upgraded_a, nano::jsonconfig & json)
{
if (!json.empty ())
{
auto version_l (json.get_optional<unsigned> ("version"));
if (!version_l)
{
version_l = 1;
json.put ("version", version_l.get ());
upgraded_a = true;
}
upgraded_a |= upgrade_json (version_l.get (), json);
auto wallet_l (json.get<std::string> ("wallet"));
auto account_l (json.get<std::string> ("account"));
auto node_l (json.get_required_child ("node"));
rpc_enable = json.get<bool> ("rpc_enable");
auto rpc_l (json.get_required_child ("rpc"));
opencl_enable = json.get<bool> ("opencl_enable");
auto opencl_l (json.get_required_child ("opencl"));
if (wallet.decode_hex (wallet_l))
{
json.get_error ().set ("Invalid wallet id. Did you open a node daemon config?");
}
else if (account.decode_account (account_l))
{
json.get_error ().set ("Invalid account");
}
if (!node_l.get_error ())
{
node.deserialize_json (upgraded_a, node_l);
}
if (!rpc_l.get_error ())
{
rpc.deserialize_json (upgraded_a, rpc_l);
}
if (!opencl_l.get_error ())
{
opencl.deserialize_json (opencl_l);
}
if (wallet.is_zero ())
{
nano::random_pool::generate_block (wallet.bytes.data (), wallet.bytes.size ());
upgraded_a = true;
}
}
else
{
serialize_json (json);
upgraded_a = true;
}
return json.get_error ();
}
void serialize_json (nano::jsonconfig & json)
{
std::string wallet_string;
wallet.encode_hex (wallet_string);
json.put ("version", json_version ());
json.put ("wallet", wallet_string);
json.put ("account", account.to_account ());
nano::jsonconfig node_l;
node.enable_voting = false;
node.bootstrap_connections_max = 4;
node.serialize_json (node_l);
json.put_child ("node", node_l);
nano::jsonconfig rpc_l;
rpc.serialize_json (rpc_l);
json.put_child ("rpc", rpc_l);
json.put ("rpc_enable", rpc_enable);
json.put ("opencl_enable", opencl_enable);
nano::jsonconfig opencl_l;
opencl.serialize_json (opencl_l);
json.put_child ("opencl", opencl_l);
}
bool serialize_json_stream (std::ostream & stream_a)
{
auto result (false);
stream_a.seekp (0);
try
{
nano::jsonconfig json;
serialize_json (json);
json.write (stream_a);
}
catch (std::runtime_error const & ex)
{
std::cerr << ex.what () << std::endl;
result = true;
}
return result;
}
nano::uint256_union wallet;
nano::account account;
nano::node_config node;
bool rpc_enable;
nano::rpc_config rpc;
bool opencl_enable;
nano::opencl_config opencl;
int json_version () const
{
return 4;
}
};
namespace
{
void show_error (std::string const & message_a)
{
QMessageBox message (QMessageBox::Critical, "Error starting Nano", message_a.c_str ());
message.setModal (true);
message.show ();
message.exec ();
}
bool update_config (qt_wallet_config & config_a, boost::filesystem::path const & config_path_a)
{
auto account (config_a.account);
auto wallet (config_a.wallet);
auto error (false);
nano::jsonconfig config;
if (!config.read_and_update (config_a, config_path_a))
{
if (account != config_a.account || wallet != config_a.wallet)
{
config_a.account = account;
config_a.wallet = wallet;
// Update json file with new account and/or wallet values
std::fstream config_file;
config_file.open (config_path_a.string (), std::ios_base::out | std::ios_base::trunc);
error = config_a.serialize_json_stream (config_file);
}
}
return error;
}
}
int run_wallet (QApplication & application, int argc, char * const * argv, boost::filesystem::path const & data_path, nano::node_flags const & flags)
{
nano_qt::eventloop_processor processor;
boost::system::error_code error_chmod;
boost::filesystem::create_directories (data_path);
nano::set_secure_perm_directory (data_path, error_chmod);
QPixmap pixmap (":/logo.png");
QSplashScreen * splash = new QSplashScreen (pixmap);
splash->show ();
application.processEvents ();
splash->showMessage (QSplashScreen::tr ("Remember - Back Up Your Wallet Seed"), Qt::AlignBottom | Qt::AlignHCenter, Qt::darkGray);
application.processEvents ();
qt_wallet_config config (data_path);
auto config_path ((data_path / "config.json"));
int result (0);
nano::jsonconfig json;
auto error (json.read_and_update (config, config_path));
nano::set_secure_perm_file (config_path, error_chmod);
if (!error)
{
boost::asio::io_context io_ctx;
config.node.logging.init (data_path);
std::shared_ptr<nano::node> node;
std::shared_ptr<nano_qt::wallet> gui;
nano::set_application_icon (application);
auto opencl (nano::opencl_work::create (config.opencl_enable, config.opencl, config.node.logging));
nano::work_pool work (config.node.work_threads, opencl ? [&opencl](nano::uint256_union const & root_a, uint64_t difficulty_a) {
return opencl->generate_work (root_a, difficulty_a);
}
: std::function<boost::optional<uint64_t> (nano::uint256_union const &, uint64_t)> (nullptr));
nano::alarm alarm (io_ctx);
nano::node_init init;
node = std::make_shared<nano::node> (init, io_ctx, data_path, alarm, config.node, work, flags);
if (!init.error ())
{
auto wallet (node->wallets.open (config.wallet));
if (wallet == nullptr)
{
auto existing (node->wallets.items.begin ());
if (existing != node->wallets.items.end ())
{
wallet = existing->second;
config.wallet = existing->first;
}
else
{
wallet = node->wallets.create (config.wallet);
}
}
if (config.account.is_zero () || !wallet->exists (config.account))
{
auto transaction (wallet->wallets.tx_begin (true));
auto existing (wallet->store.begin (transaction));
if (existing != wallet->store.end ())
{
nano::uint256_union account (existing->first);
config.account = account;
}
else
{
config.account = wallet->deterministic_insert (transaction);
}
}
assert (wallet->exists (config.account));
update_config (config, config_path);
node->start ();
std::unique_ptr<nano::rpc> rpc = get_rpc (io_ctx, *node, config.rpc);
if (rpc)
{
rpc->start (config.rpc_enable);
}
nano::ipc::ipc_server ipc (*node, *rpc);
nano::thread_runner runner (io_ctx, node->config.io_threads);
QObject::connect (&application, &QApplication::aboutToQuit, [&]() {
ipc.stop ();
rpc->stop ();
node->stop ();
});
application.postEvent (&processor, new nano_qt::eventloop_event ([&]() {
gui = std::make_shared<nano_qt::wallet> (application, processor, *node, wallet, config.account);
splash->close ();
gui->start ();
gui->client_window->show ();
}));
result = application.exec ();
runner.join ();
}
else
{
splash->hide ();
show_error ("Error initializing node");
}
update_config (config, config_path);
}
else
{
splash->hide ();
show_error ("Error deserializing config: " + json.get_error ().get_message ());
}
return result;
}
int main (int argc, char * const * argv)
{
nano::set_umask ();
try
{
QApplication application (argc, const_cast<char **> (argv));
boost::program_options::options_description description ("Command line options");
description.add_options () ("help", "Print out options");
nano::add_node_options (description);
boost::program_options::variables_map vm;
boost::program_options::store (boost::program_options::command_line_parser (argc, argv).options (description).allow_unregistered ().run (), vm);
boost::program_options::notify (vm);
int result (0);
auto network (vm.find ("network"));
if (network != vm.end ())
{
auto err (nano::network_params::set_active_network (network->second.as<std::string> ()));
if (err)
{
std::cerr << err.get_message () << std::endl;
std::exit (1);
}
}
if (!vm.count ("data_path"))
{
std::string error_string;
if (!nano::migrate_working_path (error_string))
{
throw std::runtime_error (error_string);
}
}
auto ec = nano::handle_node_options (vm);
if (ec == nano::error_cli::unknown_command)
{
if (vm.count ("help") != 0)
{
std::cout << description << std::endl;
}
else
{
try
{
boost::filesystem::path data_path;
if (vm.count ("data_path"))
{
auto name (vm["data_path"].as<std::string> ());
data_path = boost::filesystem::path (name);
}
else
{
data_path = nano::working_path ();
}
nano::node_flags flags;
auto batch_size_it = vm.find ("batch_size");
if (batch_size_it != vm.end ())
{
flags.sideband_batch_size = batch_size_it->second.as<size_t> ();
}
flags.disable_backup = (vm.count ("disable_backup") > 0);
flags.disable_lazy_bootstrap = (vm.count ("disable_lazy_bootstrap") > 0);
flags.disable_legacy_bootstrap = (vm.count ("disable_legacy_bootstrap") > 0);
flags.disable_wallet_bootstrap = (vm.count ("disable_wallet_bootstrap") > 0);
flags.disable_bootstrap_listener = (vm.count ("disable_bootstrap_listener") > 0);
flags.disable_unchecked_cleanup = (vm.count ("disable_unchecked_cleanup") > 0);
flags.disable_unchecked_drop = (vm.count ("disable_unchecked_drop") > 0);
flags.fast_bootstrap = (vm.count ("fast_bootstrap") > 0);
result = run_wallet (application, argc, argv, data_path, flags);
}
catch (std::exception const & e)
{
show_error (boost::str (boost::format ("Exception while running wallet: %1%") % e.what ()));
}
catch (...)
{
show_error ("Unknown exception while running wallet");
}
}
}
return result;
}
catch (std::exception const & e)
{
std::cerr << boost::str (boost::format ("Exception while initializing %1%") % e.what ());
}
catch (...)
{
std::cerr << boost::str (boost::format ("Unknown exception while initializing"));
}
return 1;
}