diff --git a/Cargo.lock b/Cargo.lock index 2a1e220ef61..7f0a3f8fa43 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3909,6 +3909,7 @@ dependencies = [ "hashbrown 0.14.0", "hex", "log", + "num-traits", "parity-scale-codec", "paste", "proptest", diff --git a/Cargo.toml b/Cargo.toml index d6d1f00418c..79fd4c5f919 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -453,6 +453,7 @@ heck = "0.4.1" # gsdk etc = "0.1.16" # gcli scale-decode = "0.7.0" # gsdk directories = "5.0.1" # utils/key-finder +num-traits = { version = "0.2", default-features = false } # gear-core [profile.release] panic = "unwind" diff --git a/core-backend/src/mock.rs b/core-backend/src/mock.rs index 4264aabedab..e1b8177b407 100644 --- a/core-backend/src/mock.rs +++ b/core-backend/src/mock.rs @@ -33,6 +33,7 @@ use gear_core::{ memory::{Memory, MemoryError, MemoryInterval}, message::{HandlePacket, InitPacket, ReplyPacket}, pages::{PageNumber, PageU32Size, WasmPage, WASM_PAGE_SIZE}, + percent::Percent, }; use gear_core_errors::{ReplyCode, SignalCode}; use gear_lazy_pages_common::ProcessAccessError; @@ -120,6 +121,9 @@ impl Externalities for MockExt { fn block_timestamp(&self) -> Result { Ok(0) } + fn performance_multiplier(&self) -> Result { + Ok(Percent::new(100)) + } fn send_init(&mut self) -> Result { Ok(0) } diff --git a/core-processor/src/configs.rs b/core-processor/src/configs.rs index 5d04d70271b..153d7fc23af 100644 --- a/core-processor/src/configs.rs +++ b/core-processor/src/configs.rs @@ -22,6 +22,7 @@ use alloc::{collections::BTreeSet, vec::Vec}; use gear_core::{ costs::{CostPerPage, HostFnWeights}, pages::{GearPage, WasmPage}, + percent::Percent, }; use gear_lazy_pages_common::LazyPagesWeights; use gear_wasm_instrument::syscalls::SysCallName; @@ -144,6 +145,8 @@ impl PageCosts { pub struct ExecutionSettings { /// Contextual block information. pub block_info: BlockInfo, + /// Performance multiplier. + pub performance_multiplier: Percent, /// Max amount of pages in program memory during execution. pub max_pages: WasmPage, /// Pages costs. @@ -176,6 +179,8 @@ pub struct ExecutionSettings { pub struct BlockConfig { /// Block info. pub block_info: BlockInfo, + /// Performance multiplier. + pub performance_multiplier: Percent, /// Max allowed page numbers for wasm program. pub max_pages: WasmPage, /// Allocations config. diff --git a/core-processor/src/executor.rs b/core-processor/src/executor.rs index 1f71adaf08f..05099bf8997 100644 --- a/core-processor/src/executor.rs +++ b/core-processor/src/executor.rs @@ -42,6 +42,7 @@ use gear_core::{ WasmEntryPoint, }, pages::{PageU32Size, WasmPage}, + percent::Percent, program::Program, reservation::GasReserver, }; @@ -205,6 +206,7 @@ where allocations_context, message_context, block_info: settings.block_info, + performance_multiplier: settings.performance_multiplier, max_pages: settings.max_pages, page_costs: settings.page_costs, existential_deposit: settings.existential_deposit, @@ -399,6 +401,7 @@ where ContextSettings::new(0, 0, 0, 0, 0, 0), ), block_info, + performance_multiplier: Percent::new(100), max_pages: 512.into(), page_costs: Default::default(), existential_deposit: Default::default(), diff --git a/core-processor/src/ext.rs b/core-processor/src/ext.rs index 55d1f96dec9..b1af302f147 100644 --- a/core-processor/src/ext.rs +++ b/core-processor/src/ext.rs @@ -40,6 +40,7 @@ use gear_core::{ MessageContext, Packet, ReplyPacket, }, pages::{GearPage, PageU32Size, WasmPage}, + percent::Percent, reservation::GasReserver, }; use gear_core_backend::{ @@ -75,6 +76,8 @@ pub struct ProcessorContext { pub message_context: MessageContext, /// Block info. pub block_info: BlockInfo, + /// Performance multiplier. + pub performance_multiplier: Percent, /// Max allowed wasm memory pages. pub max_pages: WasmPage, /// Allocations config. @@ -135,6 +138,7 @@ impl ProcessorContext { ContextSettings::new(0, 0, 0, 0, 0, 0), ), block_info: Default::default(), + performance_multiplier: Percent::new(100), max_pages: 512.into(), page_costs: Default::default(), existential_deposit: 0, @@ -725,6 +729,10 @@ impl Externalities for Ext { Ok(self.context.block_info.timestamp) } + fn performance_multiplier(&self) -> Result { + Ok(self.context.performance_multiplier) + } + fn send_init(&mut self) -> Result { let handle = self.context.message_context.send_init()?; Ok(handle) diff --git a/core-processor/src/processing.rs b/core-processor/src/processing.rs index 8becd057446..befb3685610 100644 --- a/core-processor/src/processing.rs +++ b/core-processor/src/processing.rs @@ -57,6 +57,7 @@ where let BlockConfig { block_info, + performance_multiplier, max_pages, page_costs, existential_deposit, @@ -75,6 +76,7 @@ where let execution_settings = ExecutionSettings { block_info, + performance_multiplier, existential_deposit, max_pages, page_costs, diff --git a/core/Cargo.toml b/core/Cargo.toml index 22a2d47f2ee..897cd2e48c8 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -22,12 +22,13 @@ wasmparser.workspace = true hex = { workspace = true, features = ["alloc"] } hashbrown.workspace = true static_assertions.workspace = true -paste = { workspace = true } +paste.workspace = true enum-iterator.workspace = true byteorder.workspace = true +num-traits.workspace = true # Optional dependencies -serde = { workspace = true, features = [ "derive" ], optional = true } +serde = { workspace = true, features = ["derive"], optional = true } [dev-dependencies] wabt.workspace = true diff --git a/core/src/env.rs b/core/src/env.rs index b17a5b7b600..f05993aae27 100644 --- a/core/src/env.rs +++ b/core/src/env.rs @@ -23,6 +23,7 @@ use crate::{ memory::Memory, message::{HandlePacket, InitPacket, MessageContext, Payload, ReplyPacket}, pages::WasmPage, + percent::Percent, }; use alloc::collections::BTreeSet; use core::{fmt::Display, mem}; @@ -203,6 +204,9 @@ pub trait Externalities { /// Get the current block timestamp. fn block_timestamp(&self) -> Result; + /// Get current performance multiplier. + fn performance_multiplier(&self) -> Result; + /// Initialize a new incomplete message for another program and return its handle. fn send_init(&mut self) -> Result; diff --git a/core/src/lib.rs b/core/src/lib.rs index 1996e7492dd..47e982393ec 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -35,6 +35,7 @@ pub mod ids; pub mod memory; pub mod message; pub mod pages; +pub mod percent; pub mod program; pub mod reservation; diff --git a/core/src/percent.rs b/core/src/percent.rs new file mode 100644 index 00000000000..e63f218fd95 --- /dev/null +++ b/core/src/percent.rs @@ -0,0 +1,52 @@ +// This file is part of Gear. + +// Copyright (C) 2021-2023 Gear Technologies Inc. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Basic struct for working with integer percentages. + +use core::cmp::Ord; +use num_traits::{cast::NumCast, Num}; +use parity_scale_codec::{Decode, Encode}; +use scale_info::TypeInfo; + +/// Basic struct for working with integer percentages. +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Encode, Decode, TypeInfo)] +pub struct Percent(u32); + +impl Percent { + /// Creates a new `Percent` from a `u32` value. The value can be + /// greater than 100. + pub fn new(value: u32) -> Self { + Self(value) + } + + /// Returns the inner `u16` value. + pub fn value(self) -> u32 { + self.0 + } + + /// Applies the percentage to the given value. + pub fn apply_to(&self, value: T) -> T { + (value * NumCast::from(self.0).unwrap()) / NumCast::from(100).unwrap() + } +} + +impl From for Percent { + fn from(value: u32) -> Self { + Self::new(value) + } +} diff --git a/gsdk/src/metadata/generated.rs b/gsdk/src/metadata/generated.rs index dc2bdd5bf5b..c7b4876eb1c 100644 --- a/gsdk/src/metadata/generated.rs +++ b/gsdk/src/metadata/generated.rs @@ -914,6 +914,17 @@ pub mod runtime_types { )] pub struct WasmPage(pub ::core::primitive::u32); } + pub mod percent { + use super::runtime_types; + #[derive( + ::subxt::ext::codec::CompactAs, + Debug, + crate::gp::Decode, + crate::gp::DecodeAsType, + crate::gp::Encode, + )] + pub struct Percent(pub ::core::primitive::u32); + } pub mod reservation { use super::runtime_types; #[derive(Debug, crate::gp::Decode, crate::gp::DecodeAsType, crate::gp::Encode)] diff --git a/gtest/src/manager.rs b/gtest/src/manager.rs index 4a45dda5dae..7563b5ded54 100644 --- a/gtest/src/manager.rs +++ b/gtest/src/manager.rs @@ -38,6 +38,7 @@ use gear_core::{ StoredMessage, }, pages::{GearPage, PageU32Size, WasmPage}, + percent::Percent, program::Program as CoreProgram, reservation::{GasReservationMap, GasReserver}, }; @@ -817,6 +818,7 @@ impl ExtManager { .expect("Unable to find gas limit for message"); let block_config = BlockConfig { block_info: self.block_info, + performance_multiplier: Percent::new(100), max_pages: TESTS_MAX_PAGES_NUMBER.into(), page_costs: PageCosts::new_for_tests(), existential_deposit: EXISTENTIAL_DEPOSIT, diff --git a/pallets/gear-debug/src/mock.rs b/pallets/gear-debug/src/mock.rs index 4d2571d8ad5..ae669dd7f33 100644 --- a/pallets/gear-debug/src/mock.rs +++ b/pallets/gear-debug/src/mock.rs @@ -116,6 +116,7 @@ parameter_types! { pub const MinimumPeriod: u64 = 500; pub const OutgoingLimit: u32 = 1024; pub const BlockGasLimit: u64 = 100_000_000_000; + pub const PerformanceMultiplier: u32 = 100; } impl pallet_timestamp::Config for Test { @@ -150,6 +151,7 @@ impl pallet_gear::Config for Test { type Randomness = TestRandomness; type WeightInfo = (); type OutgoingLimit = OutgoingLimit; + type PerformanceMultiplier = PerformanceMultiplier; type DebugInfo = super::Pallet; type Schedule = (); type CodeStorage = GearProgram; diff --git a/pallets/gear-scheduler/src/mock.rs b/pallets/gear-scheduler/src/mock.rs index 8ef9b7da76d..8b662f87b0b 100644 --- a/pallets/gear-scheduler/src/mock.rs +++ b/pallets/gear-scheduler/src/mock.rs @@ -121,6 +121,7 @@ impl pallet_gear_program::Config for Test { parameter_types! { pub const BlockGasLimit: u64 = 100_000_000_000; pub const OutgoingLimit: u32 = 1024; + pub const PerformanceMultiplier: u32 = 100; pub GearSchedule: pallet_gear::Schedule = >::default(); pub RentFreePeriod: BlockNumber = 1_000; pub RentCostPerBlock: Balance = 11; @@ -142,6 +143,7 @@ impl pallet_gear::Config for Test { type WeightInfo = (); type Schedule = GearSchedule; type OutgoingLimit = OutgoingLimit; + type PerformanceMultiplier = PerformanceMultiplier; type DebugInfo = (); type CodeStorage = GearProgram; type ProgramStorage = GearProgram; diff --git a/pallets/gear/src/benchmarking/mod.rs b/pallets/gear/src/benchmarking/mod.rs index 7a2c82c7c3a..71fde344dfd 100644 --- a/pallets/gear/src/benchmarking/mod.rs +++ b/pallets/gear/src/benchmarking/mod.rs @@ -92,6 +92,7 @@ use gear_core::{ memory::{AllocationsContext, Memory, PageBuf}, message::{ContextSettings, DispatchKind, IncomingDispatch, MessageContext}, pages::{GearPage, PageU32Size, WasmPage, GEAR_PAGE_SIZE, WASM_PAGE_SIZE}, + percent::Percent, reservation::GasReserver, }; use gear_core_backend::{ @@ -187,6 +188,7 @@ fn default_processor_context() -> ProcessorContext { ContextSettings::new(0, 0, 0, 0, 0, 0), ), block_info: Default::default(), + performance_multiplier: Percent::new(100), max_pages: TESTS_MAX_PAGES_NUMBER.into(), page_costs: PageCosts::new_for_tests(), existential_deposit: 0, diff --git a/pallets/gear/src/benchmarking/utils.rs b/pallets/gear/src/benchmarking/utils.rs index ad918924ca8..a6df303d2ac 100644 --- a/pallets/gear/src/benchmarking/utils.rs +++ b/pallets/gear/src/benchmarking/utils.rs @@ -63,6 +63,7 @@ where BlockConfig { block_info, + performance_multiplier: T::PerformanceMultiplier::get(), max_pages: T::Schedule::get().limits.memory_pages.into(), page_costs: T::Schedule::get().memory_weights.into(), existential_deposit, diff --git a/pallets/gear/src/lib.rs b/pallets/gear/src/lib.rs index ff267066288..5bef97c2c9c 100644 --- a/pallets/gear/src/lib.rs +++ b/pallets/gear/src/lib.rs @@ -72,6 +72,7 @@ use gear_core::{ memory::PageBuf, message::*, pages::{GearPage, WasmPage}, + percent::Percent, }; use manager::{CodeInfo, QueuePostProcessingData}; use primitive_types::H256; @@ -167,6 +168,10 @@ pub mod pallet { #[pallet::constant] type OutgoingLimit: Get; + /// Performance multiplier. + #[pallet::constant] + type PerformanceMultiplier: Get; + type DebugInfo: DebugInfo; /// Implementation of a storage for program binary codes. @@ -1028,6 +1033,7 @@ pub mod pallet { BlockConfig { block_info, + performance_multiplier: T::PerformanceMultiplier::get(), max_pages: schedule.limits.memory_pages.into(), page_costs: schedule.memory_weights.clone().into(), existential_deposit, diff --git a/pallets/gear/src/mock.rs b/pallets/gear/src/mock.rs index 6ddddaa70ca..a8113a9342d 100644 --- a/pallets/gear/src/mock.rs +++ b/pallets/gear/src/mock.rs @@ -155,6 +155,7 @@ parameter_types! { pub RentCostPerBlock: Balance = 11; pub ResumeMinimalPeriod: BlockNumber = 100; pub ResumeSessionDuration: BlockNumber = 1_000; + pub const PerformanceMultiplier: u32 = 100; } thread_local! { @@ -217,6 +218,7 @@ impl pallet_gear::Config for Test { type WeightInfo = pallet_gear::weights::SubstrateWeight; type Schedule = DynamicSchedule; type OutgoingLimit = OutgoingLimit; + type PerformanceMultiplier = PerformanceMultiplier; type DebugInfo = (); type CodeStorage = GearProgram; type ProgramStorage = GearProgram; diff --git a/pallets/payment/src/mock.rs b/pallets/payment/src/mock.rs index a511c7c92bc..414bef402ae 100644 --- a/pallets/payment/src/mock.rs +++ b/pallets/payment/src/mock.rs @@ -167,6 +167,7 @@ impl pallet_transaction_payment::Config for Test { parameter_types! { pub const BlockGasLimit: u64 = 500_000; pub const OutgoingLimit: u32 = 1024; + pub const PerformanceMultiplier: u32 = 100; pub GearSchedule: pallet_gear::Schedule = >::default(); pub RentFreePeriod: BlockNumber = 1_000; pub RentCostPerBlock: Balance = 11; @@ -188,6 +189,7 @@ impl pallet_gear::Config for Test { type WeightInfo = (); type Schedule = GearSchedule; type OutgoingLimit = OutgoingLimit; + type PerformanceMultiplier = PerformanceMultiplier; type DebugInfo = (); type CodeStorage = GearProgram; type ProgramStorage = GearProgram; diff --git a/runtime/gear/src/lib.rs b/runtime/gear/src/lib.rs index 9bedffb36e0..4a6b5a2dbb5 100644 --- a/runtime/gear/src/lib.rs +++ b/runtime/gear/src/lib.rs @@ -450,6 +450,8 @@ parameter_types! { pub const OutgoingLimit: u32 = 1024; pub const MailboxThreshold: u64 = 3000; + + pub const PerformanceMultiplier: u32 = 100; } parameter_types! { @@ -470,6 +472,7 @@ impl pallet_gear::Config for Runtime { type WeightInfo = weights::pallet_gear::SubstrateWeight; type Schedule = Schedule; type OutgoingLimit = OutgoingLimit; + type PerformanceMultiplier = PerformanceMultiplier; type DebugInfo = DebugInfo; type CodeStorage = GearProgram; type ProgramStorage = GearProgram; diff --git a/runtime/vara/src/lib.rs b/runtime/vara/src/lib.rs index c15660bd521..fadaac51377 100644 --- a/runtime/vara/src/lib.rs +++ b/runtime/vara/src/lib.rs @@ -954,6 +954,8 @@ parameter_types! { pub const OutgoingLimit: u32 = 1024; pub const MailboxThreshold: u64 = 3000; + + pub const PerformanceMultiplier: u32 = 100; } parameter_types! { @@ -974,6 +976,7 @@ impl pallet_gear::Config for Runtime { type WeightInfo = weights::pallet_gear::SubstrateWeight; type Schedule = Schedule; type OutgoingLimit = OutgoingLimit; + type PerformanceMultiplier = PerformanceMultiplier; type DebugInfo = DebugInfo; type CodeStorage = GearProgram; type ProgramStorage = GearProgram;