Merge pull request #4508 from clemahieu/block_cemented_callback_simplify

Block cemented callback simplify
This commit is contained in:
clemahieu 2024-03-20 14:03:04 +00:00 committed by GitHub
commit 0e6b7fa635
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 61 additions and 153 deletions

View file

@ -1444,8 +1444,9 @@ TEST (confirmation_height, pending_observer_callbacks)
node->confirmation_height_processor.add (send1);
// Confirm the callback is not called under this circumstance because there is no election information
ASSERT_TIMELY (10s, node->stats.count (nano::stat::type::http_callback, nano::stat::detail::http_callback, nano::stat::dir::out) == 1 && node->ledger.stats.count (nano::stat::type::confirmation_observer, nano::stat::detail::all, nano::stat::dir::out) == 1);
// Callback is performed for all blocks that are confirmed
ASSERT_TIMELY_EQ (5s, 2, node->stats.count (nano::stat::type::http_callback, nano::stat::detail::http_callback, nano::stat::dir::out))
ASSERT_TIMELY_EQ (5s, 2, node->ledger.stats.count (nano::stat::type::confirmation_observer, nano::stat::detail::all, nano::stat::dir::out));
ASSERT_EQ (2, node->stats.count (nano::stat::type::confirmation_height, nano::stat::detail::blocks_confirmed, nano::stat::dir::in));
ASSERT_EQ (2, node->stats.count (nano::stat::type::confirmation_height, get_stats_detail (mode_a), nano::stat::dir::in));
@ -1528,7 +1529,8 @@ TEST (confirmation_height, callback_confirmed_history)
ASSERT_TIMELY_EQ (10s, node->active.size (), 0);
ASSERT_TIMELY_EQ (10s, node->stats.count (nano::stat::type::confirmation_observer, nano::stat::detail::active_quorum, nano::stat::dir::out), 1);
ASSERT_EQ (1, node->active.recently_cemented.list ().size ());
// Each block that's confirmed is in the recently_cemented history
ASSERT_EQ (2, node->active.recently_cemented.list ().size ());
ASSERT_TRUE (node->active.empty ());
// Confirm the callback is not called under this circumstance

View file

