From 238466cbfa281733e2dbfbde7f668e8017ef4631 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Wo=CC=81jcik?= <3044353+pwojcikdev@users.noreply.github.com> Date: Sun, 31 Aug 2025 21:11:24 +0200 Subject: [PATCH] Election expose update action --- nano/core_test/active_elections_index.cpp | 2 +- nano/core_test/confirmation_solicitor.cpp | 10 ++--- nano/core_test/election.cpp | 2 +- nano/node/active_elections.cpp | 12 ++++-- nano/node/election.cpp | 47 ++++++++++++++++------- nano/node/election.hpp | 13 ++++++- 6 files changed, 61 insertions(+), 25 deletions(-) diff --git a/nano/core_test/active_elections_index.cpp b/nano/core_test/active_elections_index.cpp index 6fc680c3d..7c4cb4a5f 100644 --- a/nano/core_test/active_elections_index.cpp +++ b/nano/core_test/active_elections_index.cpp @@ -40,7 +40,7 @@ public: std::shared_ptr random_election (nano::election_behavior behavior = nano::election_behavior::priority) { - return std::make_shared (node, next_block (), nullptr, nullptr, behavior); + return std::make_shared (node, next_block (), behavior); } }; } diff --git a/nano/core_test/confirmation_solicitor.cpp b/nano/core_test/confirmation_solicitor.cpp index ca48a2ee8..096dc1474 100644 --- a/nano/core_test/confirmation_solicitor.cpp +++ b/nano/core_test/confirmation_solicitor.cpp @@ -46,11 +46,11 @@ TEST (confirmation_solicitor, batches) nano::lock_guard guard (node2.active.mutex); for (size_t i (0); i < nano::network::confirm_req_hashes_max; ++i) { - auto election (std::make_shared (node2, send, nullptr, nullptr, nano::election_behavior::priority)); + auto election (std::make_shared (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 (node2, send, nullptr, nullptr, nano::election_behavior::priority)); + auto election (std::make_shared (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 (node2, send, nullptr, nullptr, nano::election_behavior::priority)); + auto election (std::make_shared (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 (node2, send, nullptr, nullptr, nano::election_behavior::priority)); + auto election (std::make_shared (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 (node2, send, nullptr, nullptr, nano::election_behavior::priority)); + auto election2 (std::make_shared (node2, send, nano::election_behavior::priority)); ASSERT_FALSE (solicitor.add (*election2)); ASSERT_FALSE (solicitor.broadcast (*election2)); diff --git a/nano/core_test/election.cpp b/nano/core_test/election.cpp index 7fe943ad0..280cbb74e 100644 --- a/nano/core_test/election.cpp +++ b/nano/core_test/election.cpp @@ -19,7 +19,7 @@ TEST (election, construction) nano::test::system system (1); auto & node = *system.nodes[0]; auto election = std::make_shared ( - 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) diff --git a/nano/node/active_elections.cpp b/nano/node/active_elections.cpp index b627d4c22..a5a1835d3 100644 --- a/nano/node/active_elections.cpp +++ b/nano/node/active_elections.cpp @@ -157,11 +157,16 @@ auto nano::active_elections::insert (std::shared_ptr 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 (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 (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 & lo std::deque> 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); } diff --git a/nano/node/election.cpp b/nano/node/election.cpp index 443e383e4..d7199f134 100644 --- a/nano/node/election.cpp +++ b/nano/node/election.cpp @@ -23,9 +23,10 @@ std::chrono::milliseconds nano::election::base_latency () const * election */ -nano::election::election (nano::node & node_a, std::shared_ptr const & block_a, std::function const &)> const & confirmation_action_a, std::function 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 const & block_a, nano::election_behavior election_behavior_a, std::function const &)> confirmation_action_a, std::function vote_action_a, std::function 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 & 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 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; } diff --git a/nano/node/election.hpp b/nano/node/election.hpp index 9f3881cd8..1531886c1 100644 --- a/nano/node/election.hpp +++ b/nano/node/election.hpp @@ -70,6 +70,7 @@ private: // Callbacks std::function const &)> confirmation_action; std::function vote_action; + std::function 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 const & block, std::function const &)> const & confirmation_action, std::function const & vote_action, nano::election_behavior behavior); + election ( + nano::node &, + std::shared_ptr const & block, + nano::election_behavior behavior, + std::function const &)> confirmation_action = nullptr, + std::function vote_action = nullptr, + std::function update_action = nullptr); std::shared_ptr find (nano::block_hash const &) const; /*