diff --git a/core/network/peer_manager.hpp b/core/network/peer_manager.hpp index eb4559ef5c..5e00c94f20 100644 --- a/core/network/peer_manager.hpp +++ b/core/network/peer_manager.hpp @@ -25,6 +25,11 @@ namespace kagome::network { constexpr size_t kPeerStateMaxKnownBlocks = 1024; constexpr size_t kPeerStateMaxKnownGrandpaMessages = 8192; + /** + * @struct CollatingPeerState + * @brief This structure encapsulates the state of a collating peer in the + * context of parachain processing. + */ struct CollatingPeerState { network::ParachainId para_id; network::CollatorPublicKey collator_id; @@ -32,6 +37,11 @@ namespace kagome::network { std::chrono::system_clock::time_point last_active; }; + /** + * @struct CollationEvent + * @brief This structure encapsulates a collation event in the context of + * parachain processing. + */ struct CollationEvent { CollatorId collator_id; struct { diff --git a/core/network/types/collator_messages.hpp b/core/network/types/collator_messages.hpp index 7079179232..67e9620fb4 100644 --- a/core/network/types/collator_messages.hpp +++ b/core/network/types/collator_messages.hpp @@ -246,13 +246,14 @@ namespace kagome::network { SignedBitfield data; }; + /// Data that makes a statement unique. struct StatementMetadata { SCALE_TIE(2); - primitives::BlockHash relay_parent; /// Hash of the relay chain block - primitives::BlockHash - candidate_hash; /// Hash of candidate that was used create the - /// `CommitedCandidateRecept`. + /// Relay parent this statement is relevant under. + primitives::BlockHash relay_parent; + /// Hash of candidate that was used create the `CommitedCandidateRecept`. + primitives::BlockHash candidate_hash; }; /// A succinct representation of a peer's view. This consists of a bounded @@ -337,7 +338,14 @@ namespace kagome::network { /// block. }; - using ApprovalDistributionMessage = boost::variant; + /// Network messages used by the approval distribution subsystem. + using ApprovalDistributionMessage = boost::variant< + /// Assignments for candidates in recent, unfinalized blocks. + /// + /// Actually checking the assignment may yield a different result. + Assignments, + /// Approvals for candidates in some recent, unfinalized block. + Approvals>; /// Attestation is either an implicit or explicit attestation of the validity /// of a parachain candidate, where 1 implies an implicit vote (in diff --git a/core/network/types/collator_messages_vstaging.hpp b/core/network/types/collator_messages_vstaging.hpp index 9d1a47b428..6f17a3a8f0 100644 --- a/core/network/types/collator_messages_vstaging.hpp +++ b/core/network/types/collator_messages_vstaging.hpp @@ -67,9 +67,16 @@ namespace kagome::network::vstaging { CandidateHash hash; }; + /// Statements that can be made about parachain candidates. These are the + /// actual values that are signed. struct CompactStatement { std::array header = {'B', 'K', 'N', 'G'}; - boost::variant + + boost::variant inner_value{}; CompactStatement( @@ -110,6 +117,8 @@ namespace kagome::network::vstaging { UNREACHABLE; } + /// A notification of a signed statement in compact form, for a given + /// relay parent. struct StatementDistributionMessageStatement { SCALE_TIE(2); @@ -117,6 +126,14 @@ namespace kagome::network::vstaging { IndexedAndSigned compact; }; + /// All messages for V1 for compatibility with the statement distribution + /// protocol, for relay-parents that don't support asynchronous backing. + /// + /// These are illegal to send to V1 peers, and illegal to send concerning + /// relay-parents which support asynchronous backing. This backwards + /// compatibility should be considered immediately deprecated and can be + /// removed once the node software is not required to support logic from + /// before asynchronous backing anymore. using v1StatementDistributionMessage = network::StatementDistributionMessage; struct StatementFilter { @@ -134,12 +151,21 @@ namespace kagome::network::vstaging { } }; + /// A manifest of a known backed candidate, along with a description + /// of the statements backing it. struct BackedCandidateManifest { SCALE_TIE(6); + /// The relay-parent of the candidate. RelayHash relay_parent; + /// The hash of the candidate. CandidateHash candidate_hash; + /// The group index backing the candidate at the relay-parent. GroupIndex group_index; + /// The para ID of the candidate. It is illegal for this to + /// be a para ID which is not assigned to the group indicated + /// in this manifest. ParachainId para_id; + /// The head-data corresponding to the candidate. Hash parent_head_data_hash; /// A statement filter which indicates which validators in the /// para's group at the relay-parent have validated this candidate @@ -164,18 +190,38 @@ namespace kagome::network::vstaging { std::vector> statements; }; + /// An acknowledgement of a backed candidate being known. struct BackedCandidateAcknowledgement { SCALE_TIE(2); + /// The hash of the candidate. CandidateHash candidate_hash; + /// A statement filter which indicates which validators in the + /// para's group at the relay-parent have validated this candidate + /// and issued statements about it, to the advertiser's knowledge. + /// + /// This MUST have exactly the minimum amount of bytes + /// necessary to represent the number of validators in the assigned + /// backing group as-of the relay-parent. StatementFilter statement_knowledge; }; - using StatementDistributionMessage = - boost::variant; + /// Network messages used by the statement distribution subsystem. + /// Polkadot-sdk analogue: + /// https://github.com/paritytech/polkadot-sdk/blob/4220503d28f46a72c2bc71f22e7d9708618f9c68/polkadot/node/network/protocol/src/lib.rs#L769 + using StatementDistributionMessage = boost::variant< + StatementDistributionMessageStatement, // 0 + /// A notification of a backed + /// candidate being known by the + /// sending node, for the purpose + /// of being requested by the + /// receiving node if needed. + BackedCandidateManifest, // 1, + /// A notification of a backed candidate being known by the sending node, + /// for the purpose of informing a receiving node which already has the + /// candidate. + BackedCandidateAcknowledgement // 2 + // v1StatementDistributionMessage // 255 + >; struct CollationFetchingRequest { SCALE_TIE(3); diff --git a/core/parachain/types.hpp b/core/parachain/types.hpp index 497c161a22..90ea071718 100644 --- a/core/parachain/types.hpp +++ b/core/parachain/types.hpp @@ -66,6 +66,9 @@ namespace kagome::parachain { ValidatorIndex ix; }; + /** + * Appends an index and signature to the given type. + */ template using IndexedAndSigned = kagome::crypto::Sr25519Signed>; diff --git a/core/parachain/validator/impl/parachain_processor.cpp b/core/parachain/validator/impl/parachain_processor.cpp index 541f73723d..7a19177bae 100644 --- a/core/parachain/validator/impl/parachain_processor.cpp +++ b/core/parachain/validator/impl/parachain_processor.cpp @@ -315,6 +315,13 @@ namespace kagome::parachain { } } + /* + * This function is responsible for sending peer messages for a given relay + * parent. If a peer_id is provided, the messages are sent to that specific + * peer. Otherwise, the messages are sent to all peers in the validators group + * corresponding to the given relay parent. The messages include information + * about the candidate validation and the erasure coding validation. + */ void ParachainProcessorImpl::send_peer_messages_for_relay_parent( std::optional> peer_id, const RelayHash &relay_parent) { @@ -1163,6 +1170,12 @@ namespace kagome::parachain { BOOST_ASSERT(main_pool_handler_->isInCurrentThread()); SL_TRACE( logger_, "Incoming `StatementDistributionMessage`. (peer={})", peer_id); + + // Handles BackedCandidateAcknowledgement message + // code handles the case when a BackedCandidateAcknowledgement message is + // received. It performs various checks and operations, and if everything is + // successful, it sends post-acknowledgement statement messages to the + // validators group. if (auto inner = if_type( msg)) { @@ -1238,6 +1251,10 @@ namespace kagome::parachain { return; } + // Handles BackedCandidateManifest message + // It performs various checks and operations, and if everything is + // successful, it sends acknowledgement and statement messages to the + // validators group or sends a request to fetch the attested candidate. if (auto manifest = if_type(msg)) { SL_TRACE(logger_, @@ -1338,6 +1355,10 @@ namespace kagome::parachain { return; } + // Handles StatementDistributionMessageStatement message + // It performs various checks and operations, and if everything is + // successful, it sends backing fresh statements and circulates the + // statement. if (auto stm = if_type< const network::vstaging::StatementDistributionMessageStatement>( msg)) { @@ -2271,13 +2292,18 @@ namespace kagome::parachain { return {}; } + // If the relay parent state has a prospective parachains mode if (relay_parent_state_opt->get().prospective_parachains_mode) { std::vector backed; + + // Iterate over the availability cores of the relay parent state for (size_t core_idx = 0; core_idx < relay_parent_state_opt->get().availability_cores.size(); ++core_idx) { const runtime::CoreState &core = relay_parent_state_opt->get().availability_cores[core_idx]; + + // Get the response based on its type based on the core state std::optional> response = visit_in_place( core, [&](const network::ScheduledCore &scheduled_core) @@ -2319,6 +2345,7 @@ namespace kagome::parachain { continue; } + // If the attested candidate is found, add it to the backed vector if (auto attested = attested_candidate( r_hash, c_hash, @@ -3382,6 +3409,7 @@ namespace kagome::parachain { relay_parent, peer_id); + // Start the timer for the validation task TicToc _measure{"Parachain validation", logger_}; const auto candidate_hash{candidate.hash(*hasher_)}; @@ -3390,6 +3418,7 @@ namespace kagome::parachain { auto need_to_process = our_current_state_.active_leaves.count(relay_parent) != 0ull; + // If not needed, skip the validation and return if (!need_to_process) { SL_TRACE(logger_, "Candidate validation skipped because of extruded relay parent. " @@ -3401,6 +3430,8 @@ namespace kagome::parachain { } auto pvd_copy{pvd}; + + // Validate the candidate, if validation fails, log the error and return auto validation_result = validateCandidate(candidate, pov, std::move(pvd)); if (!validation_result) { logger_->warn( @@ -3414,10 +3445,10 @@ namespace kagome::parachain { } /// TODO(iceseer): do https://github.com/qdrvm/kagome/issues/1888 - /// checks if we still need to execute parachain task + /// checks if we still need to execute parachain task, if not needed, skip + /// the erasure-coding and return need_to_process = our_current_state_.active_leaves.count(relay_parent) != 0ull; - if (!need_to_process) { SL_TRACE(logger_, "Candidate validation skipped before erasure-coding because of " @@ -3429,13 +3460,17 @@ namespace kagome::parachain { return; } + // Get the commitments and data from the validation result auto &[comms, data] = validation_result.value(); runtime::AvailableData available_data{ .pov = std::move(pov), .validation_data = std::move(data), }; + // Initialize the chunks std::vector chunks; + // Validate the erasure coding, if validation fails, log the error and + // return if (auto res = validateErasureCoding(available_data, n_validators); res.has_error()) { SL_WARN(logger_, @@ -3446,6 +3481,7 @@ namespace kagome::parachain { chunks = std::move(res.value()); } + // Notify peers about the data availability notifyAvailableData(std::move(chunks), relay_parent, candidate_hash, @@ -3720,12 +3756,15 @@ namespace kagome::parachain { std::move(pending_collation), std::move(prospective_candidate)); + // Extract relay parent, peer id and parachain id from the pending collation const RelayHash &relay_parent = pending_collation.pending_collation.relay_parent; const libp2p::peer::PeerId &peer_id = pending_collation.pending_collation.peer_id; const ParachainId ¶_id = pending_collation.pending_collation.para_id; + // Try to get the state of the relay parent in the context of parachain + // processing auto opt_per_relay_parent = tryGetStateByRelayParent(relay_parent); if (!opt_per_relay_parent) { SL_TRACE( @@ -3739,12 +3778,14 @@ namespace kagome::parachain { const std::optional &assignment = per_relay_parent.assignment; + // Get the state of the remote peer auto peer_state = pm_->getPeerState(peer_id); if (!peer_state) { SL_TRACE(logger_, "Unknown peer. (peerd_id={})", peer_id); return; } + // Get the state of the collator const auto collator_state = peer_state->get().collator_state; if (!collator_state) { SL_TRACE(logger_, "Undeclared collator. (peerd_id={})", peer_id); @@ -3753,6 +3794,7 @@ namespace kagome::parachain { const ParachainId collator_para_id = collator_state->para_id; if (!assignment) { + // If the assignment is invalid, log a trace message and return SL_TRACE(logger_, "Invalid assignment. (peerd_id={}, collator={})", peer_id, @@ -3760,6 +3802,7 @@ namespace kagome::parachain { return; } + // Check for protocol mismatch if (relay_parent_mode && !prospective_candidate) { SL_WARN(logger_, "Protocol mismatch. (peer_id={})", peer_id); return; @@ -3769,15 +3812,20 @@ namespace kagome::parachain { utils::map(prospective_candidate, [](const auto &pair) { return std::cref(pair.first); }); + // Try to insert the advertisement auto insert_res = insertAdvertisement( peer_state->get(), relay_parent, relay_parent_mode, candidate_hash); if (insert_res.has_error()) { + // If there is an error inserting the advertisement, log a trace message + // and return SL_TRACE(logger_, "Insert advertisement error. (error={})", insert_res.error().message()); return; } + // Get the collator id and parachain id from the result of the advertisement + // insertion const auto &[collator_id, parachain_id] = insert_res.value(); if (!per_relay_parent.collations.hasSecondedSpace(relay_parent_mode)) { SL_TRACE(logger_, "Seconded limit reached."); @@ -3793,6 +3841,7 @@ namespace kagome::parachain { ch, parent_head_data_hash); + // If seconding is not allowed by backing, queue the advertisement if (!is_seconding_allowed) { SL_TRACE(logger_, "Seconding is not allowed by backing, queueing advertisement. " @@ -3813,6 +3862,7 @@ namespace kagome::parachain { } } + // Try to enqueue the collation if (auto result = enqueueCollation(per_relay_parent, relay_parent, para_id, diff --git a/core/parachain/validator/parachain_processor.hpp b/core/parachain/validator/parachain_processor.hpp index be68d105e1..84c06557fc 100644 --- a/core/parachain/validator/parachain_processor.hpp +++ b/core/parachain/validator/parachain_processor.hpp @@ -39,13 +39,26 @@ #include "primitives/event_types.hpp" #include "utils/non_copyable.hpp" #include "utils/safe_object.hpp" -#include "utils/weak_io_context.hpp" /** - * Parachain Processor is a class that is responsible for processing parachain - * blocks. + * The ParachainProcessorImpl class is responsible for handling the validation + * and processing of parachains in the network. It manages the lifecycle of + * parachains, including their creation, validation, and destruction. * - * It begins from the handling of view update event. + * The class contains methods for handling incoming streams of data, processing + * parachain blocks, and managing peer states. It also handles the validation of + * candidates for the parachain, including checking the validity of the erasure + * coding and the availability of data. + * + * In addition, the class manages the communication with + * other nodes in the network, sending and receiving messages related to the + * state of the parachains. It also handles the storage and retrieval of data + * related to the parachains. + * + * The class uses a variety of helper methods and + * data structures to perform its tasks, including a main pool handler for + * managing tasks, a logger for logging events, and various data structures for + * storing the state of the parachains and the peers in the network */ namespace kagome { class ThreadHandler; @@ -136,38 +149,103 @@ namespace kagome::parachain { std::shared_ptr prospective_parachains); ~ParachainProcessorImpl() = default; + /** + * @brief Prepares the Parachain Processor for operation. + * + * This method is responsible for setting up necessary configurations and + * initializations for the Parachain Processor. It should be called before + * the Parachain Processor starts processing parachain blocks. + * + * @return Returns true if the preparation is successful, false otherwise. + */ bool prepare(); + /** + * @brief Handles an incoming advertisement for a collation. + * + * @param pending_collation The CollationEvent representing the collation + * being advertised. + * @param prospective_candidate An optional pair containing the hash of the + * prospective candidate and the hash of the parent block. + */ void handleAdvertisement( network::CollationEvent &&pending_collation, std::optional> &&prospective_candidate); + + /** + * @ brief We should only process parachains if we are validator and we are + * @return outcome::result Returns an error if we cannot process the + * parachains. + */ outcome::result canProcessParachains() const; + /** + * @brief Handles an incoming collator. + * + * This function is called when a new collator is detected. It updates the + * internal state with the information about the new collator. + * + * @param peer_id The peer id of the collator. + * @param pubkey The public key of the collator. + * @param para_id The id of the parachain the collator is associated with. + */ void onIncomingCollator(const libp2p::peer::PeerId &peer_id, network::CollatorPublicKey pubkey, network::ParachainId para_id); /** - * @brief handle new stream from remote collator and open an outgoing - * collation stream to send notification to collator when it will be useful - * @param peer_id the peer id of the remote collator + * @brief Handles an incoming collation stream from a peer. + * + * @param peer_id The ID of the peer from which the collation stream is + * received. + * @param version The version of the collation protocol used in the stream. */ void onIncomingCollationStream(const libp2p::peer::PeerId &peer_id, network::CollationVersion version); + + /** + * @brief Handles an incoming validation stream from a peer. + * + * @param peer_id The ID of the peer from which the validation stream is + * received. + * @param version The version of the collation protocol used in the + * validation stream. + */ void onIncomingValidationStream(const libp2p::peer::PeerId &peer_id, network::CollationVersion version); + void onValidationProtocolMsg( const libp2p::peer::PeerId &peer_id, const network::VersionedValidatorProtocolMessage &message); + outcome::result OnFetchChunkRequest( const network::FetchChunkRequest &request); + outcome::result OnFetchAttestedCandidateRequest( const network::vstaging::AttestedCandidateRequest &request); + /** + * @brief Fetches the list of backed candidates for a given relay parent. + * + * @param relay_parent The hash of the relay chain block where the parachain + * block is attached. + * @return std::vector A vector of backed + * candidates for the given relay parent. + */ std::vector getBackedCandidates( const RelayHash &relay_parent) override; + + /** + * @brief Fetches the Proof of Validity (PoV) for a given candidate. + * + * @param candidate_hash The hash of the candidate for which the PoV is to + * be fetched. + * @return network::ResponsePov The PoV associated with the given candidate + * hash. + */ network::ResponsePov getPov(CandidateHash &&candidate_hash); + auto getAvStore() { return av_store_; } @@ -232,6 +310,11 @@ namespace kagome::parachain { boost::variant; using SignedFullStatementWithPVD = IndexedAndSigned; + + /** + * @brief Converts a SignedFullStatementWithPVD to an IndexedAndSigned + * CompactStatement. + */ IndexedAndSigned signed_to_compact( const SignedFullStatementWithPVD &s) const { const Hash h = candidateHashFrom(getPayload(s)); @@ -258,6 +341,11 @@ namespace kagome::parachain { }; } + /** + * @struct RelayParentState + * @brief This structure encapsulates the state of a relay parent in the + * context of parachain processing. + */ struct RelayParentState { ProspectiveParachainsModeOpt prospective_parachains_mode; std::optional assignment; @@ -279,6 +367,11 @@ namespace kagome::parachain { std::unordered_set backed_hashes{}; }; + /** + * @struct PerCandidateState + * @brief This structure represents the state of a candidate in the + * parachain validation process. + */ struct PerCandidateState { runtime::PersistedValidationData persisted_validation_data; bool seconded_locally; @@ -301,17 +394,66 @@ namespace kagome::parachain { /* * Validation. */ + + /** + * @brief Checks if an advertisement can be processed. + * + * This function checks if an advertisement can be processed based on the + * relay parent and the peer id. It ensures that the relay parent is in the + * current view and that the advertisement has not been processed before. If + * the advertisement can be processed, it is added to the set of processed + * advertisements. + */ outcome::result advCanBeProcessed( const primitives::BlockHash &relay_parent, const libp2p::peer::PeerId &peer_id); + + /** + * @brief Validates a candidate for a parachain block. + * + * @param candidate The candidate receipt for the parachain block. + * @param pov The parachain block that needs to be validated. + * @param pvd The persisted validation data required for validation. + * + * @return An outcome::result containing the validation result. If the + * validation is successful, the result will contain a Pvf::Result. If the + * validation fails, the result will contain an error. + */ outcome::result validateCandidate( const network::CandidateReceipt &candidate, const network::ParachainBlock &pov, runtime::PersistedValidationData &&pvd); + /** + * @brief Validates the erasure coding of the provided data. + * + * This function takes the available data from a runtime and the number of + * validators, and validates the erasure coding of the data. + * + * @param validating_data The available data from a runtime that needs to be + * validated. + * @param n_validators The number of validators that will be used for the + * validation process. + * @return Returns a vector of erasure chunks if the validation is + * successful, otherwise returns an error. + */ outcome::result> validateErasureCoding( const runtime::AvailableData &validating_data, size_t n_validators); + /** + * @brief This function is a template function that validates a candidate + * asynchronously. + * + * @tparam kMode The type of validation task to be performed. + * + * @param candidate The candidate receipt to be validated. + * @param pov The parachain block to be validated. + * @param pvd The persisted validation data to be used in the validation + * process. + * @param peer_id The peer ID of the node performing the validation. + * @param relay_parent The block hash of the relay parent. + * @param n_validators The number of validators in the network. + */ template void validateAsync(network::CandidateReceipt &&candidate, network::ParachainBlock &&pov, @@ -320,20 +462,72 @@ namespace kagome::parachain { const primitives::BlockHash &relay_parent, size_t n_validators); + /** + * @brief This function is used to make a candidate available for + * validation. + * + * @tparam kMode The type of validation task to be performed. It can be + * either 'Second' or 'Attest'. + * @param peer_id The ID of the peer that the candidate is being made + * available to. + * @param candidate_hash The hash of the candidate that is being made + * available. + * @param result The result of the validation and seconding process. + */ template void makeAvailable(const libp2p::peer::PeerId &peer_id, const primitives::BlockHash &candidate_hash, ValidateAndSecondResult &&result); + + /** + * @brief Handles a statement related to a specific relay parent. + * + * This function is responsible for processing a signed statement associated + * with a specific relay parent. The statement is provided in the form of a + * SignedFullStatementWithPVD object, which includes the payload and + * signature. The relay parent is identified by its block hash. + * + * @param relay_parent The block hash of the relay parent associated with + * the statement. + * @param statement The signed statement to be processed, encapsulated in a + * SignedFullStatementWithPVD object. + */ void handleStatement(const primitives::BlockHash &relay_parent, const SignedFullStatementWithPVD &statement); + + /** + * @brief Processes a bitfield distribution message. + * + * This function is responsible for handling a bitfield distribution message + * received from the network. The bitfield distribution message contains + * information about the availability of pieces of data in the network. + */ void process_bitfield_distribution( const network::BitfieldDistributionMessage &val); + void process_legacy_statement( const libp2p::peer::PeerId &peer_id, const network::StatementDistributionMessage &msg); + + /** + * @brief Processes a vstaging statement. + * + * This function is responsible for processing a vstaging statement received + * from a peer. It handles different types of messages: + * BackedCandidateAcknowledgement, BackedCandidateManifest, and + * StatementDistributionMessageStatement. Depending on the type of the + * message, it performs different actions such as handling incoming + * manifest, sending acknowledgement and statement messages, fetching + * attested candidate response, inserting statement to the store, and + * circulating the statement. + * + * @param peer_id The id of the peer from which the statement is received. + * @param msg The vstaging statement message to be processed. + */ void process_vstaging_statement( const libp2p::peer::PeerId &peer_id, const network::vstaging::StatementDistributionMessage &msg); + void send_backing_fresh_statements( const ConfirmedCandidate &confirmed, const RelayHash &relay_parent, @@ -389,10 +583,36 @@ namespace kagome::parachain { void send_to_validators_group( const RelayHash &relay_parent, const std::deque &messages); + + /** + * @brief Circulates a statement to the validators group. + * @param relay_parent The hash of the relay parent block. This is used to + * identify the group of validators to which the statement should be sent. + * @param statement The statement to be circulated. This is an indexed and + * signed compact statement. + */ void circulate_statement( const RelayHash &relay_parent, const IndexedAndSigned &statement); + /** + * @brief Inserts an advertisement into the peer's data. + * + * This function is responsible for inserting an advertisement into the + * peer's data. It performs several checks to ensure that the advertisement + * can be inserted, such as checking if the collator is declared, if the + * relay parent is in the implicit view, and if there are any duplicates. If + * all checks pass, the advertisement is inserted and the function returns + * the collator ID and parachain ID. + * + * @param peer_data The peer's data where the advertisement will be + * inserted. + * @param on_relay_parent The hash of the relay parent block. + * @param relay_parent_mode The mode of the relay parent. + * @param candidate_hash The hash of the candidate block. + * @return A pair containing the collator ID and the parachain ID if the + * advertisement was inserted successfully, or an error otherwise. + */ outcome::result> insertAdvertisement( network::PeerState &peer_data, const RelayHash &relay_parent, @@ -595,6 +815,14 @@ namespace kagome::parachain { */ RelayParentState &storeStateByRelayParent( const primitives::BlockHash &relay_parent, RelayParentState &&val); + + /** + * @brief Sends peer messages corresponding for a given relay parent. + * + * @param peer_id Optional reference to the PeerId of the peer to send the + * messages to. + * @param relay_parent The hash of the relay parent block + */ void send_peer_messages_for_relay_parent( std::optional> peer_id,