diff --git a/core/parachain/approval/approval.hpp b/core/parachain/approval/approval.hpp index 3fc0df0392..80fe4081c8 100644 --- a/core/parachain/approval/approval.hpp +++ b/core/parachain/approval/approval.hpp @@ -208,6 +208,9 @@ namespace kagome::parachain::approval { inline bool is_local_approval(const ApprovalStateTransition &val) { return boost::get(&val) != nullptr; } + inline bool is_remote_approval(const ApprovalStateTransition &val) { + return boost::get(&val) != nullptr; + } /// Metadata about a block which is now live in the approval protocol. struct BlockApprovalMeta { diff --git a/core/parachain/approval/approval_distribution.cpp b/core/parachain/approval/approval_distribution.cpp index 2866a803fc..5fb971799a 100644 --- a/core/parachain/approval/approval_distribution.cpp +++ b/core/parachain/approval/approval_distribution.cpp @@ -3037,6 +3037,37 @@ namespace kagome::parachain { status.block_tick, tick_now, status.required_tranches); + + if (is_approved && is_remote_approval(transition)) { + for (const auto &[fork_block_hash, fork_approval_entry] : + candidate_entry.block_assignments) { + if (fork_block_hash == block_hash) { + continue; + } + + bool assigned_on_fork_block = false; + if (validator_index) { + assigned_on_fork_block = + fork_approval_entry.is_assigned(*validator_index); + } + + if (!wakeup_for(*fork_block_hash, candidate_hash) + && !fork_approval_entry.is_approved() && assigned_on_fork_block) { + auto opt_fork_block_entry = storedBlockEntries().get(fork_block_hash); + if (!opt_fork_block_entry) { + SL_TRACE(logger_, + "Failed to load block entry. (fork_block_hash={})", + fork_block_hash); + } else { + runScheduleWakeup(fork_block_hash, + opt_fork_block_entry->get().block_number, + candidate_hash, + tick_now + 1); + } + } + } + } + if (approval::is_local_approval(transition) || newly_approved || (already_approved_by && !*already_approved_by)) { BOOST_ASSERT(storedCandidateEntries().get(candidate_hash)->get() @@ -3109,6 +3140,12 @@ namespace kagome::parachain { target_block[candidate_hash].emplace_back(tick, std::move(handle)); } + bool ApprovalDistribution::wakeup_for(const primitives::BlockHash &block_hash, + const CandidateHash &candidate_hash) { + auto it = active_tranches_.find(block_hash); + return it != active_tranches_.end() && it->second.contains(candidate_hash); + } + void ApprovalDistribution::handleTranche( const primitives::BlockHash &block_hash, primitives::BlockNumber block_number, diff --git a/core/parachain/approval/approval_distribution.hpp b/core/parachain/approval/approval_distribution.hpp index 0532933597..c03ca5581f 100644 --- a/core/parachain/approval/approval_distribution.hpp +++ b/core/parachain/approval/approval_distribution.hpp @@ -136,7 +136,7 @@ namespace kagome::parachain { } /// Whether a validator is already assigned. - bool is_assigned(ValidatorIndex validator_index) { + bool is_assigned(ValidatorIndex validator_index) const { if (validator_index < assignments.bits.size()) { return assignments.bits[validator_index]; } @@ -233,8 +233,9 @@ namespace kagome::parachain { CandidateEntry(const network::CandidateReceipt &receipt, SessionIndex session_index, size_t approvals_size) - : CandidateEntry( - HashedCandidateReceipt{receipt}, session_index, approvals_size) {} + : CandidateEntry(HashedCandidateReceipt{receipt}, + session_index, + approvals_size) {} std::optional> approval_entry( const network::RelayHash &relay_hash) { @@ -792,6 +793,9 @@ namespace kagome::parachain { void scheduleTranche(const primitives::BlockHash &head, BlockImportedCandidates &&candidate); + bool wakeup_for(const primitives::BlockHash &block_hash, + const CandidateHash &candidate_hash); + void runDistributeAssignment( const approval::IndirectAssignmentCertV2 &indirect_cert, const scale::BitVec &candidate_indices,