@ -80,75 +80,44 @@ void nano::active_transactions::stop ()
clear ();
}
void nano::active_transactions::block_cemented_callback (std::shared_ptr<nano::block> const & block_a)
void nano::active_transactions::block_cemented_callback (std::shared_ptr<nano::block> const & block)
{
auto status_type = election_status (block_a);
if (!status_type)
return;
auto transaction = node.store.tx_begin_read ();
switch (*status_type)
if (auto election_l = election (block->qualified_root ()))
{
case nano::election_status_type::inactive_confirmation_height:
process_inactive_confirmation (transaction, block_a);
break;
default:
process_active_confirmation (transaction, block_a, *status_type);
break;
election_l->try_confirm (block->hash ());
}
handle_final_votes_confirmation (block_a, transaction, *status_type);
}
boost::optional<nano::election_status_type> nano::active_transactions::election_status (std::shared_ptr<nano::block> const & block)
{
boost::optional<nano::election_status_type> status_type;
if (!confirmation_height_processor.is_processing_added_block (block->hash ()))
auto election = remove_election_winner_details (block->hash ());
nano::election_status status;
std::vector<nano::vote_with_weight_info> votes;
status.winner = block;
if (election)
{
status_type = confirm_block (block);
status = election->get_status ();
votes = election->votes_with_weight ();
}
if (confirmation_height_processor.is_processing_added_block (block->hash ()))
{
status.type = nano::election_status_type::active_confirmed_quorum;
}
else if (election)
{
status.type = nano::election_status_type::active_confirmation_height;
}
else
{
status_type = nano::election_status_type::active_confirmed_quorum;
status.type = nano::election_status_type::inactive_confirmation_height;
}
return status_type;
}
void nano::active_transactions::process_inactive_confirmation (nano::store::read_transaction const & transaction, std::shared_ptr<nano::block> const & block)
{
nano::election_status status{ block, 0, 0, std::chrono::duration_cast<std::chrono::milliseconds> (std::chrono::system_clock::now ().time_since_epoch ()), std::chrono::duration_values<std::chrono::milliseconds>::zero (), 0, 1, 0, nano::election_status_type::inactive_confirmation_height };
notify_observers (transaction, status, {});
}
void nano::active_transactions::process_active_confirmation (nano::store::read_transaction const & transaction, std::shared_ptr<nano::block> const & block, nano::election_status_type status_type)
{
auto hash (block->hash ());
nano::unique_lock<nano::mutex> election_winners_lk{ election_winner_details_mutex };
auto existing = election_winner_details.find (hash);
if (existing != election_winner_details.end ())
{
auto election = existing->second;
election_winner_details.erase (hash);
election_winners_lk.unlock ();
if (election->confirmed () && election->winner ()->hash () == hash)
{
handle_confirmation (transaction, block, election, status_type);
}
}
}
void nano::active_transactions::handle_confirmation (nano::store::read_transaction const & transaction, std::shared_ptr<nano::block> const & block, std::shared_ptr<nano::election> election, nano::election_status_type status_type)
{
nano::block_hash hash = block->hash ();
recently_cemented.put (election->get_status ());
auto status = election->set_status_type (status_type);
auto votes = election->votes_with_weight ();
recently_cemented.put (status);
auto transaction = node.store.tx_begin_read ();
notify_observers (transaction, status, votes);
bool cemented_bootstrap_count_reached = node.ledger.cache.cemented_count >= node.ledger.bootstrap_weight_max_blocks;
bool was_active = status.type == nano::election_status_type::active_confirmed_quorum || status.type == nano::election_status_type::active_confirmation_height;
// Next-block activations are only done for blocks with previously active elections
if (cemented_bootstrap_count_reached && was_active)
{
activate_successors (transaction, block);
}
}
void nano::active_transactions::notify_observers (nano::store::read_transaction const & transaction, nano::election_status const & status, std::vector<nano::vote_with_weight_info> const & votes)
@ -170,19 +139,6 @@ void nano::active_transactions::notify_observers (nano::store::read_transaction
}
}
void nano::active_transactions::handle_final_votes_confirmation (std::shared_ptr<nano::block> const & block, nano::store::read_transaction const & transaction, nano::election_status_type status)
{
auto account = block->account ();
bool cemented_bootstrap_count_reached = node.ledger.cache.cemented_count >= node.ledger.bootstrap_weight_max_blocks;
bool was_active = status == nano::election_status_type::active_confirmed_quorum || status == nano::election_status_type::active_confirmation_height;
// Next-block activations are only done for blocks with previously active elections
if (cemented_bootstrap_count_reached && was_active)
{
activate_successors (transaction, block);
}
}
void nano::active_transactions::activate_successors (nano::store::read_transaction const & transaction, std::shared_ptr<nano::block> const & block)
{
node.scheduler.priority.activate (block->account (), transaction);
@ -200,10 +156,17 @@ void nano::active_transactions::add_election_winner_details (nano::block_hash co
election_winner_details.emplace (hash_a, election_a);
}
void nano::active_transactions::remove_election_winner_details (nano::block_hash const & hash_a)
std::shared_ptr<nano::election> nano::active_transactions::remove_election_winner_details (nano::block_hash const & hash_a)
{
nano::lock_guard<nano::mutex> guard{ election_winner_details_mutex };
election_winner_details.erase (hash_a);
std::shared_ptr<nano::election> result;
auto existing = election_winner_details.find (hash_a);
if (existing != election_winner_details.end ())
{
result = existing->second;
election_winner_details.erase (existing);
}
return result;
}
void nano::active_transactions::block_already_cemented_callback (nano::block_hash const & hash_a)
@ -653,33 +616,6 @@ bool nano::active_transactions::publish (std::shared_ptr<nano::block> const & bl
return result;
}
// Returns the type of election status requiring callbacks calling later
boost::optional<nano::election_status_type> nano::active_transactions::confirm_block (std::shared_ptr<nano::block> const & block_a)
{
auto const hash = block_a->hash ();
std::shared_ptr<nano::election> election = nullptr;
{
nano::lock_guard<nano::mutex> guard{ mutex };
auto existing = blocks.find (hash);
if (existing != blocks.end ())
{
election = existing->second;
}
}
boost::optional<nano::election_status_type> status_type;
if (election)
{
status_type = election->try_confirm (hash);
}
else
{
status_type = nano::election_status_type::inactive_confirmation_height;
}
return status_type;
}
void nano::active_transactions::add_vote_cache (nano::block_hash const & hash, std::shared_ptr<nano::vote> const vote)
{
if (node.ledger.weight (vote->account) > node.minimum_principal_weight ())

View file

@ -160,7 +160,6 @@ public:
bool empty () const;
std::size_t size () const;
bool publish (std::shared_ptr<nano::block> const &);
boost::optional<nano::election_status_type> confirm_block (std::shared_ptr<nano::block> const &);
void block_cemented_callback (std::shared_ptr<nano::block> const &);
void block_already_cemented_callback (nano::block_hash const &);
@ -177,7 +176,7 @@ public:
std::size_t election_winner_details_size ();
void add_election_winner_details (nano::block_hash const &, std::shared_ptr<nano::election> const &);
void remove_election_winner_details (nano::block_hash const &);
std::shared_ptr<nano::election> remove_election_winner_details (nano::block_hash const &);
private:
// Erase elections if we're over capacity
@ -195,11 +194,6 @@ private:
* TODO: Should be moved to `vote_cache` class
*/
void add_vote_cache (nano::block_hash const & hash, std::shared_ptr<nano::vote> vote);
boost::optional<nano::election_status_type> election_status (std::shared_ptr<nano::block> const & block);
void process_inactive_confirmation (nano::store::read_transaction const & transaction, std::shared_ptr<nano::block> const & block);
void process_active_confirmation (nano::store::read_transaction const & transaction, std::shared_ptr<nano::block> const & block, nano::election_status_type status);
void handle_final_votes_confirmation (std::shared_ptr<nano::block> const & block, nano::store::read_transaction const & transaction, nano::election_status_type status);
void handle_confirmation (nano::store::read_transaction const & transaction, std::shared_ptr<nano::block> const & block, std::shared_ptr<nano::election> election, nano::election_status_type status);
void activate_successors (nano::store::read_transaction const & transaction, std::shared_ptr<nano::block> const & block);
void notify_observers (nano::store::read_transaction const & transaction, nano::election_status const & status, std::vector<nano::vote_with_weight_info> const & votes);

View file

@ -34,7 +34,7 @@ nano::election::election (nano::node & node_a, std::shared_ptr<nano::block> cons
last_blocks.emplace (block_a->hash (), block_a);
}
void nano::election::confirm_once (nano::unique_lock<nano::mutex> & lock_a, nano::election_status_type type_a)
void nano::election::confirm_once (nano::unique_lock<nano::mutex> & lock_a)
{
debug_assert (lock_a.owns_lock ());
@ -51,7 +51,6 @@ void nano::election::confirm_once (nano::unique_lock<nano::mutex> & lock_a, nano
status.confirmation_request_count = confirmation_request_count;
status.block_count = nano::narrow_cast<decltype (status.block_count)> (last_blocks.size ());
status.voter_count = nano::narrow_cast<decltype (status.voter_count)> (last_votes.size ());
status.type = type_a;
auto const status_l = status;
node.active.recently_confirmed.put (qualified_root, status_l.winner->hash ());
@ -403,44 +402,22 @@ void nano::election::confirm_if_quorum (nano::unique_lock<nano::mutex> & lock_a)
}
if (final_weight >= node.online_reps.delta ())
{
confirm_once (lock_a, nano::election_status_type::active_confirmed_quorum);
confirm_once (lock_a);
}
}
}
boost::optional<nano::election_status_type> nano::election::try_confirm (nano::block_hash const & hash)
void nano::election::try_confirm (nano::block_hash const & hash)
{
boost::optional<nano::election_status_type> status_type;
nano::unique_lock<nano::mutex> election_lock{ mutex };
auto winner = status.winner;
if (winner && winner->hash () == hash)
{
// Determine if the block was confirmed explicitly via election confirmation or implicitly via confirmation height
if (!confirmed_locked ())
{
confirm_once (election_lock, nano::election_status_type::active_confirmation_height);
status_type = nano::election_status_type::active_confirmation_height;
}
else
{
status_type = nano::election_status_type::active_confirmed_quorum;
confirm_once (election_lock);
}
}
else
{
status_type = boost::optional<nano::election_status_type>{};
}
return status_type;
}
nano::election_status nano::election::set_status_type (nano::election_status_type status_type)
{
nano::unique_lock<nano::mutex> election_lk{ mutex };
status.type = status_type;
status.confirmation_request_count = confirmation_request_count;
nano::election_status status_l{ status };
election_lk.unlock ();
return status_l;
}
std::shared_ptr<nano::block> nano::election::find (nano::block_hash const & hash_a) const
@ -709,11 +686,11 @@ bool nano::election::replace_by_weight (nano::unique_lock<nano::mutex> & lock_a,
return replaced;
}
void nano::election::force_confirm (nano::election_status_type type_a)
void nano::election::force_confirm ()
{
release_assert (node.network_params.network.is_dev_network ());
nano::unique_lock<nano::mutex> lock{ mutex };
confirm_once (lock, type_a);
confirm_once (lock);
}
std::unordered_map<nano::block_hash, std::shared_ptr<nano::block>> nano::election::blocks () const

View file

@ -146,8 +146,7 @@ public: // Interface
bool publish (std::shared_ptr<nano::block> const & block_a);
// Confirm this block if quorum is met
void confirm_if_quorum (nano::unique_lock<nano::mutex> &);
boost::optional<nano::election_status_type> try_confirm (nano::block_hash const & hash);
nano::election_status set_status_type (nano::election_status_type status_type);
void try_confirm (nano::block_hash const & hash);
/**
* Broadcasts vote for the current winner of this election
@ -173,7 +172,7 @@ private:
bool confirmed_locked () const;
nano::election_extended_status current_status_locked () const;
// lock_a does not own the mutex on return
void confirm_once (nano::unique_lock<nano::mutex> & lock_a, nano::election_status_type = nano::election_status_type::active_confirmed_quorum);
void confirm_once (nano::unique_lock<nano::mutex> & lock_a);
bool broadcast_block_predicate () const;
void broadcast_block (nano::confirmation_solicitor &);
void send_confirm_req (nano::confirmation_solicitor &);
@ -217,7 +216,7 @@ private: // Constants
friend class confirmation_solicitor;
public: // Only used in tests
void force_confirm (nano::election_status_type = nano::election_status_type::active_confirmed_quorum);
void force_confirm ();
std::unordered_map<nano::account, nano::vote_info> votes () const;
std::unordered_map<nano::block_hash, std::shared_ptr<nano::block>> blocks () const;

View file

@ -360,14 +360,14 @@ class election_status final
{
public:
std::shared_ptr<nano::block> winner;
nano::amount tally;
nano::amount final_tally;
std::chrono::milliseconds election_end;
std::chrono::milliseconds election_duration;
unsigned confirmation_request_count;
unsigned block_count;
unsigned voter_count;
election_status_type type;
nano::amount tally{ 0 };
nano::amount final_tally{ 0 };
std::chrono::milliseconds election_end{ std::chrono::duration_cast<std::chrono::milliseconds> (std::chrono::system_clock::now ().time_since_epoch ()) };
std::chrono::milliseconds election_duration{ std::chrono::duration_values<std::chrono::milliseconds>::zero () };
unsigned confirmation_request_count{ 0 };
unsigned block_count{ 0 };
unsigned voter_count{ 0 };
election_status_type type{ nano::election_status_type::inactive_confirmation_height };
};
nano::wallet_id random_wallet_id ();