diff --git a/rai/core_test/ledger.cpp b/rai/core_test/ledger.cpp index 85ebfe8c..010da22d 100644 --- a/rai/core_test/ledger.cpp +++ b/rai/core_test/ledger.cpp @@ -1494,54 +1494,6 @@ 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::stat stats; - rai::ledger ledger (store, stats, 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); - rai::block_store store (init, rai::unique_path ()); - ASSERT_TRUE (!init); - rai::stat stats; - rai::ledger ledger (store, stats, 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); - } - 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) { bool init (false); @@ -2354,8 +2306,7 @@ TEST (ledger, state_canary_blocks) rai::genesis genesis; rai::send_block parse_canary (genesis.hash (), rai::test_genesis_key.pub, rai::genesis_amount, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); rai::send_block generate_canary (parse_canary.hash (), rai::test_genesis_key.pub, rai::genesis_amount, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); - rai::stat stats; - rai::ledger ledger (store, stats, 0, parse_canary.hash (), generate_canary.hash ()); + rai::ledger ledger (store, stats, parse_canary.hash (), generate_canary.hash ()); rai::transaction transaction (store.environment, nullptr, true); genesis.initialize (transaction, store); rai::state_block state (rai::test_genesis_key.pub, genesis.hash (), rai::test_genesis_key.pub, rai::genesis_amount - rai::Gxrb_ratio, rai::test_genesis_key.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); diff --git a/rai/core_test/node.cpp b/rai/core_test/node.cpp index 0ecad7b2..f8ea466f 100644 --- a/rai/core_test/node.cpp +++ b/rai/core_test/node.cpp @@ -27,21 +27,6 @@ TEST (node, block_store_path_failure) node->stop (); } -TEST (node, inactive_supply) -{ - rai::node_init init; - auto service (boost::make_shared ()); - rai::alarm alarm (*service); - auto path (rai::unique_path ()); - rai::node_config config; - config.logging.init (path); - 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.supply.inactive_get ()); - node->stop (); -} - TEST (node, state_canaries) { rai::node_init init; @@ -199,7 +184,8 @@ TEST (node, quick_confirm) rai::keypair key; rai::block_hash previous (system.nodes[0]->latest (rai::test_genesis_key.pub)); system.wallet (0)->insert_adhoc (key.prv); - auto send (std::make_shared (previous, key.pub, 0, rai::test_genesis_key.prv, rai::test_genesis_key.pub, system.work.generate (previous))); + system.wallet (0)->insert_adhoc (rai::test_genesis_key.prv); + auto send (std::make_shared (previous, key.pub, system.nodes[0]->delta () + 1, rai::test_genesis_key.prv, rai::test_genesis_key.pub, system.work.generate (previous))); system.nodes[0]->process_active (send); auto iterations (0); while (system.nodes[0]->balance (key.pub).is_zero ()) @@ -210,6 +196,38 @@ TEST (node, quick_confirm) } } +TEST (node, node_receive_quorum) +{ + rai::system system (24000, 1); + rai::keypair key; + rai::block_hash previous (system.nodes[0]->latest (rai::test_genesis_key.pub)); + system.wallet (0)->insert_adhoc (key.prv); + auto send (std::make_shared (previous, key.pub, rai::genesis_amount - rai::Gxrb_ratio, rai::test_genesis_key.prv, rai::test_genesis_key.pub, system.work.generate (previous))); + system.nodes[0]->process_active (send); + auto iterations (0); + while (!system.nodes[0]->ledger.block_exists (send->hash ())) + { + system.poll (); + ++iterations; + ASSERT_LT (iterations, 200); + } + while (!system.nodes[0]->active.roots.empty ()) + { + system.poll (); + ++iterations; + ASSERT_LT (iterations, 200); + } + ASSERT_TRUE (system.nodes[0]->balance (key.pub).is_zero ()); + system.wallet (0)->insert_adhoc (rai::test_genesis_key.prv); + system.nodes[0]->block_confirm (send); + while (system.nodes[0]->balance (key.pub).is_zero ()) + { + system.poll (); + ++iterations; + ASSERT_LT (iterations, 200); + } +} + TEST (node, auto_bootstrap) { rai::system system (24000, 1); @@ -506,7 +524,8 @@ TEST (node_config, serialization) rai::node_config config1 (100, logging1); config1.bootstrap_fraction_numerator = 10; config1.receive_minimum = 10; - config1.inactive_supply = 10; + config1.online_weight_minimum = 10; + config1.online_weight_quorom = 10; config1.password_fanout = 10; config1.enable_voting = false; config1.callback_address = "test"; @@ -524,7 +543,8 @@ TEST (node_config, serialization) ASSERT_NE (config2.bootstrap_fraction_numerator, config1.bootstrap_fraction_numerator); ASSERT_NE (config2.peering_port, config1.peering_port); ASSERT_NE (config2.logging.node_lifetime_tracing_value, config1.logging.node_lifetime_tracing_value); - ASSERT_NE (config2.inactive_supply, config1.inactive_supply); + ASSERT_NE (config2.online_weight_minimum, config1.online_weight_minimum); + ASSERT_NE (config2.online_weight_quorom, config1.online_weight_quorom); ASSERT_NE (config2.password_fanout, config1.password_fanout); ASSERT_NE (config2.enable_voting, config1.enable_voting); ASSERT_NE (config2.callback_address, config1.callback_address); @@ -540,7 +560,8 @@ TEST (node_config, serialization) ASSERT_EQ (config2.bootstrap_fraction_numerator, config1.bootstrap_fraction_numerator); ASSERT_EQ (config2.peering_port, config1.peering_port); ASSERT_EQ (config2.logging.node_lifetime_tracing_value, config1.logging.node_lifetime_tracing_value); - ASSERT_EQ (config2.inactive_supply, config1.inactive_supply); + ASSERT_EQ (config2.online_weight_minimum, config1.online_weight_minimum); + ASSERT_EQ (config2.online_weight_quorom, config1.online_weight_quorom); ASSERT_EQ (config2.password_fanout, config1.password_fanout); ASSERT_EQ (config2.enable_voting, config1.enable_voting); ASSERT_EQ (config2.callback_address, config1.callback_address); @@ -651,7 +672,7 @@ TEST (node_config, v2_v3_upgrade) ASSERT_FALSE (tree.get_optional ("io_threads")); ASSERT_FALSE (tree.get_optional ("work_threads")); config1.deserialize_json (upgraded, tree); - ASSERT_EQ (rai::uint128_union (0).to_string_dec (), tree.get ("inactive_supply")); + //ASSERT_EQ (rai::uint128_union (0).to_string_dec (), tree.get ("inactive_supply")); ASSERT_EQ ("1024", tree.get ("password_fanout")); ASSERT_NE (0, std::stoul (tree.get ("password_fanout"))); ASSERT_NE (0, std::stoul (tree.get ("password_fanout"))); @@ -1167,7 +1188,7 @@ TEST (node, rep_self_vote) auto & active (node0->active); { rai::transaction transaction (node0->store.environment, nullptr, true); - active.start (transaction, block0, [](std::shared_ptr, bool) {}); + active.start (transaction, block0); } auto existing (active.roots.find (block0->root ())); ASSERT_NE (active.roots.end (), existing); @@ -1330,7 +1351,7 @@ TEST (node, no_voting) // Broadcast a confirm so others should know this is a rep node wallet0->send_action (rai::test_genesis_key.pub, key1.pub, rai::Mxrb_ratio); auto iterations (0); - while (node1.balance (key1.pub).is_zero ()) + while (!node1.active.roots.empty ()) { system.poll (); ++iterations; @@ -1449,6 +1470,7 @@ TEST (node, bootstrap_connection_scaling) auto & node1 (*system.nodes[0]); node1.bootstrap_initiator.bootstrap (); auto attempt (node1.bootstrap_initiator.current_attempt ()); + ASSERT_NE (nullptr, attempt); ASSERT_EQ (34, attempt->target_connections (25000)); ASSERT_EQ (4, attempt->target_connections (0)); ASSERT_EQ (64, attempt->target_connections (50000)); @@ -1484,10 +1506,10 @@ TEST (node, online_reps) { rai::system system (24000, 2); system.wallet (0)->insert_adhoc (rai::test_genesis_key.prv); - ASSERT_TRUE (system.nodes[1]->online_reps.online_stake ().is_zero ()); + ASSERT_EQ (system.nodes[1]->config.online_weight_minimum.number (), system.nodes[1]->online_reps.online_stake ()); system.wallet (0)->send_action (rai::test_genesis_key.pub, rai::test_genesis_key.pub, rai::Gxrb_ratio); auto iterations (0); - while (system.nodes[1]->online_reps.online_stake ().is_zero ()) + while (system.nodes[1]->online_reps.online_stake () == system.nodes[1]->config.online_weight_minimum.number ()) { system.poll (); ++iterations; @@ -1563,3 +1585,34 @@ TEST (node, block_arrival_time) node.block_arrival.recent (0); ASSERT_EQ (rai::block_arrival::arrival_size_min * 2, node.block_arrival.arrival.size ()); } + +TEST (node, confirm_quorom) +{ + rai::system system (24000, 1); + rai::genesis genesis; + system.wallet (0)->insert_adhoc (rai::test_genesis_key.prv); + system.nodes[0]->ledger.state_block_parse_canary = genesis.hash (); + // Put greater than online_weight_minimum in pending so quorom can't be reached + auto send1 (std::make_shared (rai::test_genesis_key.pub, genesis.hash (), rai::test_genesis_key.pub, rai::Gxrb_ratio, rai::test_genesis_key.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, system.nodes[0]->generate_work (genesis.hash ()))); + { + rai::transaction transaction (system.nodes[0]->store.environment, nullptr, true); + ASSERT_EQ (rai::process_result::progress, system.nodes[0]->ledger.process (transaction, *send1).code); + } + system.wallet (0)->send_action (rai::test_genesis_key.pub, rai::test_genesis_key.pub, rai::Gxrb_ratio); + auto iterations (0); + while (system.nodes[0]->active.roots.empty ()) + { + system.poll (); + ++iterations; + ASSERT_LT (iterations, 200); + } + ASSERT_FALSE (system.nodes[0]->active.roots.empty ()); + while (!system.nodes[0]->active.roots.empty ()) + { + system.poll (); + ++iterations; + ASSERT_LT (iterations, 200); + } + ASSERT_TRUE (system.nodes[0]->active.roots.empty ()); + ASSERT_EQ (0, system.nodes[0]->balance (rai::test_genesis_key.pub)); +} diff --git a/rai/core_test/rpc.cpp b/rai/core_test/rpc.cpp index 0a2b6dd6..c5bc9787 100644 --- a/rai/core_test/rpc.cpp +++ b/rai/core_test/rpc.cpp @@ -3516,10 +3516,10 @@ TEST (rpc, online_reps) { rai::system system (24000, 2); system.wallet (0)->insert_adhoc (rai::test_genesis_key.prv); - ASSERT_TRUE (system.nodes[1]->online_reps.online_stake ().is_zero ()); + ASSERT_TRUE (system.nodes[1]->online_reps.online_stake () == system.nodes[1]->config.online_weight_minimum.number ()); system.wallet (0)->send_action (rai::test_genesis_key.pub, rai::test_genesis_key.pub, rai::Gxrb_ratio); auto iterations (0); - while (system.nodes[1]->online_reps.online_stake ().is_zero ()) + while (system.nodes[1]->online_reps.online_stake () == system.nodes[1]->config.online_weight_minimum.number ()) { system.poll (); ++iterations; diff --git a/rai/ledger.cpp b/rai/ledger.cpp index 125519f4..3e0f29a0 100644 --- a/rai/ledger.cpp +++ b/rai/ledger.cpp @@ -505,53 +505,12 @@ 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::stat & stat_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) : +rai::ledger::ledger (rai::block_store & store_a, rai::stat & stat_a, rai::block_hash const & state_block_parse_canary_a, rai::block_hash const & state_block_generate_canary_a) : store (store_a), stats (stat_a), check_bootstrap_weights (true), state_block_parse_canary (state_block_parse_canary_a), -state_block_generate_canary (state_block_generate_canary_a), -supply (*this, inactive_supply_a) +state_block_generate_canary (state_block_generate_canary_a) { } diff --git a/rai/ledger.hpp b/rai/ledger.hpp index 04986b5c..f1131278 100644 --- a/rai/ledger.hpp +++ b/rai/ledger.hpp @@ -13,36 +13,14 @@ 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; -}; +using tally_t = std::map, std::greater>; class ledger { public: - ledger (rai::block_store &, rai::stat &, rai::uint128_t const & = 0, rai::block_hash const & = 0, rai::block_hash const & = 0); + ledger (rai::block_store &, rai::stat &, rai::block_hash const & = 0, rai::block_hash const & = 0); std::pair> winner (MDB_txn *, rai::votes const & votes_a); // Map of weight -> associated block, ordered greatest to least - std::map, std::greater> tally (MDB_txn *, rai::votes const &); + rai::tally_t tally (MDB_txn *, rai::votes const &); rai::account account (MDB_txn *, rai::block_hash const &); rai::uint128_t amount (MDB_txn *, rai::block_hash const &); rai::uint128_t balance (MDB_txn *, rai::block_hash const &); @@ -77,6 +55,5 @@ public: 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/bootstrap.cpp b/rai/node/bootstrap.cpp index 95899758..7f0ca406 100644 --- a/rai/node/bootstrap.cpp +++ b/rai/node/bootstrap.cpp @@ -1043,22 +1043,19 @@ void rai::bootstrap_attempt::process_fork (MDB_txn * transaction_a, std::shared_ if (ledger_block) { std::weak_ptr this_w (shared_from_this ()); - if (!node->active.start (transaction_a, std::make_pair (ledger_block, block_a), [this_w, root](std::shared_ptr, bool resolved) { + if (!node->active.start (transaction_a, std::make_pair (ledger_block, block_a), [this_w, root](std::shared_ptr) { if (auto this_l = this_w.lock ()) { - if (resolved) - { - rai::transaction transaction (this_l->node->store.environment, nullptr, false); - auto account (this_l->node->ledger.store.frontier_get (transaction, root)); - if (!account.is_zero ()) - { - this_l->requeue_pull (rai::pull_info (account, root, root)); - } - else if (this_l->node->ledger.store.account_exists (transaction, root)) - { - this_l->requeue_pull (rai::pull_info (root, rai::block_hash (0), rai::block_hash (0))); - } - } + rai::transaction transaction (this_l->node->store.environment, nullptr, false); + auto account (this_l->node->ledger.store.frontier_get (transaction, root)); + if (!account.is_zero ()) + { + this_l->requeue_pull (rai::pull_info (account, root, root)); + } + else if (this_l->node->ledger.store.account_exists (transaction, root)) + { + this_l->requeue_pull (rai::pull_info (root, rai::block_hash (0), rai::block_hash (0))); + } } })) { diff --git a/rai/node/node.cpp b/rai/node/node.cpp index ec762a60..f0b01df0 100644 --- a/rai/node/node.cpp +++ b/rai/node/node.cpp @@ -797,7 +797,8 @@ peering_port (peering_port_a), logging (logging_a), bootstrap_fraction_numerator (1), receive_minimum (rai::xrb_ratio), -inactive_supply (0), +online_weight_minimum (60000 * rai::Gxrb_ratio), +online_weight_quorom (50), password_fanout (1024), io_threads (std::max (4, std::thread::hardware_concurrency ())), work_threads (std::max (4, std::thread::hardware_concurrency ())), @@ -841,7 +842,7 @@ state_block_generate_canary (0) void rai::node_config::serialize_json (boost::property_tree::ptree & tree_a) const { - tree_a.put ("version", "10"); + tree_a.put ("version", "11"); 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 ()); @@ -872,7 +873,8 @@ void rai::node_config::serialize_json (boost::property_tree::ptree & tree_a) con preconfigured_representatives_l.push_back (std::make_pair ("", entry)); } tree_a.add_child ("preconfigured_representatives", preconfigured_representatives_l); - tree_a.put ("inactive_supply", inactive_supply.to_string_dec ()); + tree_a.put ("online_weight_minimum", online_weight_minimum.to_string_dec ()); + tree_a.put ("online_weight_quorom", std::to_string (online_weight_quorom)); tree_a.put ("password_fanout", std::to_string (password_fanout)); tree_a.put ("io_threads", std::to_string (io_threads)); tree_a.put ("work_threads", std::to_string (work_threads)); @@ -965,6 +967,13 @@ bool rai::node_config::upgrade_json (unsigned version, boost::property_tree::ptr tree_a.put ("version", "10"); result = 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_quorom)); + tree_a.erase ("inactive_supply"); + tree_a.erase ("version"); + tree_a.put ("version", "11"); + result = true; + case 11: break; default: throw std::runtime_error ("Unknown node_config version"); @@ -1031,7 +1040,8 @@ bool rai::node_config::deserialize_json (bool & upgraded_a, boost::property_tree { result |= stat_config.deserialize_json (stat_config_l.get ()); } - auto inactive_supply_l (tree_a.get ("inactive_supply")); + auto online_weight_minimum_l (tree_a.get ("online_weight_minimum")); + auto online_weight_quorom_l (tree_a.get ("online_weight_quorom")); auto password_fanout_l (tree_a.get ("password_fanout")); auto io_threads_l (tree_a.get ("io_threads")); auto work_threads_l (tree_a.get ("work_threads")); @@ -1055,10 +1065,12 @@ bool rai::node_config::deserialize_json (bool & upgraded_a, boost::property_tree 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_quorom = std::stoul (online_weight_quorom_l); result |= peering_port > std::numeric_limits::max (); result |= logging.deserialize_json (upgraded_a, logging_l); result |= receive_minimum.decode_dec (receive_minimum_l); - result |= inactive_supply.decode_dec (inactive_supply_l); + result |= online_weight_minimum.decode_dec (online_weight_minimum_l); + result |= online_weight_quorom > 100; result |= password_fanout < 16; result |= password_fanout > 1024 * 1024; result |= io_threads == 0; @@ -1251,7 +1263,6 @@ bool rai::block_processor::have_blocks () void rai::block_processor::process_receive_many (std::unique_lock & lock_a) { - std::deque, rai::process_return>> progress; { rai::transaction transaction (node.store.environment, nullptr, true); auto cutoff (std::chrono::steady_clock::now () + rai::transaction_timeout); @@ -1462,7 +1473,7 @@ alarm (alarm_a), work (work_a), store (init_a.block_store_init, application_path_a / "data.ldb", config_a.lmdb_max_dbs), gap_cache (*this), -ledger (store, stats, config_a.inactive_supply.number (), config.state_block_parse_canary, config.state_block_generate_canary), +ledger (store, stats, config.state_block_parse_canary, config.state_block_generate_canary), active (*this), network (*this, config.peering_port), bootstrap_initiator (*this), @@ -1607,7 +1618,7 @@ stats (config.stat_config) { rai::transaction transaction (store.environment, nullptr, false); rep_weight = ledger.weight (transaction, vote_a->account); - min_rep_weight = ledger.supply.circulating_get () / 1000; + min_rep_weight = online_reps.online_stake () / 1000; } if (rep_weight > min_rep_weight) { @@ -1762,7 +1773,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.circulating_get () / 256) * node.config.bootstrap_fraction_numerator); + auto result ((node.online_reps.online_stake () / 256) * node.config.bootstrap_fraction_numerator); return result; } @@ -1962,7 +1973,6 @@ void rai::node::start () ongoing_bootstrap (); ongoing_store_flush (); ongoing_rep_crawl (); - ongoing_supply_update (); bootstrap.start (); backup_wallet (); active.announce_votes (); @@ -2058,18 +2068,6 @@ 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 ()); @@ -2421,6 +2419,12 @@ void rai::node::block_confirm (std::shared_ptr block_a) network.broadcast_confirm_req (block_a); } +rai::uint128_t rai::node::delta () +{ + auto result ((online_reps.online_stake () / 100) * config.online_weight_quorom); + return result; +} + namespace { class confirmed_visitor : public rai::block_visitor @@ -2623,7 +2627,7 @@ void rai::online_reps::recalculate_stake () rai::uint128_t rai::online_reps::online_stake () { std::lock_guard lock (mutex); - return online_stake_total; + return std::max (online_stake_total, node.config.online_weight_minimum.number ()); } std::deque rai::online_reps::list () @@ -2997,7 +3001,7 @@ std::shared_ptr rai::node::shared () return shared_from_this (); } -rai::election::election (MDB_txn * transaction_a, rai::node & node_a, std::shared_ptr block_a, std::function, bool)> const & confirmation_action_a) : +rai::election::election (MDB_txn * transaction_a, rai::node & node_a, std::shared_ptr block_a, std::function)> const & confirmation_action_a) : confirmation_action (confirmation_action_a), votes (block_a), node (node_a), @@ -3023,27 +3027,15 @@ void rai::election::broadcast_winner () node.network.republish_block (transaction, status.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.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.circulating_get () / 16; -} - void rai::election::confirm_once (MDB_txn * transaction_a) { if (!confirmed.exchange (true)) { auto tally_l (node.ledger.tally (transaction_a, votes)); assert (tally_l.size () > 0); + auto have_quorum_l = have_quorum (tally_l); auto winner (tally_l.begin ()); auto block_l (winner->second); - auto exceeded_min_threshold = winner->first > minimum_threshold (transaction_a, node.ledger); if (node.config.logging.vote_logging () || !votes.uncontested ()) { BOOST_LOG (node.log) << boost::str (boost::format ("Vote tally for root %1%") % status.winner->root ().to_string ()); @@ -3058,7 +3050,7 @@ void rai::election::confirm_once (MDB_txn * transaction_a) } if (!(*block_l == *status.winner)) { - if (exceeded_min_threshold) + if (have_quorum_l) { auto node_l (node.shared ()); node_l->block_processor.force (block_l); @@ -3070,27 +3062,38 @@ void rai::election::confirm_once (MDB_txn * transaction_a) } } status.tally = winner->first; - auto winner_l (status.winner); - auto node_l (node.shared ()); - auto confirmation_action_l (confirmation_action); - node.background ([winner_l, confirmation_action_l, node_l, exceeded_min_threshold]() { - node_l->process_confirmed (winner_l); - confirmation_action_l (winner_l, exceeded_min_threshold); - }); + if (have_quorum_l) + { + auto winner_l (status.winner); + auto node_l (node.shared ()); + auto confirmation_action_l (confirmation_action); + node.background ([node_l, winner_l, confirmation_action_l]() { + node_l->process_confirmed (winner_l); + confirmation_action_l (winner_l); + }); + } + else + { + BOOST_LOG (node.log) << boost::str (boost::format ("Insufficient quorum for block %1% %2%") % status.winner->hash ().to_string () % status.tally.number ().convert_to ()); + } } } -bool rai::election::have_quorum (MDB_txn * transaction_a) +bool rai::election::have_quorum (rai::tally_t const & tally_a) { - auto tally_l (node.ledger.tally (transaction_a, votes)); - assert (tally_l.size () > 0); - auto result (tally_l.begin ()->first > quorum_threshold (transaction_a, node.ledger)); + auto i (tally_a.begin ()); + auto first (i->first); + ++i; + auto second (i != tally_a.end () ? i->first : 0); + auto delta_l (node.delta ()); + auto result (tally_a.begin ()->first > (second + delta_l)); return result; } void rai::election::confirm_if_quorum (MDB_txn * transaction_a) { - auto quorum (have_quorum (transaction_a)); + auto tally_l (node.ledger.tally (transaction_a, votes)); + auto quorum (have_quorum (tally_l)); if (quorum) { confirm_once (transaction_a); @@ -3108,7 +3111,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.circulating_get ()); + auto supply (node.online_reps.online_stake ()); 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 { @@ -3259,12 +3262,12 @@ void rai::active_transactions::stop () roots.clear (); } -bool rai::active_transactions::start (MDB_txn * transaction_a, std::shared_ptr block_a, std::function, bool)> const & confirmation_action_a) +bool rai::active_transactions::start (MDB_txn * transaction_a, std::shared_ptr block_a, std::function)> const & confirmation_action_a) { return start (transaction_a, std::make_pair (block_a, nullptr), confirmation_action_a); } -bool rai::active_transactions::start (MDB_txn * transaction_a, std::pair, std::shared_ptr> blocks_a, std::function, bool)> const & confirmation_action_a) +bool rai::active_transactions::start (MDB_txn * transaction_a, std::pair, std::shared_ptr> blocks_a, std::function)> const & confirmation_action_a) { assert (blocks_a.first != nullptr); std::lock_guard lock (mutex); diff --git a/rai/node/node.hpp b/rai/node/node.hpp index e0a41c57..e328b4c2 100644 --- a/rai/node/node.hpp +++ b/rai/node/node.hpp @@ -44,14 +44,14 @@ public: }; class election : public std::enable_shared_from_this { - std::function, bool)> confirmation_action; + std::function)> confirmation_action; void confirm_once (MDB_txn *); public: - election (MDB_txn *, rai::node &, std::shared_ptr, std::function, bool)> const &); + election (MDB_txn *, rai::node &, std::shared_ptr, std::function)> const &); bool vote (std::shared_ptr); // Check if we have vote quorum - bool have_quorum (MDB_txn *); + bool have_quorum (rai::tally_t const &); // Tell the network our view of the winner void broadcast_winner (); // Change our winner to agree with the network @@ -60,8 +60,6 @@ public: void confirm_if_quorum (MDB_txn *); // Confirmation method 2, settling time void confirm_cutoff (MDB_txn *); - rai::uint128_t quorum_threshold (MDB_txn *, rai::ledger &); - rai::uint128_t minimum_threshold (MDB_txn *, rai::ledger &); rai::votes votes; rai::node & node; std::unordered_map> last_votes; @@ -85,11 +83,11 @@ public: active_transactions (rai::node &); // Start an election for a block // Call action with confirmed block, may be different than what we started with - bool start (MDB_txn *, std::shared_ptr, std::function, bool)> const & = [](std::shared_ptr, bool) {}); + bool start (MDB_txn *, std::shared_ptr, std::function)> const & = [](std::shared_ptr) {}); // Also supply alternatives to block, to confirm_req reps with if the boolean argument is true // Should only be used for old elections // The first block should be the one in the ledger - bool start (MDB_txn *, std::pair, std::shared_ptr>, std::function, bool)> const & = [](std::shared_ptr, bool) {}); + bool start (MDB_txn *, std::pair, std::shared_ptr>, std::function)> const & = [](std::shared_ptr) {}); // If this returns true, the vote is a replay // If this returns false, the vote may or may not be a replay bool vote (std::shared_ptr); @@ -426,7 +424,8 @@ public: std::vector preconfigured_representatives; unsigned bootstrap_fraction_numerator; rai::amount receive_minimum; - rai::amount inactive_supply; + rai::amount online_weight_minimum; + unsigned online_weight_quorom; unsigned password_fanout; unsigned io_threads; unsigned work_threads; @@ -532,7 +531,6 @@ 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 &); @@ -540,6 +538,7 @@ public: void generate_work (rai::uint256_union const &, std::function); void add_initial_peers (); void block_confirm (std::shared_ptr); + rai::uint128_t delta (); boost::asio::io_service & service; rai::node_config config; rai::alarm & alarm; diff --git a/rai/node/wallet.cpp b/rai/node/wallet.cpp index 320c3067..3abb3e31 100644 --- a/rai/node/wallet.cpp +++ b/rai/node/wallet.cpp @@ -1229,7 +1229,7 @@ public: std::shared_ptr block_l (wallet->node.store.block_get (transaction, info.head)); wallet->node.background ([this_l, account, block_l] { rai::transaction transaction (this_l->wallet->node.store.environment, nullptr, true); - this_l->wallet->node.active.start (transaction, block_l, [this_l, account](std::shared_ptr, bool) { + this_l->wallet->node.active.start (transaction, block_l, [this_l, account](std::shared_ptr) { // If there were any forks for this account they've been rolled back and we can receive anything remaining from this account this_l->receive_all (account); });