Tally votes on conflicting block with no inactive votes (#2744)

Mostly applicable to tests, but consider this sequence of events:
- An election gets created for a processed block
- A vote arrives for a conflicting block; gets added to election, not inactive
- The conflicting block gets processed

Currently, `election::publish` calls `insert_inactive_votes_cache` but votes are not tallied since there was no inactive vote.

This fixes the above situation by calling `confirm_if_quorum` if no votes were cached when a new conflicting block is inserted.
This commit is contained in:
Guilherme Lawless 2020-04-28 13:44:20 +01:00 committed by GitHub
commit e31cdebc87
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 38 additions and 5 deletions

View file

@ -1089,3 +1089,31 @@ TEST (active_transactions, restart_dropped)
// Wait for the election to complete // Wait for the election to complete
ASSERT_TIMELY (5s, node.ledger.cache.cemented_count == 2); ASSERT_TIMELY (5s, node.ledger.cache.cemented_count == 2);
} }
// Ensures votes are tallied on election::publish even if no vote is inserted through inactive_votes_cache
TEST (active_transactions, conflicting_block_vote_existing_election)
{
nano::system system;
nano::node_flags node_flags;
node_flags.disable_request_loop = true;
auto & node = *system.add_node (node_flags);
nano::genesis genesis;
nano::keypair key;
auto send (std::make_shared<nano::state_block> (nano::test_genesis_key.pub, genesis.hash (), nano::test_genesis_key.pub, nano::genesis_amount - 100, key.pub, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *system.work.generate (genesis.hash ())));
auto fork (std::make_shared<nano::state_block> (nano::test_genesis_key.pub, genesis.hash (), nano::test_genesis_key.pub, nano::genesis_amount - 200, key.pub, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *system.work.generate (genesis.hash ())));
auto vote_fork (std::make_shared<nano::vote> (nano::test_genesis_key.pub, nano::test_genesis_key.prv, 0, fork));
ASSERT_EQ (nano::process_result::progress, node.process_local (send).code);
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);
// Block now gets processed
ASSERT_EQ (nano::process_result::fork, node.process_local (fork).code);
// Election must be confirmed
auto election (node.active.election (fork->qualified_root ()));
ASSERT_NE (nullptr, election);
ASSERT_TRUE (election->confirmed ());
}

View file

@ -481,7 +481,11 @@ bool nano::election::publish (std::shared_ptr<nano::block> block_a)
if (existing == blocks.end ()) if (existing == blocks.end ())
{ {
blocks.emplace (std::make_pair (block_a->hash (), block_a)); blocks.emplace (std::make_pair (block_a->hash (), block_a));
insert_inactive_votes_cache (block_a->hash ()); if (!insert_inactive_votes_cache (block_a->hash ()))
{
// Even if no votes were in cache, they could be in the election
confirm_if_quorum ();
}
node.network.flood_block (block_a, nano::buffer_drop_policy::no_limiter_drop); node.network.flood_block (block_a, nano::buffer_drop_policy::no_limiter_drop);
} }
else else
@ -576,10 +580,10 @@ void nano::election::cleanup ()
} }
} }
void nano::election::insert_inactive_votes_cache (nano::block_hash const & hash_a) size_t nano::election::insert_inactive_votes_cache (nano::block_hash const & hash_a)
{ {
auto cache (node.active.find_inactive_votes_cache (hash_a)); auto cache (node.active.find_inactive_votes_cache (hash_a));
for (auto & rep : cache.voters) for (auto const & rep : cache.voters)
{ {
auto inserted (last_votes.emplace (rep, nano::vote_info{ std::chrono::steady_clock::time_point::min (), 0, hash_a })); auto inserted (last_votes.emplace (rep, nano::vote_info{ std::chrono::steady_clock::time_point::min (), 0, hash_a }));
if (inserted.second) if (inserted.second)
@ -597,6 +601,7 @@ void nano::election::insert_inactive_votes_cache (nano::block_hash const & hash_
} }
confirm_if_quorum (); confirm_if_quorum ();
} }
return cache.voters.size ();
} }
bool nano::election::prioritized () const bool nano::election::prioritized () const

View file

@ -84,7 +84,7 @@ public:
size_t last_votes_size (); size_t last_votes_size ();
void update_dependent (); void update_dependent ();
void adjust_dependent_difficulty (); void adjust_dependent_difficulty ();
void insert_inactive_votes_cache (nano::block_hash const &); size_t insert_inactive_votes_cache (nano::block_hash const &);
bool prioritized () const; bool prioritized () const;
void prioritize_election (nano::vote_generator_session &); void prioritize_election (nano::vote_generator_session &);
// Erase all blocks from active and, if not confirmed, clear digests from network filters // Erase all blocks from active and, if not confirmed, clear digests from network filters