dncurrency/nano/node/confirming_set.hpp
2025-01-14 22:35:36 +01:00

130 lines
3.6 KiB
C++

#pragma once
#include <nano/lib/numbers.hpp>
#include <nano/lib/numbers_templ.hpp>
#include <nano/lib/observer_set.hpp>
#include <nano/lib/thread_pool.hpp>
#include <nano/node/fwd.hpp>
#include <nano/secure/common.hpp>
#include <nano/secure/fwd.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index_container.hpp>
#include <condition_variable>
#include <deque>
#include <mutex>
#include <thread>
#include <unordered_set>
namespace mi = boost::multi_index;
namespace nano
{
class confirming_set_config final
{
public:
// TODO: Serialization & deserialization
public:
bool enable{ true };
size_t batch_size{ 256 };
/** Maximum number of dependent blocks to be stored in memory during processing */
size_t max_blocks{ 128 * 1024 };
size_t max_queued_notifications{ 8 };
/** Maximum number of failed blocks to wait for requeuing */
size_t max_deferred{ 16 * 1024 };
/** Max age of deferred blocks before they are dropped */
std::chrono::seconds deferred_age_cutoff{ 15min };
};
/**
* Set of blocks to be durably confirmed
*/
class confirming_set final
{
friend class confirmation_heightDeathTest_missing_block_Test;
friend class confirmation_height_pruned_source_Test;
public:
confirming_set (confirming_set_config const &, nano::ledger &, nano::ledger_notifications &, nano::stats &, nano::logger &);
~confirming_set ();
void start ();
void stop ();
// Adds a block to the set of blocks to be confirmed
void add (nano::block_hash const & hash, std::shared_ptr<nano::election> const & election = nullptr);
// Added blocks will remain in this set until after ledger has them marked as confirmed.
bool contains (nano::block_hash const & hash) const;
std::size_t size () const;
nano::container_info container_info () const;
public: // Events
struct context
{
std::shared_ptr<nano::block> block;
nano::block_hash confirmation_root;
std::shared_ptr<nano::election> election;
};
nano::observer_set<std::deque<context> const &> batch_cemented;
nano::observer_set<std::deque<nano::block_hash> const &> already_cemented;
nano::observer_set<nano::block_hash> cementing_failed;
nano::observer_set<std::shared_ptr<nano::block>> cemented_observers;
private: // Dependencies
confirming_set_config const & config;
nano::ledger & ledger;
nano::ledger_notifications & ledger_notifications;
nano::stats & stats;
nano::logger & logger;
private:
struct entry
{
nano::block_hash hash;
std::shared_ptr<nano::election> election;
std::chrono::steady_clock::time_point timestamp{ std::chrono::steady_clock::now () };
};
void run ();
void run_batch (std::unique_lock<std::mutex> &);
std::deque<entry> next_batch (size_t max_count);
void cleanup (std::unique_lock<std::mutex> &);
private:
// clang-format off
class tag_hash {};
class tag_sequenced {};
using ordered_entries = boost::multi_index_container<entry,
mi::indexed_by<
mi::sequenced<mi::tag<tag_sequenced>>,
mi::hashed_unique<mi::tag<tag_hash>,
mi::member<entry, nano::block_hash, &entry::hash>>
>>;
// clang-format on
// Blocks that are ready to be cemented
ordered_entries set;
// Blocks that could not be cemented immediately (e.g. waiting for rollbacks to complete)
ordered_entries deferred;
// Blocks that are being cemented in the current batch
std::unordered_set<nano::block_hash> current;
std::atomic<bool> stopped{ false };
mutable std::mutex mutex;
std::condition_variable condition;
std::thread thread;
nano::thread_pool workers;
};
}