From a5c3266c5fc53e255ebb1634f3b8171b42e117c7 Mon Sep 17 00:00:00 2001 From: Ahmad Kaouk Date: Tue, 31 Mar 2026 15:03:56 +0200 Subject: [PATCH] fix: bound rewards window processing per block --- .../src/benchmarking.rs | 55 +++++- .../external-validators-rewards/src/lib.rs | 185 +++++++++--------- .../external-validators-rewards/src/tests.rs | 74 ++++--- .../src/weights.rs | 22 +++ 4 files changed, 202 insertions(+), 134 deletions(-) diff --git a/operator/pallets/external-validators-rewards/src/benchmarking.rs b/operator/pallets/external-validators-rewards/src/benchmarking.rs index 107bd29b..0b01fb8a 100644 --- a/operator/pallets/external-validators-rewards/src/benchmarking.rs +++ b/operator/pallets/external-validators-rewards/src/benchmarking.rs @@ -23,7 +23,7 @@ use crate::Pallet as ExternalValidatorsRewards; use { crate::types::BenchmarkHelper, frame_benchmarking::{account, v2::*, BenchmarkError}, - frame_support::traits::{Currency, EnsureOrigin}, + frame_support::traits::{Currency, EnsureOrigin, Hooks}, }; const SEED: u32 = 0; @@ -108,12 +108,44 @@ mod benchmarks { // on_initialize: unsent queue is empty (2 reads for head+tail) #[benchmark] fn process_unsent_reward_eras_empty() -> Result<(), BenchmarkError> { - // Ensure queue is empty (default state: head == tail == 0) - assert!(ExternalValidatorsRewards::::unsent_queue_is_empty()); + // Exercise the "empty slot at head" fallback path that returns the empty weight. + >::put(0); + >::put(1); + frame_system::Pallet::::set_block_number(1u32.into()); #[block] { - ExternalValidatorsRewards::::process_unsent_reward_eras(); + as Hooks< + frame_system::pallet_prelude::BlockNumberFor, + >>::on_initialize(1u32.into()); + } + + Ok(()) + } + + #[benchmark] + fn process_closed_windows_idle() -> Result<(), BenchmarkError> { + pallet_timestamp::Now::::put(35_000u64); + + #[block] + { + ExternalValidatorsRewards::::process_closed_windows(35, 0, 10); + } + + Ok(()) + } + + #[benchmark] + fn process_closed_windows_processed() -> Result<(), BenchmarkError> { + frame_system::Pallet::::set_block_number(0u32.into()); + T::BenchmarkHelper::setup(); + setup_window_reward_state::(20, 42); + >::put(20); + pallet_timestamp::Now::::put(35_000u64); + + #[block] + { + ExternalValidatorsRewards::::process_closed_windows(35, 0, 10); } Ok(()) @@ -123,10 +155,13 @@ mod benchmarks { #[benchmark] fn process_unsent_reward_eras_expired() -> Result<(), BenchmarkError> { push_unsent_entry::(999, 99, 10); + frame_system::Pallet::::set_block_number(1u32.into()); #[block] { - ExternalValidatorsRewards::::process_unsent_reward_eras(); + as Hooks< + frame_system::pallet_prelude::BlockNumberFor, + >>::on_initialize(1u32.into()); } // Entry should have been removed @@ -143,10 +178,13 @@ mod benchmarks { setup_window_reward_state::(0, 42); push_unsent_entry::(0, 0, 10); + frame_system::Pallet::::set_block_number(1u32.into()); #[block] { - ExternalValidatorsRewards::::process_unsent_reward_eras(); + as Hooks< + frame_system::pallet_prelude::BlockNumberFor, + >>::on_initialize(1u32.into()); } assert!(ExternalValidatorsRewards::::unsent_queue_is_empty()); @@ -162,10 +200,13 @@ mod benchmarks { setup_window_reward_state::(0, 42); push_unsent_entry::(0, 0, 10); + frame_system::Pallet::::set_block_number(1u32.into()); #[block] { - ExternalValidatorsRewards::::process_unsent_reward_eras(); + as Hooks< + frame_system::pallet_prelude::BlockNumberFor, + >>::on_initialize(1u32.into()); } Ok(()) diff --git a/operator/pallets/external-validators-rewards/src/lib.rs b/operator/pallets/external-validators-rewards/src/lib.rs index 97d36525..408073e1 100644 --- a/operator/pallets/external-validators-rewards/src/lib.rs +++ b/operator/pallets/external-validators-rewards/src/lib.rs @@ -193,7 +193,16 @@ pub mod pallet { #[pallet::hooks] impl Hooks> for Pallet { fn on_initialize(_n: frame_system::pallet_prelude::BlockNumberFor) -> Weight { - Self::process_unsent_reward_eras() + let head = UnsentRewardHead::::get(); + let tail = UnsentRewardTail::::get(); + + if head != tail { + return Self::process_unsent_reward_eras_from(head, tail); + } + + let (genesis, interval) = Self::rewards_window_config(); + let now = Self::now_seconds(); + Self::process_closed_windows(now, genesis, interval) } fn on_runtime_upgrade() -> Weight { @@ -210,9 +219,6 @@ pub mod pallet { // in-flight era is not partially accounted under mixed semantics. WindowModeStartsAtEra::::put(cutover_era); NextWindowToSubmit::::kill(); - for slot in 0..UNSENT_QUEUE_CAPACITY { - UnsentRewardWindow::::remove(slot); - } UnsentRewardHead::::put(0); UnsentRewardTail::::put(0); STORAGE_VERSION.put::>(); @@ -223,7 +229,7 @@ pub mod pallet { cutover_era, ); - T::DbWeight::get().reads_writes(2, 69) + T::DbWeight::get().reads_writes(2, 5) } #[cfg(feature = "try-runtime")] @@ -257,7 +263,7 @@ pub mod pallet { "Window cutover era was not initialized correctly", ); frame_support::ensure!( - NextWindowToSubmit::::get() == 0, + NextWindowToSubmit::::get().is_none(), "NextWindowToSubmit was not reset", ); frame_support::ensure!( @@ -268,10 +274,6 @@ pub mod pallet { UnsentRewardTail::::get() == 0, "UnsentRewardTail was not reset", ); - frame_support::ensure!( - UnsentRewardWindow::::iter().next().is_none(), - "UnsentRewardWindow entries were not cleared", - ); Ok(()) } @@ -429,7 +431,7 @@ pub mod pallet { /// Pointer to the next window start to submit. #[pallet::storage] - pub type NextWindowToSubmit = StorageValue<_, u32, ValueQuery>; + pub type NextWindowToSubmit = StorageValue<_, u32, OptionQuery>; /// Era at which window mode becomes active after a live upgrade. /// `0` means window mode is active immediately (fresh chains/tests). @@ -495,19 +497,6 @@ pub mod pallet { WindowOperatorPoints::::remove(window_start); } - fn earliest_window_with_state() -> Option { - let mut earliest = None; - - for window in WindowOperatorPoints::::iter_keys() { - earliest = Some(earliest.map_or(window, |current: u32| current.min(window))); - } - for window in WindowInflationAmount::::iter_keys() { - earliest = Some(earliest.map_or(window, |current: u32| current.min(window))); - } - - earliest - } - fn window_rewards_info( window_start: u32, window_index: u32, @@ -538,12 +527,21 @@ pub mod pallet { genesis: u32, interval: u32, ) { - if inflation_amount == 0 || era_end <= era_start { + if era_end <= era_start { + return; + } + + let mut window_start = Self::window_start_for(era_start, genesis, interval); + + if NextWindowToSubmit::::get().is_none() { + NextWindowToSubmit::::put(window_start); + } + + if inflation_amount == 0 { return; } let era_duration = era_end.saturating_sub(era_start).max(1); - let mut window_start = Self::window_start_for(era_start, genesis, interval); let mut allocated = 0u128; let mut last_window = None; @@ -579,85 +577,85 @@ pub mod pallet { } } - fn process_closed_windows(now: u32, genesis: u32, interval: u32) { - let mut next_window = NextWindowToSubmit::::get(); + pub(crate) fn process_closed_windows(now: u32, genesis: u32, interval: u32) -> Weight { + let Some(mut next_window) = NextWindowToSubmit::::get() else { + return T::WeightInfo::process_closed_windows_idle(); + }; - if next_window == 0 { - next_window = Self::earliest_window_with_state().unwrap_or_else(|| { - Self::window_start_for(now.saturating_sub(interval), genesis, interval) - }); + if next_window.saturating_add(interval) > now { + return T::WeightInfo::process_closed_windows_idle(); } - while next_window.saturating_add(interval) <= now { - let inflation_amount = WindowInflationAmount::::get(next_window); - let operator_points = WindowOperatorPoints::::get(next_window); - let total_points: u128 = operator_points.values().map(|p| *p as u128).sum(); - let window_index = Self::window_index_for(next_window, genesis, interval); + let inflation_amount = WindowInflationAmount::::get(next_window); + let operator_points = WindowOperatorPoints::::get(next_window); + let total_points: u128 = operator_points.values().map(|p| *p as u128).sum(); + let window_index = Self::window_index_for(next_window, genesis, interval); - if total_points == 0 || inflation_amount == 0 { - Self::clear_window(next_window); - Self::deposit_event(Event::RewardsWindowSkipped { + if total_points == 0 || inflation_amount == 0 { + Self::clear_window(next_window); + Self::deposit_event(Event::RewardsWindowSkipped { + window_start: next_window, + window_index, + }); + next_window = next_window.saturating_add(interval); + NextWindowToSubmit::::put(next_window); + return T::WeightInfo::process_closed_windows_processed(); + } + + let utils = RewardsPeriodUtils { + period_index: window_index, + period_start: next_window, + duration: interval, + total_points, + individual_points: operator_points.into_iter().collect(), + inflation_amount, + }; + + match Self::send_rewards_message(&utils) { + Some(message_id) => { + Self::deposit_event(Event::RewardsWindowSubmitted { + message_id, + window_start: next_window, + window_index, + total_points, + inflation_amount, + }); + } + None => { + Self::deposit_event(Event::RewardsWindowSubmissionFailed { window_start: next_window, window_index, }); - next_window = next_window.saturating_add(interval); - continue; - } - let utils = RewardsPeriodUtils { - period_index: window_index, - period_start: next_window, - duration: interval, - total_points, - individual_points: operator_points.into_iter().collect(), - inflation_amount, - }; + let queued_window = QueuedRewardsWindow { + window_start: next_window, + window_index, + duration: interval, + }; - match Self::send_rewards_message(&utils) { - Some(message_id) => { - Self::deposit_event(Event::RewardsWindowSubmitted { - message_id, - window_start: next_window, - window_index, - total_points, - inflation_amount, - }); + if Self::unsent_queue_push(queued_window) { + next_window = next_window.saturating_add(interval); + NextWindowToSubmit::::put(next_window); + return T::WeightInfo::process_closed_windows_processed(); } - None => { - Self::deposit_event(Event::RewardsWindowSubmissionFailed { - window_start: next_window, - window_index, - }); - let queued_window = QueuedRewardsWindow { - window_start: next_window, - window_index, - duration: interval, - }; - - if Self::unsent_queue_push(queued_window) { - next_window = next_window.saturating_add(interval); - continue; - } - - log::error!( - target: "ext_validators_rewards", - "Unsent reward queue full, cannot enqueue window {}", - next_window, - ); - Self::deposit_event(Event::UnsentWindowQueueFull { - window_start: next_window, - window_index, - }); - break; - } + log::error!( + target: "ext_validators_rewards", + "Unsent reward queue full, cannot enqueue window {}", + next_window, + ); + Self::deposit_event(Event::UnsentWindowQueueFull { + window_start: next_window, + window_index, + }); + return T::WeightInfo::process_closed_windows_processed(); } - - Self::clear_window(next_window); - next_window = next_window.saturating_add(interval); } + Self::clear_window(next_window); + next_window = next_window.saturating_add(interval); NextWindowToSubmit::::put(next_window); + T::WeightInfo::process_closed_windows_processed() } /// Reward validators. Does not check if the validators are valid, caller needs to make sure of that. @@ -794,10 +792,7 @@ pub mod pallet { /// Process at most one unsent reward window per block. /// On failure the head pointer advances to the next entry so a single /// stuck window does not block retries for subsequent windows. - pub(crate) fn process_unsent_reward_eras() -> Weight { - let head = UnsentRewardHead::::get(); - let tail = UnsentRewardTail::::get(); - + fn process_unsent_reward_eras_from(head: u32, tail: u32) -> Weight { if head == tail { return T::WeightInfo::process_unsent_reward_eras_empty(); } @@ -1284,8 +1279,6 @@ pub mod pallet { T::WeightInfo::on_era_end(), DispatchClass::Mandatory, ); - - Self::process_closed_windows(now, genesis, interval); } } } diff --git a/operator/pallets/external-validators-rewards/src/tests.rs b/operator/pallets/external-validators-rewards/src/tests.rs index ae173c76..5708b84a 100644 --- a/operator/pallets/external-validators-rewards/src/tests.rs +++ b/operator/pallets/external-validators-rewards/src/tests.rs @@ -25,6 +25,13 @@ use { sp_core::H160, }; +fn run_rewards_initialize() { + let next_block = System::block_number() + 1; + System::set_block_number(next_block); + Timestamp::set_timestamp(Timestamp::get() + BLOCK_TIME); + let _ = as Hooks>::on_initialize(next_block); +} + #[test] fn basic_setup_works() { new_test_ext().execute_with(|| { @@ -82,22 +89,13 @@ fn runtime_upgrade_schedules_window_mode_for_next_era_and_resets_retry_state() { StorageVersion::new(1).put::>(); crate::WindowModeStartsAtEra::::put(0); crate::NextWindowToSubmit::::put(123); - crate::UnsentRewardWindow::::insert( - 5, - crate::QueuedRewardsWindow { - window_start: 100, - window_index: 10, - duration: 10, - }, - ); crate::UnsentRewardHead::::put(5); crate::UnsentRewardTail::::put(9); let _ = as Hooks>::on_runtime_upgrade(); assert_eq!(crate::WindowModeStartsAtEra::::get(), 8); - assert_eq!(crate::NextWindowToSubmit::::get(), 0); - assert_eq!(crate::UnsentRewardWindow::::iter().count(), 0); + assert_eq!(crate::NextWindowToSubmit::::get(), None); assert_eq!(crate::UnsentRewardHead::::get(), 0); assert_eq!(crate::UnsentRewardTail::::get(), 0); assert_eq!( @@ -188,7 +186,7 @@ fn transition_era_on_era_end_is_skipped_before_cutover() { "transition era should not emit window-processing events before cutover" ); assert_eq!(crate::WindowInflationAmount::::iter().count(), 0); - assert_eq!(crate::NextWindowToSubmit::::get(), 0); + assert_eq!(crate::NextWindowToSubmit::::get(), None); }) } @@ -246,6 +244,8 @@ fn window_mode_submits_closed_windows_and_advances_pointer() { run_to_block(15); // now = 45s, window [30,40) is closed ExternalValidatorsRewards::on_era_end(1); + run_rewards_initialize(); + run_rewards_initialize(); // Inflation is 42 (default). After 20% treasury split: rewards_amount = 34. // Era spans 20s to 45s = 25s. Window [20,30) overlap = 10s, [30,40) overlap = 10s, @@ -267,7 +267,7 @@ fn window_mode_submits_closed_windows_and_advances_pointer() { assert_eq!( pallet_external_validators_rewards::NextWindowToSubmit::::get(), - 40 + Some(40) ); assert!( pallet_external_validators_rewards::WindowOperatorPoints::::get(30).is_empty() @@ -311,7 +311,7 @@ fn window_mode_era_inflation_split_across_multiple_windows() { ExternalValidatorsRewards::note_block_author(H160::from_low_u64_be(1)); } - // on_era_end allocates inflation across windows then processes closed ones. + // on_era_end allocates inflation across windows; on_initialize submits closed ones. // Era spans from 5s to now=35s (30s duration). // Window overlaps: // [0,10): overlap [5,10) = 5s → 5/30 of inflation @@ -319,6 +319,9 @@ fn window_mode_era_inflation_split_across_multiple_windows() { // [20,30): overlap [20,30) = 10s → 10/30 of inflation // [30,40): overlap [30,35) = 5s → 5/30 of inflation (current, not closed) ExternalValidatorsRewards::on_era_end(1); + run_rewards_initialize(); + run_rewards_initialize(); + run_rewards_initialize(); // on_era_end allocates mint_result.rewards_amount (post-treasury split) to windows. // Inflation = 42, treasury = 20% of 42 = 8, rewards_amount = 34. @@ -327,7 +330,7 @@ fn window_mode_era_inflation_split_across_multiple_windows() { let treasury_amount = InflationTreasuryProportion::get().mul_floor(inflation); let rewards_amount = inflation - treasury_amount; - // Closed windows are cleared by process_closed_windows, so verify via events. + // Closed windows are cleared one per block, so verify via events after draining them. let events = System::events(); let expected_w0 = rewards_amount * 5 / 30; @@ -431,6 +434,9 @@ fn window_mode_submits_multiple_closed_windows_in_single_era_end() { // Window [60,70) is current. run_to_block(35); // now = 65s ExternalValidatorsRewards::on_era_end(1); + run_rewards_initialize(); + run_rewards_initialize(); + run_rewards_initialize(); let events = System::events(); @@ -475,7 +481,7 @@ fn window_mode_submits_multiple_closed_windows_in_single_era_end() { // NextWindowToSubmit should advance past all closed windows assert_eq!( pallet_external_validators_rewards::NextWindowToSubmit::::get(), - 60 + Some(60) ); // All closed windows should have their storage cleared @@ -522,6 +528,8 @@ fn window_mode_delivery_failure_emits_submission_failed_event() { // Advance to block 15 (now=45s), window [30,40) is closed run_to_block(15); // now = 45s ExternalValidatorsRewards::on_era_end(1); + run_rewards_initialize(); + run_rewards_initialize(); let events = System::events(); @@ -563,7 +571,7 @@ fn window_mode_delivery_failure_emits_submission_failed_event() { // NextWindowToSubmit should still advance assert_eq!( pallet_external_validators_rewards::NextWindowToSubmit::::get(), - 40 + Some(40) ); assert_eq!(unsent_len(), 1, "failed window should be queued for retry"); }) @@ -660,6 +668,7 @@ fn test_on_era_end() { run_to_block(10); ExternalValidatorsRewards::on_era_end(1); + run_rewards_initialize(); let inflation = ::EraInflationProvider::get(); @@ -4285,6 +4294,7 @@ fn send_failure_emits_window_submission_failed_and_queues_window() { System::reset_events(); ExternalValidatorsRewards::on_era_end(1); + run_rewards_initialize(); // Verify window submission failure event let window_index = window_start.saturating_sub(genesis) / window_duration; @@ -4333,6 +4343,7 @@ fn failed_window_is_retried_on_initialize() { Timestamp::set_timestamp(((window_start + duration + 1) as u64) * 1000); ExternalValidatorsRewards::on_era_end(1); + run_rewards_initialize(); assert_eq!(unsent_len(), 1); @@ -4340,7 +4351,7 @@ fn failed_window_is_retried_on_initialize() { // Sending should succeed (send_message_fails is false by default) System::reset_events(); - ExternalValidatorsRewards::process_unsent_reward_eras(); + run_rewards_initialize(); // Queue should be empty assert!(unsent_is_empty()); @@ -4381,7 +4392,7 @@ fn on_initialize_retries_and_succeeds() { push_unsent(window_start, window_index, duration); System::reset_events(); - ExternalValidatorsRewards::process_unsent_reward_eras(); + run_rewards_initialize(); assert!(unsent_is_empty()); @@ -4414,18 +4425,18 @@ fn on_initialize_moves_failed_entry_to_back() { push_unsent(40, 4, duration); // First call: tries window 30, fails, moves it to the back of the queue - ExternalValidatorsRewards::process_unsent_reward_eras(); + run_rewards_initialize(); assert_eq!(unsent_len(), 2); // Second call: tries window 40, fails, moves it to the back - ExternalValidatorsRewards::process_unsent_reward_eras(); + run_rewards_initialize(); assert_eq!(unsent_len(), 2); Mock::mutate(|mock| mock.send_message_fails = false); // Third call: window 30 (now at front again), succeeds System::reset_events(); - ExternalValidatorsRewards::process_unsent_reward_eras(); + run_rewards_initialize(); assert_eq!(unsent_len(), 1); System::assert_has_event(RuntimeEvent::ExternalValidatorsRewards( crate::Event::RewardsWindowRetried { @@ -4438,7 +4449,7 @@ fn on_initialize_moves_failed_entry_to_back() { )); // Fourth call: window 40 succeeds - ExternalValidatorsRewards::process_unsent_reward_eras(); + run_rewards_initialize(); assert!(unsent_is_empty()); }) } @@ -4452,7 +4463,7 @@ fn on_initialize_removes_expired_window() { push_unsent(999, 99, duration); System::reset_events(); - ExternalValidatorsRewards::process_unsent_reward_eras(); + run_rewards_initialize(); assert!(unsent_is_empty()); @@ -4471,7 +4482,7 @@ fn on_initialize_noop_when_queue_empty() { run_to_block(1); System::reset_events(); - ExternalValidatorsRewards::process_unsent_reward_eras(); + run_rewards_initialize(); // No events should be emitted let events = System::events(); @@ -4495,7 +4506,7 @@ fn on_initialize_processes_only_head() { push_unsent(40, 4, duration); System::reset_events(); - ExternalValidatorsRewards::process_unsent_reward_eras(); + run_rewards_initialize(); assert_eq!(unsent_len(), 1); }) @@ -4602,10 +4613,11 @@ fn send_failure_retains_window_and_advances_pointer() { System::reset_events(); ExternalValidatorsRewards::on_era_end(1); + run_rewards_initialize(); let next_window = crate::NextWindowToSubmit::::get(); assert!( - next_window > window_start, + next_window == Some(window_start + window_duration), "NextWindowToSubmit should advance past the failed window" ); @@ -4681,15 +4693,15 @@ fn head_of_line_blocking_avoided() { Mock::mutate(|mock| mock.send_message_fails = true); // Block 1: tries window 30, fails, advances head → window 40 - ExternalValidatorsRewards::process_unsent_reward_eras(); + run_rewards_initialize(); // Block 2: tries window 40, fails, advances head → window 50 - ExternalValidatorsRewards::process_unsent_reward_eras(); + run_rewards_initialize(); Mock::mutate(|mock| mock.send_message_fails = false); // Block 3: tries window 50, succeeds System::reset_events(); - ExternalValidatorsRewards::process_unsent_reward_eras(); + run_rewards_initialize(); System::assert_has_event(RuntimeEvent::ExternalValidatorsRewards( crate::Event::RewardsWindowRetried { message_id: Default::default(), @@ -4701,7 +4713,7 @@ fn head_of_line_blocking_avoided() { )); // Block 4: wraps around to window 30, succeeds - ExternalValidatorsRewards::process_unsent_reward_eras(); + run_rewards_initialize(); System::assert_has_event(RuntimeEvent::ExternalValidatorsRewards( crate::Event::RewardsWindowRetried { message_id: Default::default(), @@ -4713,7 +4725,7 @@ fn head_of_line_blocking_avoided() { )); // Block 5: window 40 succeeds - ExternalValidatorsRewards::process_unsent_reward_eras(); + run_rewards_initialize(); assert!(unsent_is_empty()); }) } diff --git a/operator/pallets/external-validators-rewards/src/weights.rs b/operator/pallets/external-validators-rewards/src/weights.rs index 882ee019..ea0c8874 100644 --- a/operator/pallets/external-validators-rewards/src/weights.rs +++ b/operator/pallets/external-validators-rewards/src/weights.rs @@ -54,6 +54,8 @@ use core::marker::PhantomData; /// Weight functions needed for pallet_external_validators_rewards. pub trait WeightInfo { fn on_era_end() -> Weight; + fn process_closed_windows_idle() -> Weight; + fn process_closed_windows_processed() -> Weight; fn process_unsent_reward_eras_empty() -> Weight; fn process_unsent_reward_eras_expired() -> Weight; fn process_unsent_reward_eras_success() -> Weight; @@ -90,6 +92,17 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().writes(5_u64)) } + fn process_closed_windows_idle() -> Weight { + Weight::from_parts(10_000_000, 0) + .saturating_add(T::DbWeight::get().reads(3_u64)) + } + + fn process_closed_windows_processed() -> Weight { + // Use the existing resend success path as an upper bound for a single + // closed-window submission/skip attempt. + Self::process_unsent_reward_eras_success() + } + fn process_unsent_reward_eras_empty() -> Weight { // 1 read for UnsentRewardEras Weight::from_parts(5_000_000, 0) @@ -149,6 +162,15 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().writes(5_u64)) } + fn process_closed_windows_idle() -> Weight { + Weight::from_parts(10_000_000, 0) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + } + + fn process_closed_windows_processed() -> Weight { + Self::process_unsent_reward_eras_success() + } + fn process_unsent_reward_eras_empty() -> Weight { Weight::from_parts(5_000_000, 0) .saturating_add(RocksDbWeight::get().reads(1_u64))