diff --git a/rai/core_test/ledger.cpp b/rai/core_test/ledger.cpp index b316ced2..52dafc31 100644 --- a/rai/core_test/ledger.cpp +++ b/rai/core_test/ledger.cpp @@ -1447,6 +1447,29 @@ TEST (ledger, latest_root) ASSERT_EQ (send.hash (), ledger.latest_root (transaction, rai::test_genesis_key.pub)); } +TEST (ledger, supply_cache) +{ + bool init (false); + rai::block_store store (init, rai::unique_path ()); + ASSERT_TRUE (!init); + rai::ledger ledger (store, 40); + { + rai::transaction transaction (store.environment, nullptr, true); + rai::genesis genesis; + genesis.initialize (transaction, store); + rai::keypair key2; + rai::account_info info1; + ASSERT_FALSE (store.account_get (transaction, rai::test_genesis_key.pub, info1)); + rai::send_block send (info1.head, key2.pub, std::numeric_limits::max () - 50, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + ledger.process (transaction, send); + } + + // Cached (default) + ASSERT_NE (10, ledger.supply.circulating_get ()); + // Uncached + ASSERT_EQ (10, ledger.supply.circulating_get (true)); +} + TEST (ledger, inactive_supply) { bool init (false); @@ -1463,12 +1486,11 @@ TEST (ledger, inactive_supply) rai::send_block send (info1.head, key2.pub, std::numeric_limits::max () - 50, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); ledger.process (transaction, send); } - rai::transaction transaction (store.environment, nullptr, false); - ASSERT_EQ (10, ledger.supply (transaction)); - ledger.inactive_supply = 60; - ASSERT_EQ (0, ledger.supply (transaction)); - ledger.inactive_supply = 0; - ASSERT_EQ (50, ledger.supply (transaction)); + ASSERT_EQ (10, ledger.supply.circulating_get (true)); + ledger.supply.inactive_set (60); + ASSERT_EQ (0, ledger.supply.circulating_get (true)); + ledger.supply.inactive_set (0); + ASSERT_EQ (50, ledger.supply.circulating_get (true)); } TEST (ledger, change_representative_move_representation) diff --git a/rai/core_test/node.cpp b/rai/core_test/node.cpp index e689d220..8fe3ac5f 100644 --- a/rai/core_test/node.cpp +++ b/rai/core_test/node.cpp @@ -38,7 +38,7 @@ TEST (node, inactive_supply) rai::work_pool work (std::numeric_limits::max (), nullptr); config.inactive_supply = 10; auto node (std::make_shared (init, *service, path, alarm, config, work)); - ASSERT_EQ (10, node->ledger.inactive_supply); + ASSERT_EQ (10, node->ledger.supply.inactive_get ()); node->stop (); } diff --git a/rai/ledger.cpp b/rai/ledger.cpp index 98f1c524..28e31df2 100644 --- a/rai/ledger.cpp +++ b/rai/ledger.cpp @@ -495,12 +495,52 @@ bool rai::shared_ptr_block_hash::operator() (std::shared_ptr const & return *lhs == *rhs; } +rai::supply::supply (rai::ledger & ledger_a, rai::uint128_t const & inactive_supply_a) : +ledger (ledger_a), +inactive_supply (inactive_supply_a) +{ + circulating_update (); +} + +rai::uint128_t rai::supply::circulating_get (bool force_update) +{ + rai::uint128_t supply; + { + std::unique_lock lock (mutex); + if (force_update) + { + update_cache (); + } + supply = cached_supply; + } + return supply; +} + +void rai::supply::circulating_update () +{ + std::unique_lock lock (mutex); + update_cache (); +} + +void rai::supply::update_cache () +{ + if (ledger.store.environment) + { + rai::transaction transaction (ledger.store.environment, nullptr, false); + auto unallocated (ledger.account_balance (transaction, rai::genesis_account)); + auto burned (ledger.account_pending (transaction, 0)); + auto absolute_supply (rai::genesis_amount - unallocated - burned); + auto adjusted_supply (absolute_supply - inactive_supply); + cached_supply = adjusted_supply <= absolute_supply ? adjusted_supply : 0; + } +} + rai::ledger::ledger (rai::block_store & store_a, rai::uint128_t const & inactive_supply_a, rai::block_hash const & state_block_parse_canary_a, rai::block_hash const & state_block_generate_canary_a) : store (store_a), -inactive_supply (inactive_supply_a), check_bootstrap_weights (true), state_block_parse_canary (state_block_parse_canary_a), -state_block_generate_canary (state_block_generate_canary_a) +state_block_generate_canary (state_block_generate_canary_a), +supply (*this, inactive_supply_a) { } @@ -577,16 +617,6 @@ rai::process_return rai::ledger::process (MDB_txn * transaction_a, rai::block co return processor.result; } -// Money supply for heuristically calculating vote percentages -rai::uint128_t rai::ledger::supply (MDB_txn * transaction_a) -{ - auto unallocated (account_balance (transaction_a, rai::genesis_account)); - auto burned (account_pending (transaction_a, 0)); - auto absolute_supply (rai::genesis_amount - unallocated - burned); - auto adjusted_supply (absolute_supply - inactive_supply); - return adjusted_supply <= absolute_supply ? adjusted_supply : 0; -} - rai::block_hash rai::ledger::representative (MDB_txn * transaction_a, rai::block_hash const & hash_a) { auto result (representative_calculated (transaction_a, hash_a)); diff --git a/rai/ledger.hpp b/rai/ledger.hpp index 6d199282..69ece89c 100644 --- a/rai/ledger.hpp +++ b/rai/ledger.hpp @@ -12,7 +12,29 @@ public: size_t operator() (std::shared_ptr const &) const; bool operator() (std::shared_ptr const &, std::shared_ptr const &) const; }; +class ledger; +class supply +{ +public: + supply (rai::ledger & ledger_a, rai::uint128_t const & inactive_supply_a); + rai::uint128_t circulating_get (bool force_update = false); + void circulating_update (); + inline rai::uint128_t inactive_get () const + { + return inactive_supply; + }; + inline void inactive_set (rai::uint128_t const & inactive_supply_a) + { + inactive_supply = inactive_supply_a; + }; +private: + void update_cache (); + rai::ledger & ledger; + rai::uint128_t inactive_supply; + rai::uint128_t cached_supply; + std::mutex mutex; +}; class ledger { public: @@ -38,7 +60,6 @@ public: bool is_send (MDB_txn *, rai::state_block const &); rai::block_hash block_destination (MDB_txn *, rai::block const &); rai::block_hash block_source (MDB_txn *, rai::block const &); - rai::uint128_t supply (MDB_txn *); rai::process_return process (MDB_txn *, rai::block const &); void rollback (MDB_txn *, rai::block_hash const &); void change_latest (MDB_txn *, rai::account const &, rai::block_hash const &, rai::account const &, rai::uint128_union const &, uint64_t, bool = false); @@ -49,11 +70,11 @@ public: bool state_block_generation_enabled (MDB_txn *); static rai::uint128_t const unit; rai::block_store & store; - rai::uint128_t inactive_supply; std::unordered_map bootstrap_weights; uint64_t bootstrap_weight_max_blocks; std::atomic check_bootstrap_weights; rai::block_hash state_block_parse_canary; rai::block_hash state_block_generate_canary; + rai::supply supply; }; }; diff --git a/rai/node/node.cpp b/rai/node/node.cpp index 45d02058..f3317358 100644 --- a/rai/node/node.cpp +++ b/rai/node/node.cpp @@ -1603,7 +1603,7 @@ online_reps (*this) { rai::transaction transaction (store.environment, nullptr, false); rep_weight = ledger.weight (transaction, vote_a->account); - min_rep_weight = ledger.supply (transaction) / 1000; + min_rep_weight = ledger.supply.circulating_get () / 1000; } if (rep_weight > min_rep_weight) { @@ -1758,7 +1758,7 @@ void rai::gap_cache::vote (std::shared_ptr vote_a) rai::uint128_t rai::gap_cache::bootstrap_threshold (MDB_txn * transaction_a) { - auto result ((node.ledger.supply (transaction_a) / 256) * node.config.bootstrap_fraction_numerator); + auto result ((node.ledger.supply.circulating_get () / 256) * node.config.bootstrap_fraction_numerator); return result; } @@ -1955,6 +1955,7 @@ void rai::node::start () ongoing_bootstrap (); ongoing_store_flush (); ongoing_rep_crawl (); + ongoing_supply_update (); bootstrap.start (); backup_wallet (); active.announce_votes (); @@ -2050,6 +2051,18 @@ void rai::node::ongoing_keepalive () }); } +void rai::node::ongoing_supply_update () +{ + ledger.supply.circulating_update (); + std::weak_ptr node_w (shared_from_this ()); + alarm.add (std::chrono::steady_clock::now () + std::chrono::minutes (5), [node_w]() { + if (auto node_l = node_w.lock ()) + { + node_l->ongoing_supply_update (); + } + }); +} + void rai::node::ongoing_rep_crawl () { auto now (std::chrono::steady_clock::now ()); @@ -2968,13 +2981,13 @@ void rai::election::broadcast_winner () rai::uint128_t rai::election::quorum_threshold (MDB_txn * transaction_a, rai::ledger & ledger_a) { // Threshold over which unanimous voting implies confirmation - return ledger_a.supply (transaction_a) / 2; + return ledger_a.supply.circulating_get () / 2; } rai::uint128_t rai::election::minimum_threshold (MDB_txn * transaction_a, rai::ledger & ledger_a) { // Minimum number of votes needed to change our ledger, under which we're probably disconnected - return ledger_a.supply (transaction_a) / 16; + return ledger_a.supply.circulating_get () / 16; } void rai::election::confirm_once (MDB_txn * transaction_a) @@ -3050,7 +3063,7 @@ bool rai::election::vote (std::shared_ptr vote_a) // see republish_vote documentation for an explanation of these rules rai::transaction transaction (node.store.environment, nullptr, false); auto replay (false); - auto supply (node.ledger.supply (transaction)); + auto supply (node.ledger.supply.circulating_get ()); auto weight (node.ledger.weight (transaction, vote_a->account)); if (rai::rai_network == rai::rai_networks::rai_test_network || weight > supply / 1000) // 0.1% or above { diff --git a/rai/node/node.hpp b/rai/node/node.hpp index d459b1f5..3d862c35 100644 --- a/rai/node/node.hpp +++ b/rai/node/node.hpp @@ -543,6 +543,7 @@ public: void ongoing_rep_crawl (); void ongoing_bootstrap (); void ongoing_store_flush (); + void ongoing_supply_update (); void backup_wallet (); int price (rai::uint128_t const &, int); void generate_work (rai::block &);