Skip to content

Commit 305b2f1

Browse files
committed
refactor: streamline submission clearing process
1 parent f908969 commit 305b2f1

1 file changed

Lines changed: 145 additions & 106 deletions

File tree

src/commands/multi_block/monitor.rs

Lines changed: 145 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ where
112112
prometheus::set_balance(account_info.data.free as f64);
113113

114114
let current_block_round = state.round;
115-
let mut rounds_to_remove = Vec::new();
115+
let rounds_to_remove = Vec::new();
116116
let mut rounds_to_potentially_clear = Vec::new();
117117

118118
// Scope to release lock quickly
@@ -128,111 +128,18 @@ where
128128
} // Lock released
129129

130130
// This checking logic runs on EVERY block
131-
if !rounds_to_potentially_clear.is_empty() {
132-
log::debug!(target: LOG_TARGET, "Checking status of PAST rounds (< {}): {:?}", current_block_round, rounds_to_potentially_clear.iter().map(|(r,_,_)| r).collect::<Vec<_>>());
133-
134-
// Use finalized state for checking past rounds
135-
let get_finalized_storage = async {
136-
let finalized_hash = client.rpc().chain_get_finalized_head().await?;
137-
utils::storage_at(Some(finalized_hash), client.chain_api()).await
138-
};
139-
let storage_finalized = match get_finalized_storage.await {
140-
Ok(s) => s,
141-
Err::<_, Error>(e) => {
142-
log::warn!(target: LOG_TARGET, "Failed to get finalized storage state for checking old rounds: {:?}. Skipping check.", e);
143-
// Skip checking old rounds this iteration if we can't get finalized state
144-
rounds_to_potentially_clear.clear(); // Clear the list to avoid processing below
145-
continue; // Skip the rest of the checks for this block
146-
}
147-
};
148-
149-
for (round_to_check, n_pages, submitted_score) in rounds_to_potentially_clear {
150-
// Check if our submission metadata still exists for this PAST round
151-
let maybe_submission_metadata = storage_finalized
152-
.fetch(
153-
&runtime::storage()
154-
.multi_block_signed()
155-
.submission_metadata_storage(round_to_check, signer.account_id()),
156-
)
157-
.await?;
158-
159-
if maybe_submission_metadata.is_none() {
160-
log::debug!(target: LOG_TARGET, "Submission metadata for past round {} gone. Removing from tracking.", round_to_check);
161-
rounds_to_remove.push(round_to_check);
162-
continue; // Move to the next round to check
163-
}
164-
165-
// Metadata exists for this PAST round. Check phase and potential winning solution.
166-
let maybe_round_phase = storage_finalized
167-
.fetch(&runtime::storage().multi_block().current_phase())
168-
.await?;
169-
170-
let mut should_clear = false;
171-
let mut clear_reason = "";
172-
173-
match maybe_round_phase {
174-
Some(Phase::SignedValidation(_)) => {
175-
// Check if a better solution was confirmed during its validation phase
176-
let sorted_scores = storage_finalized
177-
.fetch_or_default(
178-
&runtime::storage()
179-
.multi_block_signed()
180-
.sorted_scores(round_to_check),
181-
)
182-
.await?;
183-
if let Some((_, winning_score)) = sorted_scores.0.first() {
184-
if score_passes_strategy(
185-
winning_score.0, // Access the inner ElectionScore from Static<ElectionScore>
186-
submitted_score,
187-
SubmissionStrategy::IfLeading,
188-
) && winning_score.0 != submitted_score
189-
{
190-
should_clear = true;
191-
clear_reason =
192-
"Better solution validated during its SignedValidation phase";
193-
} else {
194-
log::trace!(target: LOG_TARGET, "Past round {} was in SignedValidation, but no better score confirmed.", round_to_check);
195-
}
196-
} else {
197-
log::trace!(target: LOG_TARGET, "Past round {} was in SignedValidation, but SortedScores is empty.", round_to_check);
198-
}
199-
}
200-
Some(Phase::Signed(_)) => {
201-
// Still in Signed phase, should not happen if round_to_check < current_block_round and finalized state is used.
202-
log::trace!(target: LOG_TARGET, "Past round {} unexpectedly found in Signed phase in finalized state.", round_to_check);
203-
}
204-
Some(_) | None => {
205-
should_clear = true;
206-
clear_reason = "Phase is past Signed/SignedValidation or round gone, and metadata still exists";
207-
}
208-
}
209-
210-
// Attempt clearing if needed
211-
if should_clear {
212-
log::info!(target: LOG_TARGET, "Submission for past round {} detected as DISCARDED (Reason: {}). Attempting to clear.", round_to_check, clear_reason);
213-
match clear_submission(
214-
config.listen,
215-
&client,
216-
signer.clone(),
217-
round_to_check,
218-
n_pages,
219-
)
220-
.await
221-
{
222-
Ok(_) => {
223-
log::info!(target: LOG_TARGET, "Successfully cleared submission for past round {}", round_to_check);
224-
rounds_to_remove.push(round_to_check); // Mark for removal
225-
}
226-
Err(e) => {
227-
log::error!(target: LOG_TARGET, "Failed to clear submission for past round {}: {:?}. Will retry.", round_to_check, e);
228-
// Don't remove, retry next block
229-
}
230-
}
231-
} else {
232-
log::trace!(target: LOG_TARGET, "Conditions not met to clear past round {}.", round_to_check);
233-
}
234-
}
235-
}
131+
let rounds_to_potentially_clear = {
132+
let submitted_data = submitted_rounds.lock().await;
133+
collect_past_rounds_to_clear(&submitted_data, current_block_round)
134+
};
135+
check_and_clear_discarded_submissions(
136+
&client,
137+
&config,
138+
&signer,
139+
rounds_to_potentially_clear,
140+
&submitted_rounds,
141+
)
142+
.await?;
236143

237144
// Remove successfully cleared or confirmed non-existent rounds from tracking
238145
if !rounds_to_remove.is_empty() {
@@ -758,3 +665,135 @@ async fn clear_submission(
758665

759666
Ok(())
760667
}
668+
669+
async fn check_and_clear_discarded_submissions(
670+
client: &Client,
671+
config: &ExperimentalMultiBlockMonitorConfig,
672+
signer: &Signer,
673+
rounds_to_potentially_clear: Vec<(u32, u32, ElectionScore)>,
674+
submitted_rounds: &Arc<Mutex<HashMap<u32, (u32, ElectionScore)>>>,
675+
) -> Result<(), Error> {
676+
if rounds_to_potentially_clear.is_empty() {
677+
return Ok(());
678+
}
679+
680+
log::debug!(
681+
target: LOG_TARGET,
682+
"Checking status of PAST rounds: {:?}",
683+
rounds_to_potentially_clear.iter().map(|(r,_,_)| r).collect::<Vec<_>>()
684+
);
685+
686+
let get_finalized_storage = async {
687+
let finalized_hash = client.rpc().chain_get_finalized_head().await?;
688+
utils::storage_at(Some(finalized_hash), client.chain_api()).await
689+
};
690+
let storage_finalized = match get_finalized_storage.await {
691+
Ok(s) => s,
692+
Err(e) => {
693+
log::warn!(target: LOG_TARGET, "Failed to get finalized storage state for checking old rounds: {:?}. Skipping check.", e);
694+
return Ok(());
695+
}
696+
};
697+
698+
let mut rounds_to_remove = Vec::new();
699+
700+
for (round_to_check, n_pages, submitted_score) in rounds_to_potentially_clear {
701+
let maybe_submission_metadata = storage_finalized
702+
.fetch(
703+
&runtime::storage()
704+
.multi_block_signed()
705+
.submission_metadata_storage(round_to_check, signer.account_id()),
706+
)
707+
.await?;
708+
709+
if maybe_submission_metadata.is_none() {
710+
log::debug!(target: LOG_TARGET, "Submission metadata for past round {} gone. Removing from tracking.", round_to_check);
711+
rounds_to_remove.push(round_to_check);
712+
continue;
713+
}
714+
715+
let maybe_round_phase = storage_finalized
716+
.fetch(&runtime::storage().multi_block().current_phase())
717+
.await?;
718+
719+
let mut should_clear = false;
720+
let mut clear_reason = "";
721+
722+
match maybe_round_phase {
723+
Some(Phase::SignedValidation(_)) => {
724+
let sorted_scores = storage_finalized
725+
.fetch_or_default(
726+
&runtime::storage()
727+
.multi_block_signed()
728+
.sorted_scores(round_to_check),
729+
)
730+
.await?;
731+
if let Some((_, winning_score)) = sorted_scores.0.first() {
732+
if score_passes_strategy(
733+
winning_score.0,
734+
submitted_score,
735+
SubmissionStrategy::IfLeading,
736+
) && winning_score.0 != submitted_score
737+
{
738+
should_clear = true;
739+
clear_reason =
740+
"Better solution validated during its SignedValidation phase";
741+
}
742+
}
743+
}
744+
Some(Phase::Signed(_)) => {}
745+
Some(_) | None => {
746+
should_clear = true;
747+
clear_reason = "Phase is past Signed/SignedValidation or round gone, and metadata still exists";
748+
}
749+
}
750+
751+
if should_clear {
752+
log::info!(target: LOG_TARGET, "Submission for past round {} detected as DISCARDED (Reason: {}). Attempting to clear.", round_to_check, clear_reason);
753+
match clear_submission(
754+
config.listen,
755+
client,
756+
signer.clone(),
757+
round_to_check,
758+
n_pages,
759+
)
760+
.await
761+
{
762+
Ok(_) => {
763+
log::info!(target: LOG_TARGET, "Successfully cleared submission for past round {}", round_to_check);
764+
rounds_to_remove.push(round_to_check);
765+
}
766+
Err(e) => {
767+
log::error!(target: LOG_TARGET, "Failed to clear submission for past round {}: {:?}. Will retry.", round_to_check, e);
768+
}
769+
}
770+
}
771+
}
772+
773+
if !rounds_to_remove.is_empty() {
774+
let mut submitted_data = submitted_rounds.lock().await;
775+
for round_index in rounds_to_remove {
776+
if submitted_data.remove(&round_index).is_some() {
777+
log::info!(target: LOG_TARGET, "Removed past round {} from local tracking.", round_index);
778+
}
779+
}
780+
}
781+
782+
Ok(())
783+
}
784+
785+
fn collect_past_rounds_to_clear(
786+
submitted_rounds: &HashMap<u32, (u32, ElectionScore)>,
787+
current_block_round: u32,
788+
) -> Vec<(u32, u32, ElectionScore)> {
789+
submitted_rounds
790+
.iter()
791+
.filter_map(|(&round_to_check, &(n_pages, submitted_score))| {
792+
if round_to_check < current_block_round {
793+
Some((round_to_check, n_pages, submitted_score))
794+
} else {
795+
None
796+
}
797+
})
798+
.collect()
799+
}

0 commit comments

Comments
 (0)