Update online weight before checking quorum (#3048)
* Update online weight before checking quorum * Make test compatible with quorum hardcoded changes * Fix test network quorum overflow Co-authored-by: Sergey Kroshnin <sergiysw@gmail.com>
This commit is contained in:
parent
f15adfebc4
commit
f448e29279
19 changed files with 171 additions and 76 deletions
|
@ -613,19 +613,19 @@ TEST (active_transactions, vote_replays)
|
|||
ASSERT_EQ (2, node.active.size ());
|
||||
// First vote is not a replay and confirms the election, second vote should be a replay since the election has confirmed but not yet removed
|
||||
auto vote_send1 (std::make_shared<nano::vote> (nano::dev_genesis_key.pub, nano::dev_genesis_key.prv, 0, send1));
|
||||
ASSERT_EQ (nano::vote_code::vote, node.active.vote (vote_send1));
|
||||
ASSERT_EQ (nano::vote_code::vote, node.active.vote (vote_send1, true));
|
||||
ASSERT_EQ (2, node.active.size ());
|
||||
ASSERT_EQ (nano::vote_code::replay, node.active.vote (vote_send1));
|
||||
ASSERT_EQ (nano::vote_code::replay, node.active.vote (vote_send1, true));
|
||||
// Wait until the election is removed, at which point the vote is still a replay since it's been recently confirmed
|
||||
ASSERT_TIMELY (3s, node.active.size () == 1);
|
||||
ASSERT_EQ (nano::vote_code::replay, node.active.vote (vote_send1));
|
||||
ASSERT_EQ (nano::vote_code::replay, node.active.vote (vote_send1, true));
|
||||
// Open new account
|
||||
auto vote_open1 (std::make_shared<nano::vote> (nano::dev_genesis_key.pub, nano::dev_genesis_key.prv, 0, open1));
|
||||
ASSERT_EQ (nano::vote_code::vote, node.active.vote (vote_open1));
|
||||
ASSERT_EQ (nano::vote_code::vote, node.active.vote (vote_open1, true));
|
||||
ASSERT_EQ (1, node.active.size ());
|
||||
ASSERT_EQ (nano::vote_code::replay, node.active.vote (vote_open1));
|
||||
ASSERT_EQ (nano::vote_code::replay, node.active.vote (vote_open1, true));
|
||||
ASSERT_TIMELY (3s, node.active.empty ());
|
||||
ASSERT_EQ (nano::vote_code::replay, node.active.vote (vote_open1));
|
||||
ASSERT_EQ (nano::vote_code::replay, node.active.vote (vote_open1, true));
|
||||
ASSERT_EQ (nano::Gxrb_ratio, node.ledger.weight (key.pub));
|
||||
|
||||
auto send2 = builder.make_block ()
|
||||
|
@ -643,27 +643,27 @@ TEST (active_transactions, vote_replays)
|
|||
ASSERT_EQ (1, node.active.size ());
|
||||
auto vote1_send2 (std::make_shared<nano::vote> (nano::dev_genesis_key.pub, nano::dev_genesis_key.prv, 0, send2));
|
||||
auto vote2_send2 (std::make_shared<nano::vote> (key.pub, key.prv, 0, send2));
|
||||
ASSERT_EQ (nano::vote_code::vote, node.active.vote (vote2_send2));
|
||||
ASSERT_EQ (nano::vote_code::vote, node.active.vote (vote2_send2, true));
|
||||
ASSERT_EQ (1, node.active.size ());
|
||||
ASSERT_EQ (nano::vote_code::replay, node.active.vote (vote2_send2));
|
||||
ASSERT_EQ (nano::vote_code::replay, node.active.vote (vote2_send2, true));
|
||||
ASSERT_EQ (1, node.active.size ());
|
||||
ASSERT_EQ (nano::vote_code::vote, node.active.vote (vote1_send2));
|
||||
ASSERT_EQ (nano::vote_code::vote, node.active.vote (vote1_send2, true));
|
||||
ASSERT_EQ (1, node.active.size ());
|
||||
ASSERT_EQ (nano::vote_code::replay, node.active.vote (vote1_send2));
|
||||
ASSERT_EQ (nano::vote_code::replay, node.active.vote (vote1_send2, true));
|
||||
ASSERT_TIMELY (3s, node.active.empty ());
|
||||
ASSERT_EQ (0, node.active.size ());
|
||||
ASSERT_EQ (nano::vote_code::replay, node.active.vote (vote1_send2));
|
||||
ASSERT_EQ (nano::vote_code::replay, node.active.vote (vote2_send2));
|
||||
ASSERT_EQ (nano::vote_code::replay, node.active.vote (vote1_send2, true));
|
||||
ASSERT_EQ (nano::vote_code::replay, node.active.vote (vote2_send2, true));
|
||||
|
||||
// Removing blocks as recently confirmed makes every vote indeterminate
|
||||
{
|
||||
nano::lock_guard<std::mutex> guard (node.active.mutex);
|
||||
node.active.recently_confirmed.clear ();
|
||||
}
|
||||
ASSERT_EQ (nano::vote_code::indeterminate, node.active.vote (vote_send1));
|
||||
ASSERT_EQ (nano::vote_code::indeterminate, node.active.vote (vote_open1));
|
||||
ASSERT_EQ (nano::vote_code::indeterminate, node.active.vote (vote1_send2));
|
||||
ASSERT_EQ (nano::vote_code::indeterminate, node.active.vote (vote2_send2));
|
||||
ASSERT_EQ (nano::vote_code::indeterminate, node.active.vote (vote_send1, true));
|
||||
ASSERT_EQ (nano::vote_code::indeterminate, node.active.vote (vote_open1, true));
|
||||
ASSERT_EQ (nano::vote_code::indeterminate, node.active.vote (vote1_send2, true));
|
||||
ASSERT_EQ (nano::vote_code::indeterminate, node.active.vote (vote2_send2, true));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1498,7 +1498,7 @@ TEST (active_transactions, conflicting_block_vote_existing_election)
|
|||
ASSERT_EQ (1, node.active.size ());
|
||||
|
||||
// Vote for conflicting block, but the block does not yet exist in the ledger
|
||||
node.active.vote (vote_fork);
|
||||
node.active.vote (vote_fork, true);
|
||||
|
||||
// Block now gets processed
|
||||
ASSERT_EQ (nano::process_result::fork, node.process_local (fork).code);
|
||||
|
@ -1735,9 +1735,9 @@ TEST (active_transactions, pessimistic_elections)
|
|||
// Make dummy election with winner.
|
||||
{
|
||||
nano::election election1 (
|
||||
node, send, [](auto const & block) {}, false, nano::election_behavior::normal);
|
||||
node, send, [](auto const &) {}, [](auto const &, bool) {}, false, nano::election_behavior::normal);
|
||||
nano::election election2 (
|
||||
node, open, [](auto const & block) {}, false, nano::election_behavior::normal);
|
||||
node, open, [](auto const &) {}, [](auto const &, bool) {}, false, nano::election_behavior::normal);
|
||||
node.active.add_expired_optimistic_election (election1);
|
||||
node.active.add_expired_optimistic_election (election2);
|
||||
}
|
||||
|
|
|
@ -34,12 +34,12 @@ TEST (confirmation_solicitor, batches)
|
|||
nano::lock_guard<std::mutex> guard (node2.active.mutex);
|
||||
for (size_t i (0); i < nano::network::confirm_req_hashes_max; ++i)
|
||||
{
|
||||
auto election (std::make_shared<nano::election> (node2, send, nullptr, false, nano::election_behavior::normal));
|
||||
auto election (std::make_shared<nano::election> (node2, send, nullptr, nullptr, false, nano::election_behavior::normal));
|
||||
ASSERT_FALSE (solicitor.add (*election));
|
||||
}
|
||||
ASSERT_EQ (1, solicitor.max_confirm_req_batches);
|
||||
// Reached the maximum amount of requests for the channel
|
||||
auto election (std::make_shared<nano::election> (node2, send, nullptr, false, nano::election_behavior::normal));
|
||||
auto election (std::make_shared<nano::election> (node2, send, nullptr, nullptr, false, nano::election_behavior::normal));
|
||||
ASSERT_TRUE (solicitor.add (*election));
|
||||
// Broadcasting should be immediate
|
||||
ASSERT_EQ (0, node2.stats.count (nano::stat::type::message, nano::stat::detail::publish, nano::stat::dir::out));
|
||||
|
@ -75,7 +75,7 @@ TEST (confirmation_solicitor, different_hash)
|
|||
ASSERT_TIMELY (3s, node2.network.size () == 1);
|
||||
auto send (std::make_shared<nano::send_block> (nano::genesis_hash, nano::keypair ().pub, nano::genesis_amount - 100, nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, *system.work.generate (nano::genesis_hash)));
|
||||
send->sideband_set ({});
|
||||
auto election (std::make_shared<nano::election> (node2, send, nullptr, false, nano::election_behavior::normal));
|
||||
auto election (std::make_shared<nano::election> (node2, send, nullptr, nullptr, false, nano::election_behavior::normal));
|
||||
// Add a vote for something else, not the winner
|
||||
election->last_votes[representative.account] = { std::chrono::steady_clock::now (), 1, 1 };
|
||||
// Ensure the request and broadcast goes through
|
||||
|
@ -111,7 +111,7 @@ TEST (confirmation_solicitor, bypass_max_requests_cap)
|
|||
ASSERT_TIMELY (3s, node2.network.size () == 1);
|
||||
auto send (std::make_shared<nano::send_block> (nano::genesis_hash, nano::keypair ().pub, nano::genesis_amount - 100, nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, *system.work.generate (nano::genesis_hash)));
|
||||
send->sideband_set ({});
|
||||
auto election (std::make_shared<nano::election> (node2, send, nullptr, false, nano::election_behavior::normal));
|
||||
auto election (std::make_shared<nano::election> (node2, send, nullptr, nullptr, false, nano::election_behavior::normal));
|
||||
// Add a vote for something else, not the winner
|
||||
for (auto const & rep : representatives)
|
||||
{
|
||||
|
@ -125,7 +125,7 @@ TEST (confirmation_solicitor, bypass_max_requests_cap)
|
|||
ASSERT_EQ (max_representatives + 1, node2.stats.count (nano::stat::type::message, nano::stat::detail::confirm_req, nano::stat::dir::out));
|
||||
|
||||
solicitor.prepare (representatives);
|
||||
auto election2 (std::make_shared<nano::election> (node2, send, nullptr, false, nano::election_behavior::normal));
|
||||
auto election2 (std::make_shared<nano::election> (node2, send, nullptr, nullptr, false, nano::election_behavior::normal));
|
||||
ASSERT_FALSE (solicitor.add (*election2));
|
||||
ASSERT_FALSE (solicitor.broadcast (*election2));
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ TEST (conflicts, add_existing)
|
|||
auto election1 = node1.active.insert (send2);
|
||||
ASSERT_EQ (1, node1.active.size ());
|
||||
auto vote1 (std::make_shared<nano::vote> (key2.pub, key2.prv, 0, send2));
|
||||
node1.active.vote (vote1);
|
||||
node1.active.vote (vote1, true);
|
||||
ASSERT_NE (nullptr, election1.election);
|
||||
ASSERT_EQ (2, election1.election->votes ().size ());
|
||||
auto votes (election1.election->votes ());
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
TEST (election, construction)
|
||||
{
|
||||
nano::system system (1);
|
||||
|
@ -52,7 +54,7 @@ TEST (election, quorum_minimum_flip_success)
|
|||
ASSERT_NE (nullptr, election.election);
|
||||
ASSERT_EQ (2, election.election->blocks ().size ());
|
||||
auto vote1 (std::make_shared<nano::vote> (nano::dev_genesis_key.pub, nano::dev_genesis_key.prv, 1, send2));
|
||||
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote1));
|
||||
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote1, true));
|
||||
node1.block_processor.flush ();
|
||||
ASSERT_NE (nullptr, node1.block (send2->hash ()));
|
||||
ASSERT_TRUE (election.election->confirmed ());
|
||||
|
@ -96,7 +98,7 @@ TEST (election, quorum_minimum_flip_fail)
|
|||
ASSERT_NE (nullptr, election.election);
|
||||
ASSERT_EQ (2, election.election->blocks ().size ());
|
||||
auto vote1 (std::make_shared<nano::vote> (nano::dev_genesis_key.pub, nano::dev_genesis_key.prv, 1, send2));
|
||||
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote1));
|
||||
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote1, true));
|
||||
node1.block_processor.flush ();
|
||||
ASSERT_NE (nullptr, node1.block (send1->hash ()));
|
||||
ASSERT_FALSE (election.election->confirmed ());
|
||||
|
@ -128,7 +130,7 @@ TEST (election, quorum_minimum_confirm_success)
|
|||
ASSERT_NE (nullptr, election.election);
|
||||
ASSERT_EQ (1, election.election->blocks ().size ());
|
||||
auto vote1 (std::make_shared<nano::vote> (nano::dev_genesis_key.pub, nano::dev_genesis_key.prv, 1, send1));
|
||||
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote1));
|
||||
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote1, true));
|
||||
node1.block_processor.flush ();
|
||||
ASSERT_NE (nullptr, node1.block (send1->hash ()));
|
||||
ASSERT_TRUE (election.election->confirmed ());
|
||||
|
@ -160,8 +162,90 @@ TEST (election, quorum_minimum_confirm_fail)
|
|||
ASSERT_NE (nullptr, election.election);
|
||||
ASSERT_EQ (1, election.election->blocks ().size ());
|
||||
auto vote1 (std::make_shared<nano::vote> (nano::dev_genesis_key.pub, nano::dev_genesis_key.prv, 1, send1));
|
||||
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote1));
|
||||
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote1, true));
|
||||
node1.block_processor.flush ();
|
||||
ASSERT_NE (nullptr, node1.block (send1->hash ()));
|
||||
ASSERT_FALSE (election.election->confirmed ());
|
||||
}
|
||||
|
||||
namespace nano
|
||||
{
|
||||
TEST (election, quorum_minimum_update_weight_before_quorum_checks)
|
||||
{
|
||||
nano::system system;
|
||||
nano::node_config node_config (nano::get_available_port (), system.logging);
|
||||
node_config.frontiers_confirmation = nano::frontiers_confirmation_mode::disabled;
|
||||
auto & node1 = *system.add_node (node_config);
|
||||
system.wallet (0)->insert_adhoc (nano::dev_genesis_key.prv);
|
||||
auto amount = ((nano::uint256_t (node_config.online_weight_minimum.number ()) * nano::online_reps::online_weight_quorum) / 100).convert_to<nano::uint128_t> () - 1;
|
||||
nano::keypair key1;
|
||||
nano::block_builder builder;
|
||||
auto send1 = builder.state ()
|
||||
.account (nano::dev_genesis_key.pub)
|
||||
.previous (nano::genesis_hash)
|
||||
.representative (nano::dev_genesis_key.pub)
|
||||
.balance (amount)
|
||||
.link (key1.pub)
|
||||
.work (0)
|
||||
.sign (nano::dev_genesis_key.prv, nano::dev_genesis_key.pub)
|
||||
.build_shared ();
|
||||
node1.work_generate_blocking (*send1);
|
||||
auto open1 = builder.state ()
|
||||
.account (key1.pub)
|
||||
.previous (0)
|
||||
.representative (key1.pub)
|
||||
.balance (nano::genesis_amount - amount)
|
||||
.link (send1->hash ())
|
||||
.work (0)
|
||||
.sign (key1.prv, key1.pub)
|
||||
.build_shared ();
|
||||
nano::keypair key2;
|
||||
auto send2 = builder.state ()
|
||||
.account (key1.pub)
|
||||
.previous (open1->hash ())
|
||||
.representative (key1.pub)
|
||||
.balance (3)
|
||||
.link (key2.pub)
|
||||
.work (0)
|
||||
.sign (key1.prv, key1.pub)
|
||||
.build_shared ();
|
||||
node1.work_generate_blocking (*open1);
|
||||
node1.work_generate_blocking (*send2);
|
||||
node1.process_active (send1);
|
||||
node1.block_processor.flush ();
|
||||
node1.process (*open1);
|
||||
node1.process (*send2);
|
||||
node1.block_processor.flush ();
|
||||
ASSERT_EQ (node1.ledger.cache.block_count, 4);
|
||||
|
||||
node_config.peering_port = nano::get_available_port ();
|
||||
auto & node2 = *system.add_node (node_config);
|
||||
node2.process (*send1);
|
||||
node2.process (*open1);
|
||||
node2.process (*send2);
|
||||
system.wallet (1)->insert_adhoc (key1.prv);
|
||||
node2.block_processor.flush ();
|
||||
ASSERT_EQ (node2.ledger.cache.block_count, 4);
|
||||
|
||||
auto election{ node1.active.insert (send1) };
|
||||
ASSERT_FALSE (election.inserted);
|
||||
ASSERT_NE (nullptr, election.election);
|
||||
ASSERT_EQ (1, election.election->blocks ().size ());
|
||||
auto vote1 (std::make_shared<nano::vote> (nano::dev_genesis_key.pub, nano::dev_genesis_key.prv, nano::milliseconds_since_epoch (), send1));
|
||||
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote1, true));
|
||||
auto vote2 (std::make_shared<nano::vote> (key1.pub, key1.prv, nano::milliseconds_since_epoch (), send1));
|
||||
auto channel = node1.network.find_channel (node2.network.endpoint ());
|
||||
ASSERT_NE (channel, nullptr);
|
||||
ASSERT_TIMELY (10s, !node1.rep_crawler.response (channel, vote2));
|
||||
ASSERT_FALSE (election.election->confirmed ());
|
||||
{
|
||||
nano::lock_guard<std::mutex> guard (node1.online_reps.mutex);
|
||||
// Modify online_m for online_reps to more than is available, this checks that voting below updates it to current online reps.
|
||||
node1.online_reps.online_m = node_config.online_weight_minimum.number () + 20;
|
||||
}
|
||||
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote2, true));
|
||||
node1.block_processor.flush ();
|
||||
ASSERT_NE (nullptr, node1.block (send1->hash ()));
|
||||
ASSERT_TRUE (election.election->confirmed ());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -790,9 +790,9 @@ TEST (votes, add_one)
|
|||
auto election1 = node1.active.insert (send1);
|
||||
ASSERT_EQ (1, election1.election->votes ().size ());
|
||||
auto vote1 (std::make_shared<nano::vote> (nano::dev_genesis_key.pub, nano::dev_genesis_key.prv, 1, send1));
|
||||
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote1));
|
||||
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote1, true));
|
||||
auto vote2 (std::make_shared<nano::vote> (nano::dev_genesis_key.pub, nano::dev_genesis_key.prv, 2, send1));
|
||||
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote2));
|
||||
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote2, true));
|
||||
ASSERT_EQ (2, election1.election->votes ().size ());
|
||||
auto votes1 (election1.election->votes ());
|
||||
auto existing1 (votes1.find (nano::dev_genesis_key.pub));
|
||||
|
@ -818,9 +818,9 @@ TEST (votes, add_two)
|
|||
nano::keypair key2;
|
||||
auto send2 (std::make_shared<nano::send_block> (genesis.hash (), key2.pub, 0, nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, 0));
|
||||
auto vote2 (std::make_shared<nano::vote> (key2.pub, key2.prv, 1, send2));
|
||||
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote2));
|
||||
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote2, true));
|
||||
auto vote1 (std::make_shared<nano::vote> (nano::dev_genesis_key.pub, nano::dev_genesis_key.prv, 1, send1));
|
||||
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote1));
|
||||
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote1, true));
|
||||
ASSERT_EQ (3, election1.election->votes ().size ());
|
||||
auto votes1 (election1.election->votes ());
|
||||
ASSERT_NE (votes1.end (), votes1.find (nano::dev_genesis_key.pub));
|
||||
|
@ -855,7 +855,7 @@ TEST (votes, add_existing)
|
|||
ASSERT_EQ (nano::process_result::progress, node1.ledger.process (node1.store.tx_begin_write (), *send1).code);
|
||||
auto election1 = node1.active.insert (send1);
|
||||
auto vote1 (std::make_shared<nano::vote> (nano::dev_genesis_key.pub, nano::dev_genesis_key.prv, 1, send1));
|
||||
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote1));
|
||||
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote1, true));
|
||||
// Block is already processed from vote
|
||||
ASSERT_TRUE (node1.active.publish (send1));
|
||||
ASSERT_EQ (1, election1.election->last_votes[nano::dev_genesis_key.pub].timestamp);
|
||||
|
@ -875,14 +875,14 @@ TEST (votes, add_existing)
|
|||
nano::unique_lock<std::mutex> lock (election1.election->mutex);
|
||||
election1.election->last_votes[nano::dev_genesis_key.pub].time = std::chrono::steady_clock::now () - std::chrono::seconds (20);
|
||||
lock.unlock ();
|
||||
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote2));
|
||||
ASSERT_EQ (nano::vote_code::vote, node1.active.vote (vote2, true));
|
||||
ASSERT_FALSE (node1.active.publish (send2));
|
||||
ASSERT_EQ (2, election1.election->last_votes[nano::dev_genesis_key.pub].timestamp);
|
||||
// Also resend the old vote, and see if we respect the timestamp
|
||||
lock.lock ();
|
||||
election1.election->last_votes[nano::dev_genesis_key.pub].time = std::chrono::steady_clock::now () - std::chrono::seconds (20);
|
||||
lock.unlock ();
|
||||
ASSERT_EQ (nano::vote_code::replay, node1.active.vote (vote1));
|
||||
ASSERT_EQ (nano::vote_code::replay, node1.active.vote (vote1, true));
|
||||
ASSERT_EQ (2, election1.election->votes ()[nano::dev_genesis_key.pub].timestamp);
|
||||
auto votes (election1.election->votes ());
|
||||
ASSERT_EQ (2, votes.size ());
|
||||
|
|
|
@ -3946,7 +3946,7 @@ TEST (node, rollback_vote_self)
|
|||
{
|
||||
ASSERT_EQ (1, election->votes ().size ());
|
||||
// Vote with key to switch the winner
|
||||
election->vote (key.pub, 0, fork->hash ());
|
||||
election->vote (key.pub, 0, fork->hash (), true);
|
||||
ASSERT_EQ (2, election->votes ().size ());
|
||||
// The winner changed
|
||||
ASSERT_EQ (election->winner (), fork);
|
||||
|
|
|
@ -209,7 +209,7 @@ TEST (vote_processor, no_broadcast_local)
|
|||
ASSERT_FALSE (node.wallets.reps ().have_half_rep ());
|
||||
// Process a vote
|
||||
auto vote = std::make_shared<nano::vote> (nano::dev_genesis_key.pub, nano::dev_genesis_key.prv, nano::milliseconds_since_epoch (), std::vector<nano::block_hash>{ send->hash () });
|
||||
ASSERT_EQ (nano::vote_code::vote, node.active.vote (vote));
|
||||
ASSERT_EQ (nano::vote_code::vote, node.active.vote (vote, true));
|
||||
// Make sure the vote was processed
|
||||
auto election (node.active.election (send->qualified_root ()));
|
||||
ASSERT_NE (nullptr, election);
|
||||
|
@ -242,7 +242,7 @@ TEST (vote_processor, no_broadcast_local)
|
|||
node.block_confirm (send2);
|
||||
// Process a vote
|
||||
auto vote2 = std::make_shared<nano::vote> (nano::dev_genesis_key.pub, nano::dev_genesis_key.prv, nano::milliseconds_since_epoch (), std::vector<nano::block_hash>{ send2->hash () });
|
||||
ASSERT_EQ (nano::vote_code::vote, node.active.vote (vote2));
|
||||
ASSERT_EQ (nano::vote_code::vote, node.active.vote (vote2, true));
|
||||
// Make sure the vote was processed
|
||||
auto election2 (node.active.election (send2->qualified_root ()));
|
||||
ASSERT_NE (nullptr, election2);
|
||||
|
@ -276,7 +276,7 @@ TEST (vote_processor, no_broadcast_local)
|
|||
ASSERT_TRUE (node.wallets.reps ().have_half_rep ());
|
||||
// Process a vote
|
||||
auto vote3 = std::make_shared<nano::vote> (nano::dev_genesis_key.pub, nano::dev_genesis_key.prv, nano::milliseconds_since_epoch (), std::vector<nano::block_hash>{ open->hash () });
|
||||
ASSERT_EQ (nano::vote_code::vote, node.active.vote (vote3));
|
||||
ASSERT_EQ (nano::vote_code::vote, node.active.vote (vote3, true));
|
||||
// Make sure the vote was processed
|
||||
auto election3 (node.active.election (open->qualified_root ()));
|
||||
ASSERT_NE (nullptr, election3);
|
||||
|
|
|
@ -825,7 +825,15 @@ nano::election_insertion_result nano::active_transactions::insert_impl (nano::un
|
|||
}
|
||||
double multiplier (normalized_multiplier (*block_a));
|
||||
bool prioritized = roots.size () < prioritized_cutoff || multiplier > last_prioritized_multiplier.value_or (0);
|
||||
result.election = nano::make_shared<nano::election> (node, block_a, confirmation_action_a, prioritized, election_behavior_a);
|
||||
result.election = nano::make_shared<nano::election> (
|
||||
node, block_a, confirmation_action_a, [& node = node](auto const & rep_a, bool rep_is_active_a) {
|
||||
if (rep_is_active_a)
|
||||
{
|
||||
// Representative is defined as online if replying to live votes or rep_crawler queries
|
||||
node.online_reps.observe (rep_a);
|
||||
}
|
||||
},
|
||||
prioritized, election_behavior_a);
|
||||
roots.get<tag_root> ().emplace (nano::active_transactions::conflict_info{ root, multiplier, result.election, epoch, previous_balance });
|
||||
blocks.emplace (hash, result.election);
|
||||
auto const cache = find_inactive_votes_cache_impl (hash);
|
||||
|
@ -861,7 +869,7 @@ nano::election_insertion_result nano::active_transactions::insert (std::shared_p
|
|||
}
|
||||
|
||||
// Validate a vote and apply it to the current election if one exists
|
||||
nano::vote_code nano::active_transactions::vote (std::shared_ptr<nano::vote> vote_a)
|
||||
nano::vote_code nano::active_transactions::vote (std::shared_ptr<nano::vote> vote_a, bool active_in_rep_crawler_a)
|
||||
{
|
||||
nano::vote_code result{ nano::vote_code::indeterminate };
|
||||
// If all hashes were recently confirmed then it is a replay
|
||||
|
@ -915,7 +923,7 @@ nano::vote_code nano::active_transactions::vote (std::shared_ptr<nano::vote> vot
|
|||
bool processed (false);
|
||||
for (auto const & [election, block_hash] : process)
|
||||
{
|
||||
auto const result_l = election->vote (vote_a->account, vote_a->timestamp, block_hash);
|
||||
auto const result_l = election->vote (vote_a->account, vote_a->timestamp, block_hash, active_in_rep_crawler_a);
|
||||
processed = processed || result_l.processed;
|
||||
replay = replay || result_l.replay;
|
||||
}
|
||||
|
|
|
@ -178,7 +178,7 @@ public:
|
|||
nano::election_insertion_result insert (std::shared_ptr<nano::block> const &, boost::optional<nano::uint128_t> const & = boost::none, nano::election_behavior = nano::election_behavior::normal, std::function<void(std::shared_ptr<nano::block>)> const & = nullptr);
|
||||
// clang-format on
|
||||
// Distinguishes replay votes, cannot be determined if the block is not in any election
|
||||
nano::vote_code vote (std::shared_ptr<nano::vote>);
|
||||
nano::vote_code vote (std::shared_ptr<nano::vote>, bool);
|
||||
// Is the root of this block in the roots container
|
||||
bool active (nano::block const &);
|
||||
bool active (nano::qualified_root const &);
|
||||
|
|
|
@ -18,8 +18,9 @@ nano::election_vote_result::election_vote_result (bool replay_a, bool processed_
|
|||
processed = processed_a;
|
||||
}
|
||||
|
||||
nano::election::election (nano::node & node_a, std::shared_ptr<nano::block> block_a, std::function<void(std::shared_ptr<nano::block>)> const & confirmation_action_a, bool prioritized_a, nano::election_behavior election_behavior_a) :
|
||||
nano::election::election (nano::node & node_a, std::shared_ptr<nano::block> block_a, std::function<void(std::shared_ptr<nano::block>)> const & confirmation_action_a, std::function<void(nano::account const &, bool)> const & pre_confirm_action_a, bool prioritized_a, nano::election_behavior election_behavior_a) :
|
||||
confirmation_action (confirmation_action_a),
|
||||
pre_confirm_action (pre_confirm_action_a),
|
||||
prioritized_m (prioritized_a),
|
||||
behavior (election_behavior_a),
|
||||
node (node_a),
|
||||
|
@ -235,7 +236,8 @@ bool nano::election::have_quorum (nano::tally_t const & tally_a) const
|
|||
++i;
|
||||
auto second (i != tally_a.end () ? i->first : 0);
|
||||
auto delta_l (node.online_reps.delta ());
|
||||
bool result{ tally_a.begin ()->first >= (second + delta_l) };
|
||||
release_assert (tally_a.begin ()->first >= second);
|
||||
bool result{ (tally_a.begin ()->first - second) >= delta_l };
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -254,12 +256,12 @@ nano::tally_t nano::election::tally_impl () const
|
|||
}
|
||||
last_tally = block_weights;
|
||||
nano::tally_t result;
|
||||
for (auto item : block_weights)
|
||||
for (auto const & [hash, amount] : block_weights)
|
||||
{
|
||||
auto block (last_blocks.find (item.first));
|
||||
auto block (last_blocks.find (hash));
|
||||
if (block != last_blocks.end ())
|
||||
{
|
||||
result.emplace (item.second, block->second);
|
||||
result.emplace (amount, block->second);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
@ -326,9 +328,8 @@ std::shared_ptr<nano::block> nano::election::find (nano::block_hash const & hash
|
|||
return result;
|
||||
}
|
||||
|
||||
nano::election_vote_result nano::election::vote (nano::account const & rep, uint64_t timestamp_a, nano::block_hash const & block_hash)
|
||||
nano::election_vote_result nano::election::vote (nano::account const & rep, uint64_t timestamp_a, nano::block_hash const & block_hash_a, bool rep_is_active_a)
|
||||
{
|
||||
// see republish_vote documentation for an explanation of these rules
|
||||
auto replay (false);
|
||||
auto online_stake (node.online_reps.trended ());
|
||||
auto weight (node.ledger.weight (rep));
|
||||
|
@ -359,12 +360,9 @@ nano::election_vote_result nano::election::vote (nano::account const & rep, uint
|
|||
else
|
||||
{
|
||||
auto last_vote_l (last_vote_it->second);
|
||||
if (last_vote_l.timestamp < timestamp_a || (last_vote_l.timestamp == timestamp_a && last_vote_l.hash < block_hash))
|
||||
if (last_vote_l.timestamp < timestamp_a || (last_vote_l.timestamp == timestamp_a && last_vote_l.hash < block_hash_a))
|
||||
{
|
||||
if (last_vote_l.time <= std::chrono::steady_clock::now () - std::chrono::seconds (cooldown))
|
||||
{
|
||||
should_process = true;
|
||||
}
|
||||
should_process = last_vote_l.time <= std::chrono::steady_clock::now () - std::chrono::seconds (cooldown);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -374,7 +372,8 @@ nano::election_vote_result nano::election::vote (nano::account const & rep, uint
|
|||
if (should_process)
|
||||
{
|
||||
node.stats.inc (nano::stat::type::election, nano::stat::detail::vote_new);
|
||||
last_votes[rep] = { std::chrono::steady_clock::now (), timestamp_a, block_hash };
|
||||
last_votes[rep] = { std::chrono::steady_clock::now (), timestamp_a, block_hash_a };
|
||||
pre_confirm_action (rep, rep_is_active_a);
|
||||
if (!confirmed ())
|
||||
{
|
||||
confirm_if_quorum (lock);
|
||||
|
|
|
@ -54,6 +54,7 @@ class election final : public std::enable_shared_from_this<nano::election>
|
|||
// Minimum time between broadcasts of the current winner of an election, as a backup to requesting confirmations
|
||||
std::chrono::milliseconds base_latency () const;
|
||||
std::function<void(std::shared_ptr<nano::block>)> confirmation_action;
|
||||
std::function<void(nano::account, bool)> pre_confirm_action;
|
||||
|
||||
private: // State management
|
||||
enum class state_t
|
||||
|
@ -102,9 +103,9 @@ public: // Status
|
|||
nano::election_status status;
|
||||
|
||||
public: // Interface
|
||||
election (nano::node &, std::shared_ptr<nano::block>, std::function<void(std::shared_ptr<nano::block>)> const &, bool, nano::election_behavior);
|
||||
election (nano::node &, std::shared_ptr<nano::block>, std::function<void(std::shared_ptr<nano::block>)> const &, std::function<void(nano::account const &, bool)> const &, bool, nano::election_behavior);
|
||||
std::shared_ptr<nano::block> find (nano::block_hash const &) const;
|
||||
nano::election_vote_result vote (nano::account const &, uint64_t, nano::block_hash const &);
|
||||
nano::election_vote_result vote (nano::account const &, uint64_t, nano::block_hash const &, bool);
|
||||
bool publish (std::shared_ptr<nano::block> const & block_a);
|
||||
size_t insert_inactive_votes_cache (nano::inactive_cache_information const &);
|
||||
// Confirm this block if quorum is met
|
||||
|
|
|
@ -108,8 +108,8 @@ bootstrap_initiator (*this),
|
|||
bootstrap (config.peering_port, *this),
|
||||
application_path (application_path_a),
|
||||
port_mapping (*this),
|
||||
vote_processor (checker, active, observers, stats, config, flags, logger, online_reps, ledger, network_params),
|
||||
rep_crawler (*this),
|
||||
vote_processor (checker, active, observers, stats, config, flags, logger, online_reps, rep_crawler, ledger, network_params),
|
||||
warmed_up (0),
|
||||
block_processor (*this, write_database_queue),
|
||||
// clang-format off
|
||||
|
@ -299,17 +299,15 @@ node_seq (seq)
|
|||
});
|
||||
observers.vote.add ([this](std::shared_ptr<nano::vote> vote_a, std::shared_ptr<nano::transport::channel> channel_a, nano::vote_code code_a) {
|
||||
debug_assert (code_a != nano::vote_code::invalid);
|
||||
if (code_a != nano::vote_code::replay)
|
||||
// The vote_code::vote is handled inside the election
|
||||
if (code_a == nano::vote_code::indeterminate)
|
||||
{
|
||||
auto active_in_rep_crawler (!this->rep_crawler.response (channel_a, vote_a));
|
||||
if (active_in_rep_crawler || code_a == nano::vote_code::vote)
|
||||
if (active_in_rep_crawler)
|
||||
{
|
||||
// Representative is defined as online if replying to live votes or rep_crawler queries
|
||||
this->online_reps.observe (vote_a->account);
|
||||
}
|
||||
}
|
||||
if (code_a == nano::vote_code::indeterminate)
|
||||
{
|
||||
this->gap_cache.vote (vote_a);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -184,13 +184,13 @@ public:
|
|||
boost::filesystem::path application_path;
|
||||
nano::node_observers observers;
|
||||
nano::port_mapping port_mapping;
|
||||
nano::vote_processor vote_processor;
|
||||
nano::online_reps online_reps;
|
||||
nano::rep_crawler rep_crawler;
|
||||
nano::vote_processor vote_processor;
|
||||
unsigned warmed_up;
|
||||
nano::block_processor block_processor;
|
||||
std::thread block_processor_thread;
|
||||
nano::block_arrival block_arrival;
|
||||
nano::online_reps online_reps;
|
||||
nano::local_vote_history history;
|
||||
nano::keypair node_id;
|
||||
nano::block_uniquer block_uniquer;
|
||||
|
|
|
@ -96,9 +96,9 @@ nano::uint128_t nano::online_reps::online () const
|
|||
nano::uint128_t nano::online_reps::delta () const
|
||||
{
|
||||
nano::lock_guard<std::mutex> lock (mutex);
|
||||
auto weight = std::max ({ online_m, trended_m, config.online_weight_minimum.number () });
|
||||
auto result ((weight / 100) * online_weight_quorum);
|
||||
return result;
|
||||
// Using a larger container to ensure maximum precision
|
||||
auto weight = static_cast<nano::uint256_t> (std::max ({ online_m, trended_m, config.online_weight_minimum.number () }));
|
||||
return ((weight * online_weight_quorum) / 100).convert_to<nano::uint128_t> ();
|
||||
}
|
||||
|
||||
std::vector<nano::account> nano::online_reps::list ()
|
||||
|
|
|
@ -68,6 +68,7 @@ private:
|
|||
nano::uint128_t online_m;
|
||||
nano::uint128_t minimum;
|
||||
|
||||
friend class election_quorum_minimum_update_weight_before_quorum_checks_Test;
|
||||
friend std::unique_ptr<container_info_component> collect_container_info (online_reps & online_reps, const std::string & name);
|
||||
};
|
||||
|
||||
|
|
|
@ -179,7 +179,7 @@ bool nano::rep_crawler::is_pr (nano::transport::channel const & channel_a) const
|
|||
return result;
|
||||
}
|
||||
|
||||
bool nano::rep_crawler::response (std::shared_ptr<nano::transport::channel> & channel_a, std::shared_ptr<nano::vote> & vote_a)
|
||||
bool nano::rep_crawler::response (std::shared_ptr<nano::transport::channel> const & channel_a, std::shared_ptr<nano::vote> const & vote_a)
|
||||
{
|
||||
bool error = true;
|
||||
nano::lock_guard<std::mutex> lock (active_mutex);
|
||||
|
|
|
@ -93,11 +93,11 @@ public:
|
|||
bool is_pr (nano::transport::channel const &) const;
|
||||
|
||||
/**
|
||||
* Called when a non-replay vote on a block previously sent by query() is received. This indiciates
|
||||
* Called when a non-replay vote on a block previously sent by query() is received. This indicates
|
||||
* with high probability that the endpoint is a representative node.
|
||||
* @return false if the vote corresponded to any active hash.
|
||||
*/
|
||||
bool response (std::shared_ptr<nano::transport::channel> &, std::shared_ptr<nano::vote> &);
|
||||
bool response (std::shared_ptr<nano::transport::channel> const &, std::shared_ptr<nano::vote> const &);
|
||||
|
||||
/** Get total available weight from representatives */
|
||||
nano::uint128_t total_weight () const;
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <nano/node/node_observers.hpp>
|
||||
#include <nano/node/nodeconfig.hpp>
|
||||
#include <nano/node/online_reps.hpp>
|
||||
#include <nano/node/repcrawler.hpp>
|
||||
#include <nano/node/signatures.hpp>
|
||||
#include <nano/node/vote_processor.hpp>
|
||||
#include <nano/secure/blockstore.hpp>
|
||||
|
@ -14,7 +15,7 @@
|
|||
|
||||
#include <boost/format.hpp>
|
||||
|
||||
nano::vote_processor::vote_processor (nano::signature_checker & checker_a, nano::active_transactions & active_a, nano::node_observers & observers_a, nano::stat & stats_a, nano::node_config & config_a, nano::node_flags & flags_a, nano::logger_mt & logger_a, nano::online_reps & online_reps_a, nano::ledger & ledger_a, nano::network_params & network_params_a) :
|
||||
nano::vote_processor::vote_processor (nano::signature_checker & checker_a, nano::active_transactions & active_a, nano::node_observers & observers_a, nano::stat & stats_a, nano::node_config & config_a, nano::node_flags & flags_a, nano::logger_mt & logger_a, nano::online_reps & online_reps_a, nano::rep_crawler & rep_crawler_a, nano::ledger & ledger_a, nano::network_params & network_params_a) :
|
||||
checker (checker_a),
|
||||
active (active_a),
|
||||
observers (observers_a),
|
||||
|
@ -22,6 +23,7 @@ stats (stats_a),
|
|||
config (config_a),
|
||||
logger (logger_a),
|
||||
online_reps (online_reps_a),
|
||||
rep_crawler (rep_crawler_a),
|
||||
ledger (ledger_a),
|
||||
network_params (network_params_a),
|
||||
max_votes (flags_a.vote_processor_capacity),
|
||||
|
@ -170,7 +172,7 @@ nano::vote_code nano::vote_processor::vote_blocking (std::shared_ptr<nano::vote>
|
|||
auto result (nano::vote_code::invalid);
|
||||
if (validated || !vote_a->validate ())
|
||||
{
|
||||
result = active.vote (vote_a);
|
||||
result = active.vote (vote_a, !rep_crawler.response (channel_a, vote_a));
|
||||
observers.vote.notify (vote_a, channel_a, result);
|
||||
}
|
||||
std::string status;
|
||||
|
|
|
@ -20,6 +20,7 @@ class stats;
|
|||
class node_config;
|
||||
class logger_mt;
|
||||
class online_reps;
|
||||
class rep_crawler;
|
||||
class ledger;
|
||||
class network_params;
|
||||
class node_flags;
|
||||
|
@ -33,7 +34,7 @@ namespace transport
|
|||
class vote_processor final
|
||||
{
|
||||
public:
|
||||
explicit vote_processor (nano::signature_checker & checker_a, nano::active_transactions & active_a, nano::node_observers & observers_a, nano::stat & stats_a, nano::node_config & config_a, nano::node_flags & flags_a, nano::logger_mt & logger_a, nano::online_reps & online_reps_a, nano::ledger & ledger_a, nano::network_params & network_params_a);
|
||||
explicit vote_processor (nano::signature_checker & checker_a, nano::active_transactions & active_a, nano::node_observers & observers_a, nano::stat & stats_a, nano::node_config & config_a, nano::node_flags & flags_a, nano::logger_mt & logger_a, nano::online_reps & online_reps_a, nano::rep_crawler & rep_crawler_a, nano::ledger & ledger_a, nano::network_params & network_params_a);
|
||||
/** Returns false if the vote was processed */
|
||||
bool vote (std::shared_ptr<nano::vote>, std::shared_ptr<nano::transport::channel>);
|
||||
/** Note: node.active.mutex lock is required */
|
||||
|
@ -58,6 +59,7 @@ private:
|
|||
nano::node_config & config;
|
||||
nano::logger_mt & logger;
|
||||
nano::online_reps & online_reps;
|
||||
nano::rep_crawler & rep_crawler;
|
||||
nano::ledger & ledger;
|
||||
nano::network_params & network_params;
|
||||
size_t max_votes;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue