Error type and config handling (#1416)
* Error type and config handling * Prevent splash screen from obscuring error dialog * Remove unnecessary string conversions * Add missing include * msvc barks at inline constexpr (N3652) * Remove unnecessary inline specifier * Incorporate review feedback * Remove superfluous inline keywords, fix size->empty * Use any_of instead of raw loop * Simplify file/stream handling and tests * Missing header * Explicit conversion operators, defaulted c'tors
This commit is contained in:
		
					parent
					
						
							
								79e6756151
							
						
					
				
			
			
				commit
				
					
						282cc0ddd3
					
				
			
		
					 23 changed files with 1420 additions and 687 deletions
				
			
		| 
						 | 
				
			
			@ -1,5 +1,6 @@
 | 
			
		|||
#include <gtest/gtest.h>
 | 
			
		||||
#include <nano/core_test/testutil.hpp>
 | 
			
		||||
#include <nano/lib/jsonconfig.hpp>
 | 
			
		||||
#include <nano/node/testing.hpp>
 | 
			
		||||
#include <nano/node/working.hpp>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -428,7 +429,7 @@ TEST (logging, serialization)
 | 
			
		|||
	logging1.work_generation_time_value = !logging1.work_generation_time_value;
 | 
			
		||||
	logging1.log_to_cerr_value = !logging1.log_to_cerr_value;
 | 
			
		||||
	logging1.max_size = 10;
 | 
			
		||||
	boost::property_tree::ptree tree;
 | 
			
		||||
	nano::jsonconfig tree;
 | 
			
		||||
	logging1.serialize_json (tree);
 | 
			
		||||
	nano::logging logging2;
 | 
			
		||||
	logging2.init (path);
 | 
			
		||||
| 
						 | 
				
			
			@ -460,7 +461,7 @@ TEST (logging, upgrade_v1_v2)
 | 
			
		|||
	logging1.init (path1);
 | 
			
		||||
	nano::logging logging2;
 | 
			
		||||
	logging2.init (path2);
 | 
			
		||||
	boost::property_tree::ptree tree;
 | 
			
		||||
	nano::jsonconfig tree;
 | 
			
		||||
	logging1.serialize_json (tree);
 | 
			
		||||
	tree.erase ("version");
 | 
			
		||||
	tree.erase ("vote");
 | 
			
		||||
| 
						 | 
				
			
			@ -499,7 +500,7 @@ TEST (node_config, serialization)
 | 
			
		|||
	config1.callback_port = 10;
 | 
			
		||||
	config1.callback_target = "test";
 | 
			
		||||
	config1.lmdb_max_dbs = 256;
 | 
			
		||||
	boost::property_tree::ptree tree;
 | 
			
		||||
	nano::jsonconfig tree;
 | 
			
		||||
	config1.serialize_json (tree);
 | 
			
		||||
	nano::logging logging2;
 | 
			
		||||
	logging2.init (path);
 | 
			
		||||
| 
						 | 
				
			
			@ -541,27 +542,27 @@ TEST (node_config, v1_v2_upgrade)
 | 
			
		|||
	auto path (nano::unique_path ());
 | 
			
		||||
	nano::logging logging1;
 | 
			
		||||
	logging1.init (path);
 | 
			
		||||
	boost::property_tree::ptree tree;
 | 
			
		||||
	nano::jsonconfig tree;
 | 
			
		||||
	tree.put ("peering_port", std::to_string (0));
 | 
			
		||||
	tree.put ("packet_delay_microseconds", std::to_string (0));
 | 
			
		||||
	tree.put ("bootstrap_fraction_numerator", std::to_string (0));
 | 
			
		||||
	tree.put ("creation_rebroadcast", std::to_string (0));
 | 
			
		||||
	tree.put ("rebroadcast_delay", std::to_string (0));
 | 
			
		||||
	tree.put ("receive_minimum", nano::amount (0).to_string_dec ());
 | 
			
		||||
	boost::property_tree::ptree logging_l;
 | 
			
		||||
	nano::jsonconfig logging_l;
 | 
			
		||||
	logging1.serialize_json (logging_l);
 | 
			
		||||
	tree.add_child ("logging", logging_l);
 | 
			
		||||
	boost::property_tree::ptree preconfigured_peers_l;
 | 
			
		||||
	tree.add_child ("preconfigured_peers", preconfigured_peers_l);
 | 
			
		||||
	boost::property_tree::ptree preconfigured_representatives_l;
 | 
			
		||||
	tree.add_child ("preconfigured_representatives", preconfigured_representatives_l);
 | 
			
		||||
	tree.put_child ("logging", logging_l);
 | 
			
		||||
	nano::jsonconfig preconfigured_peers_l;
 | 
			
		||||
	tree.put_child ("preconfigured_peers", preconfigured_peers_l);
 | 
			
		||||
	nano::jsonconfig preconfigured_representatives_l;
 | 
			
		||||
	tree.put_child ("preconfigured_representatives", preconfigured_representatives_l);
 | 
			
		||||
	bool upgraded (false);
 | 
			
		||||
	nano::node_config config1;
 | 
			
		||||
	config1.logging.init (path);
 | 
			
		||||
	ASSERT_FALSE (tree.get_child_optional ("work_peers"));
 | 
			
		||||
	ASSERT_FALSE (tree.get_optional_child ("work_peers"));
 | 
			
		||||
	config1.deserialize_json (upgraded, tree);
 | 
			
		||||
	ASSERT_TRUE (upgraded);
 | 
			
		||||
	ASSERT_TRUE (!!tree.get_child_optional ("work_peers"));
 | 
			
		||||
	ASSERT_TRUE (!!tree.get_optional_child ("work_peers"));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST (node_config, v2_v3_upgrade)
 | 
			
		||||
| 
						 | 
				
			
			@ -569,7 +570,7 @@ TEST (node_config, v2_v3_upgrade)
 | 
			
		|||
	auto path (nano::unique_path ());
 | 
			
		||||
	nano::logging logging1;
 | 
			
		||||
	logging1.init (path);
 | 
			
		||||
	boost::property_tree::ptree tree;
 | 
			
		||||
	nano::jsonconfig tree;
 | 
			
		||||
	tree.put ("peering_port", std::to_string (0));
 | 
			
		||||
	tree.put ("packet_delay_microseconds", std::to_string (0));
 | 
			
		||||
	tree.put ("bootstrap_fraction_numerator", std::to_string (0));
 | 
			
		||||
| 
						 | 
				
			
			@ -577,18 +578,16 @@ TEST (node_config, v2_v3_upgrade)
 | 
			
		|||
	tree.put ("rebroadcast_delay", std::to_string (0));
 | 
			
		||||
	tree.put ("receive_minimum", nano::amount (0).to_string_dec ());
 | 
			
		||||
	tree.put ("version", "2");
 | 
			
		||||
	boost::property_tree::ptree logging_l;
 | 
			
		||||
	nano::jsonconfig logging_l;
 | 
			
		||||
	logging1.serialize_json (logging_l);
 | 
			
		||||
	tree.add_child ("logging", logging_l);
 | 
			
		||||
	boost::property_tree::ptree preconfigured_peers_l;
 | 
			
		||||
	tree.add_child ("preconfigured_peers", preconfigured_peers_l);
 | 
			
		||||
	boost::property_tree::ptree preconfigured_representatives_l;
 | 
			
		||||
	boost::property_tree::ptree entry;
 | 
			
		||||
	entry.put ("", "TR6ZJ4pdp6HC76xMRpVDny5x2s8AEbrhFue3NKVxYYdmKuTEib");
 | 
			
		||||
	preconfigured_representatives_l.push_back (std::make_pair ("", entry));
 | 
			
		||||
	tree.add_child ("preconfigured_representatives", preconfigured_representatives_l);
 | 
			
		||||
	boost::property_tree::ptree work_peers_l;
 | 
			
		||||
	tree.add_child ("work_peers", work_peers_l);
 | 
			
		||||
	tree.put_child ("logging", logging_l);
 | 
			
		||||
	nano::jsonconfig preconfigured_peers_l;
 | 
			
		||||
	tree.put_child ("preconfigured_peers", preconfigured_peers_l);
 | 
			
		||||
	nano::jsonconfig preconfigured_representatives_l;
 | 
			
		||||
	preconfigured_representatives_l.push ("TR6ZJ4pdp6HC76xMRpVDny5x2s8AEbrhFue3NKVxYYdmKuTEib");
 | 
			
		||||
	tree.put_child ("preconfigured_representatives", preconfigured_representatives_l);
 | 
			
		||||
	nano::jsonconfig work_peers_l;
 | 
			
		||||
	tree.put_child ("work_peers", work_peers_l);
 | 
			
		||||
	bool upgraded (false);
 | 
			
		||||
	nano::node_config config1;
 | 
			
		||||
	config1.logging.init (path);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,6 +6,7 @@
 | 
			
		|||
#include <boost/property_tree/ptree.hpp>
 | 
			
		||||
#include <boost/thread.hpp>
 | 
			
		||||
#include <nano/core_test/testutil.hpp>
 | 
			
		||||
#include <nano/lib/jsonconfig.hpp>
 | 
			
		||||
#include <nano/node/common.hpp>
 | 
			
		||||
#include <nano/node/rpc.hpp>
 | 
			
		||||
#include <nano/node/testing.hpp>
 | 
			
		||||
| 
						 | 
				
			
			@ -1578,7 +1579,7 @@ TEST (rpc_config, serialization)
 | 
			
		|||
	config1.enable_control = true;
 | 
			
		||||
	config1.frontier_request_limit = 8192;
 | 
			
		||||
	config1.chain_request_limit = 4096;
 | 
			
		||||
	boost::property_tree::ptree tree;
 | 
			
		||||
	nano::jsonconfig tree;
 | 
			
		||||
	config1.serialize_json (tree);
 | 
			
		||||
	nano::rpc_config config2;
 | 
			
		||||
	ASSERT_NE (config2.address, config1.address);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,7 @@
 | 
			
		|||
#include <gtest/gtest.h>
 | 
			
		||||
 | 
			
		||||
#include <nano/lib/interface.h>
 | 
			
		||||
#include <nano/lib/jsonconfig.hpp>
 | 
			
		||||
#include <nano/secure/common.hpp>
 | 
			
		||||
 | 
			
		||||
namespace
 | 
			
		||||
| 
						 | 
				
			
			@ -427,24 +428,38 @@ TEST (uint256_union, operator_less_than)
 | 
			
		|||
	test_union_operator_less_than<nano::uint256_union, nano::uint256_t> ();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class json_initial_value_test
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	json_initial_value_test (std::string text_a) :
 | 
			
		||||
	text (std::move (text_a))
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
	nano::error serialize_json (nano::jsonconfig & json)
 | 
			
		||||
	{
 | 
			
		||||
		json.put ("thing", text);
 | 
			
		||||
		return json.get_error ();
 | 
			
		||||
	}
 | 
			
		||||
	std::string text;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class json_upgrade_test
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	bool deserialize_json (bool & upgraded, boost::property_tree::ptree & tree_a)
 | 
			
		||||
	nano::error deserialize_json (bool & upgraded, nano::jsonconfig & json)
 | 
			
		||||
	{
 | 
			
		||||
		auto error (false);
 | 
			
		||||
		if (!tree_a.empty ())
 | 
			
		||||
		if (!json.empty ())
 | 
			
		||||
		{
 | 
			
		||||
			auto text_l (tree_a.get<std::string> ("thing"));
 | 
			
		||||
			if (text_l == "junktest")
 | 
			
		||||
			auto text_l (json.get<std::string> ("thing"));
 | 
			
		||||
			if (text_l == "junktest" || text_l == "created")
 | 
			
		||||
			{
 | 
			
		||||
				upgraded = true;
 | 
			
		||||
				text_l = "changed";
 | 
			
		||||
				tree_a.put ("thing", text_l);
 | 
			
		||||
				json.put ("thing", text_l);
 | 
			
		||||
			}
 | 
			
		||||
			if (text_l == "error")
 | 
			
		||||
			{
 | 
			
		||||
				error = true;
 | 
			
		||||
				json.get_error () = nano::error_common::generic;
 | 
			
		||||
			}
 | 
			
		||||
			text = text_l;
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -452,63 +467,41 @@ public:
 | 
			
		|||
		{
 | 
			
		||||
			upgraded = true;
 | 
			
		||||
			text = "created";
 | 
			
		||||
			tree_a.put ("thing", text);
 | 
			
		||||
			json.put ("thing", text);
 | 
			
		||||
		}
 | 
			
		||||
		return error;
 | 
			
		||||
		return json.get_error ();
 | 
			
		||||
	}
 | 
			
		||||
	std::string text;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
TEST (json, fetch_object)
 | 
			
		||||
/** Both create and upgrade via read_and_update() */
 | 
			
		||||
TEST (json, create_and_upgrade)
 | 
			
		||||
{
 | 
			
		||||
	auto path1 (nano::unique_path ());
 | 
			
		||||
	std::fstream stream1;
 | 
			
		||||
	nano::open_or_create (stream1, path1.string ());
 | 
			
		||||
	stream1 << "{ \"thing\": \"junktest\" }";
 | 
			
		||||
	stream1.close ();
 | 
			
		||||
	nano::open_or_create (stream1, path1.string ());
 | 
			
		||||
	auto path (nano::unique_path ());
 | 
			
		||||
	nano::jsonconfig json;
 | 
			
		||||
	json_upgrade_test object1;
 | 
			
		||||
	auto error1 (nano::fetch_object (object1, path1));
 | 
			
		||||
	ASSERT_FALSE (error1);
 | 
			
		||||
	ASSERT_EQ ("changed", object1.text);
 | 
			
		||||
	boost::property_tree::ptree tree1;
 | 
			
		||||
	stream1.close ();
 | 
			
		||||
	nano::open_or_create (stream1, path1.string ());
 | 
			
		||||
	boost::property_tree::read_json (stream1, tree1);
 | 
			
		||||
	ASSERT_EQ ("changed", tree1.get<std::string> ("thing"));
 | 
			
		||||
	std::string string2 ("{ \"thing\": \"junktest2\" }");
 | 
			
		||||
	std::stringstream stream2 (string2);
 | 
			
		||||
	ASSERT_FALSE (json.read_and_update (object1, path));
 | 
			
		||||
	ASSERT_EQ ("created", object1.text);
 | 
			
		||||
 | 
			
		||||
	nano::jsonconfig json2;
 | 
			
		||||
	json_upgrade_test object2;
 | 
			
		||||
	auto error2 (nano::fetch_object (object2, stream2));
 | 
			
		||||
	ASSERT_FALSE (error2);
 | 
			
		||||
	ASSERT_EQ ("junktest2", object2.text);
 | 
			
		||||
	ASSERT_EQ ("{ \"thing\": \"junktest2\" }", string2);
 | 
			
		||||
	std::string string3 ("{ \"thing\": \"error\" }");
 | 
			
		||||
	std::stringstream stream3 (string3);
 | 
			
		||||
	json_upgrade_test object3;
 | 
			
		||||
	auto error3 (nano::fetch_object (object3, stream3));
 | 
			
		||||
	ASSERT_TRUE (error3);
 | 
			
		||||
	auto path2 (nano::unique_path ());
 | 
			
		||||
	std::fstream stream4;
 | 
			
		||||
	nano::open_or_create (stream4, path2.string ());
 | 
			
		||||
	json_upgrade_test object4;
 | 
			
		||||
	auto error4 (nano::fetch_object (object4, path2));
 | 
			
		||||
	ASSERT_FALSE (error4);
 | 
			
		||||
	ASSERT_EQ ("created", object4.text);
 | 
			
		||||
	boost::property_tree::ptree tree2;
 | 
			
		||||
	stream4.close ();
 | 
			
		||||
	nano::open_or_create (stream4, path2.string ());
 | 
			
		||||
	boost::property_tree::read_json (stream4, tree2);
 | 
			
		||||
	ASSERT_EQ ("created", tree2.get<std::string> ("thing"));
 | 
			
		||||
	ASSERT_FALSE (json2.read_and_update (object2, path));
 | 
			
		||||
	ASSERT_EQ ("changed", object2.text);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST (json, DISABLED_fetch_write_fail)
 | 
			
		||||
/** Create config manually, then upgrade via read_and_update() with multiple calls to test idempotence */
 | 
			
		||||
TEST (json, upgrade_from_existing)
 | 
			
		||||
{
 | 
			
		||||
	std::string string4 ("");
 | 
			
		||||
	std::stringstream stream4 (string4, std::ios_base::in);
 | 
			
		||||
	json_upgrade_test object4;
 | 
			
		||||
	auto error4 (nano::fetch_object (object4, stream4));
 | 
			
		||||
	ASSERT_TRUE (error4);
 | 
			
		||||
	auto path (nano::unique_path ());
 | 
			
		||||
	nano::jsonconfig json;
 | 
			
		||||
	json_initial_value_test junktest ("junktest");
 | 
			
		||||
	junktest.serialize_json (json);
 | 
			
		||||
	json.write (path);
 | 
			
		||||
	json_upgrade_test object1;
 | 
			
		||||
	ASSERT_FALSE (json.read_and_update (object1, path));
 | 
			
		||||
	ASSERT_EQ ("changed", object1.text);
 | 
			
		||||
	ASSERT_FALSE (json.read_and_update (object1, path));
 | 
			
		||||
	ASSERT_EQ ("changed", object1.text);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST (uint64_t, parse)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,6 @@
 | 
			
		|||
#include <gtest/gtest.h>
 | 
			
		||||
 | 
			
		||||
#include <nano/lib/jsonconfig.hpp>
 | 
			
		||||
#include <nano/node/node.hpp>
 | 
			
		||||
#include <nano/node/wallet.hpp>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -88,7 +89,7 @@ TEST (work, opencl_config)
 | 
			
		|||
	config1.platform = 1;
 | 
			
		||||
	config1.device = 2;
 | 
			
		||||
	config1.threads = 3;
 | 
			
		||||
	boost::property_tree::ptree tree;
 | 
			
		||||
	nano::jsonconfig tree;
 | 
			
		||||
	config1.serialize_json (tree);
 | 
			
		||||
	nano::opencl_config config2;
 | 
			
		||||
	ASSERT_FALSE (config2.deserialize_json (tree));
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,6 +22,7 @@ add_library (nano_lib
 | 
			
		|||
	config.hpp
 | 
			
		||||
	interface.cpp
 | 
			
		||||
	interface.h
 | 
			
		||||
	jsonconfig.hpp
 | 
			
		||||
	numbers.cpp
 | 
			
		||||
	numbers.hpp
 | 
			
		||||
	timer.hpp
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,6 +20,8 @@ std::string nano::error_common_messages::message (int ev) const
 | 
			
		|||
			return "Missing signature";
 | 
			
		||||
		case nano::error_common::missing_work:
 | 
			
		||||
			return "Missing work";
 | 
			
		||||
		case nano::error_common::exception:
 | 
			
		||||
			return "Exception thrown";
 | 
			
		||||
		case nano::error_common::account_exists:
 | 
			
		||||
			return "Account already exists";
 | 
			
		||||
		case nano::error_common::account_not_found:
 | 
			
		||||
| 
						 | 
				
			
			@ -66,6 +68,8 @@ std::string nano::error_common_messages::message (int ev) const
 | 
			
		|||
			return "Invalid port";
 | 
			
		||||
		case nano::error_common::invalid_index:
 | 
			
		||||
			return "Invalid index";
 | 
			
		||||
		case nano::error_common::invalid_type_conversion:
 | 
			
		||||
			return "Invalid type conversion";
 | 
			
		||||
		case nano::error_common::invalid_work:
 | 
			
		||||
			return "Invalid work";
 | 
			
		||||
		case nano::error_common::numeric_conversion:
 | 
			
		||||
| 
						 | 
				
			
			@ -199,3 +203,18 @@ std::string nano::error_process_messages::message (int ev) const
 | 
			
		|||
 | 
			
		||||
	return "Invalid error code";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string nano::error_config_messages::message (int ev) const
 | 
			
		||||
{
 | 
			
		||||
	switch (static_cast<nano::error_config> (ev))
 | 
			
		||||
	{
 | 
			
		||||
		case nano::error_config::generic:
 | 
			
		||||
			return "Unknown error";
 | 
			
		||||
		case nano::error_config::invalid_value:
 | 
			
		||||
			return "Invalid configuration value";
 | 
			
		||||
		case nano::error_config::missing_value:
 | 
			
		||||
			return "Missing value in configuration";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return "Invalid error code";
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,8 @@
 | 
			
		|||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <boost/system/error_code.hpp>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <nano/lib/expected.hpp>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <system_error>
 | 
			
		||||
| 
						 | 
				
			
			@ -10,24 +13,11 @@ using tl::make_unexpected;
 | 
			
		|||
 | 
			
		||||
namespace nano
 | 
			
		||||
{
 | 
			
		||||
/** Returns the error code if non-zero, otherwise the value */
 | 
			
		||||
template <class T>
 | 
			
		||||
auto either (T && value, std::error_code ec) -> expected<typename std::remove_reference<T>::type, std::error_code>
 | 
			
		||||
{
 | 
			
		||||
	if (ec)
 | 
			
		||||
	{
 | 
			
		||||
		return make_unexpected (ec);
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		return std::move (value);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Common error codes */
 | 
			
		||||
enum class error_common
 | 
			
		||||
{
 | 
			
		||||
	generic = 1,
 | 
			
		||||
	exception,
 | 
			
		||||
	account_not_found,
 | 
			
		||||
	account_not_found_wallet,
 | 
			
		||||
	account_exists,
 | 
			
		||||
| 
						 | 
				
			
			@ -57,6 +47,7 @@ enum class error_common
 | 
			
		|||
	invalid_index,
 | 
			
		||||
	invalid_ip_address,
 | 
			
		||||
	invalid_port,
 | 
			
		||||
	invalid_type_conversion,
 | 
			
		||||
	invalid_work,
 | 
			
		||||
	insufficient_balance,
 | 
			
		||||
	numeric_conversion,
 | 
			
		||||
| 
						 | 
				
			
			@ -125,6 +116,29 @@ enum class error_process
 | 
			
		|||
	block_position, // This block cannot follow the previous block
 | 
			
		||||
	other
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** config.json deserialization related errors */
 | 
			
		||||
enum class error_config
 | 
			
		||||
{
 | 
			
		||||
	generic = 1,
 | 
			
		||||
	invalid_value,
 | 
			
		||||
	missing_value,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // nano namespace
 | 
			
		||||
 | 
			
		||||
/** Returns the error code if non-zero, otherwise the value */
 | 
			
		||||
template <class T>
 | 
			
		||||
auto either (T && value, std::error_code ec) -> expected<typename std::remove_reference_t<T>, std::error_code>
 | 
			
		||||
{
 | 
			
		||||
	if (ec)
 | 
			
		||||
	{
 | 
			
		||||
		return make_unexpected (ec);
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		return std::move (value);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Convenience macro to implement the standard boilerplate for using std::error_code with enums
 | 
			
		||||
| 
						 | 
				
			
			@ -172,3 +186,290 @@ REGISTER_ERROR_CODES (nano, error_common);
 | 
			
		|||
REGISTER_ERROR_CODES (nano, error_blocks);
 | 
			
		||||
REGISTER_ERROR_CODES (nano, error_rpc);
 | 
			
		||||
REGISTER_ERROR_CODES (nano, error_process);
 | 
			
		||||
REGISTER_ERROR_CODES (nano, error_config);
 | 
			
		||||
 | 
			
		||||
/* boost->std error_code bridge */
 | 
			
		||||
namespace nano
 | 
			
		||||
{
 | 
			
		||||
namespace error_conversion
 | 
			
		||||
{
 | 
			
		||||
	const std::error_category & generic_category ();
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace std
 | 
			
		||||
{
 | 
			
		||||
template <>
 | 
			
		||||
struct is_error_code_enum<boost::system::errc::errc_t>
 | 
			
		||||
: public std::true_type
 | 
			
		||||
{
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
inline std::error_code make_error_code (boost::system::errc::errc_t e)
 | 
			
		||||
{
 | 
			
		||||
	return std::error_code (static_cast<int> (e),
 | 
			
		||||
	::nano::error_conversion::generic_category ());
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
namespace nano
 | 
			
		||||
{
 | 
			
		||||
namespace error_conversion
 | 
			
		||||
{
 | 
			
		||||
	namespace detail
 | 
			
		||||
	{
 | 
			
		||||
		class generic_category : public std::error_category
 | 
			
		||||
		{
 | 
			
		||||
		public:
 | 
			
		||||
			virtual const char * name () const noexcept override
 | 
			
		||||
			{
 | 
			
		||||
				return boost::system::generic_category ().name ();
 | 
			
		||||
			}
 | 
			
		||||
			virtual std::string message (int value) const override
 | 
			
		||||
			{
 | 
			
		||||
				return boost::system::generic_category ().message (value);
 | 
			
		||||
			}
 | 
			
		||||
		};
 | 
			
		||||
	}
 | 
			
		||||
	inline const std::error_category & generic_category ()
 | 
			
		||||
	{
 | 
			
		||||
		static detail::generic_category instance;
 | 
			
		||||
		return instance;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inline std::error_code convert (const boost::system::error_code & error)
 | 
			
		||||
	{
 | 
			
		||||
		if (error.category () == boost::system::generic_category ())
 | 
			
		||||
		{
 | 
			
		||||
			return std::error_code (error.value (),
 | 
			
		||||
			nano::error_conversion::generic_category ());
 | 
			
		||||
		}
 | 
			
		||||
		assert (false);
 | 
			
		||||
 | 
			
		||||
		return nano::error_common::invalid_type_conversion;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace nano
 | 
			
		||||
{
 | 
			
		||||
/** Adapter for std/boost::error_code, std::exception and bool flags to facilitate unified error handling */
 | 
			
		||||
class error
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	error () = default;
 | 
			
		||||
	error (nano::error const & error_a) = default;
 | 
			
		||||
	error (nano::error && error_a) = default;
 | 
			
		||||
 | 
			
		||||
	error (std::error_code code_a)
 | 
			
		||||
	{
 | 
			
		||||
		code = code_a;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	error (std::string message_a)
 | 
			
		||||
	{
 | 
			
		||||
		code = nano::error_common::generic;
 | 
			
		||||
		message = std::move (message_a);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	error (std::exception const & exception_a)
 | 
			
		||||
	{
 | 
			
		||||
		code = nano::error_common::exception;
 | 
			
		||||
		message = exception_a.what ();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	error & operator= (nano::error const & err_a)
 | 
			
		||||
	{
 | 
			
		||||
		code = err_a.code;
 | 
			
		||||
		message = err_a.message;
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	error & operator= (nano::error && err_a)
 | 
			
		||||
	{
 | 
			
		||||
		code = err_a.code;
 | 
			
		||||
		message = std::move (err_a.message);
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** Assign error code */
 | 
			
		||||
	error & operator= (const std::error_code code_a)
 | 
			
		||||
	{
 | 
			
		||||
		code = code_a;
 | 
			
		||||
		message.clear ();
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** Assign boost error code (as converted to std::error_code) */
 | 
			
		||||
	error & operator= (const boost::system::error_code & code_a)
 | 
			
		||||
	{
 | 
			
		||||
		code = nano::error_conversion::convert (code_a);
 | 
			
		||||
		message.clear ();
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** Assign boost error code (as converted to std::error_code) */
 | 
			
		||||
	error & operator= (const boost::system::errc::errc_t & code_a)
 | 
			
		||||
	{
 | 
			
		||||
		code = nano::error_conversion::convert (boost::system::errc::make_error_code (code_a));
 | 
			
		||||
		message.clear ();
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** Set the error to nano::error_common::generic and the error message to \p message_a */
 | 
			
		||||
	error & operator= (const std::string message_a)
 | 
			
		||||
	{
 | 
			
		||||
		code = nano::error_common::generic;
 | 
			
		||||
		message = std::move (message_a);
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** Set the error to nano::error_common::generic. */
 | 
			
		||||
	error & operator= (bool is_error)
 | 
			
		||||
	{
 | 
			
		||||
		if (is_error)
 | 
			
		||||
		{
 | 
			
		||||
			code = nano::error_common::generic;
 | 
			
		||||
		}
 | 
			
		||||
		message.clear ();
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** Sets the error to nano::error_common::exception and adopts the exception error message. */
 | 
			
		||||
	error & operator= (std::exception const & exception_a)
 | 
			
		||||
	{
 | 
			
		||||
		code = nano::error_common::exception;
 | 
			
		||||
		message = exception_a.what ();
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** Return true if this#error_code equals the parameter */
 | 
			
		||||
	bool operator== (const std::error_code code_a)
 | 
			
		||||
	{
 | 
			
		||||
		return code == code_a;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** Return true if this#error_code equals the parameter */
 | 
			
		||||
	bool operator== (const boost::system::error_code code_a)
 | 
			
		||||
	{
 | 
			
		||||
		return code.value () == code_a.value ();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** Call the function iff the current error is zero */
 | 
			
		||||
	error & then (std::function<nano::error &()> next)
 | 
			
		||||
	{
 | 
			
		||||
		return code ? *this : next ();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** If the current error is one of the listed codes, reset the error code */
 | 
			
		||||
	template <typename... ErrorCode>
 | 
			
		||||
	error & accept (ErrorCode... err)
 | 
			
		||||
	{
 | 
			
		||||
		// Convert variadic arguments to std::error_code
 | 
			
		||||
		auto codes = { std::error_code (err)... };
 | 
			
		||||
		if (std::any_of (codes.begin (), codes.end (), [this, &codes](auto & code_a) { return code == code_a; }))
 | 
			
		||||
		{
 | 
			
		||||
			code.clear ();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** Implicit error_code conversion */
 | 
			
		||||
	explicit operator std::error_code () const
 | 
			
		||||
	{
 | 
			
		||||
		return code;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** Implicit bool conversion; true if there's an error */
 | 
			
		||||
	explicit operator bool () const
 | 
			
		||||
	{
 | 
			
		||||
		return code.value () != 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** Implicit string conversion; returns the error message or an empty string. */
 | 
			
		||||
	explicit operator std::string () const
 | 
			
		||||
	{
 | 
			
		||||
		return get_message ();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Get error message, or an empty string if there's no error. If a custom error message is set,
 | 
			
		||||
	 * that will be returned, otherwise the error_code#message() is returned.
 | 
			
		||||
	 */
 | 
			
		||||
	std::string get_message () const
 | 
			
		||||
	{
 | 
			
		||||
		std::string res = message;
 | 
			
		||||
		if (code && res.empty ())
 | 
			
		||||
		{
 | 
			
		||||
			res = code.message ();
 | 
			
		||||
		}
 | 
			
		||||
		return res;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** Set an error message, but only if the error code is already set */
 | 
			
		||||
	error & on_error (std::string message_a)
 | 
			
		||||
	{
 | 
			
		||||
		if (code)
 | 
			
		||||
		{
 | 
			
		||||
			message = std::move (message_a);
 | 
			
		||||
		}
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** Set an error message if the current error code matches \p code_a */
 | 
			
		||||
	error & on_error (std::error_code code_a, std::string message_a)
 | 
			
		||||
	{
 | 
			
		||||
		if (code == code_a)
 | 
			
		||||
		{
 | 
			
		||||
			message = std::move (message_a);
 | 
			
		||||
		}
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** Set an error message and an error code */
 | 
			
		||||
	error & set (std::string message_a, std::error_code code_a = nano::error_common::generic)
 | 
			
		||||
	{
 | 
			
		||||
		message = message_a;
 | 
			
		||||
		code = code_a;
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** Set a custom error message. If the error code is not set, it will be set to nano::error_common::generic. */
 | 
			
		||||
	error & set_message (std::string message_a)
 | 
			
		||||
	{
 | 
			
		||||
		if (!code)
 | 
			
		||||
		{
 | 
			
		||||
			code = nano::error_common::generic;
 | 
			
		||||
		}
 | 
			
		||||
		message = std::move (message_a);
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** Clear an errors */
 | 
			
		||||
	error & clear ()
 | 
			
		||||
	{
 | 
			
		||||
		code.clear ();
 | 
			
		||||
		message.clear ();
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	std::error_code code;
 | 
			
		||||
	std::string message;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A type that manages a nano::error.
 | 
			
		||||
 * The default return type is nano::error&, though shared_ptr<nano::error> is a good option in cases
 | 
			
		||||
 * where shared error state is desirable.
 | 
			
		||||
 */
 | 
			
		||||
template <typename RET_TYPE = nano::error &>
 | 
			
		||||
class error_aware
 | 
			
		||||
{
 | 
			
		||||
	static_assert (std::is_same<RET_TYPE, nano::error &>::value || std::is_same<RET_TYPE, std::shared_ptr<nano::error>>::value, "Must be nano::error& or shared_ptr<nano::error>");
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
	/** Returns the error object managed by this object */
 | 
			
		||||
	virtual RET_TYPE get_error () = 0;
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										487
									
								
								nano/lib/jsonconfig.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										487
									
								
								nano/lib/jsonconfig.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,487 @@
 | 
			
		|||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <boost/asio.hpp>
 | 
			
		||||
#include <boost/filesystem.hpp>
 | 
			
		||||
#include <boost/lexical_cast.hpp>
 | 
			
		||||
#include <boost/optional.hpp>
 | 
			
		||||
#include <boost/property_tree/json_parser.hpp>
 | 
			
		||||
#include <fstream>
 | 
			
		||||
#include <nano/lib/errors.hpp>
 | 
			
		||||
 | 
			
		||||
namespace nano
 | 
			
		||||
{
 | 
			
		||||
/** Type trait to determine if T is compatible with boost's lexical_cast */
 | 
			
		||||
template <class T>
 | 
			
		||||
struct is_lexical_castable : std::integral_constant<bool,
 | 
			
		||||
                             (std::is_default_constructible<T>::value && (boost::has_right_shift<std::basic_istream<wchar_t>, T>::value || boost::has_right_shift<std::basic_istream<char>, T>::value))>
 | 
			
		||||
{
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Type descriptions are used to automatically construct configuration error messages */
 | 
			
		||||
// clang-format off
 | 
			
		||||
template <typename T> inline std::string type_desc (void) { return "an unknown type"; }
 | 
			
		||||
template <> inline std::string type_desc<int8_t> (void) { return "an integer between -128 and 127"; }
 | 
			
		||||
template <> inline std::string type_desc<uint8_t> (void) { return "an integer between 0 and 255"; }
 | 
			
		||||
template <> inline std::string type_desc<int16_t> (void) { return "an integer between -32768 and 32767"; }
 | 
			
		||||
template <> inline std::string type_desc<uint16_t> (void) { return "an integer between 0 and 65535"; }
 | 
			
		||||
template <> inline std::string type_desc<int32_t> (void) { return "a 32-bit signed integer"; }
 | 
			
		||||
template <> inline std::string type_desc<uint32_t> (void) { return "a 32-bit unsigned integer"; }
 | 
			
		||||
template <> inline std::string type_desc<int64_t> (void) { return "a 64-bit signed integer"; }
 | 
			
		||||
template <> inline std::string type_desc<uint64_t> (void) { return "a 64-bit unsigned integer"; }
 | 
			
		||||
template <> inline std::string type_desc<float> (void) { return "a single precision floating point number"; }
 | 
			
		||||
template <> inline std::string type_desc<double> (void) { return "a double precison floating point number"; }
 | 
			
		||||
template <> inline std::string type_desc<char> (void) { return "a character"; }
 | 
			
		||||
template <> inline std::string type_desc<std::string> (void) { return "a string"; }
 | 
			
		||||
template <> inline std::string type_desc<bool> (void) { return "a boolean"; }
 | 
			
		||||
template <> inline std::string type_desc<boost::asio::ip::address_v6> (void) { return "an IP address"; }
 | 
			
		||||
// clang-format on
 | 
			
		||||
 | 
			
		||||
/** Manages a node in a boost configuration tree. */
 | 
			
		||||
class jsonconfig : public nano::error_aware<>
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	jsonconfig ()
 | 
			
		||||
	{
 | 
			
		||||
		error = std::make_shared<nano::error> ();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	jsonconfig (boost::property_tree::ptree const & tree_a, std::shared_ptr<nano::error> error_a = nullptr) :
 | 
			
		||||
	tree (tree_a), error (error_a)
 | 
			
		||||
	{
 | 
			
		||||
		if (!error)
 | 
			
		||||
		{
 | 
			
		||||
			error = std::make_shared<nano::error> ();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Reads a json object from the stream and if it was changed, write the object back to the stream.
 | 
			
		||||
	 * @return nano::error&, including a descriptive error message if the config file is malformed.
 | 
			
		||||
	 */
 | 
			
		||||
	template <typename T>
 | 
			
		||||
	nano::error & read_and_update (T & object, boost::filesystem::path const & path_a)
 | 
			
		||||
	{
 | 
			
		||||
		std::fstream stream;
 | 
			
		||||
		open_or_create (stream, path_a.string ());
 | 
			
		||||
		if (!stream.fail ())
 | 
			
		||||
		{
 | 
			
		||||
			try
 | 
			
		||||
			{
 | 
			
		||||
				boost::property_tree::read_json (stream, tree);
 | 
			
		||||
			}
 | 
			
		||||
			catch (std::runtime_error const & ex)
 | 
			
		||||
			{
 | 
			
		||||
				auto pos (stream.tellg ());
 | 
			
		||||
				if (pos != std::streampos (0))
 | 
			
		||||
				{
 | 
			
		||||
					*error = ex;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			stream.close ();
 | 
			
		||||
			if (!*error)
 | 
			
		||||
			{
 | 
			
		||||
				auto updated (false);
 | 
			
		||||
				*error = object.deserialize_json (updated, *this);
 | 
			
		||||
				if (!*error && updated)
 | 
			
		||||
				{
 | 
			
		||||
					stream.open (path_a.string (), std::ios_base::out | std::ios_base::trunc);
 | 
			
		||||
					try
 | 
			
		||||
					{
 | 
			
		||||
						boost::property_tree::write_json (stream, tree);
 | 
			
		||||
					}
 | 
			
		||||
					catch (std::runtime_error const & ex)
 | 
			
		||||
					{
 | 
			
		||||
						*error = ex;
 | 
			
		||||
					}
 | 
			
		||||
					stream.close ();
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return *error;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void write (boost::filesystem::path const & path_a)
 | 
			
		||||
	{
 | 
			
		||||
		std::fstream stream;
 | 
			
		||||
		open_or_create (stream, path_a.string ());
 | 
			
		||||
		write (stream);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void write (std::ostream & stream_a) const
 | 
			
		||||
	{
 | 
			
		||||
		boost::property_tree::write_json (stream_a, tree);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void read (std::istream & stream_a)
 | 
			
		||||
	{
 | 
			
		||||
		boost::property_tree::read_json (stream_a, tree);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** Open confiruation file, create if necessary */
 | 
			
		||||
	void open_or_create (std::fstream & stream_a, std::string const & path_a)
 | 
			
		||||
	{
 | 
			
		||||
		stream_a.open (path_a, std::ios_base::in);
 | 
			
		||||
		if (stream_a.fail ())
 | 
			
		||||
		{
 | 
			
		||||
			stream_a.open (path_a, std::ios_base::out);
 | 
			
		||||
		}
 | 
			
		||||
		stream_a.close ();
 | 
			
		||||
		stream_a.open (path_a, std::ios_base::in | std::ios_base::out);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** Returns the boost property node managed by this instance */
 | 
			
		||||
	boost::property_tree::ptree const & get_tree ()
 | 
			
		||||
	{
 | 
			
		||||
		return tree;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** Returns true if the property tree node is empty */
 | 
			
		||||
	bool empty () const
 | 
			
		||||
	{
 | 
			
		||||
		return tree.empty ();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** Optionally returns the given child node */
 | 
			
		||||
	jsonconfig & get_optional_child (std::string const & key_a, boost::optional<jsonconfig> & child_config)
 | 
			
		||||
	{
 | 
			
		||||
		auto child = tree.get_child_optional (key_a);
 | 
			
		||||
		if (child)
 | 
			
		||||
		{
 | 
			
		||||
			child_config = jsonconfig (child.get (), error);
 | 
			
		||||
		}
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	boost::optional<jsonconfig> get_optional_child (std::string const & key_a)
 | 
			
		||||
	{
 | 
			
		||||
		boost::optional<jsonconfig> child_config;
 | 
			
		||||
		auto child = tree.get_child_optional (key_a);
 | 
			
		||||
		if (child)
 | 
			
		||||
		{
 | 
			
		||||
			child_config = jsonconfig (child.get (), error);
 | 
			
		||||
		}
 | 
			
		||||
		return child_config;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	jsonconfig & get_required_child (std::string const & key_a, jsonconfig & child_config /*out*/)
 | 
			
		||||
	{
 | 
			
		||||
		auto child = tree.get_child_optional (key_a);
 | 
			
		||||
		if (child)
 | 
			
		||||
		{
 | 
			
		||||
			child_config = jsonconfig (child.get (), error);
 | 
			
		||||
		}
 | 
			
		||||
		else if (!*error)
 | 
			
		||||
		{
 | 
			
		||||
			*error = nano::error_config::missing_value;
 | 
			
		||||
			error->set_message ("Missing configuration node: " + key_a);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	jsonconfig get_required_child (std::string const & key_a)
 | 
			
		||||
	{
 | 
			
		||||
		jsonconfig child_config;
 | 
			
		||||
		get_required_child (key_a, child_config);
 | 
			
		||||
		return child_config;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	jsonconfig & put_child (std::string const & key_a, nano::jsonconfig & conf_a)
 | 
			
		||||
	{
 | 
			
		||||
		tree.add_child (key_a, conf_a.get_tree ());
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	jsonconfig & replace_child (std::string const & key_a, nano::jsonconfig & conf_a)
 | 
			
		||||
	{
 | 
			
		||||
		conf_a.erase (key_a);
 | 
			
		||||
		conf_a.put_child (key_a, conf_a);
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** Set value for the given key. Any existing value will be overwritten. */
 | 
			
		||||
	template <typename T>
 | 
			
		||||
	jsonconfig & put (std::string const & key, T const & value)
 | 
			
		||||
	{
 | 
			
		||||
		tree.put (key, value);
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** Push array element */
 | 
			
		||||
	template <typename T>
 | 
			
		||||
	jsonconfig & push (T const & value)
 | 
			
		||||
	{
 | 
			
		||||
		boost::property_tree::ptree entry;
 | 
			
		||||
		entry.put ("", value);
 | 
			
		||||
		tree.push_back (std::make_pair ("", entry));
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** Iterate array entries */
 | 
			
		||||
	template <typename T>
 | 
			
		||||
	jsonconfig & array_entries (std::function<void(T)> callback)
 | 
			
		||||
	{
 | 
			
		||||
		for (auto & entry : tree)
 | 
			
		||||
		{
 | 
			
		||||
			callback (entry.second.get<T> (""));
 | 
			
		||||
		}
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** Returns true if \p key_a is present */
 | 
			
		||||
	bool has_key (std::string const & key_a)
 | 
			
		||||
	{
 | 
			
		||||
		return tree.find (key_a) != tree.not_found ();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** Erase the property of given key */
 | 
			
		||||
	jsonconfig & erase (std::string const & key_a)
 | 
			
		||||
	{
 | 
			
		||||
		tree.erase (key_a);
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** Get optional, using \p default_value if \p key is missing. */
 | 
			
		||||
	template <typename T>
 | 
			
		||||
	jsonconfig & get_optional (std::string const & key, T & target, T default_value)
 | 
			
		||||
	{
 | 
			
		||||
		get_config<T> (true, key, target, default_value);
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Get optional value, using the current value of \p target as the default if \p key is missing.
 | 
			
		||||
	 * @return May return nano::error_config::invalid_value
 | 
			
		||||
	 */
 | 
			
		||||
	template <typename T>
 | 
			
		||||
	jsonconfig & get_optional (std::string const & key, T & target)
 | 
			
		||||
	{
 | 
			
		||||
		get_config<T> (true, key, target, target);
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** Return a boost::optional<T> for the given key */
 | 
			
		||||
	template <typename T>
 | 
			
		||||
	boost::optional<T> get_optional (std::string const & key)
 | 
			
		||||
	{
 | 
			
		||||
		boost::optional<T> res;
 | 
			
		||||
		if (has_key (key))
 | 
			
		||||
		{
 | 
			
		||||
			T target{};
 | 
			
		||||
			get_config<T> (true, key, target, target);
 | 
			
		||||
			res = target;
 | 
			
		||||
		}
 | 
			
		||||
		return res;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** Get value, using the current value of \p target as the default if \p key is missing. */
 | 
			
		||||
	template <typename T>
 | 
			
		||||
	jsonconfig & get (std::string const & key, T & target)
 | 
			
		||||
	{
 | 
			
		||||
		get_config<T> (true, key, target, target);
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Get value of required key
 | 
			
		||||
	 * @note May set nano::error_config::missing_value if \p key is missing, nano::error_config::invalid_value if value is invalid.
 | 
			
		||||
	 */
 | 
			
		||||
	template <typename T>
 | 
			
		||||
	T get (std::string const & key)
 | 
			
		||||
	{
 | 
			
		||||
		T target{};
 | 
			
		||||
		get_config<T> (true, key, target, target);
 | 
			
		||||
		return target;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Get required value.
 | 
			
		||||
	 * @note May set nano::error_config::missing_value if \p key is missing, nano::error_config::invalid_value if value is invalid.
 | 
			
		||||
	 */
 | 
			
		||||
	template <typename T>
 | 
			
		||||
	jsonconfig & get_required (std::string const & key, T & target)
 | 
			
		||||
	{
 | 
			
		||||
		get_config<T> (false, key, target);
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** Turn on or off automatic error message generation */
 | 
			
		||||
	void set_auto_error_message (bool auto_a)
 | 
			
		||||
	{
 | 
			
		||||
		auto_error_message = auto_a;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	nano::error & get_error () override
 | 
			
		||||
	{
 | 
			
		||||
		return *error;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
	template <typename T>
 | 
			
		||||
	void construct_error_message (bool optional, std::string const & key)
 | 
			
		||||
	{
 | 
			
		||||
		if (auto_error_message && *error)
 | 
			
		||||
		{
 | 
			
		||||
			if (optional)
 | 
			
		||||
			{
 | 
			
		||||
				error->set_message (key + " is not " + type_desc<T> ());
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				error->set_message (key + " is required and must be " + type_desc<T> ());
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** Set error if not already set. That is, first error remains until get_error().clear() is called. */
 | 
			
		||||
	template <typename T, typename V>
 | 
			
		||||
	void conditionally_set_error (V error_a, bool optional, std::string const & key)
 | 
			
		||||
	{
 | 
			
		||||
		if (!*error)
 | 
			
		||||
		{
 | 
			
		||||
			*error = error_a;
 | 
			
		||||
			construct_error_message<T> (optional, key);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	template <typename T, typename = std::enable_if_t<nano::is_lexical_castable<T>::value>>
 | 
			
		||||
	jsonconfig & get_config (bool optional, std::string key, T & target, T default_value = T ())
 | 
			
		||||
	{
 | 
			
		||||
		try
 | 
			
		||||
		{
 | 
			
		||||
			auto val (tree.get<std::string> (key));
 | 
			
		||||
			if (!boost::conversion::try_lexical_convert<T> (val, target))
 | 
			
		||||
			{
 | 
			
		||||
				conditionally_set_error<T> (nano::error_config::invalid_value, optional, key);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		catch (boost::property_tree::ptree_bad_path const & ex)
 | 
			
		||||
		{
 | 
			
		||||
			if (!optional)
 | 
			
		||||
			{
 | 
			
		||||
				conditionally_set_error<T> (nano::error_config::missing_value, optional, key);
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				target = default_value;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		catch (std::runtime_error & ex)
 | 
			
		||||
		{
 | 
			
		||||
			conditionally_set_error<T> (ex, optional, key);
 | 
			
		||||
		}
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// boost's lexical cast doesn't handle (u)int8_t
 | 
			
		||||
	template <typename T, typename = std::enable_if_t<std::is_same<T, uint8_t>::value>>
 | 
			
		||||
	jsonconfig & get_config (bool optional, std::string key, uint8_t & target, uint8_t default_value = T ())
 | 
			
		||||
	{
 | 
			
		||||
		int64_t tmp;
 | 
			
		||||
		try
 | 
			
		||||
		{
 | 
			
		||||
			auto val (tree.get<std::string> (key));
 | 
			
		||||
			if (!boost::conversion::try_lexical_convert<int64_t> (val, tmp) || tmp < 0 || tmp > 255)
 | 
			
		||||
			{
 | 
			
		||||
				conditionally_set_error<T> (nano::error_config::invalid_value, optional, key);
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				target = static_cast<uint8_t> (tmp);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		catch (boost::property_tree::ptree_bad_path const & ex)
 | 
			
		||||
		{
 | 
			
		||||
			if (!optional)
 | 
			
		||||
			{
 | 
			
		||||
				conditionally_set_error<T> (nano::error_config::missing_value, optional, key);
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				target = default_value;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		catch (std::runtime_error & ex)
 | 
			
		||||
		{
 | 
			
		||||
			conditionally_set_error<T> (ex, optional, key);
 | 
			
		||||
		}
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	template <typename T, typename = std::enable_if_t<std::is_same<T, bool>::value>>
 | 
			
		||||
	jsonconfig & get_config (bool optional, std::string key, bool & target, bool default_value = false)
 | 
			
		||||
	{
 | 
			
		||||
		auto bool_conv = [this, &target, &key, optional](std::string val) {
 | 
			
		||||
			if (val == "true")
 | 
			
		||||
			{
 | 
			
		||||
				target = true;
 | 
			
		||||
			}
 | 
			
		||||
			else if (val == "false")
 | 
			
		||||
			{
 | 
			
		||||
				target = false;
 | 
			
		||||
			}
 | 
			
		||||
			else if (!*error)
 | 
			
		||||
			{
 | 
			
		||||
				conditionally_set_error<T> (nano::error_config::invalid_value, optional, key);
 | 
			
		||||
			}
 | 
			
		||||
		};
 | 
			
		||||
		try
 | 
			
		||||
		{
 | 
			
		||||
			auto val (tree.get<std::string> (key));
 | 
			
		||||
			bool_conv (val);
 | 
			
		||||
		}
 | 
			
		||||
		catch (boost::property_tree::ptree_bad_path const & ex)
 | 
			
		||||
		{
 | 
			
		||||
			if (!optional)
 | 
			
		||||
			{
 | 
			
		||||
				conditionally_set_error<T> (nano::error_config::missing_value, optional, key);
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				target = default_value;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		catch (std::runtime_error & ex)
 | 
			
		||||
		{
 | 
			
		||||
			conditionally_set_error<T> (ex, optional, key);
 | 
			
		||||
		}
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	template <typename T, typename = std::enable_if_t<std::is_same<T, boost::asio::ip::address_v6>::value>>
 | 
			
		||||
	jsonconfig & get_config (bool optional, std::string key, boost::asio::ip::address_v6 & target, boost::asio::ip::address_v6 default_value = T ())
 | 
			
		||||
	{
 | 
			
		||||
		try
 | 
			
		||||
		{
 | 
			
		||||
			auto address_l (tree.get<std::string> (key));
 | 
			
		||||
			boost::system::error_code bec;
 | 
			
		||||
			target = boost::asio::ip::address_v6::from_string (address_l, bec);
 | 
			
		||||
			if (bec)
 | 
			
		||||
			{
 | 
			
		||||
				conditionally_set_error<T> (nano::error_config::invalid_value, optional, key);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		catch (boost::property_tree::ptree_bad_path const & ex)
 | 
			
		||||
		{
 | 
			
		||||
			if (!optional)
 | 
			
		||||
			{
 | 
			
		||||
				conditionally_set_error<T> (nano::error_config::missing_value, optional, key);
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				target = default_value;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	/** The property node being managed */
 | 
			
		||||
	boost::property_tree::ptree tree;
 | 
			
		||||
 | 
			
		||||
	/** If set, automatically construct error messages based on parameters and type information. */
 | 
			
		||||
	bool auto_error_message{ true };
 | 
			
		||||
 | 
			
		||||
	/** We're a nano::error_aware type. Child nodes share the error state. */
 | 
			
		||||
	std::shared_ptr<nano::error> error;
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,3 +1,4 @@
 | 
			
		|||
#include <nano/lib/jsonconfig.hpp>
 | 
			
		||||
#include <nano/lib/utility.hpp>
 | 
			
		||||
#include <nano/nano_node/daemon.hpp>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -12,86 +13,104 @@ opencl_enable (false)
 | 
			
		|||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nano_daemon::daemon_config::serialize_json (boost::property_tree::ptree & tree_a)
 | 
			
		||||
nano::error nano_daemon::daemon_config::serialize_json (nano::jsonconfig & json)
 | 
			
		||||
{
 | 
			
		||||
	tree_a.put ("version", std::to_string (json_version));
 | 
			
		||||
	tree_a.put ("rpc_enable", rpc_enable);
 | 
			
		||||
	boost::property_tree::ptree rpc_l;
 | 
			
		||||
	json.put ("version", json_version ());
 | 
			
		||||
	json.put ("rpc_enable", rpc_enable);
 | 
			
		||||
 | 
			
		||||
	nano::jsonconfig rpc_l;
 | 
			
		||||
	rpc.serialize_json (rpc_l);
 | 
			
		||||
	tree_a.add_child ("rpc", rpc_l);
 | 
			
		||||
	boost::property_tree::ptree node_l;
 | 
			
		||||
	json.put_child ("rpc", rpc_l);
 | 
			
		||||
 | 
			
		||||
	nano::jsonconfig node_l;
 | 
			
		||||
	node.serialize_json (node_l);
 | 
			
		||||
	tree_a.add_child ("node", node_l);
 | 
			
		||||
	tree_a.put ("opencl_enable", opencl_enable);
 | 
			
		||||
	boost::property_tree::ptree opencl_l;
 | 
			
		||||
	nano::jsonconfig node (node_l);
 | 
			
		||||
	json.put_child ("node", node);
 | 
			
		||||
 | 
			
		||||
	json.put ("opencl_enable", opencl_enable);
 | 
			
		||||
	nano::jsonconfig opencl_l;
 | 
			
		||||
	opencl.serialize_json (opencl_l);
 | 
			
		||||
	tree_a.add_child ("opencl", opencl_l);
 | 
			
		||||
	json.put_child ("opencl", opencl_l);
 | 
			
		||||
	return json.get_error ();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool nano_daemon::daemon_config::deserialize_json (bool & upgraded_a, boost::property_tree::ptree & tree_a)
 | 
			
		||||
nano::error nano_daemon::daemon_config::deserialize_json (bool & upgraded_a, nano::jsonconfig & json)
 | 
			
		||||
{
 | 
			
		||||
	auto error (false);
 | 
			
		||||
	try
 | 
			
		||||
	{
 | 
			
		||||
		if (!tree_a.empty ())
 | 
			
		||||
		if (!json.empty ())
 | 
			
		||||
		{
 | 
			
		||||
			auto version_l (tree_a.get_optional<std::string> ("version"));
 | 
			
		||||
			if (!version_l)
 | 
			
		||||
			int version_l;
 | 
			
		||||
			json.get_optional<int> ("version", version_l);
 | 
			
		||||
			upgraded_a |= upgrade_json (version_l, json);
 | 
			
		||||
 | 
			
		||||
			json.get_optional<bool> ("rpc_enable", rpc_enable);
 | 
			
		||||
			nano::jsonconfig rpc_l;
 | 
			
		||||
			json.get_required_child ("rpc", rpc_l);
 | 
			
		||||
 | 
			
		||||
			if (!rpc.deserialize_json (rpc_l))
 | 
			
		||||
			{
 | 
			
		||||
				tree_a.put ("version", "1");
 | 
			
		||||
				version_l = "1";
 | 
			
		||||
				nano::jsonconfig node_l;
 | 
			
		||||
				json.get_required_child ("node", node_l);
 | 
			
		||||
				if (!json.get_error ())
 | 
			
		||||
				{
 | 
			
		||||
					node.deserialize_json (upgraded_a, node_l);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if (!json.get_error ())
 | 
			
		||||
			{
 | 
			
		||||
				json.get_required<bool> ("opencl_enable", opencl_enable);
 | 
			
		||||
				nano::jsonconfig opencl_l;
 | 
			
		||||
				json.get_required_child ("opencl", opencl_l);
 | 
			
		||||
				if (!json.get_error ())
 | 
			
		||||
				{
 | 
			
		||||
					opencl.deserialize_json (opencl_l);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			upgraded_a |= upgrade_json (std::stoull (version_l.get ()), tree_a);
 | 
			
		||||
			rpc_enable = tree_a.get<bool> ("rpc_enable");
 | 
			
		||||
			auto rpc_l (tree_a.get_child ("rpc"));
 | 
			
		||||
			error |= rpc.deserialize_json (rpc_l);
 | 
			
		||||
			auto & node_l (tree_a.get_child ("node"));
 | 
			
		||||
			error |= node.deserialize_json (upgraded_a, node_l);
 | 
			
		||||
			opencl_enable = tree_a.get<bool> ("opencl_enable");
 | 
			
		||||
			auto & opencl_l (tree_a.get_child ("opencl"));
 | 
			
		||||
			error |= opencl.deserialize_json (opencl_l);
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			upgraded_a = true;
 | 
			
		||||
			serialize_json (tree_a);
 | 
			
		||||
			serialize_json (json);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	catch (std::runtime_error const &)
 | 
			
		||||
	catch (std::runtime_error const & ex)
 | 
			
		||||
	{
 | 
			
		||||
		error = true;
 | 
			
		||||
		json.get_error () = ex;
 | 
			
		||||
	}
 | 
			
		||||
	return error;
 | 
			
		||||
	return json.get_error ();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool nano_daemon::daemon_config::upgrade_json (unsigned version_a, boost::property_tree::ptree & tree_a)
 | 
			
		||||
bool nano_daemon::daemon_config::upgrade_json (unsigned version_a, nano::jsonconfig & json)
 | 
			
		||||
{
 | 
			
		||||
	tree_a.put ("version", std::to_string (json_version));
 | 
			
		||||
	auto result (false);
 | 
			
		||||
	json.put ("version", json_version ());
 | 
			
		||||
	auto upgraded_l (false);
 | 
			
		||||
	switch (version_a)
 | 
			
		||||
	{
 | 
			
		||||
		case 1:
 | 
			
		||||
		{
 | 
			
		||||
			auto opencl_enable_l (tree_a.get_optional<bool> ("opencl_enable"));
 | 
			
		||||
			bool opencl_enable_l;
 | 
			
		||||
			json.get_optional<bool> ("opencl_enable", opencl_enable_l);
 | 
			
		||||
			if (!opencl_enable_l)
 | 
			
		||||
			{
 | 
			
		||||
				tree_a.put ("opencl_enable", "false");
 | 
			
		||||
				json.put ("opencl_enable", false);
 | 
			
		||||
			}
 | 
			
		||||
			auto opencl_l (tree_a.get_child_optional ("opencl"));
 | 
			
		||||
			boost::optional<nano::jsonconfig> opencl_l;
 | 
			
		||||
			json.get_optional_child ("opencl", opencl_l);
 | 
			
		||||
			if (!opencl_l)
 | 
			
		||||
			{
 | 
			
		||||
				boost::property_tree::ptree opencl_l;
 | 
			
		||||
				nano::jsonconfig opencl_l;
 | 
			
		||||
				opencl.serialize_json (opencl_l);
 | 
			
		||||
				tree_a.put_child ("opencl", opencl_l);
 | 
			
		||||
				json.put_child ("opencl", opencl_l);
 | 
			
		||||
			}
 | 
			
		||||
			result = true;
 | 
			
		||||
			upgraded_l = true;
 | 
			
		||||
		}
 | 
			
		||||
		case 2:
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			throw std::runtime_error ("Unknown daemon_config version");
 | 
			
		||||
	}
 | 
			
		||||
	return result;
 | 
			
		||||
	return upgraded_l;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nano_daemon::daemon::run (boost::filesystem::path const & data_path, nano::node_flags const & flags)
 | 
			
		||||
| 
						 | 
				
			
			@ -102,7 +121,8 @@ void nano_daemon::daemon::run (boost::filesystem::path const & data_path, nano::
 | 
			
		|||
	nano::set_secure_perm_directory (data_path, error_chmod);
 | 
			
		||||
	auto config_path ((data_path / "config.json"));
 | 
			
		||||
	std::unique_ptr<nano::thread_runner> runner;
 | 
			
		||||
	auto error (nano::fetch_object (config, config_path));
 | 
			
		||||
	nano::jsonconfig json;
 | 
			
		||||
	auto error (json.read_and_update (config, config_path));
 | 
			
		||||
	nano::set_secure_perm_file (config_path, error_chmod);
 | 
			
		||||
	if (!error)
 | 
			
		||||
	{
 | 
			
		||||
| 
						 | 
				
			
			@ -142,6 +162,6 @@ void nano_daemon::daemon::run (boost::filesystem::path const & data_path, nano::
 | 
			
		|||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		std::cerr << "Error deserializing config\n";
 | 
			
		||||
		std::cerr << "Error deserializing config: " << error.get_message () << std::endl;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,4 @@
 | 
			
		|||
#include <nano/lib/errors.hpp>
 | 
			
		||||
#include <nano/node/node.hpp>
 | 
			
		||||
#include <nano/node/rpc.hpp>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -12,14 +13,22 @@ class daemon_config
 | 
			
		|||
{
 | 
			
		||||
public:
 | 
			
		||||
	daemon_config ();
 | 
			
		||||
	bool deserialize_json (bool &, boost::property_tree::ptree &);
 | 
			
		||||
	void serialize_json (boost::property_tree::ptree &);
 | 
			
		||||
	bool upgrade_json (unsigned, boost::property_tree::ptree &);
 | 
			
		||||
	nano::error deserialize_json (bool &, nano::jsonconfig &);
 | 
			
		||||
	nano::error serialize_json (nano::jsonconfig &);
 | 
			
		||||
	/** 
 | 
			
		||||
	 * Returns true if an upgrade occurred
 | 
			
		||||
	 * @param version The version to upgrade to.
 | 
			
		||||
	 * @param config Configuration to upgrade.
 | 
			
		||||
	 */
 | 
			
		||||
	bool upgrade_json (unsigned version, nano::jsonconfig & config);
 | 
			
		||||
	bool rpc_enable;
 | 
			
		||||
	nano::rpc_config rpc;
 | 
			
		||||
	nano::node_config node;
 | 
			
		||||
	bool opencl_enable;
 | 
			
		||||
	nano::opencl_config opencl;
 | 
			
		||||
	static constexpr int json_version = 2;
 | 
			
		||||
	int json_version () const
 | 
			
		||||
	{
 | 
			
		||||
		return 2;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,5 @@
 | 
			
		|||
#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>
 | 
			
		||||
| 
						 | 
				
			
			@ -21,135 +23,139 @@ public:
 | 
			
		|||
		nano::random_pool.GenerateBlock (wallet.bytes.data (), wallet.bytes.size ());
 | 
			
		||||
		assert (!wallet.is_zero ());
 | 
			
		||||
	}
 | 
			
		||||
	bool upgrade_json (unsigned version_a, boost::property_tree::ptree & tree_a)
 | 
			
		||||
	bool upgrade_json (unsigned version_a, nano::jsonconfig & json)
 | 
			
		||||
	{
 | 
			
		||||
		tree_a.put ("version", std::to_string (json_version));
 | 
			
		||||
		auto result (false);
 | 
			
		||||
		json.put ("version", json_version ());
 | 
			
		||||
		auto upgraded (false);
 | 
			
		||||
		switch (version_a)
 | 
			
		||||
		{
 | 
			
		||||
			case 1:
 | 
			
		||||
			{
 | 
			
		||||
				nano::account account;
 | 
			
		||||
				account.decode_account (tree_a.get<std::string> ("account"));
 | 
			
		||||
				tree_a.erase ("account");
 | 
			
		||||
				tree_a.put ("account", account.to_account ());
 | 
			
		||||
				tree_a.erase ("version");
 | 
			
		||||
				result = true;
 | 
			
		||||
				account.decode_account (json.get<std::string> ("account"));
 | 
			
		||||
				json.erase ("account");
 | 
			
		||||
				json.put ("account", account.to_account ());
 | 
			
		||||
				json.erase ("version");
 | 
			
		||||
				upgraded = true;
 | 
			
		||||
			}
 | 
			
		||||
			case 2:
 | 
			
		||||
			{
 | 
			
		||||
				boost::property_tree::ptree rpc_l;
 | 
			
		||||
				nano::jsonconfig rpc_l;
 | 
			
		||||
				rpc.serialize_json (rpc_l);
 | 
			
		||||
				tree_a.put ("rpc_enable", "false");
 | 
			
		||||
				tree_a.put_child ("rpc", rpc_l);
 | 
			
		||||
				tree_a.erase ("version");
 | 
			
		||||
				result = true;
 | 
			
		||||
				json.put ("rpc_enable", "false");
 | 
			
		||||
				json.put_child ("rpc", rpc_l);
 | 
			
		||||
				json.erase ("version");
 | 
			
		||||
				upgraded = true;
 | 
			
		||||
			}
 | 
			
		||||
			case 3:
 | 
			
		||||
			{
 | 
			
		||||
				auto opencl_enable_l (tree_a.get_optional<bool> ("opencl_enable"));
 | 
			
		||||
				auto opencl_enable_l (json.get_optional<bool> ("opencl_enable"));
 | 
			
		||||
				if (!opencl_enable_l)
 | 
			
		||||
				{
 | 
			
		||||
					tree_a.put ("opencl_enable", "false");
 | 
			
		||||
					json.put ("opencl_enable", "false");
 | 
			
		||||
				}
 | 
			
		||||
				auto opencl_l (tree_a.get_child_optional ("opencl"));
 | 
			
		||||
				auto opencl_l (json.get_optional_child ("opencl"));
 | 
			
		||||
				if (!opencl_l)
 | 
			
		||||
				{
 | 
			
		||||
					boost::property_tree::ptree opencl_l;
 | 
			
		||||
					nano::jsonconfig opencl_l;
 | 
			
		||||
					opencl.serialize_json (opencl_l);
 | 
			
		||||
					tree_a.put_child ("opencl", opencl_l);
 | 
			
		||||
					json.put_child ("opencl", opencl_l);
 | 
			
		||||
				}
 | 
			
		||||
				result = true;
 | 
			
		||||
				upgraded = true;
 | 
			
		||||
			}
 | 
			
		||||
			case 4:
 | 
			
		||||
				break;
 | 
			
		||||
			default:
 | 
			
		||||
				throw std::runtime_error ("Unknown qt_wallet_config version");
 | 
			
		||||
		}
 | 
			
		||||
		return result;
 | 
			
		||||
		return upgraded;
 | 
			
		||||
	}
 | 
			
		||||
	bool deserialize_json (bool & upgraded_a, boost::property_tree::ptree & tree_a)
 | 
			
		||||
 | 
			
		||||
	nano::error deserialize_json (bool & upgraded_a, nano::jsonconfig & json)
 | 
			
		||||
	{
 | 
			
		||||
		auto error (false);
 | 
			
		||||
		if (!tree_a.empty ())
 | 
			
		||||
		if (!json.empty ())
 | 
			
		||||
		{
 | 
			
		||||
			auto version_l (tree_a.get_optional<std::string> ("version"));
 | 
			
		||||
			auto version_l (json.get_optional<unsigned> ("version"));
 | 
			
		||||
			if (!version_l)
 | 
			
		||||
			{
 | 
			
		||||
				tree_a.put ("version", "1");
 | 
			
		||||
				version_l = "1";
 | 
			
		||||
				version_l = 1;
 | 
			
		||||
				json.put ("version", version_l.get ());
 | 
			
		||||
				upgraded_a = true;
 | 
			
		||||
			}
 | 
			
		||||
			upgraded_a |= upgrade_json (std::stoull (version_l.get ()), tree_a);
 | 
			
		||||
			auto wallet_l (tree_a.get<std::string> ("wallet"));
 | 
			
		||||
			auto account_l (tree_a.get<std::string> ("account"));
 | 
			
		||||
			auto & node_l (tree_a.get_child ("node"));
 | 
			
		||||
			rpc_enable = tree_a.get<bool> ("rpc_enable");
 | 
			
		||||
			auto & rpc_l (tree_a.get_child ("rpc"));
 | 
			
		||||
			opencl_enable = tree_a.get<bool> ("opencl_enable");
 | 
			
		||||
			auto & opencl_l (tree_a.get_child ("opencl"));
 | 
			
		||||
			try
 | 
			
		||||
			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))
 | 
			
		||||
			{
 | 
			
		||||
				error |= wallet.decode_hex (wallet_l);
 | 
			
		||||
				error |= account.decode_account (account_l);
 | 
			
		||||
				error |= node.deserialize_json (upgraded_a, node_l);
 | 
			
		||||
				error |= rpc.deserialize_json (rpc_l);
 | 
			
		||||
				error |= opencl.deserialize_json (opencl_l);
 | 
			
		||||
				if (wallet.is_zero ())
 | 
			
		||||
				{
 | 
			
		||||
					nano::random_pool.GenerateBlock (wallet.bytes.data (), wallet.bytes.size ());
 | 
			
		||||
					upgraded_a = true;
 | 
			
		||||
				}
 | 
			
		||||
				json.get_error ().set ("Invalid wallet id. Did you open a node daemon config?");
 | 
			
		||||
			}
 | 
			
		||||
			catch (std::logic_error const &)
 | 
			
		||||
			else if (account.decode_account (account_l))
 | 
			
		||||
			{
 | 
			
		||||
				error = true;
 | 
			
		||||
				json.get_error ().set ("Invalid account");
 | 
			
		||||
			}
 | 
			
		||||
			node.deserialize_json (upgraded_a, node_l);
 | 
			
		||||
			rpc.deserialize_json (rpc_l);
 | 
			
		||||
			opencl.deserialize_json (opencl_l);
 | 
			
		||||
			if (wallet.is_zero ())
 | 
			
		||||
			{
 | 
			
		||||
				nano::random_pool.GenerateBlock (wallet.bytes.data (), wallet.bytes.size ());
 | 
			
		||||
				upgraded_a = true;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			serialize_json (tree_a);
 | 
			
		||||
			serialize_json (json);
 | 
			
		||||
			upgraded_a = true;
 | 
			
		||||
		}
 | 
			
		||||
		return error;
 | 
			
		||||
		return json.get_error ();
 | 
			
		||||
	}
 | 
			
		||||
	void serialize_json (boost::property_tree::ptree & tree_a)
 | 
			
		||||
 | 
			
		||||
	void serialize_json (nano::jsonconfig & json)
 | 
			
		||||
	{
 | 
			
		||||
		std::string wallet_string;
 | 
			
		||||
		wallet.encode_hex (wallet_string);
 | 
			
		||||
		tree_a.put ("version", std::to_string (json_version));
 | 
			
		||||
		tree_a.put ("wallet", wallet_string);
 | 
			
		||||
		tree_a.put ("account", account.to_account ());
 | 
			
		||||
		boost::property_tree::ptree node_l;
 | 
			
		||||
		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);
 | 
			
		||||
		tree_a.add_child ("node", node_l);
 | 
			
		||||
		boost::property_tree::ptree rpc_l;
 | 
			
		||||
		json.put_child ("node", node_l);
 | 
			
		||||
		nano::jsonconfig rpc_l;
 | 
			
		||||
		rpc.serialize_json (rpc_l);
 | 
			
		||||
		tree_a.add_child ("rpc", rpc_l);
 | 
			
		||||
		tree_a.put ("rpc_enable", rpc_enable);
 | 
			
		||||
		tree_a.put ("opencl_enable", opencl_enable);
 | 
			
		||||
		boost::property_tree::ptree opencl_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);
 | 
			
		||||
		tree_a.add_child ("opencl", opencl_l);
 | 
			
		||||
		json.put_child ("opencl", opencl_l);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool serialize_json_stream (std::ostream & stream_a)
 | 
			
		||||
	{
 | 
			
		||||
		auto result (false);
 | 
			
		||||
		stream_a.seekp (0);
 | 
			
		||||
		try
 | 
			
		||||
		{
 | 
			
		||||
			boost::property_tree::ptree tree;
 | 
			
		||||
			serialize_json (tree);
 | 
			
		||||
			boost::property_tree::write_json (stream_a, tree);
 | 
			
		||||
			nano::jsonconfig json;
 | 
			
		||||
			serialize_json (json);
 | 
			
		||||
			json.write (stream_a);
 | 
			
		||||
		}
 | 
			
		||||
		catch (std::runtime_error const &)
 | 
			
		||||
		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;
 | 
			
		||||
| 
						 | 
				
			
			@ -157,7 +163,10 @@ public:
 | 
			
		|||
	nano::rpc_config rpc;
 | 
			
		||||
	bool opencl_enable;
 | 
			
		||||
	nano::opencl_config opencl;
 | 
			
		||||
	static constexpr int json_version = 4;
 | 
			
		||||
	int json_version () const
 | 
			
		||||
	{
 | 
			
		||||
		return 4;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
namespace
 | 
			
		||||
| 
						 | 
				
			
			@ -169,19 +178,23 @@ void show_error (std::string const & message_a)
 | 
			
		|||
	message.show ();
 | 
			
		||||
	message.exec ();
 | 
			
		||||
}
 | 
			
		||||
bool update_config (qt_wallet_config & config_a, boost::filesystem::path const & config_path_a, std::fstream & config_file_a)
 | 
			
		||||
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);
 | 
			
		||||
	if (!nano::fetch_object (config_a, config_path_a))
 | 
			
		||||
	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;
 | 
			
		||||
			config_file_a.open (config_path_a.string (), std::ios_base::out | std::ios_base::trunc);
 | 
			
		||||
			error = config_a.serialize_json_stream (config_file_a);
 | 
			
		||||
 | 
			
		||||
			// 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;
 | 
			
		||||
| 
						 | 
				
			
			@ -203,9 +216,8 @@ int run_wallet (QApplication & application, int argc, char * const * argv, boost
 | 
			
		|||
	qt_wallet_config config (data_path);
 | 
			
		||||
	auto config_path ((data_path / "config.json"));
 | 
			
		||||
	int result (0);
 | 
			
		||||
	std::fstream config_file;
 | 
			
		||||
	auto error (nano::fetch_object (config, config_path));
 | 
			
		||||
	config_file.close ();
 | 
			
		||||
	nano::jsonconfig json;
 | 
			
		||||
	auto error (json.read_and_update (config, config_path));
 | 
			
		||||
	nano::set_secure_perm_file (config_path, error_chmod);
 | 
			
		||||
	if (!error)
 | 
			
		||||
	{
 | 
			
		||||
| 
						 | 
				
			
			@ -253,7 +265,7 @@ int run_wallet (QApplication & application, int argc, char * const * argv, boost
 | 
			
		|||
				}
 | 
			
		||||
			}
 | 
			
		||||
			assert (wallet->exists (config.account));
 | 
			
		||||
			update_config (config, config_path, config_file);
 | 
			
		||||
			update_config (config, config_path);
 | 
			
		||||
			node->start ();
 | 
			
		||||
			std::unique_ptr<nano::rpc> rpc = get_rpc (io_ctx, *node, config.rpc);
 | 
			
		||||
			if (rpc && config.rpc_enable)
 | 
			
		||||
| 
						 | 
				
			
			@ -276,13 +288,15 @@ int run_wallet (QApplication & application, int argc, char * const * argv, boost
 | 
			
		|||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			splash->hide ();
 | 
			
		||||
			show_error ("Error initializing node");
 | 
			
		||||
		}
 | 
			
		||||
		update_config (config, config_path, config_file);
 | 
			
		||||
		update_config (config, config_path);
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		show_error ("Error deserializing config");
 | 
			
		||||
		splash->hide ();
 | 
			
		||||
		show_error ("Error deserializing config: " + json.get_error ().get_message ());
 | 
			
		||||
	}
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,6 +2,7 @@
 | 
			
		|||
#include <boost/log/utility/setup/common_attributes.hpp>
 | 
			
		||||
#include <boost/log/utility/setup/console.hpp>
 | 
			
		||||
#include <boost/log/utility/setup/file.hpp>
 | 
			
		||||
#include <boost/property_tree/ptree.hpp>
 | 
			
		||||
#include <nano/node/logging.hpp>
 | 
			
		||||
 | 
			
		||||
nano::logging::logging () :
 | 
			
		||||
| 
						 | 
				
			
			@ -42,104 +43,106 @@ void nano::logging::init (boost::filesystem::path const & application_path_a)
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nano::logging::serialize_json (boost::property_tree::ptree & tree_a) const
 | 
			
		||||
nano::error nano::logging::serialize_json (nano::jsonconfig & json) const
 | 
			
		||||
{
 | 
			
		||||
	tree_a.put ("version", std::to_string (json_version));
 | 
			
		||||
	tree_a.put ("ledger", ledger_logging_value);
 | 
			
		||||
	tree_a.put ("ledger_duplicate", ledger_duplicate_logging_value);
 | 
			
		||||
	tree_a.put ("vote", vote_logging_value);
 | 
			
		||||
	tree_a.put ("network", network_logging_value);
 | 
			
		||||
	tree_a.put ("network_message", network_message_logging_value);
 | 
			
		||||
	tree_a.put ("network_publish", network_publish_logging_value);
 | 
			
		||||
	tree_a.put ("network_packet", network_packet_logging_value);
 | 
			
		||||
	tree_a.put ("network_keepalive", network_keepalive_logging_value);
 | 
			
		||||
	tree_a.put ("network_node_id_handshake", network_node_id_handshake_logging_value);
 | 
			
		||||
	tree_a.put ("node_lifetime_tracing", node_lifetime_tracing_value);
 | 
			
		||||
	tree_a.put ("insufficient_work", insufficient_work_logging_value);
 | 
			
		||||
	tree_a.put ("log_rpc", log_rpc_value);
 | 
			
		||||
	tree_a.put ("bulk_pull", bulk_pull_logging_value);
 | 
			
		||||
	tree_a.put ("work_generation_time", work_generation_time_value);
 | 
			
		||||
	tree_a.put ("upnp_details", upnp_details_logging_value);
 | 
			
		||||
	tree_a.put ("timing", timing_logging_value);
 | 
			
		||||
	tree_a.put ("log_to_cerr", log_to_cerr_value);
 | 
			
		||||
	tree_a.put ("max_size", max_size);
 | 
			
		||||
	tree_a.put ("rotation_size", rotation_size);
 | 
			
		||||
	tree_a.put ("flush", flush);
 | 
			
		||||
	json.put ("version", json_version ());
 | 
			
		||||
	json.put ("ledger", ledger_logging_value);
 | 
			
		||||
	json.put ("ledger_duplicate", ledger_duplicate_logging_value);
 | 
			
		||||
	json.put ("vote", vote_logging_value);
 | 
			
		||||
	json.put ("network", network_logging_value);
 | 
			
		||||
	json.put ("network_message", network_message_logging_value);
 | 
			
		||||
	json.put ("network_publish", network_publish_logging_value);
 | 
			
		||||
	json.put ("network_packet", network_packet_logging_value);
 | 
			
		||||
	json.put ("network_keepalive", network_keepalive_logging_value);
 | 
			
		||||
	json.put ("network_node_id_handshake", network_node_id_handshake_logging_value);
 | 
			
		||||
	json.put ("node_lifetime_tracing", node_lifetime_tracing_value);
 | 
			
		||||
	json.put ("insufficient_work", insufficient_work_logging_value);
 | 
			
		||||
	json.put ("log_rpc", log_rpc_value);
 | 
			
		||||
	json.put ("bulk_pull", bulk_pull_logging_value);
 | 
			
		||||
	json.put ("work_generation_time", work_generation_time_value);
 | 
			
		||||
	json.put ("upnp_details", upnp_details_logging_value);
 | 
			
		||||
	json.put ("timing", timing_logging_value);
 | 
			
		||||
	json.put ("log_to_cerr", log_to_cerr_value);
 | 
			
		||||
	json.put ("max_size", max_size);
 | 
			
		||||
	json.put ("rotation_size", rotation_size);
 | 
			
		||||
	json.put ("flush", flush);
 | 
			
		||||
	return json.get_error ();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool nano::logging::upgrade_json (unsigned version_a, boost::property_tree::ptree & tree_a)
 | 
			
		||||
bool nano::logging::upgrade_json (unsigned version_a, nano::jsonconfig & json)
 | 
			
		||||
{
 | 
			
		||||
	tree_a.put ("version", std::to_string (json_version));
 | 
			
		||||
	auto result (false);
 | 
			
		||||
	json.put ("version", json_version ());
 | 
			
		||||
	auto upgraded_l (false);
 | 
			
		||||
	switch (version_a)
 | 
			
		||||
	{
 | 
			
		||||
		case 1:
 | 
			
		||||
			tree_a.put ("vote", vote_logging_value);
 | 
			
		||||
			result = true;
 | 
			
		||||
			json.put ("vote", vote_logging_value);
 | 
			
		||||
			upgraded_l = true;
 | 
			
		||||
		case 2:
 | 
			
		||||
			tree_a.put ("rotation_size", "4194304");
 | 
			
		||||
			tree_a.put ("flush", "true");
 | 
			
		||||
			result = true;
 | 
			
		||||
			json.put ("rotation_size", rotation_size);
 | 
			
		||||
			json.put ("flush", true);
 | 
			
		||||
			upgraded_l = true;
 | 
			
		||||
		case 3:
 | 
			
		||||
			tree_a.put ("network_node_id_handshake", "false");
 | 
			
		||||
			result = true;
 | 
			
		||||
			json.put ("network_node_id_handshake", false);
 | 
			
		||||
			upgraded_l = true;
 | 
			
		||||
		case 4:
 | 
			
		||||
			tree_a.put ("upnp_details", "false");
 | 
			
		||||
			tree_a.put ("timing", "false");
 | 
			
		||||
			result = true;
 | 
			
		||||
			json.put ("upnp_details", "false");
 | 
			
		||||
			json.put ("timing", "false");
 | 
			
		||||
			upgraded_l = true;
 | 
			
		||||
		case 5:
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			throw std::runtime_error ("Unknown logging_config version");
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
	return result;
 | 
			
		||||
	return upgraded_l;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool nano::logging::deserialize_json (bool & upgraded_a, boost::property_tree::ptree & tree_a)
 | 
			
		||||
nano::error nano::logging::deserialize_json (bool & upgraded_a, nano::jsonconfig & json)
 | 
			
		||||
{
 | 
			
		||||
	auto result (false);
 | 
			
		||||
	try
 | 
			
		||||
	int version_l;
 | 
			
		||||
	if (!json.has_key ("version"))
 | 
			
		||||
	{
 | 
			
		||||
		auto version_l (tree_a.get_optional<std::string> ("version"));
 | 
			
		||||
		if (!version_l)
 | 
			
		||||
		version_l = 1;
 | 
			
		||||
		json.put ("version", version_l);
 | 
			
		||||
 | 
			
		||||
		boost::optional<nano::jsonconfig> work_peers_l;
 | 
			
		||||
		json.get_optional_child ("work_peers", work_peers_l);
 | 
			
		||||
		if (!work_peers_l)
 | 
			
		||||
		{
 | 
			
		||||
			tree_a.put ("version", "1");
 | 
			
		||||
			version_l = "1";
 | 
			
		||||
			auto work_peers_l (tree_a.get_child_optional ("work_peers"));
 | 
			
		||||
			if (!work_peers_l)
 | 
			
		||||
			{
 | 
			
		||||
				tree_a.add_child ("work_peers", boost::property_tree::ptree ());
 | 
			
		||||
			}
 | 
			
		||||
			upgraded_a = true;
 | 
			
		||||
			nano::jsonconfig peers;
 | 
			
		||||
			json.put_child ("work_peers", peers);
 | 
			
		||||
		}
 | 
			
		||||
		upgraded_a |= upgrade_json (std::stoull (version_l.get ()), tree_a);
 | 
			
		||||
		ledger_logging_value = tree_a.get<bool> ("ledger");
 | 
			
		||||
		ledger_duplicate_logging_value = tree_a.get<bool> ("ledger_duplicate");
 | 
			
		||||
		vote_logging_value = tree_a.get<bool> ("vote");
 | 
			
		||||
		network_logging_value = tree_a.get<bool> ("network");
 | 
			
		||||
		network_message_logging_value = tree_a.get<bool> ("network_message");
 | 
			
		||||
		network_publish_logging_value = tree_a.get<bool> ("network_publish");
 | 
			
		||||
		network_packet_logging_value = tree_a.get<bool> ("network_packet");
 | 
			
		||||
		network_keepalive_logging_value = tree_a.get<bool> ("network_keepalive");
 | 
			
		||||
		network_node_id_handshake_logging_value = tree_a.get<bool> ("network_node_id_handshake");
 | 
			
		||||
		node_lifetime_tracing_value = tree_a.get<bool> ("node_lifetime_tracing");
 | 
			
		||||
		insufficient_work_logging_value = tree_a.get<bool> ("insufficient_work");
 | 
			
		||||
		log_rpc_value = tree_a.get<bool> ("log_rpc");
 | 
			
		||||
		bulk_pull_logging_value = tree_a.get<bool> ("bulk_pull");
 | 
			
		||||
		work_generation_time_value = tree_a.get<bool> ("work_generation_time");
 | 
			
		||||
		upnp_details_logging_value = tree_a.get<bool> ("upnp_details");
 | 
			
		||||
		timing_logging_value = tree_a.get<bool> ("timing");
 | 
			
		||||
		log_to_cerr_value = tree_a.get<bool> ("log_to_cerr");
 | 
			
		||||
		max_size = tree_a.get<uintmax_t> ("max_size");
 | 
			
		||||
		rotation_size = tree_a.get<uintmax_t> ("rotation_size", 4194304);
 | 
			
		||||
		flush = tree_a.get<bool> ("flush", true);
 | 
			
		||||
		upgraded_a = true;
 | 
			
		||||
	}
 | 
			
		||||
	catch (std::runtime_error const &)
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		result = true;
 | 
			
		||||
		json.get_required<int> ("version", version_l);
 | 
			
		||||
	}
 | 
			
		||||
	return result;
 | 
			
		||||
 | 
			
		||||
	upgraded_a |= upgrade_json (version_l, json);
 | 
			
		||||
	json.get<bool> ("ledger", ledger_logging_value);
 | 
			
		||||
	json.get<bool> ("ledger_duplicate", ledger_duplicate_logging_value);
 | 
			
		||||
	json.get<bool> ("vote", vote_logging_value);
 | 
			
		||||
	json.get<bool> ("network", network_logging_value);
 | 
			
		||||
	json.get<bool> ("network_message", network_message_logging_value);
 | 
			
		||||
	json.get<bool> ("network_publish", network_publish_logging_value);
 | 
			
		||||
	json.get<bool> ("network_packet", network_packet_logging_value);
 | 
			
		||||
	json.get<bool> ("network_keepalive", network_keepalive_logging_value);
 | 
			
		||||
	json.get<bool> ("network_node_id_handshake", network_node_id_handshake_logging_value);
 | 
			
		||||
	json.get<bool> ("node_lifetime_tracing", node_lifetime_tracing_value);
 | 
			
		||||
	json.get<bool> ("insufficient_work", insufficient_work_logging_value);
 | 
			
		||||
	json.get<bool> ("log_rpc", log_rpc_value);
 | 
			
		||||
	json.get<bool> ("bulk_pull", bulk_pull_logging_value);
 | 
			
		||||
	json.get<bool> ("work_generation_time", work_generation_time_value);
 | 
			
		||||
	json.get<bool> ("upnp_details", upnp_details_logging_value);
 | 
			
		||||
	json.get<bool> ("timing", timing_logging_value);
 | 
			
		||||
	json.get<bool> ("log_to_cerr", log_to_cerr_value);
 | 
			
		||||
	json.get<bool> ("flush", flush);
 | 
			
		||||
	json.get<uintmax_t> ("max_size", max_size);
 | 
			
		||||
	json.get<uintmax_t> ("rotation_size", rotation_size);
 | 
			
		||||
 | 
			
		||||
	return json.get_error ();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool nano::logging::ledger_logging () const
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,8 +3,9 @@
 | 
			
		|||
#include <boost/filesystem.hpp>
 | 
			
		||||
#include <boost/log/sources/logger.hpp>
 | 
			
		||||
#include <boost/log/trivial.hpp>
 | 
			
		||||
#include <boost/property_tree/ptree.hpp>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <nano/lib/errors.hpp>
 | 
			
		||||
#include <nano/lib/jsonconfig.hpp>
 | 
			
		||||
 | 
			
		||||
#define FATAL_LOG_PREFIX "FATAL ERROR: "
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -14,9 +15,9 @@ class logging
 | 
			
		|||
{
 | 
			
		||||
public:
 | 
			
		||||
	logging ();
 | 
			
		||||
	void serialize_json (boost::property_tree::ptree &) const;
 | 
			
		||||
	bool deserialize_json (bool &, boost::property_tree::ptree &);
 | 
			
		||||
	bool upgrade_json (unsigned, boost::property_tree::ptree &);
 | 
			
		||||
	nano::error serialize_json (nano::jsonconfig &) const;
 | 
			
		||||
	nano::error deserialize_json (bool &, nano::jsonconfig &);
 | 
			
		||||
	bool upgrade_json (unsigned, nano::jsonconfig &);
 | 
			
		||||
	bool ledger_logging () const;
 | 
			
		||||
	bool ledger_duplicate_logging () const;
 | 
			
		||||
	bool vote_logging () const;
 | 
			
		||||
| 
						 | 
				
			
			@ -58,6 +59,9 @@ public:
 | 
			
		|||
	uintmax_t max_size;
 | 
			
		||||
	uintmax_t rotation_size;
 | 
			
		||||
	boost::log::sources::logger_mt log;
 | 
			
		||||
	static constexpr int json_version = 5;
 | 
			
		||||
	int json_version () const
 | 
			
		||||
	{
 | 
			
		||||
		return 5;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,4 @@
 | 
			
		|||
#include <nano/lib/jsonconfig.hpp>
 | 
			
		||||
#include <nano/node/nodeconfig.hpp>
 | 
			
		||||
// NOTE: to reduce compile times, this include can be replaced by more narrow includes
 | 
			
		||||
// once nano::network is factored out of node.{c|h}pp
 | 
			
		||||
| 
						 | 
				
			
			@ -61,262 +62,270 @@ block_processor_batch_max_time (std::chrono::milliseconds (5000))
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nano::node_config::serialize_json (boost::property_tree::ptree & tree_a) const
 | 
			
		||||
nano::error nano::node_config::serialize_json (nano::jsonconfig & json) const
 | 
			
		||||
{
 | 
			
		||||
	tree_a.put ("version", std::to_string (json_version));
 | 
			
		||||
	tree_a.put ("peering_port", std::to_string (peering_port));
 | 
			
		||||
	tree_a.put ("bootstrap_fraction_numerator", std::to_string (bootstrap_fraction_numerator));
 | 
			
		||||
	tree_a.put ("receive_minimum", receive_minimum.to_string_dec ());
 | 
			
		||||
	boost::property_tree::ptree logging_l;
 | 
			
		||||
	json.put ("version", json_version ());
 | 
			
		||||
	json.put ("peering_port", peering_port);
 | 
			
		||||
	json.put ("bootstrap_fraction_numerator", bootstrap_fraction_numerator);
 | 
			
		||||
	json.put ("receive_minimum", receive_minimum.to_string_dec ());
 | 
			
		||||
 | 
			
		||||
	nano::jsonconfig logging_l;
 | 
			
		||||
	logging.serialize_json (logging_l);
 | 
			
		||||
	tree_a.add_child ("logging", logging_l);
 | 
			
		||||
	boost::property_tree::ptree work_peers_l;
 | 
			
		||||
	json.put_child ("logging", logging_l);
 | 
			
		||||
 | 
			
		||||
	nano::jsonconfig work_peers_l;
 | 
			
		||||
	for (auto i (work_peers.begin ()), n (work_peers.end ()); i != n; ++i)
 | 
			
		||||
	{
 | 
			
		||||
		boost::property_tree::ptree entry;
 | 
			
		||||
		entry.put ("", boost::str (boost::format ("%1%:%2%") % i->first % i->second));
 | 
			
		||||
		work_peers_l.push_back (std::make_pair ("", entry));
 | 
			
		||||
		work_peers_l.push (boost::str (boost::format ("%1%:%2%") % i->first % i->second));
 | 
			
		||||
	}
 | 
			
		||||
	tree_a.add_child ("work_peers", work_peers_l);
 | 
			
		||||
	boost::property_tree::ptree preconfigured_peers_l;
 | 
			
		||||
	json.put_child ("work_peers", work_peers_l);
 | 
			
		||||
	nano::jsonconfig preconfigured_peers_l;
 | 
			
		||||
	for (auto i (preconfigured_peers.begin ()), n (preconfigured_peers.end ()); i != n; ++i)
 | 
			
		||||
	{
 | 
			
		||||
		boost::property_tree::ptree entry;
 | 
			
		||||
		entry.put ("", *i);
 | 
			
		||||
		preconfigured_peers_l.push_back (std::make_pair ("", entry));
 | 
			
		||||
		preconfigured_peers_l.push (*i);
 | 
			
		||||
	}
 | 
			
		||||
	tree_a.add_child ("preconfigured_peers", preconfigured_peers_l);
 | 
			
		||||
	boost::property_tree::ptree preconfigured_representatives_l;
 | 
			
		||||
	json.put_child ("preconfigured_peers", preconfigured_peers_l);
 | 
			
		||||
 | 
			
		||||
	nano::jsonconfig preconfigured_representatives_l;
 | 
			
		||||
	for (auto i (preconfigured_representatives.begin ()), n (preconfigured_representatives.end ()); i != n; ++i)
 | 
			
		||||
	{
 | 
			
		||||
		boost::property_tree::ptree entry;
 | 
			
		||||
		entry.put ("", i->to_account ());
 | 
			
		||||
		preconfigured_representatives_l.push_back (std::make_pair ("", entry));
 | 
			
		||||
		preconfigured_representatives_l.push (i->to_account ());
 | 
			
		||||
	}
 | 
			
		||||
	tree_a.add_child ("preconfigured_representatives", preconfigured_representatives_l);
 | 
			
		||||
	tree_a.put ("online_weight_minimum", online_weight_minimum.to_string_dec ());
 | 
			
		||||
	tree_a.put ("online_weight_quorum", std::to_string (online_weight_quorum));
 | 
			
		||||
	tree_a.put ("password_fanout", std::to_string (password_fanout));
 | 
			
		||||
	tree_a.put ("io_threads", std::to_string (io_threads));
 | 
			
		||||
	tree_a.put ("network_threads", std::to_string (network_threads));
 | 
			
		||||
	tree_a.put ("work_threads", std::to_string (work_threads));
 | 
			
		||||
	tree_a.put ("enable_voting", enable_voting);
 | 
			
		||||
	tree_a.put ("bootstrap_connections", bootstrap_connections);
 | 
			
		||||
	tree_a.put ("bootstrap_connections_max", bootstrap_connections_max);
 | 
			
		||||
	tree_a.put ("callback_address", callback_address);
 | 
			
		||||
	tree_a.put ("callback_port", std::to_string (callback_port));
 | 
			
		||||
	tree_a.put ("callback_target", callback_target);
 | 
			
		||||
	tree_a.put ("lmdb_max_dbs", lmdb_max_dbs);
 | 
			
		||||
	tree_a.put ("block_processor_batch_max_time", block_processor_batch_max_time.count ());
 | 
			
		||||
	tree_a.put ("allow_local_peers", allow_local_peers);
 | 
			
		||||
	json.put_child ("preconfigured_representatives", preconfigured_representatives_l);
 | 
			
		||||
 | 
			
		||||
	json.put ("online_weight_minimum", online_weight_minimum.to_string_dec ());
 | 
			
		||||
	json.put ("online_weight_quorum", online_weight_quorum);
 | 
			
		||||
	json.put ("password_fanout", password_fanout);
 | 
			
		||||
	json.put ("io_threads", io_threads);
 | 
			
		||||
	json.put ("network_threads", network_threads);
 | 
			
		||||
	json.put ("work_threads", work_threads);
 | 
			
		||||
	json.put ("enable_voting", enable_voting);
 | 
			
		||||
	json.put ("bootstrap_connections", bootstrap_connections);
 | 
			
		||||
	json.put ("bootstrap_connections_max", bootstrap_connections_max);
 | 
			
		||||
	json.put ("callback_address", callback_address);
 | 
			
		||||
	json.put ("callback_port", callback_port);
 | 
			
		||||
	json.put ("callback_target", callback_target);
 | 
			
		||||
	json.put ("lmdb_max_dbs", lmdb_max_dbs);
 | 
			
		||||
	json.put ("block_processor_batch_max_time", block_processor_batch_max_time.count ());
 | 
			
		||||
	json.put ("allow_local_peers", allow_local_peers);
 | 
			
		||||
	return json.get_error ();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool nano::node_config::upgrade_json (unsigned version_a, boost::property_tree::ptree & tree_a)
 | 
			
		||||
bool nano::node_config::upgrade_json (unsigned version_a, nano::jsonconfig & json)
 | 
			
		||||
{
 | 
			
		||||
	tree_a.put ("version", std::to_string (json_version));
 | 
			
		||||
	auto result (false);
 | 
			
		||||
	json.put ("version", json_version ());
 | 
			
		||||
	auto upgraded (false);
 | 
			
		||||
	switch (version_a)
 | 
			
		||||
	{
 | 
			
		||||
		case 1:
 | 
			
		||||
		{
 | 
			
		||||
			auto reps_l (tree_a.get_child ("preconfigured_representatives"));
 | 
			
		||||
			boost::property_tree::ptree reps;
 | 
			
		||||
			for (auto i (reps_l.begin ()), n (reps_l.end ()); i != n; ++i)
 | 
			
		||||
			{
 | 
			
		||||
			nano::jsonconfig reps_l;
 | 
			
		||||
			json.get_required_child ("preconfigured_representatives", reps_l);
 | 
			
		||||
			nano::jsonconfig reps;
 | 
			
		||||
			reps_l.array_entries<std::string> ([&reps](std::string entry) {
 | 
			
		||||
				nano::uint256_union account;
 | 
			
		||||
				account.decode_account (i->second.get<std::string> (""));
 | 
			
		||||
				boost::property_tree::ptree entry;
 | 
			
		||||
				entry.put ("", account.to_account ());
 | 
			
		||||
				reps.push_back (std::make_pair ("", entry));
 | 
			
		||||
			}
 | 
			
		||||
			tree_a.erase ("preconfigured_representatives");
 | 
			
		||||
			tree_a.add_child ("preconfigured_representatives", reps);
 | 
			
		||||
			result = true;
 | 
			
		||||
				account.decode_account (entry);
 | 
			
		||||
				reps.push (account.to_account ());
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			json.replace_child ("preconfigured_representatives", reps);
 | 
			
		||||
			upgraded = true;
 | 
			
		||||
		}
 | 
			
		||||
		case 2:
 | 
			
		||||
		{
 | 
			
		||||
			tree_a.put ("inactive_supply", nano::uint128_union (0).to_string_dec ());
 | 
			
		||||
			tree_a.put ("password_fanout", std::to_string (1024));
 | 
			
		||||
			tree_a.put ("io_threads", std::to_string (io_threads));
 | 
			
		||||
			tree_a.put ("work_threads", std::to_string (work_threads));
 | 
			
		||||
			result = true;
 | 
			
		||||
			json.put ("inactive_supply", nano::uint128_union (0).to_string_dec ());
 | 
			
		||||
			json.put ("password_fanout", std::to_string (1024));
 | 
			
		||||
			json.put ("io_threads", std::to_string (io_threads));
 | 
			
		||||
			json.put ("work_threads", std::to_string (work_threads));
 | 
			
		||||
			upgraded = true;
 | 
			
		||||
		}
 | 
			
		||||
		case 3:
 | 
			
		||||
			tree_a.erase ("receive_minimum");
 | 
			
		||||
			tree_a.put ("receive_minimum", nano::xrb_ratio.convert_to<std::string> ());
 | 
			
		||||
			result = true;
 | 
			
		||||
			json.erase ("receive_minimum");
 | 
			
		||||
			json.put ("receive_minimum", nano::xrb_ratio.convert_to<std::string> ());
 | 
			
		||||
			upgraded = true;
 | 
			
		||||
		case 4:
 | 
			
		||||
			tree_a.erase ("receive_minimum");
 | 
			
		||||
			tree_a.put ("receive_minimum", nano::xrb_ratio.convert_to<std::string> ());
 | 
			
		||||
			result = true;
 | 
			
		||||
			json.erase ("receive_minimum");
 | 
			
		||||
			json.put ("receive_minimum", nano::xrb_ratio.convert_to<std::string> ());
 | 
			
		||||
			upgraded = true;
 | 
			
		||||
		case 5:
 | 
			
		||||
			tree_a.put ("enable_voting", enable_voting);
 | 
			
		||||
			tree_a.erase ("packet_delay_microseconds");
 | 
			
		||||
			tree_a.erase ("rebroadcast_delay");
 | 
			
		||||
			tree_a.erase ("creation_rebroadcast");
 | 
			
		||||
			result = true;
 | 
			
		||||
			json.put ("enable_voting", enable_voting);
 | 
			
		||||
			json.erase ("packet_delay_microseconds");
 | 
			
		||||
			json.erase ("rebroadcast_delay");
 | 
			
		||||
			json.erase ("creation_rebroadcast");
 | 
			
		||||
			upgraded = true;
 | 
			
		||||
		case 6:
 | 
			
		||||
			tree_a.put ("bootstrap_connections", 16);
 | 
			
		||||
			tree_a.put ("callback_address", "");
 | 
			
		||||
			tree_a.put ("callback_port", "0");
 | 
			
		||||
			tree_a.put ("callback_target", "");
 | 
			
		||||
			result = true;
 | 
			
		||||
			json.put ("bootstrap_connections", 16);
 | 
			
		||||
			json.put ("callback_address", "");
 | 
			
		||||
			json.put ("callback_port", 0);
 | 
			
		||||
			json.put ("callback_target", "");
 | 
			
		||||
			upgraded = true;
 | 
			
		||||
		case 7:
 | 
			
		||||
			tree_a.put ("lmdb_max_dbs", "128");
 | 
			
		||||
			result = true;
 | 
			
		||||
			json.put ("lmdb_max_dbs", 128);
 | 
			
		||||
			upgraded = true;
 | 
			
		||||
		case 8:
 | 
			
		||||
			tree_a.put ("bootstrap_connections_max", "64");
 | 
			
		||||
			result = true;
 | 
			
		||||
			json.put ("bootstrap_connections_max", "64");
 | 
			
		||||
			upgraded = true;
 | 
			
		||||
		case 9:
 | 
			
		||||
			tree_a.put ("state_block_parse_canary", nano::block_hash (0).to_string ());
 | 
			
		||||
			tree_a.put ("state_block_generate_canary", nano::block_hash (0).to_string ());
 | 
			
		||||
			result = true;
 | 
			
		||||
			json.put ("state_block_parse_canary", nano::block_hash (0).to_string ());
 | 
			
		||||
			json.put ("state_block_generate_canary", nano::block_hash (0).to_string ());
 | 
			
		||||
			upgraded = true;
 | 
			
		||||
		case 10:
 | 
			
		||||
			tree_a.put ("online_weight_minimum", online_weight_minimum.to_string_dec ());
 | 
			
		||||
			tree_a.put ("online_weight_quorom", std::to_string (online_weight_quorum));
 | 
			
		||||
			tree_a.erase ("inactive_supply");
 | 
			
		||||
			result = true;
 | 
			
		||||
			json.put ("online_weight_minimum", online_weight_minimum.to_string_dec ());
 | 
			
		||||
			json.put ("online_weight_quorom", std::to_string (online_weight_quorum));
 | 
			
		||||
			json.erase ("inactive_supply");
 | 
			
		||||
			upgraded = true;
 | 
			
		||||
		case 11:
 | 
			
		||||
		{
 | 
			
		||||
			auto online_weight_quorum_l (tree_a.get<std::string> ("online_weight_quorom"));
 | 
			
		||||
			tree_a.erase ("online_weight_quorom");
 | 
			
		||||
			tree_a.put ("online_weight_quorum", online_weight_quorum_l);
 | 
			
		||||
			result = true;
 | 
			
		||||
			// Rename
 | 
			
		||||
			std::string online_weight_quorum_l;
 | 
			
		||||
			json.get<std::string> ("online_weight_quorom", online_weight_quorum_l);
 | 
			
		||||
			json.erase ("online_weight_quorom");
 | 
			
		||||
			json.put ("online_weight_quorum", online_weight_quorum_l);
 | 
			
		||||
			upgraded = true;
 | 
			
		||||
		}
 | 
			
		||||
		case 12:
 | 
			
		||||
			tree_a.erase ("state_block_parse_canary");
 | 
			
		||||
			tree_a.erase ("state_block_generate_canary");
 | 
			
		||||
			result = true;
 | 
			
		||||
			json.erase ("state_block_parse_canary");
 | 
			
		||||
			json.erase ("state_block_generate_canary");
 | 
			
		||||
			upgraded = true;
 | 
			
		||||
		case 13:
 | 
			
		||||
			tree_a.put ("generate_hash_votes_at", "0");
 | 
			
		||||
			result = true;
 | 
			
		||||
			json.put ("generate_hash_votes_at", 0);
 | 
			
		||||
			upgraded = true;
 | 
			
		||||
		case 14:
 | 
			
		||||
			tree_a.put ("network_threads", std::to_string (network_threads));
 | 
			
		||||
			tree_a.erase ("generate_hash_votes_at");
 | 
			
		||||
			tree_a.put ("block_processor_batch_max_time", block_processor_batch_max_time.count ());
 | 
			
		||||
			result = true;
 | 
			
		||||
			json.put ("network_threads", std::to_string (network_threads));
 | 
			
		||||
			json.erase ("generate_hash_votes_at");
 | 
			
		||||
			json.put ("block_processor_batch_max_time", block_processor_batch_max_time.count ());
 | 
			
		||||
			upgraded = true;
 | 
			
		||||
		case 15:
 | 
			
		||||
			tree_a.put ("allow_local_peers", allow_local_peers);
 | 
			
		||||
			result = true;
 | 
			
		||||
			json.put ("allow_local_peers", allow_local_peers);
 | 
			
		||||
			upgraded = true;
 | 
			
		||||
		case 16:
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			throw std::runtime_error ("Unknown node_config version");
 | 
			
		||||
	}
 | 
			
		||||
	return result;
 | 
			
		||||
	return upgraded;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool nano::node_config::deserialize_json (bool & upgraded_a, boost::property_tree::ptree & tree_a)
 | 
			
		||||
nano::error nano::node_config::deserialize_json (bool & upgraded_a, nano::jsonconfig & json)
 | 
			
		||||
{
 | 
			
		||||
	auto result (false);
 | 
			
		||||
	try
 | 
			
		||||
	{
 | 
			
		||||
		auto version_l (tree_a.get_optional<std::string> ("version"));
 | 
			
		||||
		auto version_l (json.get_optional<unsigned> ("version"));
 | 
			
		||||
		if (!version_l)
 | 
			
		||||
		{
 | 
			
		||||
			tree_a.put ("version", "1");
 | 
			
		||||
			version_l = "1";
 | 
			
		||||
			auto work_peers_l (tree_a.get_child_optional ("work_peers"));
 | 
			
		||||
			version_l = 1;
 | 
			
		||||
			json.put ("version", version_l);
 | 
			
		||||
			auto work_peers_l (json.get_optional_child ("work_peers"));
 | 
			
		||||
			if (!work_peers_l)
 | 
			
		||||
			{
 | 
			
		||||
				tree_a.add_child ("work_peers", boost::property_tree::ptree ());
 | 
			
		||||
				nano::jsonconfig empty;
 | 
			
		||||
				json.put_child ("work_peers", empty);
 | 
			
		||||
			}
 | 
			
		||||
			upgraded_a = true;
 | 
			
		||||
		}
 | 
			
		||||
		upgraded_a |= upgrade_json (std::stoull (version_l.get ()), tree_a);
 | 
			
		||||
		auto peering_port_l (tree_a.get<std::string> ("peering_port"));
 | 
			
		||||
		auto bootstrap_fraction_numerator_l (tree_a.get<std::string> ("bootstrap_fraction_numerator"));
 | 
			
		||||
		auto receive_minimum_l (tree_a.get<std::string> ("receive_minimum"));
 | 
			
		||||
		auto & logging_l (tree_a.get_child ("logging"));
 | 
			
		||||
 | 
			
		||||
		upgraded_a |= upgrade_json (version_l.get (), json);
 | 
			
		||||
 | 
			
		||||
		auto logging_l (json.get_required_child ("logging"));
 | 
			
		||||
		logging.deserialize_json (upgraded_a, logging_l);
 | 
			
		||||
 | 
			
		||||
		work_peers.clear ();
 | 
			
		||||
		auto work_peers_l (tree_a.get_child ("work_peers"));
 | 
			
		||||
		for (auto i (work_peers_l.begin ()), n (work_peers_l.end ()); i != n; ++i)
 | 
			
		||||
		{
 | 
			
		||||
			auto work_peer (i->second.get<std::string> (""));
 | 
			
		||||
			auto port_position (work_peer.rfind (':'));
 | 
			
		||||
			result |= port_position == -1;
 | 
			
		||||
		auto work_peers_l (json.get_required_child ("work_peers"));
 | 
			
		||||
		work_peers_l.array_entries<std::string> ([this](std::string entry) {
 | 
			
		||||
			auto port_position (entry.rfind (':'));
 | 
			
		||||
			bool result = port_position == -1;
 | 
			
		||||
			if (!result)
 | 
			
		||||
			{
 | 
			
		||||
				auto port_str (work_peer.substr (port_position + 1));
 | 
			
		||||
				auto port_str (entry.substr (port_position + 1));
 | 
			
		||||
				uint16_t port;
 | 
			
		||||
				result |= parse_port (port_str, port);
 | 
			
		||||
				if (!result)
 | 
			
		||||
				{
 | 
			
		||||
					auto address (work_peer.substr (0, port_position));
 | 
			
		||||
					work_peers.push_back (std::make_pair (address, port));
 | 
			
		||||
					auto address (entry.substr (0, port_position));
 | 
			
		||||
					this->work_peers.push_back (std::make_pair (address, port));
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		auto preconfigured_peers_l (tree_a.get_child ("preconfigured_peers"));
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		nano::jsonconfig preconfigured_peers_l;
 | 
			
		||||
		json.get_required_child ("preconfigured_peers", preconfigured_peers_l);
 | 
			
		||||
		preconfigured_peers.clear ();
 | 
			
		||||
		for (auto i (preconfigured_peers_l.begin ()), n (preconfigured_peers_l.end ()); i != n; ++i)
 | 
			
		||||
		{
 | 
			
		||||
			auto bootstrap_peer (i->second.get<std::string> (""));
 | 
			
		||||
			preconfigured_peers.push_back (bootstrap_peer);
 | 
			
		||||
		}
 | 
			
		||||
		auto preconfigured_representatives_l (tree_a.get_child ("preconfigured_representatives"));
 | 
			
		||||
		preconfigured_peers_l.array_entries<std::string> ([this](std::string entry) {
 | 
			
		||||
			preconfigured_peers.push_back (entry);
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		nano::jsonconfig preconfigured_representatives_l;
 | 
			
		||||
		json.get_required_child ("preconfigured_representatives", preconfigured_representatives_l);
 | 
			
		||||
		preconfigured_representatives.clear ();
 | 
			
		||||
		for (auto i (preconfigured_representatives_l.begin ()), n (preconfigured_representatives_l.end ()); i != n; ++i)
 | 
			
		||||
		{
 | 
			
		||||
		preconfigured_representatives_l.array_entries<std::string> ([this, &json](std::string entry) {
 | 
			
		||||
			nano::account representative (0);
 | 
			
		||||
			result = result || representative.decode_account (i->second.get<std::string> (""));
 | 
			
		||||
			if (representative.decode_account (entry))
 | 
			
		||||
			{
 | 
			
		||||
				json.get_error ().set ("Invalid representative account: " + entry);
 | 
			
		||||
			}
 | 
			
		||||
			preconfigured_representatives.push_back (representative);
 | 
			
		||||
		}
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		if (preconfigured_representatives.empty ())
 | 
			
		||||
		{
 | 
			
		||||
			result = true;
 | 
			
		||||
			json.get_error ().set ("At least one representative account must be set");
 | 
			
		||||
		}
 | 
			
		||||
		auto stat_config_l (tree_a.get_child_optional ("statistics"));
 | 
			
		||||
		auto stat_config_l (json.get_optional_child ("statistics"));
 | 
			
		||||
		if (stat_config_l)
 | 
			
		||||
		{
 | 
			
		||||
			result |= stat_config.deserialize_json (stat_config_l.get ());
 | 
			
		||||
			stat_config.deserialize_json (stat_config_l.get ());
 | 
			
		||||
		}
 | 
			
		||||
		auto online_weight_minimum_l (tree_a.get<std::string> ("online_weight_minimum"));
 | 
			
		||||
		auto online_weight_quorum_l (tree_a.get<std::string> ("online_weight_quorum"));
 | 
			
		||||
		auto password_fanout_l (tree_a.get<std::string> ("password_fanout"));
 | 
			
		||||
		auto io_threads_l (tree_a.get<std::string> ("io_threads"));
 | 
			
		||||
		auto work_threads_l (tree_a.get<std::string> ("work_threads"));
 | 
			
		||||
		enable_voting = tree_a.get<bool> ("enable_voting");
 | 
			
		||||
		auto bootstrap_connections_l (tree_a.get<std::string> ("bootstrap_connections"));
 | 
			
		||||
		auto bootstrap_connections_max_l (tree_a.get<std::string> ("bootstrap_connections_max"));
 | 
			
		||||
		callback_address = tree_a.get<std::string> ("callback_address");
 | 
			
		||||
		auto callback_port_l (tree_a.get<std::string> ("callback_port"));
 | 
			
		||||
		callback_target = tree_a.get<std::string> ("callback_target");
 | 
			
		||||
		auto lmdb_max_dbs_l = tree_a.get<std::string> ("lmdb_max_dbs");
 | 
			
		||||
		result |= parse_port (callback_port_l, callback_port);
 | 
			
		||||
		auto block_processor_batch_max_time_l = tree_a.get<std::string> ("block_processor_batch_max_time");
 | 
			
		||||
		try
 | 
			
		||||
 | 
			
		||||
		auto receive_minimum_l (json.get<std::string> ("receive_minimum"));
 | 
			
		||||
		if (receive_minimum.decode_dec (receive_minimum_l))
 | 
			
		||||
		{
 | 
			
		||||
			peering_port = std::stoul (peering_port_l);
 | 
			
		||||
			bootstrap_fraction_numerator = std::stoul (bootstrap_fraction_numerator_l);
 | 
			
		||||
			password_fanout = std::stoul (password_fanout_l);
 | 
			
		||||
			io_threads = std::stoul (io_threads_l);
 | 
			
		||||
			network_threads = tree_a.get<unsigned> ("network_threads", network_threads);
 | 
			
		||||
			work_threads = std::stoul (work_threads_l);
 | 
			
		||||
			bootstrap_connections = std::stoul (bootstrap_connections_l);
 | 
			
		||||
			bootstrap_connections_max = std::stoul (bootstrap_connections_max_l);
 | 
			
		||||
			lmdb_max_dbs = std::stoi (lmdb_max_dbs_l);
 | 
			
		||||
			online_weight_quorum = std::stoul (online_weight_quorum_l);
 | 
			
		||||
			block_processor_batch_max_time = std::chrono::milliseconds (std::stoul (block_processor_batch_max_time_l));
 | 
			
		||||
			result |= peering_port > std::numeric_limits<uint16_t>::max ();
 | 
			
		||||
			result |= logging.deserialize_json (upgraded_a, logging_l);
 | 
			
		||||
			result |= receive_minimum.decode_dec (receive_minimum_l);
 | 
			
		||||
			result |= online_weight_minimum.decode_dec (online_weight_minimum_l);
 | 
			
		||||
			result |= online_weight_quorum > 100;
 | 
			
		||||
			result |= password_fanout < 16;
 | 
			
		||||
			result |= password_fanout > 1024 * 1024;
 | 
			
		||||
			result |= io_threads == 0;
 | 
			
		||||
			json.get_error ().set ("receive_minimum contains an invalid decimal amount");
 | 
			
		||||
		}
 | 
			
		||||
		catch (std::logic_error const &)
 | 
			
		||||
 | 
			
		||||
		auto online_weight_minimum_l (json.get<std::string> ("online_weight_minimum"));
 | 
			
		||||
		if (online_weight_minimum.decode_dec (online_weight_minimum_l))
 | 
			
		||||
		{
 | 
			
		||||
			result = true;
 | 
			
		||||
			json.get_error ().set ("online_weight_minimum contains an invalid decimal amount");
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		auto block_processor_batch_max_time_l (json.get<unsigned long> ("block_processor_batch_max_time"));
 | 
			
		||||
		block_processor_batch_max_time = std::chrono::milliseconds (block_processor_batch_max_time_l);
 | 
			
		||||
 | 
			
		||||
		json.get<uint16_t> ("peering_port", peering_port);
 | 
			
		||||
		json.get<unsigned> ("bootstrap_fraction_numerator", bootstrap_fraction_numerator);
 | 
			
		||||
		json.get<unsigned> ("online_weight_quorum", online_weight_quorum);
 | 
			
		||||
		json.get<unsigned> ("password_fanout", password_fanout);
 | 
			
		||||
		json.get<unsigned> ("io_threads", io_threads);
 | 
			
		||||
		json.get<unsigned> ("work_threads", work_threads);
 | 
			
		||||
		json.get<unsigned> ("network_threads", network_threads);
 | 
			
		||||
		json.get<unsigned> ("bootstrap_connections", bootstrap_connections);
 | 
			
		||||
		json.get<unsigned> ("bootstrap_connections_max", bootstrap_connections_max);
 | 
			
		||||
		json.get<std::string> ("callback_address", callback_address);
 | 
			
		||||
		json.get<uint16_t> ("callback_port", callback_port);
 | 
			
		||||
		json.get<std::string> ("callback_target", callback_target);
 | 
			
		||||
		json.get<int> ("lmdb_max_dbs", lmdb_max_dbs);
 | 
			
		||||
		json.get<bool> ("enable_voting", enable_voting);
 | 
			
		||||
 | 
			
		||||
		// Validate ranges
 | 
			
		||||
 | 
			
		||||
		if (online_weight_quorum > 100)
 | 
			
		||||
		{
 | 
			
		||||
			json.get_error ().set ("online_weight_quorum must be less than 100");
 | 
			
		||||
		}
 | 
			
		||||
		if (password_fanout < 16 || password_fanout > 1024 * 1024)
 | 
			
		||||
		{
 | 
			
		||||
			json.get_error ().set ("password_fanout must a number between 16 and 1048576");
 | 
			
		||||
		}
 | 
			
		||||
		if (io_threads == 0)
 | 
			
		||||
		{
 | 
			
		||||
			json.get_error ().set ("io_threads must be non-zero");
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	catch (std::runtime_error const &)
 | 
			
		||||
	catch (std::runtime_error const & ex)
 | 
			
		||||
	{
 | 
			
		||||
		result = true;
 | 
			
		||||
		json.get_error ().set (ex.what ());
 | 
			
		||||
	}
 | 
			
		||||
	return result;
 | 
			
		||||
	return json.get_error ();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
nano::account nano::node_config::random_representative ()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,8 @@
 | 
			
		|||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <boost/property_tree/ptree.hpp>
 | 
			
		||||
#include <chrono>
 | 
			
		||||
#include <nano/lib/errors.hpp>
 | 
			
		||||
#include <nano/lib/jsonconfig.hpp>
 | 
			
		||||
#include <nano/lib/numbers.hpp>
 | 
			
		||||
#include <nano/node/logging.hpp>
 | 
			
		||||
#include <nano/node/stats.hpp>
 | 
			
		||||
| 
						 | 
				
			
			@ -17,9 +18,9 @@ class node_config
 | 
			
		|||
public:
 | 
			
		||||
	node_config ();
 | 
			
		||||
	node_config (uint16_t, nano::logging const &);
 | 
			
		||||
	void serialize_json (boost::property_tree::ptree &) const;
 | 
			
		||||
	bool deserialize_json (bool &, boost::property_tree::ptree &);
 | 
			
		||||
	bool upgrade_json (unsigned, boost::property_tree::ptree &);
 | 
			
		||||
	nano::error serialize_json (nano::jsonconfig &) const;
 | 
			
		||||
	nano::error deserialize_json (bool &, nano::jsonconfig &);
 | 
			
		||||
	bool upgrade_json (unsigned, nano::jsonconfig &);
 | 
			
		||||
	nano::account random_representative ();
 | 
			
		||||
	uint16_t peering_port;
 | 
			
		||||
	nano::logging logging;
 | 
			
		||||
| 
						 | 
				
			
			@ -49,7 +50,10 @@ public:
 | 
			
		|||
	static std::chrono::seconds constexpr keepalive_period = std::chrono::seconds (60);
 | 
			
		||||
	static std::chrono::seconds constexpr keepalive_cutoff = keepalive_period * 5;
 | 
			
		||||
	static std::chrono::minutes constexpr wallet_backup_interval = std::chrono::minutes (5);
 | 
			
		||||
	static constexpr int json_version = 16;
 | 
			
		||||
	inline int json_version () const
 | 
			
		||||
	{
 | 
			
		||||
		return 16;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class node_flags
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -512,37 +512,20 @@ threads (threads_a)
 | 
			
		|||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nano::opencl_config::serialize_json (boost::property_tree::ptree & tree_a) const
 | 
			
		||||
nano::error nano::opencl_config::serialize_json (nano::jsonconfig & json) const
 | 
			
		||||
{
 | 
			
		||||
	tree_a.put ("platform", std::to_string (platform));
 | 
			
		||||
	tree_a.put ("device", std::to_string (device));
 | 
			
		||||
	tree_a.put ("threads", std::to_string (threads));
 | 
			
		||||
	json.put ("platform", platform);
 | 
			
		||||
	json.put ("device", device);
 | 
			
		||||
	json.put ("threads", threads);
 | 
			
		||||
	return json.get_error ();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool nano::opencl_config::deserialize_json (boost::property_tree::ptree const & tree_a)
 | 
			
		||||
nano::error nano::opencl_config::deserialize_json (nano::jsonconfig & json)
 | 
			
		||||
{
 | 
			
		||||
	auto result (false);
 | 
			
		||||
	try
 | 
			
		||||
	{
 | 
			
		||||
		auto platform_l (tree_a.get<std::string> ("platform"));
 | 
			
		||||
		auto device_l (tree_a.get<std::string> ("device"));
 | 
			
		||||
		auto threads_l (tree_a.get<std::string> ("threads"));
 | 
			
		||||
		try
 | 
			
		||||
		{
 | 
			
		||||
			platform = std::stoull (platform_l);
 | 
			
		||||
			device = std::stoull (device_l);
 | 
			
		||||
			threads = std::stoull (threads_l);
 | 
			
		||||
		}
 | 
			
		||||
		catch (std::logic_error const &)
 | 
			
		||||
		{
 | 
			
		||||
			result = true;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	catch (std::runtime_error const &)
 | 
			
		||||
	{
 | 
			
		||||
		result = true;
 | 
			
		||||
	}
 | 
			
		||||
	return result;
 | 
			
		||||
	json.get_optional<unsigned> ("platform", platform);
 | 
			
		||||
	json.get_optional<unsigned> ("device", device);
 | 
			
		||||
	json.get_optional<unsigned> ("threads", threads);
 | 
			
		||||
	return json.get_error ();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
nano::opencl_work::opencl_work (bool & error_a, nano::opencl_config const & config_a, nano::opencl_environment & environment_a, nano::logging & logging_a) :
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,9 +1,10 @@
 | 
			
		|||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <nano/node/xorshift.hpp>
 | 
			
		||||
 | 
			
		||||
#include <boost/optional.hpp>
 | 
			
		||||
#include <boost/property_tree/ptree.hpp>
 | 
			
		||||
#include <nano/lib/errors.hpp>
 | 
			
		||||
#include <nano/lib/jsonconfig.hpp>
 | 
			
		||||
#include <nano/node/xorshift.hpp>
 | 
			
		||||
 | 
			
		||||
#include <map>
 | 
			
		||||
#include <mutex>
 | 
			
		||||
| 
						 | 
				
			
			@ -39,8 +40,8 @@ class opencl_config
 | 
			
		|||
public:
 | 
			
		||||
	opencl_config ();
 | 
			
		||||
	opencl_config (unsigned, unsigned, unsigned);
 | 
			
		||||
	void serialize_json (boost::property_tree::ptree &) const;
 | 
			
		||||
	bool deserialize_json (boost::property_tree::ptree const &);
 | 
			
		||||
	nano::error serialize_json (nano::jsonconfig &) const;
 | 
			
		||||
	nano::error deserialize_json (nano::jsonconfig &);
 | 
			
		||||
	unsigned platform;
 | 
			
		||||
	unsigned device;
 | 
			
		||||
	unsigned threads;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,8 +1,7 @@
 | 
			
		|||
#include <boost/algorithm/string.hpp>
 | 
			
		||||
#include <nano/node/rpc.hpp>
 | 
			
		||||
 | 
			
		||||
#include <nano/lib/interface.h>
 | 
			
		||||
#include <nano/node/node.hpp>
 | 
			
		||||
#include <nano/node/rpc.hpp>
 | 
			
		||||
 | 
			
		||||
#ifdef NANO_SECURE_RPC
 | 
			
		||||
#include <nano/node/rpc_secure.hpp>
 | 
			
		||||
| 
						 | 
				
			
			@ -16,35 +15,28 @@ verbose_logging (false)
 | 
			
		|||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nano::rpc_secure_config::serialize_json (boost::property_tree::ptree & tree_a) const
 | 
			
		||||
nano::error nano::rpc_secure_config::serialize_json (nano::jsonconfig & json) const
 | 
			
		||||
{
 | 
			
		||||
	tree_a.put ("enable", enable);
 | 
			
		||||
	tree_a.put ("verbose_logging", verbose_logging);
 | 
			
		||||
	tree_a.put ("server_key_passphrase", server_key_passphrase);
 | 
			
		||||
	tree_a.put ("server_cert_path", server_cert_path);
 | 
			
		||||
	tree_a.put ("server_key_path", server_key_path);
 | 
			
		||||
	tree_a.put ("server_dh_path", server_dh_path);
 | 
			
		||||
	tree_a.put ("client_certs_path", client_certs_path);
 | 
			
		||||
	json.put ("enable", enable);
 | 
			
		||||
	json.put ("verbose_logging", verbose_logging);
 | 
			
		||||
	json.put ("server_key_passphrase", server_key_passphrase);
 | 
			
		||||
	json.put ("server_cert_path", server_cert_path);
 | 
			
		||||
	json.put ("server_key_path", server_key_path);
 | 
			
		||||
	json.put ("server_dh_path", server_dh_path);
 | 
			
		||||
	json.put ("client_certs_path", client_certs_path);
 | 
			
		||||
	return json.get_error ();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool nano::rpc_secure_config::deserialize_json (boost::property_tree::ptree const & tree_a)
 | 
			
		||||
nano::error nano::rpc_secure_config::deserialize_json (nano::jsonconfig & json)
 | 
			
		||||
{
 | 
			
		||||
	auto error (false);
 | 
			
		||||
	try
 | 
			
		||||
	{
 | 
			
		||||
		enable = tree_a.get<bool> ("enable");
 | 
			
		||||
		verbose_logging = tree_a.get<bool> ("verbose_logging");
 | 
			
		||||
		server_key_passphrase = tree_a.get<std::string> ("server_key_passphrase");
 | 
			
		||||
		server_cert_path = tree_a.get<std::string> ("server_cert_path");
 | 
			
		||||
		server_key_path = tree_a.get<std::string> ("server_key_path");
 | 
			
		||||
		server_dh_path = tree_a.get<std::string> ("server_dh_path");
 | 
			
		||||
		client_certs_path = tree_a.get<std::string> ("client_certs_path");
 | 
			
		||||
	}
 | 
			
		||||
	catch (std::runtime_error const &)
 | 
			
		||||
	{
 | 
			
		||||
		error = true;
 | 
			
		||||
	}
 | 
			
		||||
	return error;
 | 
			
		||||
	json.get_required<bool> ("enable", enable);
 | 
			
		||||
	json.get_required<bool> ("verbose_logging", verbose_logging);
 | 
			
		||||
	json.get_required<std::string> ("server_key_passphrase", server_key_passphrase);
 | 
			
		||||
	json.get_required<std::string> ("server_cert_path", server_cert_path);
 | 
			
		||||
	json.get_required<std::string> ("server_key_path", server_key_path);
 | 
			
		||||
	json.get_required<std::string> ("server_dh_path", server_dh_path);
 | 
			
		||||
	json.get_required<std::string> ("client_certs_path", client_certs_path);
 | 
			
		||||
	return json.get_error ();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
nano::rpc_config::rpc_config () :
 | 
			
		||||
| 
						 | 
				
			
			@ -67,59 +59,33 @@ max_json_depth (20)
 | 
			
		|||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nano::rpc_config::serialize_json (boost::property_tree::ptree & tree_a) const
 | 
			
		||||
nano::error nano::rpc_config::serialize_json (nano::jsonconfig & json) const
 | 
			
		||||
{
 | 
			
		||||
	tree_a.put ("address", address.to_string ());
 | 
			
		||||
	tree_a.put ("port", std::to_string (port));
 | 
			
		||||
	tree_a.put ("enable_control", enable_control);
 | 
			
		||||
	tree_a.put ("frontier_request_limit", frontier_request_limit);
 | 
			
		||||
	tree_a.put ("chain_request_limit", chain_request_limit);
 | 
			
		||||
	tree_a.put ("max_json_depth", max_json_depth);
 | 
			
		||||
	json.put ("address", address.to_string ());
 | 
			
		||||
	json.put ("port", port);
 | 
			
		||||
	json.put ("enable_control", enable_control);
 | 
			
		||||
	json.put ("frontier_request_limit", frontier_request_limit);
 | 
			
		||||
	json.put ("chain_request_limit", chain_request_limit);
 | 
			
		||||
	json.put ("max_json_depth", max_json_depth);
 | 
			
		||||
	return json.get_error ();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool nano::rpc_config::deserialize_json (boost::property_tree::ptree const & tree_a)
 | 
			
		||||
nano::error nano::rpc_config::deserialize_json (nano::jsonconfig & json)
 | 
			
		||||
{
 | 
			
		||||
	auto result (false);
 | 
			
		||||
	try
 | 
			
		||||
	boost::optional<nano::jsonconfig> rpc_secure_l;
 | 
			
		||||
	json.get_optional_child ("secure", rpc_secure_l);
 | 
			
		||||
	if (rpc_secure_l)
 | 
			
		||||
	{
 | 
			
		||||
		auto rpc_secure_l (tree_a.get_child_optional ("secure"));
 | 
			
		||||
		if (rpc_secure_l)
 | 
			
		||||
		{
 | 
			
		||||
			result = secure.deserialize_json (rpc_secure_l.get ());
 | 
			
		||||
		}
 | 
			
		||||
		secure.deserialize_json (*rpc_secure_l);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
		if (!result)
 | 
			
		||||
		{
 | 
			
		||||
			auto address_l (tree_a.get<std::string> ("address"));
 | 
			
		||||
			auto port_l (tree_a.get<std::string> ("port"));
 | 
			
		||||
			enable_control = tree_a.get<bool> ("enable_control");
 | 
			
		||||
			auto frontier_request_limit_l (tree_a.get<std::string> ("frontier_request_limit"));
 | 
			
		||||
			auto chain_request_limit_l (tree_a.get<std::string> ("chain_request_limit"));
 | 
			
		||||
			max_json_depth = tree_a.get<uint8_t> ("max_json_depth", max_json_depth);
 | 
			
		||||
			try
 | 
			
		||||
			{
 | 
			
		||||
				port = std::stoul (port_l);
 | 
			
		||||
				result = port > std::numeric_limits<uint16_t>::max ();
 | 
			
		||||
				frontier_request_limit = std::stoull (frontier_request_limit_l);
 | 
			
		||||
				chain_request_limit = std::stoull (chain_request_limit_l);
 | 
			
		||||
			}
 | 
			
		||||
			catch (std::logic_error const &)
 | 
			
		||||
			{
 | 
			
		||||
				result = true;
 | 
			
		||||
			}
 | 
			
		||||
			boost::system::error_code ec;
 | 
			
		||||
			address = boost::asio::ip::address_v6::from_string (address_l, ec);
 | 
			
		||||
			if (ec)
 | 
			
		||||
			{
 | 
			
		||||
				result = true;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	catch (std::runtime_error const &)
 | 
			
		||||
	{
 | 
			
		||||
		result = true;
 | 
			
		||||
	}
 | 
			
		||||
	return result;
 | 
			
		||||
	json.get_required<boost::asio::ip::address_v6> ("address", address);
 | 
			
		||||
	json.get_optional<uint16_t> ("port", port);
 | 
			
		||||
	json.get_optional<bool> ("enable_control", enable_control);
 | 
			
		||||
	json.get_optional<uint64_t> ("frontier_request_limit", frontier_request_limit);
 | 
			
		||||
	json.get_optional<uint64_t> ("chain_request_limit", chain_request_limit);
 | 
			
		||||
	json.get_optional<uint8_t> ("max_json_depth", max_json_depth);
 | 
			
		||||
	return json.get_error ();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
nano::rpc::rpc (boost::asio::io_context & io_ctx_a, nano::node & node_a, nano::rpc_config const & config_a) :
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,6 +5,8 @@
 | 
			
		|||
#include <boost/beast.hpp>
 | 
			
		||||
#include <boost/property_tree/json_parser.hpp>
 | 
			
		||||
#include <boost/property_tree/ptree.hpp>
 | 
			
		||||
#include <nano/lib/errors.hpp>
 | 
			
		||||
#include <nano/lib/jsonconfig.hpp>
 | 
			
		||||
#include <nano/secure/utility.hpp>
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -17,8 +19,8 @@ class rpc_secure_config
 | 
			
		|||
{
 | 
			
		||||
public:
 | 
			
		||||
	rpc_secure_config ();
 | 
			
		||||
	void serialize_json (boost::property_tree::ptree &) const;
 | 
			
		||||
	bool deserialize_json (boost::property_tree::ptree const &);
 | 
			
		||||
	nano::error serialize_json (nano::jsonconfig &) const;
 | 
			
		||||
	nano::error deserialize_json (nano::jsonconfig &);
 | 
			
		||||
 | 
			
		||||
	/** If true, enable TLS */
 | 
			
		||||
	bool enable;
 | 
			
		||||
| 
						 | 
				
			
			@ -40,8 +42,8 @@ class rpc_config
 | 
			
		|||
public:
 | 
			
		||||
	rpc_config ();
 | 
			
		||||
	rpc_config (bool);
 | 
			
		||||
	void serialize_json (boost::property_tree::ptree &) const;
 | 
			
		||||
	bool deserialize_json (boost::property_tree::ptree const &);
 | 
			
		||||
	nano::error serialize_json (nano::jsonconfig &) const;
 | 
			
		||||
	nano::error deserialize_json (nano::jsonconfig &);
 | 
			
		||||
	boost::asio::ip::address_v6 address;
 | 
			
		||||
	uint16_t port;
 | 
			
		||||
	bool enable_control;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,33 +9,34 @@
 | 
			
		|||
#include <sstream>
 | 
			
		||||
#include <tuple>
 | 
			
		||||
 | 
			
		||||
bool nano::stat_config::deserialize_json (boost::property_tree::ptree & tree_a)
 | 
			
		||||
nano::error nano::stat_config::deserialize_json (nano::jsonconfig & json)
 | 
			
		||||
{
 | 
			
		||||
	bool error = false;
 | 
			
		||||
 | 
			
		||||
	auto sampling_l (tree_a.get_child_optional ("sampling"));
 | 
			
		||||
	auto sampling_l (json.get_optional_child ("sampling"));
 | 
			
		||||
	if (sampling_l)
 | 
			
		||||
	{
 | 
			
		||||
		sampling_enabled = sampling_l->get<bool> ("enabled", sampling_enabled);
 | 
			
		||||
		capacity = sampling_l->get<size_t> ("capacity", capacity);
 | 
			
		||||
		interval = sampling_l->get<size_t> ("interval", interval);
 | 
			
		||||
		sampling_l->get<bool> ("enabled", sampling_enabled);
 | 
			
		||||
		sampling_l->get<size_t> ("capacity", capacity);
 | 
			
		||||
		sampling_l->get<size_t> ("interval", interval);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	auto log_l (tree_a.get_child_optional ("log"));
 | 
			
		||||
	auto log_l (json.get_optional_child ("log"));
 | 
			
		||||
	if (log_l)
 | 
			
		||||
	{
 | 
			
		||||
		log_headers = log_l->get<bool> ("headers", log_headers);
 | 
			
		||||
		log_interval_counters = log_l->get<size_t> ("interval_counters", log_interval_counters);
 | 
			
		||||
		log_interval_samples = log_l->get<size_t> ("interval_samples", log_interval_samples);
 | 
			
		||||
		log_rotation_count = log_l->get<size_t> ("rotation_count", log_rotation_count);
 | 
			
		||||
		log_counters_filename = log_l->get<std::string> ("filename_counters", log_counters_filename);
 | 
			
		||||
		log_samples_filename = log_l->get<std::string> ("filename_samples", log_samples_filename);
 | 
			
		||||
		log_l->get<bool> ("headers", log_headers);
 | 
			
		||||
		log_l->get<size_t> ("interval_counters", log_interval_counters);
 | 
			
		||||
		log_l->get<size_t> ("interval_samples", log_interval_samples);
 | 
			
		||||
		log_l->get<size_t> ("rotation_count", log_rotation_count);
 | 
			
		||||
		log_l->get<std::string> ("filename_counters", log_counters_filename);
 | 
			
		||||
		log_l->get<std::string> ("filename_samples", log_samples_filename);
 | 
			
		||||
 | 
			
		||||
		// Don't allow specifying the same file name for counter and samples logs
 | 
			
		||||
		error = (log_counters_filename == log_samples_filename);
 | 
			
		||||
		if (log_counters_filename == log_samples_filename)
 | 
			
		||||
		{
 | 
			
		||||
			json.get_error ().set ("The statistics counter and samples config values must be different");
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return error;
 | 
			
		||||
	return json.get_error ();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string nano::stat_log_sink::tm_to_string (tm & tm)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,6 +6,8 @@
 | 
			
		|||
#include <chrono>
 | 
			
		||||
#include <map>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <nano/lib/errors.hpp>
 | 
			
		||||
#include <nano/lib/jsonconfig.hpp>
 | 
			
		||||
#include <nano/lib/utility.hpp>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
| 
						 | 
				
			
			@ -23,7 +25,7 @@ class stat_config
 | 
			
		|||
{
 | 
			
		||||
public:
 | 
			
		||||
	/** Reads the JSON statistics node */
 | 
			
		||||
	bool deserialize_json (boost::property_tree::ptree & tree_a);
 | 
			
		||||
	nano::error deserialize_json (nano::jsonconfig & json);
 | 
			
		||||
 | 
			
		||||
	/** If true, sampling of counters is enabled */
 | 
			
		||||
	bool sampling_enabled{ false };
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -109,14 +109,3 @@ std::vector<boost::filesystem::path> nano::remove_temporary_directories ()
 | 
			
		|||
	}
 | 
			
		||||
	return all_unique_paths;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nano::open_or_create (std::fstream & stream_a, std::string const & path_a)
 | 
			
		||||
{
 | 
			
		||||
	stream_a.open (path_a, std::ios_base::in);
 | 
			
		||||
	if (stream_a.fail ())
 | 
			
		||||
	{
 | 
			
		||||
		stream_a.open (path_a, std::ios_base::out);
 | 
			
		||||
	}
 | 
			
		||||
	stream_a.close ();
 | 
			
		||||
	stream_a.open (path_a, std::ios_base::in | std::ios_base::out);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,6 +13,7 @@
 | 
			
		|||
#include <cryptopp/osrng.h>
 | 
			
		||||
 | 
			
		||||
#include <nano/lib/config.hpp>
 | 
			
		||||
#include <nano/lib/errors.hpp>
 | 
			
		||||
#include <nano/lib/interface.h>
 | 
			
		||||
#include <nano/lib/numbers.hpp>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -29,81 +30,4 @@ bool migrate_working_path (std::string &);
 | 
			
		|||
boost::filesystem::path unique_path ();
 | 
			
		||||
// Remove all unique tmp directories created by the process. The list of unique paths are returned.
 | 
			
		||||
std::vector<boost::filesystem::path> remove_temporary_directories ();
 | 
			
		||||
// C++ stream are absolutely horrible so I need this helper function to do the most basic operation of creating a file if it doesn't exist or truncating it.
 | 
			
		||||
void open_or_create (std::fstream &, std::string const &);
 | 
			
		||||
// Reads a json object from the stream and if was changed, write the object back to the stream
 | 
			
		||||
template <typename T>
 | 
			
		||||
bool fetch_object (T & object, std::iostream & stream_a)
 | 
			
		||||
{
 | 
			
		||||
	assert (stream_a.tellg () == std::streampos (0) || stream_a.tellg () == std::streampos (-1));
 | 
			
		||||
	assert (stream_a.tellp () == std::streampos (0) || stream_a.tellp () == std::streampos (-1));
 | 
			
		||||
	bool error (false);
 | 
			
		||||
	boost::property_tree::ptree tree;
 | 
			
		||||
	try
 | 
			
		||||
	{
 | 
			
		||||
		boost::property_tree::read_json (stream_a, tree);
 | 
			
		||||
	}
 | 
			
		||||
	catch (std::runtime_error const &)
 | 
			
		||||
	{
 | 
			
		||||
		auto pos (stream_a.tellg ());
 | 
			
		||||
		if (pos != std::streampos (0))
 | 
			
		||||
		{
 | 
			
		||||
			error = true;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if (!error)
 | 
			
		||||
	{
 | 
			
		||||
		auto updated (false);
 | 
			
		||||
		error = object.deserialize_json (updated, tree);
 | 
			
		||||
	}
 | 
			
		||||
	return error;
 | 
			
		||||
}
 | 
			
		||||
// Reads a json object from the stream and if was changed, write the object back to the stream
 | 
			
		||||
template <typename T>
 | 
			
		||||
bool fetch_object (T & object, boost::filesystem::path const & path_a)
 | 
			
		||||
{
 | 
			
		||||
	bool error (false);
 | 
			
		||||
	std::fstream config_file;
 | 
			
		||||
	nano::open_or_create (config_file, path_a.string ());
 | 
			
		||||
 | 
			
		||||
	if (!config_file.fail ())
 | 
			
		||||
	{
 | 
			
		||||
		boost::property_tree::ptree tree;
 | 
			
		||||
		try
 | 
			
		||||
		{
 | 
			
		||||
			boost::property_tree::read_json (config_file, tree);
 | 
			
		||||
		}
 | 
			
		||||
		catch (std::runtime_error const &)
 | 
			
		||||
		{
 | 
			
		||||
			auto pos (config_file.tellg ());
 | 
			
		||||
			if (pos != std::streampos (0))
 | 
			
		||||
			{
 | 
			
		||||
				error = true;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		config_file.close ();
 | 
			
		||||
 | 
			
		||||
		if (!error)
 | 
			
		||||
		{
 | 
			
		||||
			auto updated (false);
 | 
			
		||||
			error = object.deserialize_json (updated, tree);
 | 
			
		||||
			if (!error && updated)
 | 
			
		||||
			{
 | 
			
		||||
				config_file.open (path_a.string (), std::ios_base::out | std::ios_base::trunc);
 | 
			
		||||
				try
 | 
			
		||||
				{
 | 
			
		||||
					boost::property_tree::write_json (config_file, tree);
 | 
			
		||||
				}
 | 
			
		||||
				catch (std::runtime_error const &)
 | 
			
		||||
				{
 | 
			
		||||
					error = true;
 | 
			
		||||
				}
 | 
			
		||||
				config_file.close ();
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return error;
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue