Skip to content

Commit

Permalink
Merge pull request #4485 from simpago/rep-cache-min-weight
Browse files Browse the repository at this point in the history
rep_weights part 3 - Add mininum weight to representative cache
  • Loading branch information
clemahieu authored Mar 22, 2024
2 parents c2a90d1 + b6ec773 commit 35da7e6
Show file tree
Hide file tree
Showing 15 changed files with 94 additions and 18 deletions.
30 changes: 30 additions & 0 deletions nano/core_test/ledger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

#include <gtest/gtest.h>

#include <limits>

using namespace std::chrono_literals;

// Init returns an error if it can't open files at the path
Expand Down Expand Up @@ -691,6 +693,34 @@ TEST (ledger, delete_rep_weight_of_zero)
ASSERT_EQ (0, store->rep_weight.count (txn));
}

TEST (ledger, rep_cache_min_weight)
{
auto store{ nano::test::make_store () };
nano::uint128_t min_weight{ 10 };
nano::rep_weights rep_weights{ store->rep_weight, min_weight };
auto txn{ store->tx_begin_write () };

// one below min weight
rep_weights.representation_add (txn, 1, 9);
ASSERT_EQ (0, rep_weights.size ());
ASSERT_EQ (1, store->rep_weight.count (txn));

// exactly min weight
rep_weights.representation_add (txn, 1, 1);
ASSERT_EQ (1, rep_weights.size ());
ASSERT_EQ (1, store->rep_weight.count (txn));

// above min weight
rep_weights.representation_add (txn, 1, 1);
ASSERT_EQ (1, rep_weights.size ());
ASSERT_EQ (1, store->rep_weight.count (txn));

// fall blow min weight
rep_weights.representation_add (txn, 1, nano::uint128_t{ 0 } - 5);
ASSERT_EQ (0, rep_weights.size ());
ASSERT_EQ (1, store->rep_weight.count (txn));
}

TEST (ledger, representation)
{
auto ctx = nano::test::context::ledger_empty ();
Expand Down
3 changes: 3 additions & 0 deletions nano/core_test/toml.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ TEST (toml, daemon_config_deserialize_defaults)
ASSERT_EQ (conf.node.background_threads, defaults.node.background_threads);
ASSERT_EQ (conf.node.secondary_work_peers, defaults.node.secondary_work_peers);
ASSERT_EQ (conf.node.online_weight_minimum, defaults.node.online_weight_minimum);
ASSERT_EQ (conf.node.representative_vote_weight_minimum, defaults.node.representative_vote_weight_minimum);
ASSERT_EQ (conf.node.rep_crawler_weight_minimum, defaults.node.rep_crawler_weight_minimum);
ASSERT_EQ (conf.node.password_fanout, defaults.node.password_fanout);
ASSERT_EQ (conf.node.peering_port, defaults.node.peering_port);
Expand Down Expand Up @@ -405,6 +406,7 @@ TEST (toml, daemon_config_deserialize_no_defaults)
network_threads = 999
background_threads = 999
online_weight_minimum = "999"
representative_vote_weight_minimum = "999"
rep_crawler_weight_minimum = "999"
password_fanout = 999
peering_port = 999
Expand Down Expand Up @@ -599,6 +601,7 @@ TEST (toml, daemon_config_deserialize_no_defaults)
ASSERT_NE (conf.node.max_pruning_age, defaults.node.max_pruning_age);
ASSERT_NE (conf.node.max_pruning_depth, defaults.node.max_pruning_depth);
ASSERT_NE (conf.node.online_weight_minimum, defaults.node.online_weight_minimum);
ASSERT_NE (conf.node.representative_vote_weight_minimum, defaults.node.representative_vote_weight_minimum);
ASSERT_NE (conf.node.rep_crawler_weight_minimum, defaults.node.rep_crawler_weight_minimum);
ASSERT_NE (conf.node.password_fanout, defaults.node.password_fanout);
ASSERT_NE (conf.node.peering_port, defaults.node.peering_port);
Expand Down
4 changes: 4 additions & 0 deletions nano/core_test/vote_processor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,10 @@ TEST (vote_processor, no_broadcast_local)
nano::node_flags flags;
flags.disable_request_loop = true;
nano::node_config config1, config2;
config1.representative_vote_weight_minimum = 0;
config1.frontiers_confirmation = nano::frontiers_confirmation_mode::disabled;
auto & node (*system.add_node (config1, flags));
config2.representative_vote_weight_minimum = 0;
config2.frontiers_confirmation = nano::frontiers_confirmation_mode::disabled;
config2.peering_port = system.get_available_port ();
system.add_node (config2, flags);
Expand Down Expand Up @@ -231,8 +233,10 @@ TEST (vote_processor, local_broadcast_without_a_representative)
nano::node_flags flags;
flags.disable_request_loop = true;
nano::node_config config1, config2;
config1.representative_vote_weight_minimum = 0;
config1.frontiers_confirmation = nano::frontiers_confirmation_mode::disabled;
auto & node (*system.add_node (config1, flags));
config2.representative_vote_weight_minimum = 0;
config2.frontiers_confirmation = nano::frontiers_confirmation_mode::disabled;
config2.peering_port = system.get_available_port ();
system.add_node (config2, flags);
Expand Down
8 changes: 4 additions & 4 deletions nano/node/json_handler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -699,7 +699,7 @@ void nano::json_handler::account_info ()
}
if (weight)
{
auto account_weight (node.ledger.weight (account));
auto account_weight (node.ledger.weight_exact (transaction, account));
response_l.put ("weight", account_weight.convert_to<std::string> ());
}
if (receivable)
Expand Down Expand Up @@ -2785,7 +2785,7 @@ void nano::json_handler::ledger ()
}
if (weight)
{
auto account_weight (node.ledger.weight (account));
auto account_weight (node.ledger.weight_exact (transaction, account));
response_a.put ("weight", account_weight.convert_to<std::string> ());
}
accounts.push_back (std::make_pair (account.to_account (), response_a));
Expand Down Expand Up @@ -2838,7 +2838,7 @@ void nano::json_handler::ledger ()
}
if (weight)
{
auto account_weight (node.ledger.weight (account));
auto account_weight (node.ledger.weight_exact (transaction, account));
response_a.put ("weight", account_weight.convert_to<std::string> ());
}
accounts.push_back (std::make_pair (account.to_account (), response_a));
Expand Down Expand Up @@ -4717,7 +4717,7 @@ void nano::json_handler::wallet_ledger ()
}
if (weight)
{
auto account_weight (node.ledger.weight (account));
auto account_weight (node.ledger.weight_exact (block_transaction, account));
entry.put ("weight", account_weight.convert_to<std::string> ());
}
if (receivable)
Expand Down
5 changes: 3 additions & 2 deletions nano/node/node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ nano::node::node (std::shared_ptr<boost::asio::io_context> io_ctx_a, std::filesy
unchecked{ config.max_unchecked_blocks, stats, flags.disable_block_processor_unchecked_deletion },
wallets_store_impl (std::make_unique<nano::mdb_wallets_store> (application_path_a / "wallets.ldb", config_a.lmdb_config)),
wallets_store (*wallets_store_impl),
ledger_impl{ std::make_unique<nano::ledger> (store, stats, network_params.ledger, flags_a.generate_cache) },
ledger_impl{ std::make_unique<nano::ledger> (store, stats, network_params.ledger, flags_a.generate_cache, config_a.representative_vote_weight_minimum.number ()) },
ledger{ *ledger_impl },
outbound_limiter{ outbound_bandwidth_limiter_config (config) },
// empty `config.peering_port` means the user made no port choice at all;
Expand Down Expand Up @@ -756,7 +756,8 @@ std::pair<nano::uint128_t, nano::uint128_t> nano::node::balance_pending (nano::a

nano::uint128_t nano::node::weight (nano::account const & account_a)
{
return ledger.weight (account_a);
auto txn{ ledger.store.tx_begin_read () };
return ledger.weight_exact (txn, account_a);
}

nano::uint128_t nano::node::minimum_principal_weight ()
Expand Down
11 changes: 11 additions & 0 deletions nano/node/nodeconfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ nano::error nano::node_config::serialize_toml (nano::tomlconfig & toml) const
toml.put ("bootstrap_fraction_numerator", bootstrap_fraction_numerator, "Change bootstrap threshold (online stake / 256 * bootstrap_fraction_numerator).\ntype:uint32");
toml.put ("receive_minimum", receive_minimum.to_string_dec (), "Minimum receive amount. Only affects node wallets. A large amount is recommended to avoid automatic work generation for tiny transactions.\ntype:string,amount,raw");
toml.put ("online_weight_minimum", online_weight_minimum.to_string_dec (), "When calculating online weight, the node is forced to assume at least this much voting weight is online, thus setting a floor for voting weight to confirm transactions at online_weight_minimum * \"quorum delta\".\ntype:string,amount,raw");
toml.put ("representative_vote_weight_minimum", representative_vote_weight_minimum.to_string_dec (), "Minimum vote weight that a representative must have for its vote to be counted.\nAll representatives above this weight will be kept in memory!\ntype:string,amount,raw");
toml.put ("password_fanout", password_fanout, "Password fanout factor.\ntype:uint64");
toml.put ("io_threads", io_threads, "Number of threads dedicated to I/O operations. Defaults to the number of CPU threads, and at least 4.\ntype:uint64");
toml.put ("network_threads", network_threads, "Number of threads dedicated to processing network messages. Defaults to the number of CPU threads, and at least 4.\ntype:uint64");
Expand Down Expand Up @@ -340,6 +341,16 @@ nano::error nano::node_config::deserialize_toml (nano::tomlconfig & toml)
toml.get_error ().set ("online_weight_minimum contains an invalid decimal amount");
}

auto representative_vote_weight_minimum_l{ representative_vote_weight_minimum.to_string_dec () };
if (toml.has_key ("representative_vote_weight_minimum"))
{
representative_vote_weight_minimum_l = toml.get<std::string> ("representative_vote_weight_minimum");
}
if (representative_vote_weight_minimum.decode_dec (representative_vote_weight_minimum_l))
{
toml.get_error ().set ("representative_vote_weight_minimum contains an invalid decimal amount");
}

auto vote_minimum_l (vote_minimum.to_string_dec ());
if (toml.has_key ("vote_minimum"))
{
Expand Down
5 changes: 5 additions & 0 deletions nano/node/nodeconfig.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ class node_config
std::chrono::milliseconds vote_generator_delay{ std::chrono::milliseconds (100) };
unsigned vote_generator_threshold{ 3 };
nano::amount online_weight_minimum{ 60000 * nano::Gxrb_ratio };
/*
* The minimum vote weight that a representative must have for its vote to be counted.
* All representatives above this weight will be kept in memory!
*/
nano::amount representative_vote_weight_minimum{ 10 * nano::Mxrb_ratio };
unsigned password_fanout{ 1024 };
unsigned io_threads{ std::max (4u, nano::hardware_concurrency ()) };
unsigned network_threads{ std::max (4u, nano::hardware_concurrency ()) };
Expand Down
9 changes: 7 additions & 2 deletions nano/node/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1537,6 +1537,7 @@ void nano::wallets::foreach_representative (std::function<void (nano::public_key
std::vector<std::pair<nano::public_key const, nano::raw_key const>> action_accounts_l;
{
auto transaction_l (tx_begin_read ());
auto ledger_txn{ node.ledger.store.tx_begin_read () };
nano::lock_guard<nano::mutex> lock{ mutex };
for (auto i (items.begin ()), n (items.end ()); i != n; ++i)
{
Expand All @@ -1551,7 +1552,7 @@ void nano::wallets::foreach_representative (std::function<void (nano::public_key
{
if (wallet.store.exists (transaction_l, account))
{
if (!node.ledger.weight (account).is_zero ())
if (!node.ledger.weight_exact (ledger_txn, account).is_zero ())
{
if (wallet.store.valid_password (transaction_l))
{
Expand Down Expand Up @@ -1642,7 +1643,11 @@ nano::wallet_representatives nano::wallets::reps () const

bool nano::wallets::check_rep (nano::account const & account_a, nano::uint128_t const & half_principal_weight_a, bool const acquire_lock_a)
{
auto weight = node.ledger.weight (account_a);
nano::uint128_t weight;
{
auto ledger_txn{ node.ledger.store.tx_begin_read () };
weight = node.ledger.weight_exact (ledger_txn, account_a);
}

if (weight < node.config.vote_minimum.number ())
{
Expand Down
9 changes: 7 additions & 2 deletions nano/secure/ledger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -749,10 +749,10 @@ void representative_visitor::state_block (nano::state_block const & block_a)
}
} // namespace

nano::ledger::ledger (nano::store::component & store_a, nano::stats & stat_a, nano::ledger_constants & constants, nano::generate_cache_flags const & generate_cache_flags_a) :
nano::ledger::ledger (nano::store::component & store_a, nano::stats & stat_a, nano::ledger_constants & constants, nano::generate_cache_flags const & generate_cache_flags_a, nano::uint128_t min_rep_weight_a) :
constants{ constants },
store{ store_a },
cache{ store_a.rep_weight },
cache{ store_a.rep_weight, min_rep_weight_a },
stats{ stat_a },
check_bootstrap_weights{ true }
{
Expand Down Expand Up @@ -982,6 +982,11 @@ nano::uint128_t nano::ledger::weight (nano::account const & account_a)
return cache.rep_weights.representation_get (account_a);
}

nano::uint128_t nano::ledger::weight_exact (store::transaction const & txn_a, nano::account const & representative_a)
{
return store.rep_weight.get (txn_a, representative_a);
}

// Rollback blocks until `block_a' doesn't exist or it tries to penetrate the confirmation height
bool nano::ledger::rollback (store::write_transaction const & transaction_a, nano::block_hash const & block_a, std::vector<std::shared_ptr<nano::block>> & list_a)
{
Expand Down
9 changes: 8 additions & 1 deletion nano/secure/ledger.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class ledger final
friend class receivable_iterator;

public:
ledger (nano::store::component &, nano::stats &, nano::ledger_constants & constants, nano::generate_cache_flags const & = nano::generate_cache_flags{});
ledger (nano::store::component &, nano::stats &, nano::ledger_constants & constants, nano::generate_cache_flags const & = nano::generate_cache_flags{}, nano::uint128_t min_rep_weight_a = 0);
/**
* Returns the account for a given hash
* Returns std::nullopt if the block doesn't exist or has been pruned
Expand All @@ -53,9 +53,16 @@ class ledger final
bool block_exists (store::transaction const & transaction, nano::block_hash const & hash) const;
nano::uint128_t account_balance (store::transaction const &, nano::account const &, bool = false);
nano::uint128_t account_receivable (store::transaction const &, nano::account const &, bool = false);
/**
* Returns the cached vote weight for the given representative.
* If the weight is below the cache limit it returns 0.
* During bootstrap it returns the preconfigured bootstrap weights.
*/
nano::uint128_t weight (nano::account const &);
std::optional<nano::block_hash> successor (store::transaction const &, nano::qualified_root const &) const noexcept;
std::optional<nano::block_hash> successor (store::transaction const & transaction, nano::block_hash const & hash) const noexcept;
/* Returns the exact vote weight for the given representative by doing a database lookup */
nano::uint128_t weight_exact (store::transaction const &, nano::account const &);
std::shared_ptr<nano::block> forked_block (store::transaction const &, nano::block const &);
std::shared_ptr<nano::block> head_block (store::transaction const &, nano::account const &);
bool block_confirmed (store::transaction const &, nano::block_hash const &) const;
Expand Down
4 changes: 2 additions & 2 deletions nano/secure/ledger_cache.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#include <nano/secure/ledger_cache.hpp>

nano::ledger_cache::ledger_cache (nano::store::rep_weight & rep_weight_store_a) :
rep_weights{ rep_weight_store_a }
nano::ledger_cache::ledger_cache (nano::store::rep_weight & rep_weight_store_a, nano::uint128_t min_rep_weight_a) :
rep_weights{ rep_weight_store_a, min_rep_weight_a }
{
}
3 changes: 2 additions & 1 deletion nano/secure/ledger_cache.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include <nano/lib/numbers.hpp>
#include <nano/secure/rep_weights.hpp>
#include <nano/store/rep_weight.hpp>

Expand All @@ -11,7 +12,7 @@ namespace nano
class ledger_cache
{
public:
explicit ledger_cache (nano::store::rep_weight & rep_weight_store_a);
explicit ledger_cache (nano::store::rep_weight & rep_weight_store_a, nano::uint128_t min_rep_weight_a = 0);
nano::rep_weights rep_weights;
std::atomic<uint64_t> cemented_count{ 0 };
std::atomic<uint64_t> block_count{ 0 };
Expand Down
8 changes: 5 additions & 3 deletions nano/secure/rep_weights.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
#include <nano/lib/numbers.hpp>
#include <nano/secure/rep_weights.hpp>
#include <nano/store/component.hpp>
#include <nano/store/rep_weight.hpp>

nano::rep_weights::rep_weights (nano::store::rep_weight & rep_weight_store_a) :
rep_weight_store{ rep_weight_store_a }
nano::rep_weights::rep_weights (nano::store::rep_weight & rep_weight_store_a, nano::uint128_t min_weight_a) :
rep_weight_store{ rep_weight_store_a },
min_weight{ min_weight_a }
{
}

Expand Down Expand Up @@ -69,7 +71,7 @@ void nano::rep_weights::copy_from (nano::rep_weights & other_a)
void nano::rep_weights::put_cache (nano::account const & account_a, nano::uint128_union const & representation_a)
{
auto it = rep_amounts.find (account_a);
if (representation_a.is_zero ())
if (representation_a < min_weight || representation_a.is_zero ())
{
if (it != rep_amounts.end ())
{
Expand Down
3 changes: 2 additions & 1 deletion nano/secure/rep_weights.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ namespace store
class rep_weights
{
public:
explicit rep_weights (nano::store::rep_weight & rep_weight_store_a);
explicit rep_weights (nano::store::rep_weight & rep_weight_store_a, nano::uint128_t min_weight_a = 0);
void representation_add (store::write_transaction const & txn_a, nano::account const & source_rep_a, nano::uint128_t const & amount_a);
void representation_add_dual (store::write_transaction const & txn_a, nano::account const & source_rep_1, nano::uint128_t const & amount_1, nano::account const & source_rep_2, nano::uint128_t const & amount_2);
nano::uint128_t representation_get (nano::account const & account_a) const;
Expand All @@ -35,6 +35,7 @@ class rep_weights
mutable nano::mutex mutex;
std::unordered_map<nano::account, nano::uint128_t> rep_amounts;
nano::store::rep_weight & rep_weight_store;
nano::uint128_t min_weight;
void put_cache (nano::account const & account_a, nano::uint128_union const & representation_a);
void put_store (store::write_transaction const & txn_a, nano::account const & rep_a, nano::uint128_t const & previous_weight_a, nano::uint128_t const & new_weight_a);
nano::uint128_t get (nano::account const & account_a) const;
Expand Down
1 change: 1 addition & 0 deletions nano/test_common/system.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,7 @@ void nano::test::system::stop ()
nano::node_config nano::test::system::default_config ()
{
nano::node_config config{ get_available_port () };
config.representative_vote_weight_minimum = 0;
return config;
}

Expand Down

0 comments on commit 35da7e6

Please sign in to comment.