Election expose update action

This commit is contained in:
Piotr Wójcik 2025-08-31 21:11:24 +02:00
commit 238466cbfa
6 changed files with 61 additions and 25 deletions

View file

@ -40,7 +40,7 @@ public:
std::shared_ptr<nano::election> random_election (nano::election_behavior behavior = nano::election_behavior::priority)
{
return std::make_shared<nano::election> (node, next_block (), nullptr, nullptr, behavior);
return std::make_shared<nano::election> (node, next_block (), behavior);
}
};
}

View file

@ -46,11 +46,11 @@ TEST (confirmation_solicitor, batches)
nano::lock_guard<nano::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, nullptr, nano::election_behavior::priority));
auto election (std::make_shared<nano::election> (node2, send, nano::election_behavior::priority));
ASSERT_FALSE (solicitor.add (*election));
}
// Reached the maximum amount of requests for the channel
auto election (std::make_shared<nano::election> (node2, send, nullptr, nullptr, nano::election_behavior::priority));
auto election (std::make_shared<nano::election> (node2, send, nano::election_behavior::priority));
// Broadcasting should be immediate
ASSERT_EQ (0, node2.stats.count (nano::stat::type::message, nano::stat::detail::publish, nano::stat::dir::out));
ASSERT_FALSE (solicitor.broadcast (*election));
@ -92,7 +92,7 @@ TEST (confirmation_solicitor, different_hash)
.work (*system.work.generate (nano::dev::genesis->hash ()))
.build ();
send->sideband_set ({});
auto election (std::make_shared<nano::election> (node2, send, nullptr, nullptr, nano::election_behavior::priority));
auto election (std::make_shared<nano::election> (node2, send, nano::election_behavior::priority));
// 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
@ -136,7 +136,7 @@ TEST (confirmation_solicitor, bypass_max_requests_cap)
.work (*system.work.generate (nano::dev::genesis->hash ()))
.build ();
send->sideband_set ({});
auto election (std::make_shared<nano::election> (node2, send, nullptr, nullptr, nano::election_behavior::priority));
auto election (std::make_shared<nano::election> (node2, send, nano::election_behavior::priority));
// Add a vote for something else, not the winner
for (auto const & rep : representatives)
{
@ -149,7 +149,7 @@ TEST (confirmation_solicitor, bypass_max_requests_cap)
ASSERT_TIMELY_EQ (6s, 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, nullptr, nano::election_behavior::priority));
auto election2 (std::make_shared<nano::election> (node2, send, nano::election_behavior::priority));
ASSERT_FALSE (solicitor.add (*election2));
ASSERT_FALSE (solicitor.broadcast (*election2));

View file

@ -19,7 +19,7 @@ TEST (election, construction)
nano::test::system system (1);
auto & node = *system.nodes[0];
auto election = std::make_shared<nano::election> (
node, nano::dev::genesis, [] (auto const &) {}, [] (auto const &) {}, nano::election_behavior::priority);
node, nano::dev::genesis, nano::election_behavior::priority, [] (auto const &) {}, [] (auto const &) {}, [] (auto const &) {});
}
TEST (election, behavior)

View file

@ -157,11 +157,16 @@ auto nano::active_elections::insert (std::shared_ptr<nano::block> const & block,
// Passing this callback into the election is important
// We need to observe and update the online voting weight *before* election quorum is checked
auto observe_rep_callback = [&node = node] (auto const & rep) {
auto observe_rep_action = [&node = node] (auto const & rep) {
node.online_reps.observe (rep);
};
result.election = nano::make_shared<nano::election> (node, block, nullptr, observe_rep_callback, behavior);
// On any election state update, schedule a call to tick it immediately
auto update_action = [this] (auto const & root) {
trigger (root);
};
result.election = std::make_shared<nano::election> (node, block, behavior, nullptr, observe_rep_action, update_action);
// Store erased callback if provided
if (erased_callback)
@ -496,7 +501,8 @@ void nano::active_elections::tick_elections (nano::unique_lock<nano::mutex> & lo
std::deque<std::shared_ptr<nano::election>> stale_elections;
for (auto const & election : election_list)
{
if (election->transition_time (solicitor))
bool tick_result = election->tick (solicitor);
if (tick_result)
{
erase (election->qualified_root);
}

View file

@ -23,9 +23,10 @@ std::chrono::milliseconds nano::election::base_latency () const
* election
*/
nano::election::election (nano::node & node_a, std::shared_ptr<nano::block> const & block_a, std::function<void (std::shared_ptr<nano::block> const &)> const & confirmation_action_a, std::function<void (nano::account const &)> const & vote_action_a, nano::election_behavior election_behavior_a) :
confirmation_action (confirmation_action_a),
vote_action (vote_action_a),
nano::election::election (nano::node & node_a, std::shared_ptr<nano::block> const & block_a, nano::election_behavior election_behavior_a, std::function<void (std::shared_ptr<nano::block> const &)> confirmation_action_a, std::function<void (nano::account const &)> vote_action_a, std::function<void (nano::qualified_root const &)> update_action_a) :
confirmation_action (std::move (confirmation_action_a)),
vote_action (std::move (vote_action_a)),
update_action (std::move (update_action_a)),
node (node_a),
behavior_m (election_behavior_a),
status (block_a),
@ -78,14 +79,19 @@ void nano::election::confirm_once (nano::unique_lock<nano::mutex> & lock)
lock.unlock ();
node.active.trigger (qualified_root);
if (update_action)
{
node.election_workers.post ([qualified_root_l = qualified_root, update_action_l = update_action] () {
update_action_l (qualified_root_l);
});
}
node.election_workers.post ([status_l, confirmation_action_l = confirmation_action] () {
if (confirmation_action_l)
{
if (confirmation_action)
{
node.election_workers.post ([status_l, confirmation_action_l = confirmation_action] () {
confirmation_action_l (status_l.winner);
}
});
});
}
}
else
{
@ -149,6 +155,13 @@ bool nano::election::state_change (nano::election_state expected_a, nano::electi
state_m = desired_a;
state_start = std::chrono::steady_clock::now ().time_since_epoch ();
result = false;
if (update_action)
{
node.election_workers.post ([qualified_root_l = qualified_root, update_action_l = update_action] () {
update_action_l (qualified_root_l);
});
}
}
}
return result;
@ -216,6 +229,13 @@ bool nano::election::transition_priority ()
qualified_root,
duration ().count ());
if (update_action)
{
node.election_workers.post ([qualified_root_l = qualified_root, update_action_l = update_action] () {
update_action_l (qualified_root_l);
});
}
return true;
}
@ -308,7 +328,7 @@ nano::election_status nano::election::get_status () const
return status;
}
bool nano::election::transition_time (nano::confirmation_solicitor & solicitor_a)
bool nano::election::tick (nano::confirmation_solicitor & solicitor)
{
nano::unique_lock<nano::mutex> lock{ mutex };
bool result = false;
@ -322,12 +342,12 @@ bool nano::election::transition_time (nano::confirmation_solicitor & solicitor_a
break;
case nano::election_state::active:
broadcast_vote_locked (lock);
broadcast_block (solicitor_a);
send_confirm_req (solicitor_a);
broadcast_block (solicitor);
send_confirm_req (solicitor);
break;
case nano::election_state::confirmed:
result = true; // Return true to indicate this election should be cleaned up
broadcast_block (solicitor_a); // Ensure election winner is broadcasted
broadcast_block (solicitor); // Ensure election winner is broadcasted
state_change (nano::election_state::confirmed, nano::election_state::expired_confirmed);
break;
case nano::election_state::expired_unconfirmed:
@ -353,6 +373,7 @@ bool nano::election::transition_time (nano::confirmation_solicitor & solicitor_a
status.type = nano::election_status_type::stopped;
}
}
return result;
}

View file

@ -70,6 +70,7 @@ private:
// Callbacks
std::function<void (std::shared_ptr<nano::block> const &)> confirmation_action;
std::function<void (nano::account const &)> vote_action;
std::function<void (nano::qualified_root const &)> update_action;
private: // State management
static unsigned constexpr passive_duration_factor = 5;
@ -89,7 +90,9 @@ private: // State management
bool state_change (nano::election_state, nano::election_state);
public: // State transitions
bool transition_time (nano::confirmation_solicitor &);
// Returns true if the election should be cleaned up
bool tick (nano::confirmation_solicitor &);
void transition_active ();
bool transition_priority ();
void cancel ();
@ -110,7 +113,13 @@ public: // Status
nano::election_status status;
public: // Interface
election (nano::node &, std::shared_ptr<nano::block> const & block, std::function<void (std::shared_ptr<nano::block> const &)> const & confirmation_action, std::function<void (nano::account const &)> const & vote_action, nano::election_behavior behavior);
election (
nano::node &,
std::shared_ptr<nano::block> const & block,
nano::election_behavior behavior,
std::function<void (std::shared_ptr<nano::block> const &)> confirmation_action = nullptr,
std::function<void (nano::account const &)> vote_action = nullptr,
std::function<void (nano::qualified_root const &)> update_action = nullptr);
std::shared_ptr<nano::block> find (nano::block_hash const &) const;
/*