From 86843d31f8349e3543614d01479edf6783a03a8a Mon Sep 17 00:00:00 2001 From: playX18 <158266309+playX18@users.noreply.github.com> Date: Wed, 4 Sep 2024 23:24:36 +0700 Subject: [PATCH] feat(gtest): proper charging of gas allowance in gtest (#4216) --- core/src/gas_metering/schedule.rs | 67 ++++++++++++++++++ gsdk/src/metadata/generated.rs | 14 ++++ gtest/src/lib.rs | 8 --- gtest/src/manager.rs | 25 ++++--- gtest/src/manager/block_exec.rs | 109 +++++++++++++++++++++++++++-- gtest/src/manager/expend.rs | 12 +++- gtest/src/manager/journal.rs | 39 ++++------- gtest/src/manager/reservations.rs | 13 ++-- gtest/src/manager/send_dispatch.rs | 5 +- gtest/src/manager/task.rs | 50 ++++++++++--- gtest/src/manager/wait_wake.rs | 17 +++-- gtest/src/state/mailbox/actor.rs | 9 +-- pallets/gear/src/schedule.rs | 46 ++++++++++++ utils/weight-diff/src/main.rs | 3 + 14 files changed, 342 insertions(+), 75 deletions(-) diff --git a/core/src/gas_metering/schedule.rs b/core/src/gas_metering/schedule.rs index 9fd25d67620..b723bdaa35d 100644 --- a/core/src/gas_metering/schedule.rs +++ b/core/src/gas_metering/schedule.rs @@ -39,6 +39,8 @@ pub struct Schedule { pub rent_weights: RentWeights, #[doc = " The weights for database access."] pub db_weights: DbWeights, + #[doc = " The weights for executing tasks."] + pub task_weights: TaskWeights, #[doc = " The weights for instantiation of the module."] pub instantiation_weights: InstantiationWeights, #[doc = " WASM code instrumentation base cost."] @@ -58,6 +60,7 @@ impl Default for Schedule { memory_weights: MemoryWeights::default(), rent_weights: RentWeights::default(), db_weights: DbWeights::default(), + task_weights: TaskWeights::default(), instantiation_weights: InstantiationWeights::default(), code_instrumentation_cost: Weight { ref_time: 306821000, @@ -961,6 +964,10 @@ pub struct RentWeights { pub dispatch_stash: Weight, #[doc = " Holding reservation weight."] pub reservation: Weight, + #[doc = " Holding message in mailbox weight."] + pub mailbox: Weight, + #[doc = " The minimal gas amount for message to be inserted in mailbox."] + pub mailbox_threshold: Weight, } impl Default for RentWeights { @@ -978,6 +985,14 @@ impl Default for RentWeights { ref_time: 100, proof_size: 0, }, + mailbox: Weight { + ref_time: 100, + proof_size: 0, + }, + mailbox_threshold: Weight { + ref_time: 3000, + proof_size: 0, + }, } } } @@ -1014,6 +1029,58 @@ impl Default for DbWeights { } } +#[derive(Debug, Clone)] +#[doc = " Describes weights for running tasks."] +pub struct TaskWeights { + pub remove_gas_reservation: Weight, + pub send_user_message_to_mailbox: Weight, + pub send_user_message: Weight, + pub send_dispatch: Weight, + pub wake_message: Weight, + pub wake_message_no_wake: Weight, + pub remove_from_waitlist: Weight, + pub remove_from_mailbox: Weight, +} + +impl Default for TaskWeights { + fn default() -> Self { + Self { + remove_gas_reservation: Weight { + ref_time: 904369000, + proof_size: 6196, + }, + send_user_message_to_mailbox: Weight { + ref_time: 694016000, + proof_size: 4323, + }, + send_user_message: Weight { + ref_time: 1414815000, + proof_size: 6196, + }, + send_dispatch: Weight { + ref_time: 806277000, + proof_size: 4159, + }, + wake_message: Weight { + ref_time: 843879000, + proof_size: 4402, + }, + wake_message_no_wake: Weight { + ref_time: 30115000, + proof_size: 3545, + }, + remove_from_waitlist: Weight { + ref_time: 1846716000, + proof_size: 7609, + }, + remove_from_mailbox: Weight { + ref_time: 1806798000, + proof_size: 7338, + }, + } + } +} + #[doc = r" Represents the computational time and storage space required for an operation."] #[derive(Debug, Clone, Copy)] pub struct Weight { diff --git a/gsdk/src/metadata/generated.rs b/gsdk/src/metadata/generated.rs index 9b2e0fa0c9d..a116b58360d 100644 --- a/gsdk/src/metadata/generated.rs +++ b/gsdk/src/metadata/generated.rs @@ -2565,6 +2565,8 @@ pub mod runtime_types { pub waitlist: runtime_types::sp_weights::weight_v2::Weight, pub dispatch_stash: runtime_types::sp_weights::weight_v2::Weight, pub reservation: runtime_types::sp_weights::weight_v2::Weight, + pub mailbox: runtime_types::sp_weights::weight_v2::Weight, + pub mailbox_threshold: runtime_types::sp_weights::weight_v2::Weight, } #[derive(Debug, crate::gp::Decode, crate::gp::DecodeAsType, crate::gp::Encode)] pub struct Schedule { @@ -2575,6 +2577,7 @@ pub mod runtime_types { pub memory_weights: runtime_types::pallet_gear::schedule::MemoryWeights, pub rent_weights: runtime_types::pallet_gear::schedule::RentWeights, pub db_weights: runtime_types::pallet_gear::schedule::DbWeights, + pub task_weights: runtime_types::pallet_gear::schedule::TaskWeights, pub instantiation_weights: runtime_types::pallet_gear::schedule::InstantiationWeights, pub code_instrumentation_cost: runtime_types::sp_weights::weight_v2::Weight, @@ -2659,6 +2662,17 @@ pub mod runtime_types { pub gr_create_program_wgas_salt_per_byte: runtime_types::sp_weights::weight_v2::Weight, } + #[derive(Debug, crate::gp::Decode, crate::gp::DecodeAsType, crate::gp::Encode)] + pub struct TaskWeights { + pub remove_gas_reservation: runtime_types::sp_weights::weight_v2::Weight, + pub send_user_message_to_mailbox: runtime_types::sp_weights::weight_v2::Weight, + pub send_user_message: runtime_types::sp_weights::weight_v2::Weight, + pub send_dispatch: runtime_types::sp_weights::weight_v2::Weight, + pub wake_message: runtime_types::sp_weights::weight_v2::Weight, + pub wake_message_no_wake: runtime_types::sp_weights::weight_v2::Weight, + pub remove_from_waitlist: runtime_types::sp_weights::weight_v2::Weight, + pub remove_from_mailbox: runtime_types::sp_weights::weight_v2::Weight, + } } } pub mod pallet_gear_bank { diff --git a/gtest/src/lib.rs b/gtest/src/lib.rs index 7ee2835b95b..46ebfaae02e 100644 --- a/gtest/src/lib.rs +++ b/gtest/src/lib.rs @@ -551,17 +551,9 @@ pub mod constants { pub const EPOCH_DURATION_IN_BLOCKS: Block = 600; /* Storage-related constants */ - - /// Minimal amount of gas required to be inserted into Mailbox. - pub const MAILBOX_THRESHOLD: Gas = 3_000; /// Extra amount of blocks must be reserved for storing in storage. pub const RESERVE_FOR: Block = 1; - /* Rent-related constants */ - - /// Cost of storing message in mailbox - pub const MAILBOX_COST: Gas = 100; - /* Execution-related constants */ /// Maximal amount of reservations program may have. diff --git a/gtest/src/manager.rs b/gtest/src/manager.rs index 68d6214ecee..d356f09c2f8 100644 --- a/gtest/src/manager.rs +++ b/gtest/src/manager.rs @@ -41,8 +41,7 @@ use crate::{ waitlist::WaitlistManager, }, Result, TestError, EPOCH_DURATION_IN_BLOCKS, EXISTENTIAL_DEPOSIT, GAS_ALLOWANCE, - GAS_MULTIPLIER, INITIAL_RANDOM_SEED, MAILBOX_COST, MAILBOX_THRESHOLD, MAX_RESERVATIONS, - RESERVE_FOR, VALUE_PER_GAS, + GAS_MULTIPLIER, INITIAL_RANDOM_SEED, MAX_RESERVATIONS, RESERVE_FOR, VALUE_PER_GAS, }; use core_processor::{ common::*, @@ -61,7 +60,7 @@ use gear_common::{ }; use gear_core::{ code::{Code, CodeAndId, InstrumentedCode, InstrumentedCodeAndId, TryNewCodeConfig}, - gas_metering::{RentWeights, Schedule}, + gas_metering::{DbWeights, RentWeights, Schedule}, ids::{prelude::*, CodeId, MessageId, ProgramId, ReservationId}, memory::PageBuf, message::{ @@ -105,7 +104,7 @@ pub(crate) struct ExtManager { pub(crate) gas_allowance: Gas, pub(crate) dispatches_stash: HashMap)>, pub(crate) messages_processing_enabled: bool, - + pub(crate) first_incomplete_tasks_block: Option, // Last block execution info pub(crate) succeed: BTreeSet, pub(crate) failed: BTreeSet, @@ -231,6 +230,11 @@ impl ExtManager { Accounts::override_balance(id, balance); } + pub(crate) fn on_task_pool_change(&mut self) { + let write = DbWeights::default().write.ref_time; + self.gas_allowance = self.gas_allowance.saturating_sub(Gas(write)); + } + #[track_caller] fn init_success(&mut self, program_id: ProgramId) { Actors::modify(program_id, |actor| { @@ -280,10 +284,15 @@ impl ExtManager { self.bank.transfer_value(from, user_id, message.value()); - let _ = self.task_pool.delete( - expected, - ScheduledTask::RemoveFromMailbox(user_id, message.id()), - ); + let _ = self + .task_pool + .delete( + expected, + ScheduledTask::RemoveFromMailbox(user_id, message.id()), + ) + .map(|_| { + self.on_task_pool_change(); + }); Ok(message) } diff --git a/gtest/src/manager/block_exec.rs b/gtest/src/manager/block_exec.rs index b8816f87423..027fc4ed864 100644 --- a/gtest/src/manager/block_exec.rs +++ b/gtest/src/manager/block_exec.rs @@ -18,6 +18,7 @@ use core_processor::SuccessfulDispatchResultKind; use gear_core::{gas::GasCounter, str::LimitedStr}; +use task::get_maximum_task_gas; use super::*; @@ -140,10 +141,108 @@ impl ExtManager { } #[track_caller] - pub(crate) fn process_tasks(&mut self, bn: u32) { - for task in self.task_pool.drain_prefix_keys(bn) { - log::debug!("⚙️ Processing task {task:?} at the block {bn}"); - task.process_with(self); + pub(crate) fn process_tasks(&mut self, current_bn: u32) { + let db_weights = DbWeights::default(); + + let (first_incomplete_block, were_empty) = self + .first_incomplete_tasks_block + .take() + .map(|block| { + self.gas_allowance = self + .gas_allowance + .saturating_sub(Gas(db_weights.write.ref_time)); + (block, false) + }) + .unwrap_or_else(|| { + self.gas_allowance = self + .gas_allowance + .saturating_sub(Gas(db_weights.read.ref_time)); + (current_bn, true) + }); + + // When we had to stop processing due to insufficient gas allowance. + let mut stopped_at = None; + + let missing_blocks = first_incomplete_block..=current_bn; + for bn in missing_blocks { + if self.gas_allowance.0 <= db_weights.write.ref_time.saturating_mul(2) { + stopped_at = Some(bn); + log::debug!( + "Stopped processing tasks at: {stopped_at:?} due to insufficient allowance" + ); + break; + } + + let mut last_task = None; + for task in self.task_pool.drain_prefix_keys(bn) { + // decreasing allowance due to DB deletion + self.on_task_pool_change(); + + let max_task_gas = get_maximum_task_gas(&task); + log::debug!( + "⚙️ Processing task {task:?} at the block {bn}, max gas = {max_task_gas}" + ); + + if self.gas_allowance.saturating_sub(max_task_gas) <= Gas(db_weights.write.ref_time) + { + // Since the task is not processed write DB cost should be refunded. + // In the same time gas allowance should be charged for read DB cost. + self.gas_allowance = self + .gas_allowance + .saturating_add(Gas(db_weights.write.ref_time)) + .saturating_sub(Gas(db_weights.read.ref_time)); + + last_task = Some(task); + + log::debug!("Not enough gas to process task at {bn:?}"); + + break; + } + + let task_gas = task.process_with(self); + + self.gas_allowance = self.gas_allowance.saturating_sub(Gas(task_gas)); + + if self.gas_allowance <= Gas(db_weights.write.ref_time + db_weights.read.ref_time) { + stopped_at = Some(bn); + log::debug!("Stopping processing tasks at (read next): {stopped_at:?}"); + break; + } + } + + if let Some(task) = last_task { + stopped_at = Some(bn); + + self.gas_allowance = self + .gas_allowance + .saturating_add(Gas(db_weights.write.ref_time)); + + self.task_pool.add(bn, task.clone()).unwrap_or_else(|e| { + let err_msg = format!( + "process_tasks: failed adding not processed last task to task pool. \ + Bn - {bn:?}, task - {task:?}. Got error - {e:?}" + ); + + unreachable!("{err_msg}"); + }); + self.on_task_pool_change(); + } + + if stopped_at.is_some() { + break; + } + } + + if let Some(stopped_at) = stopped_at { + if were_empty { + // Charging for inserting into storage of the first block of incomplete tasks, + // if we were reading it only (they were empty). + self.gas_allowance = self + .gas_allowance + .saturating_sub(Gas(db_weights.write.ref_time)); + } + + self.first_incomplete_tasks_block = Some(stopped_at); } } @@ -446,7 +545,7 @@ impl ExtManager { gas_multiplier: gsys::GasMultiplier::from_value_per_gas(VALUE_PER_GAS), costs: schedule.process_costs(), existential_deposit: EXISTENTIAL_DEPOSIT, - mailbox_threshold: MAILBOX_THRESHOLD, + mailbox_threshold: schedule.rent_weights.mailbox_threshold.ref_time, max_reservations: MAX_RESERVATIONS, max_pages: TESTS_MAX_PAGES_NUMBER.into(), outgoing_limit: OUTGOING_LIMIT, diff --git a/gtest/src/manager/expend.rs b/gtest/src/manager/expend.rs index 54b2632dabc..2941b82cf33 100644 --- a/gtest/src/manager/expend.rs +++ b/gtest/src/manager/expend.rs @@ -47,6 +47,14 @@ impl ExtManager { self.bank.spend_gas(external.cast(), amount, multiplier) } + pub(crate) fn spend_burned(&mut self, id: MessageId, amount: u64) { + self.gas_burned + .entry(id) + .and_modify(|v| *v = v.saturating_sub(Gas(amount))) + .or_insert(Gas(amount)); + self.spend_gas(id, amount); + } + pub(crate) fn cost_by_storage_type(storage_type: StorageType) -> u64 { // Cost per block based on the storage used for holding let schedule = Schedule::default(); @@ -54,11 +62,13 @@ impl ExtManager { waitlist, dispatch_stash, reservation, + mailbox, + .. } = schedule.rent_weights; match storage_type { StorageType::Code => todo!("#646"), StorageType::Waitlist => waitlist.ref_time, - StorageType::Mailbox => MAILBOX_COST, + StorageType::Mailbox => mailbox.ref_time, StorageType::DispatchStash => dispatch_stash.ref_time, StorageType::Program => todo!("#646"), StorageType::Reservation => reservation.ref_time, diff --git a/gtest/src/manager/journal.rs b/gtest/src/manager/journal.rs index bb2ecd001c7..8a1e39d97c3 100644 --- a/gtest/src/manager/journal.rs +++ b/gtest/src/manager/journal.rs @@ -28,7 +28,6 @@ use core_processor::common::{DispatchOutcome, JournalHandler}; use gear_common::{ event::{MessageWaitedRuntimeReason, RuntimeReason}, scheduler::{ScheduledTask, StorageType, TaskHandler}, - Origin, }; use gear_core::{ ids::{CodeId, MessageId, ProgramId, ReservationId}, @@ -79,24 +78,7 @@ impl JournalHandler for ExtManager { log::debug!("Burned: {:?} from: {:?}", amount, message_id); self.gas_allowance = self.gas_allowance.saturating_sub(Gas(amount)); - self.gas_tree - .spend(message_id, amount) - .unwrap_or_else(|e| unreachable!("GasTree corrupted! {e:?}")); - - self.gas_burned - .entry(message_id) - .and_modify(|gas| { - *gas += Gas(amount); - }) - .or_insert(Gas(amount)); - - let (external, multiplier, _) = self - .gas_tree - .get_origin_node(message_id) - .unwrap_or_else(|e| unreachable!("GasTree corrupted! {e:?}")); - - let id: ProgramId = external.into_origin().into(); - self.bank.spend_gas(id, amount, multiplier); + self.spend_burned(message_id, amount); } fn exit_dispatch(&mut self, id_exited: ProgramId, value_destination: ProgramId) { @@ -257,6 +239,7 @@ impl JournalHandler for ExtManager { unreachable!("{err_msg}"); }); + self.on_task_pool_change(); } return; @@ -349,7 +332,7 @@ impl JournalHandler for ExtManager { self.gas_allowance, gas_burned, ); - + self.gas_allowance = self.gas_allowance.saturating_sub(Gas(gas_burned)); self.messages_processing_enabled = false; self.dispatches.push_front(dispatch); } @@ -417,10 +400,9 @@ impl JournalHandler for ExtManager { Expected bn - {bn:?}, program id - {program_id}, reservation id - {reservation_id}. Got error - {e:?}", bn = hold.expected() ); - - unreachable!("{err_msg}"); }); + self.on_task_pool_change(); } fn unreserve_gas( @@ -431,10 +413,15 @@ impl JournalHandler for ExtManager { ) { >::remove_gas_reservation(self, program_id, reservation_id); - let _ = self.task_pool.delete( - expiration, - ScheduledTask::RemoveGasReservation(program_id, reservation_id), - ); + let _ = self + .task_pool + .delete( + expiration, + ScheduledTask::RemoveGasReservation(program_id, reservation_id), + ) + .map(|_| { + self.on_task_pool_change(); + }); } #[track_caller] diff --git a/gtest/src/manager/reservations.rs b/gtest/src/manager/reservations.rs index 80915d86705..e63bef8046a 100644 --- a/gtest/src/manager/reservations.rs +++ b/gtest/src/manager/reservations.rs @@ -55,10 +55,15 @@ impl ExtManager { ) { let slot = self.remove_gas_reservation_impl(program_id, reservation); - let _ = self.task_pool.delete( - slot.finish, - ScheduledTask::RemoveGasReservation(program_id, reservation), - ); + let _ = self + .task_pool + .delete( + slot.finish, + ScheduledTask::RemoveGasReservation(program_id, reservation), + ) + .map(|_| { + self.on_task_pool_change(); + }); } pub(crate) fn remove_gas_reservation_slot( diff --git a/gtest/src/manager/send_dispatch.rs b/gtest/src/manager/send_dispatch.rs index 851fcbb3149..28662ac5f20 100644 --- a/gtest/src/manager/send_dispatch.rs +++ b/gtest/src/manager/send_dispatch.rs @@ -70,7 +70,7 @@ impl ExtManager { let gas_for_delay = delay_hold.lock_amount(self); let interval_finish = if to_user { - let threshold = MAILBOX_THRESHOLD; + let threshold = RentWeights::default().mailbox_threshold.ref_time; let gas_limit = dispatch .gas_limit() @@ -258,6 +258,7 @@ impl ExtManager { unreachable!("{err_msg}"); }); + self.on_task_pool_change(); } pub(crate) fn send_user_message( @@ -266,7 +267,7 @@ impl ExtManager { message: Message, reservation: Option, ) { - let threshold = MAILBOX_THRESHOLD; + let threshold = RentWeights::default().mailbox_threshold.ref_time; let msg_id = reservation .map(Origin::into_origin) diff --git a/gtest/src/manager/task.rs b/gtest/src/manager/task.rs index f403c1e9133..53c58d0f9e0 100644 --- a/gtest/src/manager/task.rs +++ b/gtest/src/manager/task.rs @@ -19,18 +19,44 @@ //! Implementation of the `TaskHandler` trait for the `ExtManager`. use super::ExtManager; -use crate::state::actors::Actors; +use crate::{state::actors::Actors, Gas}; use core_processor::common::JournalHandler; use gear_common::{ - scheduler::{StorageType, TaskHandler}, + scheduler::{ScheduledTask, StorageType, TaskHandler}, Gas as GearCommonGas, }; use gear_core::{ + gas_metering::TaskWeights, ids::{CodeId, MessageId, ProgramId, ReservationId}, message::{DispatchKind, ReplyMessage}, }; use gear_core_errors::{ErrorReplyReason, SignalCode}; +pub(crate) fn get_maximum_task_gas(task: &ScheduledTask) -> Gas { + use ScheduledTask::*; + let weights = TaskWeights::default(); + match task { + PauseProgram(_) => Gas(0), + #[allow(deprecated)] + RemoveResumeSession(_) => Gas(0), + + RemoveFromMailbox(_, _) => Gas(weights.remove_from_mailbox.ref_time), + RemoveFromWaitlist(_, _) => Gas(weights.remove_from_waitlist.ref_time), + RemovePausedProgram(_) => todo!("#646"), + RemoveCode(_) => todo!("#646"), + WakeMessage(_, _) => Gas(weights + .wake_message + .ref_time + .max(weights.wake_message_no_wake.ref_time)), + SendDispatch(_) => Gas(weights.send_dispatch.ref_time), + SendUserMessage { .. } => Gas(weights + .send_user_message_to_mailbox + .ref_time + .max(weights.send_user_message.ref_time)), + RemoveGasReservation(_, _) => Gas(weights.remove_gas_reservation.ref_time), + } +} + impl TaskHandler for ExtManager { fn pause_program(&mut self, _program_id: ProgramId) -> GearCommonGas { log::debug!("Program rent logic is disabled."); @@ -61,7 +87,7 @@ impl TaskHandler for ExtManager { self.dispatches.push_back(dispatch); - GearCommonGas::MIN + TaskWeights::default().remove_from_mailbox.ref_time } fn remove_from_waitlist( @@ -122,7 +148,7 @@ impl TaskHandler for ExtManager { self.init_failure(program_id, origin); } - GearCommonGas::MIN + TaskWeights::default().remove_from_waitlist.ref_time } fn remove_paused_program(&mut self, _program_id: ProgramId) -> GearCommonGas { @@ -132,9 +158,10 @@ impl TaskHandler for ExtManager { fn wake_message(&mut self, program_id: ProgramId, message_id: MessageId) -> GearCommonGas { if let Ok(dispatch) = self.wake_dispatch_impl(program_id, message_id) { self.dispatches.push_back(dispatch); + TaskWeights::default().wake_message.ref_time + } else { + TaskWeights::default().wake_message_no_wake.ref_time } - - GearCommonGas::MIN } fn send_dispatch(&mut self, stashed_message_id: MessageId) -> GearCommonGas { @@ -146,7 +173,7 @@ impl TaskHandler for ExtManager { self.charge_for_hold(dispatch.id(), hold_interval, StorageType::DispatchStash); self.dispatches.push_back(dispatch.into()); - GearCommonGas::MIN + TaskWeights::default().send_dispatch.ref_time } fn send_user_message( @@ -167,8 +194,11 @@ impl TaskHandler for ExtManager { }); self.send_user_message_after_delay(mailbox_message, to_mailbox); - - GearCommonGas::MIN + if to_mailbox { + TaskWeights::default().send_user_message_to_mailbox.ref_time + } else { + TaskWeights::default().send_user_message.ref_time + } } fn remove_gas_reservation( @@ -177,7 +207,7 @@ impl TaskHandler for ExtManager { reservation_id: ReservationId, ) -> GearCommonGas { let _slot = self.remove_gas_reservation_impl(program_id, reservation_id); - GearCommonGas::MIN + TaskWeights::default().remove_gas_reservation.ref_time } fn remove_resume_session(&mut self, _session_id: u32) -> GearCommonGas { diff --git a/gtest/src/manager/wait_wake.rs b/gtest/src/manager/wait_wake.rs index 2df892f4cfd..8b65890e356 100644 --- a/gtest/src/manager/wait_wake.rs +++ b/gtest/src/manager/wait_wake.rs @@ -20,7 +20,7 @@ use super::*; impl ExtManager { pub(crate) fn wait_dispatch_impl( - &self, + &mut self, dispatch: StoredDispatch, duration: Option, reason: MessageWaitedReason, @@ -94,6 +94,7 @@ impl ExtManager { unreachable!("{err_msg}"); }); + self.on_task_pool_change(); } } MessageWaitedReason::Runtime(WaitCalled | WaitUpToCalled) => { @@ -110,6 +111,7 @@ impl ExtManager { unreachable!("{err_msg}"); }); + self.on_task_pool_change(); } MessageWaitedReason::System(reason) => match reason {}, } @@ -144,10 +146,15 @@ impl ExtManager { self.charge_for_hold(waitlisted.id(), hold_interval, StorageType::Waitlist); - let _ = self.task_pool.delete( - expected, - ScheduledTask::RemoveFromWaitlist(waitlisted.destination(), waitlisted.id()), - ); + let _ = self + .task_pool + .delete( + expected, + ScheduledTask::RemoveFromWaitlist(waitlisted.destination(), waitlisted.id()), + ) + .map(|_| { + self.on_task_pool_change(); + }); waitlisted } diff --git a/gtest/src/state/mailbox/actor.rs b/gtest/src/state/mailbox/actor.rs index 9ffeff30a47..b8d62931129 100644 --- a/gtest/src/state/mailbox/actor.rs +++ b/gtest/src/state/mailbox/actor.rs @@ -173,13 +173,10 @@ impl<'a> ActorMailbox<'a> { #[cfg(test)] mod tests { - use crate::{ - Log, Program, System, DEFAULT_USER_ALICE, EXISTENTIAL_DEPOSIT, GAS_MULTIPLIER, - MAILBOX_THRESHOLD, - }; + use crate::{Log, Program, System, DEFAULT_USER_ALICE, EXISTENTIAL_DEPOSIT, GAS_MULTIPLIER}; use codec::Encode; use demo_constructor::{Call, Calls, Scheme, WASM_BINARY}; - use gear_core::ids::ProgramId; + use gear_core::{gas_metering::RentWeights, ids::ProgramId}; fn prepare_program(system: &System) -> (Program<'_>, ([u8; 32], Vec, Log)) { let program = Program::from_binary_with_id(system, 121, WASM_BINARY); @@ -214,7 +211,7 @@ mod tests { original_balance - value_send - res.spent_value() - - GAS_MULTIPLIER.gas_to_value(MAILBOX_THRESHOLD) + - GAS_MULTIPLIER.gas_to_value(RentWeights::default().mailbox_threshold.ref_time) ); let mailbox = system.get_mailbox(sender); diff --git a/pallets/gear/src/schedule.rs b/pallets/gear/src/schedule.rs index de7cff995b2..95aacc42727 100644 --- a/pallets/gear/src/schedule.rs +++ b/pallets/gear/src/schedule.rs @@ -130,6 +130,9 @@ pub struct Schedule { /// The weights for database access. pub db_weights: DbWeights, + /// The weights for executing tasks. + pub task_weights: TaskWeights, + /// The weights for instantiation of the module. pub instantiation_weights: InstantiationWeights, @@ -671,6 +674,10 @@ pub struct RentWeights { pub dispatch_stash: Weight, /// Holding reservation weight. pub reservation: Weight, + /// Holding message in mailbox weight. + pub mailbox: Weight, + /// The minimal gas amount for message to be inserted in mailbox. + pub mailbox_threshold: Weight, /// The type parameter is used in the default implementation. #[codec(skip)] #[cfg_attr(feature = "std", serde(skip))] @@ -692,6 +699,42 @@ pub struct DbWeights { pub _phantom: PhantomData, } +/// Describes weights for running tasks. +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +#[derive(Clone, Encode, Decode, PartialEq, Eq, WeightDebug, TypeInfo)] +#[scale_info(skip_type_params(T))] +pub struct TaskWeights { + pub remove_gas_reservation: Weight, + pub send_user_message_to_mailbox: Weight, + pub send_user_message: Weight, + pub send_dispatch: Weight, + pub wake_message: Weight, + pub wake_message_no_wake: Weight, + pub remove_from_waitlist: Weight, + pub remove_from_mailbox: Weight, + /// The type parameter is used in the default implementation. + #[codec(skip)] + #[cfg_attr(feature = "std", serde(skip))] + pub _phantom: PhantomData, +} +impl Default for TaskWeights { + fn default() -> Self { + type W = ::WeightInfo; + + Self { + remove_gas_reservation: W::::tasks_remove_gas_reservation(), + send_user_message_to_mailbox: W::::tasks_send_user_message_to_mailbox(), + send_user_message: W::::tasks_send_user_message(), + send_dispatch: W::::tasks_send_dispatch(), + wake_message: W::::tasks_wake_message(), + wake_message_no_wake: W::::tasks_wake_message_no_wake(), + remove_from_waitlist: W::::tasks_remove_from_waitlist(), + remove_from_mailbox: W::::tasks_remove_from_mailbox(), + _phantom: PhantomData, + } + } +} + #[inline] fn cost(w: fn(u32) -> Weight) -> Weight { Weight::from_parts(w(1).saturating_sub(w(0)).ref_time(), 0) @@ -768,6 +811,7 @@ impl Default for Schedule { memory_weights: Default::default(), rent_weights: Default::default(), db_weights: Default::default(), + task_weights: Default::default(), instantiation_weights: Default::default(), code_instrumentation_cost: cost_zero(W::::reinstrument_per_kb), code_instrumentation_byte_cost: cost_byte(W::::reinstrument_per_kb), @@ -1297,6 +1341,8 @@ impl Default for RentWeights { waitlist: Weight::from_parts(CostsPerBlockOf::::waitlist(), 0), dispatch_stash: Weight::from_parts(CostsPerBlockOf::::dispatch_stash(), 0), reservation: Weight::from_parts(CostsPerBlockOf::::reservation(), 0), + mailbox: Weight::from_parts(CostsPerBlockOf::::mailbox(), 0), + mailbox_threshold: Weight::from_parts(T::MailboxThreshold::get(), 0), _phantom: PhantomData, } } diff --git a/utils/weight-diff/src/main.rs b/utils/weight-diff/src/main.rs index 4baa0792e73..51f4056d94d 100644 --- a/utils/weight-diff/src/main.rs +++ b/utils/weight-diff/src/main.rs @@ -125,6 +125,7 @@ struct DeserializableSchedule { memory_weights: IndexMap, rent_weights: IndexMap, db_weights: IndexMap, + task_weights: IndexMap, instantiation_weights: IndexMap, #[serde(flatten)] other_fields: IndexMap, @@ -229,6 +230,7 @@ impl<'ast> Visit<'ast> for StructuresVisitor { | "MemoryWeights" | "RentWeights" | "DbWeights" + | "TaskWeights" | "InstantiationWeights" ) { return; @@ -548,6 +550,7 @@ fn main() -> Result<()> { | "MemoryWeights" | "RentWeights" | "DbWeights" + | "TaskWeights" | "InstantiationWeights" => { &raw_schedule[structure_name_snake_case.as_str()][field_name] }