Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Node configuration auto updater #4579

Merged
merged 7 commits into from
Apr 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions nano/core_test/toml.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1038,3 +1038,47 @@ TEST (toml, log_config_no_required)

ASSERT_FALSE (toml.get_error ()) << toml.get_error ().get_message ();
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think in this case, a systest would had been a better option.
But you have done it now...

TEST (toml, merge_config_files)
{
nano::network_params network_params{ nano::network_constants::active_network };
nano::tomlconfig default_toml;
nano::tomlconfig current_toml;
nano::tomlconfig merged_toml;
nano::daemon_config default_config{ ".", network_params };
nano::daemon_config current_config{ ".", network_params };
nano::daemon_config merged_config{ ".", network_params };

std::stringstream ss;

ss << R"toml(
[node]
active_elections_size = 999
# backlog_scan_batch_size = 7777
[node.bootstrap_ascending]
block_wait_count = 33333
old_entry = 34
)toml";

current_toml.read (ss);
current_config.deserialize_toml (current_toml);

current_config.serialize_toml (current_toml);
default_config.serialize_toml (default_toml);

auto merged_config_string = current_toml.merge_defaults (current_toml, default_toml);

// Configs have been merged. Let's read and parse the new config file and verify the values

std::stringstream ss2;
ss2 << merged_config_string;

merged_toml.read (ss2);
merged_config.deserialize_toml (merged_toml);

ASSERT_NE (merged_config.node.active_elections_size, default_config.node.active_elections_size);
ASSERT_EQ (merged_config.node.active_elections_size, 999);
ASSERT_NE (merged_config.node.backlog_scan_batch_size, 7777);
ASSERT_EQ (merged_config.node.bootstrap_ascending.block_wait_count, 33333);
ASSERT_TRUE (merged_config_string.find ("old_entry") == std::string::npos);
}
32 changes: 32 additions & 0 deletions nano/lib/tomlconfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,38 @@ void nano::tomlconfig::erase_default_values (tomlconfig & defaults_a)
erase_defaults (defaults_l.get_tree (), self.get_tree (), get_tree ());
}

// Merges two TOML configurations and commenting values that are identical
std::string nano::tomlconfig::merge_defaults (nano::tomlconfig & current_config, nano::tomlconfig & default_config)
{
// Serialize both configs to commented strings
std::string defaults_str = default_config.to_string (true);
std::string current_str = current_config.to_string (true);

// Read both configs line by line
std::istringstream stream_defaults (defaults_str);
std::istringstream stream_current (current_str);
std::string line_defaults, line_current, result;

while (std::getline (stream_defaults, line_defaults) && std::getline (stream_current, line_current))
Copy link
Contributor

@dsiganos dsiganos Apr 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This loop will only work correctly if the defaults and current lists are sorted and have the same number of elements. Is this guranteed to happen? If yes, how do you know?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current list and default list will always follow the exact same layout. This is because we use the serialize_toml function to create the configs. That function will create all the tree nodes, config items, and docs based on the input

{
if (line_defaults == line_current)
{
// Use default value
result += line_defaults + "\n";
}
else
{
// Non default value. Removing the # to uncomment
dsiganos marked this conversation as resolved.
Show resolved Hide resolved
size_t pos = line_current.find ('#');
debug_assert (pos != std::string::npos);
debug_assert (pos < line_current.length ());
result += line_current.substr (0, pos) + line_current.substr (pos + 1) + "\n";
}
}

return result;
}

std::string nano::tomlconfig::to_string (bool comment_values)
{
std::stringstream ss, ss_processed;
Expand Down
1 change: 1 addition & 0 deletions nano/lib/tomlconfig.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ class tomlconfig : public nano::configbase
std::shared_ptr<cpptoml::array> create_array (std::string const & key, boost::optional<char const *> documentation_a);
void erase_default_values (tomlconfig & defaults_a);
std::string to_string (bool comment_values);
std::string merge_defaults (nano::tomlconfig & current_config, nano::tomlconfig & default_config);

/** Set value for the given key. Any existing value will be overwritten. */
template <typename T>
Expand Down
26 changes: 26 additions & 0 deletions nano/node/cli.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ void nano::add_node_options (boost::program_options::options_description & descr
("migrate_database_lmdb_to_rocksdb", "Migrates LMDB database to RocksDB")
("diagnostics", "Run internal diagnostics")
("generate_config", boost::program_options::value<std::string> (), "Write configuration to stdout, populated with defaults suitable for this system. Pass the configuration type node, rpc or log. See also use_defaults.")
("update_config", "Reads the current node configuration and updates it with missing keys and values and delete keys that are no longer used. Updated configuration is written to stdout.")
("key_create", "Generates a adhoc random keypair and prints it to stdout")
("key_expand", "Derive public key and account number from <key>")
("wallet_add_adhoc", "Insert <key> in to <wallet>")
Expand Down Expand Up @@ -711,6 +712,31 @@ std::error_code nano::handle_node_options (boost::program_options::variables_map
}
}
}
else if (vm.count ("update_config"))
{
nano::network_params network_params{ nano::network_constants::active_network };
nano::tomlconfig default_toml;
nano::tomlconfig current_toml;
nano::daemon_config default_config{ data_path, network_params };
nano::daemon_config current_config{ data_path, network_params };

std::vector<std::string> config_overrides;
auto error = nano::read_node_config_toml (data_path, current_config, config_overrides);
if (error)
{
std::cerr << "Could not read existing config file\n";
ec = nano::error_cli::reading_config;
}
else
{
current_config.serialize_toml (current_toml);
default_config.serialize_toml (default_toml);

auto output = current_toml.merge_defaults (current_toml, default_toml);

std::cout << output;
}
}
else if (vm.count ("diagnostics"))
{
auto inactive_node = nano::default_inactive_node (data_path, vm);
Expand Down
Loading