diff --git a/evm-tests b/evm-tests index e16c64abe..b9829deca 160000 --- a/evm-tests +++ b/evm-tests @@ -1 +1 @@ -Subproject commit e16c64abefac7201204f6fbf070c5d746fc501bf +Subproject commit b9829decaa7c8861aad91374c9a20a2c62d785a0 diff --git a/modules/evm/src/bench/mock.rs b/modules/evm/src/bench/mock.rs index c67b4c859..fc0ea5363 100644 --- a/modules/evm/src/bench/mock.rs +++ b/modules/evm/src/bench/mock.rs @@ -34,7 +34,7 @@ pub use primitives::{ }; use sp_core::{H160, H256}; use sp_runtime::{ - traits::{BlakeTwo256, IdentityLookup}, + traits::{BlakeTwo256, BlockNumberProvider, IdentityLookup}, AccountId32, }; @@ -141,13 +141,26 @@ define_combined_task! { parameter_types!( pub MinimumWeightRemainInBlock: Weight = u64::MIN; + pub const DisableBlockThreshold: BlockNumber = 6; ); +pub struct MockBlockNumberProvider; + +impl BlockNumberProvider for MockBlockNumberProvider { + type BlockNumber = u32; + + fn current_block_number() -> Self::BlockNumber { + Zero::zero() + } +} + impl module_idle_scheduler::Config for Runtime { type Event = Event; type WeightInfo = (); type Task = ScheduledTasks; type MinimumWeightRemainInBlock = MinimumWeightRemainInBlock; + type RelayChainBlockNumberProvider = MockBlockNumberProvider; + type DisableBlockThreshold = DisableBlockThreshold; } pub struct GasToWeight; diff --git a/modules/evm/src/mock.rs b/modules/evm/src/mock.rs index f75ca3a70..9832cffb2 100644 --- a/modules/evm/src/mock.rs +++ b/modules/evm/src/mock.rs @@ -32,7 +32,7 @@ use primitives::{define_combined_task, Amount, BlockNumber, CurrencyId, ReserveI use sp_core::{H160, H256}; use sp_runtime::{ testing::Header, - traits::{BlakeTwo256, IdentityLookup}, + traits::{BlakeTwo256, BlockNumberProvider, IdentityLookup}, AccountId32, }; use std::{collections::BTreeMap, str::FromStr}; @@ -140,13 +140,26 @@ define_combined_task! { parameter_types!( pub MinimumWeightRemainInBlock: Weight = u64::MIN; + pub DisableBlockThreshold: BlockNumber = u32::MAX; ); +pub struct MockBlockNumberProvider; + +impl BlockNumberProvider for MockBlockNumberProvider { + type BlockNumber = u32; + + fn current_block_number() -> Self::BlockNumber { + Zero::zero() + } +} + impl module_idle_scheduler::Config for Runtime { type Event = Event; type WeightInfo = (); type Task = ScheduledTasks; type MinimumWeightRemainInBlock = MinimumWeightRemainInBlock; + type RelayChainBlockNumberProvider = MockBlockNumberProvider; + type DisableBlockThreshold = DisableBlockThreshold; } pub struct GasToWeight; diff --git a/modules/idle-scheduler/src/lib.rs b/modules/idle-scheduler/src/lib.rs index 47dc40553..eaa74d055 100644 --- a/modules/idle-scheduler/src/lib.rs +++ b/modules/idle-scheduler/src/lib.rs @@ -23,14 +23,15 @@ #![cfg_attr(not(feature = "std"), no_std)] #![allow(clippy::unused_unit)] #![allow(unused_must_use)] -use acala_primitives::{task::TaskResult, Nonce}; +use acala_primitives::{task::TaskResult, BlockNumber, Nonce}; use codec::FullCodec; +use frame_support::log; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; pub use module_support::{DispatchableTask, IdleScheduler}; use scale_info::TypeInfo; use sp_runtime::{ - traits::{One, Zero}, + traits::{BlockNumberProvider, One}, ArithmeticError, }; use sp_std::{cmp::PartialEq, fmt::Debug, prelude::*}; @@ -58,6 +59,15 @@ pub mod module { /// The minimum weight that should remain before idle tasks are dispatched. #[pallet::constant] type MinimumWeightRemainInBlock: Get; + + /// Gets RelayChain Block Number + type RelayChainBlockNumberProvider: BlockNumberProvider; + + /// Number of Relay Chain blocks skipped to disable `on_idle` dispatching scheduled tasks + /// this shuts down idle-scheduler when block production is slower than this number of + /// relaychain blocks + #[pallet::constant] + type DisableBlockThreshold: Get; } #[pallet::event] @@ -76,14 +86,50 @@ pub mod module { #[pallet::getter(fn next_task_id)] pub type NextTaskId = StorageValue<_, Nonce, ValueQuery>; + /// + #[pallet::storage] + #[pallet::getter(fn previous_relay_block)] + pub type PreviousRelayBlockNumber = StorageValue<_, BlockNumber, ValueQuery>; + #[pallet::pallet] #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::hooks] impl Hooks for Pallet { + fn on_initialize(_n: T::BlockNumber) -> Weight { + // This is the previous relay block because `on_initialize` is executed + // before the inherent that sets the new relay chain block number + let previous_relay_block: BlockNumber = T::RelayChainBlockNumberProvider::current_block_number(); + + PreviousRelayBlockNumber::::put(previous_relay_block); + T::WeightInfo::on_initialize() + } + fn on_idle(_n: T::BlockNumber, remaining_weight: Weight) -> Weight { - Self::do_dispatch_tasks(remaining_weight) + // Checks if we have skipped enough relay blocks without block production to skip dispatching + // scheduled tasks + let current_relay_block_number: BlockNumber = T::RelayChainBlockNumberProvider::current_block_number(); + let previous_relay_block_number = PreviousRelayBlockNumber::::take(); + if current_relay_block_number.saturating_sub(previous_relay_block_number) >= T::DisableBlockThreshold::get() + { + log::debug!( + target: "idle-scheduler", + "Relaychain produced blocks without finalizing parachain blocks. Idle-scheduler will not execute.\ncurrent relay block number: {:?}\nprevious relay block number: {:?}", + current_relay_block_number, + previous_relay_block_number + ); + // something is not correct so exaust all remaining weight (note: any on_idle hooks after + // IdleScheduler won't execute) + remaining_weight + } else { + Self::do_dispatch_tasks(remaining_weight) + } + } + + fn on_finalize(_n: T::BlockNumber) { + // Don't commit to storage, needed for the case block is full and `on_idle` isn't called + PreviousRelayBlockNumber::::kill(); } } @@ -116,9 +162,10 @@ impl Pallet { /// Keep dispatching tasks in Storage, until insufficient weight remains. pub fn do_dispatch_tasks(total_weight: Weight) -> Weight { - let mut weight_remaining = total_weight; + let mut weight_remaining = total_weight.saturating_sub(T::WeightInfo::on_idle_base()); if weight_remaining <= T::MinimumWeightRemainInBlock::get() { - return Zero::zero(); + // return total weight so no `on_idle` hook will execute after IdleScheduler + return total_weight; } let mut completed_tasks: Vec<(Nonce, TaskResult)> = vec![]; @@ -128,6 +175,7 @@ impl Pallet { weight_remaining = weight_remaining.saturating_sub(result.used_weight); if result.finished { completed_tasks.push((id, result)); + weight_remaining = weight_remaining.saturating_sub(T::WeightInfo::clear_tasks()); } // If remaining weight falls below the minimmum, break from the loop. @@ -136,6 +184,13 @@ impl Pallet { } } + Self::remove_completed_tasks(completed_tasks); + + total_weight.saturating_sub(weight_remaining) + } + + // Removes completed tasks and deposits events + pub fn remove_completed_tasks(completed_tasks: Vec<(Nonce, TaskResult)>) { // Deposit event and remove completed tasks. for (id, result) in completed_tasks { Self::deposit_event(Event::::TaskDispatched { @@ -144,8 +199,6 @@ impl Pallet { }); Tasks::::remove(id); } - - total_weight.saturating_sub(weight_remaining) } } diff --git a/modules/idle-scheduler/src/mock.rs b/modules/idle-scheduler/src/mock.rs index 16045fc7d..d7e76c0c9 100644 --- a/modules/idle-scheduler/src/mock.rs +++ b/modules/idle-scheduler/src/mock.rs @@ -25,11 +25,14 @@ use acala_primitives::{define_combined_task, task::TaskResult}; use frame_support::weights::Weight; use frame_support::{construct_runtime, parameter_types, traits::Everything}; use module_support::DispatchableTask; +pub use sp_runtime::offchain::storage::StorageValueRef; +use super::*; use codec::{Decode, Encode}; use scale_info::TypeInfo; pub const BASE_WEIGHT: Weight = 1_000_000; +pub const RELAY_BLOCK_KEY: [u8; 32] = [0; 32]; parameter_types!( pub const BlockHashCount: u32 = 250; @@ -65,13 +68,27 @@ impl frame_system::Config for Runtime { parameter_types!( pub const MinimumWeightRemainInBlock: Weight = 100_000_000_000; + pub const DisableBlockThreshold: BlockNumber = 6; ); +pub struct MockBlockNumberProvider; + +impl BlockNumberProvider for MockBlockNumberProvider { + type BlockNumber = u32; + + fn current_block_number() -> Self::BlockNumber { + // gets a local mock storage value + u32::decode(&mut &sp_io::storage::get(&RELAY_BLOCK_KEY).unwrap()[..]).unwrap() + } +} + impl module_idle_scheduler::Config for Runtime { type Event = Event; type WeightInfo = (); type Task = ScheduledTasks; type MinimumWeightRemainInBlock = MinimumWeightRemainInBlock; + type RelayChainBlockNumberProvider = MockBlockNumberProvider; + type DisableBlockThreshold = DisableBlockThreshold; } // Mock dispatachable tasks @@ -137,6 +154,7 @@ impl ExtBuilder { let mut ext = sp_io::TestExternalities::new(t); ext.execute_with(|| System::set_block_number(1)); + ext.execute_with(|| sp_io::storage::set(&RELAY_BLOCK_KEY, &0_u32.encode())); ext } } diff --git a/modules/idle-scheduler/src/tests.rs b/modules/idle-scheduler/src/tests.rs index 997c69460..225f22305 100644 --- a/modules/idle-scheduler/src/tests.rs +++ b/modules/idle-scheduler/src/tests.rs @@ -69,8 +69,9 @@ fn can_process_tasks_up_to_weight_limit() { ScheduledTasks::HomaLiteTask(HomaLiteTask::OnIdle) )); - // Given enough weights for only 2 tasks: MinimumWeightRemainInBlock::get() + BASE_WEIGHT*2 - IdleScheduler::on_idle(0, 100_002_000_000); + // Given enough weights for only 2 tasks: MinimumWeightRemainInBlock::get() + BASE_WEIGHT*2 + + // on_idle_base() + IdleScheduler::on_idle(0, 100_002_000_000 + <()>::on_idle_base() + (<()>::clear_tasks() * 2)); // Due to hashing, excution is not guaranteed to be in order. assert_eq!( @@ -80,13 +81,13 @@ fn can_process_tasks_up_to_weight_limit() { assert_eq!(Tasks::::get(1), None); assert_eq!(Tasks::::get(2), None); - IdleScheduler::on_idle(0, 100_000_000_000); + IdleScheduler::on_idle(0, 100_000_000_000 + <()>::on_idle_base()); assert_eq!( Tasks::::get(0), Some(ScheduledTasks::BalancesTask(BalancesTask::OnIdle)) ); - IdleScheduler::on_idle(0, 100_001_000_000); + IdleScheduler::on_idle(0, 100_001_000_000 + <()>::on_idle_base()); assert_eq!(Tasks::::get(0), None); }); } @@ -104,3 +105,26 @@ fn can_increment_next_task_id() { assert_eq!(NextTaskId::::get(), 1); }); } + +#[test] +fn on_idle_works() { + ExtBuilder::default().build().execute_with(|| { + IdleScheduler::on_initialize(0); + assert_ok!(IdleScheduler::schedule_task( + Origin::root(), + ScheduledTasks::BalancesTask(BalancesTask::OnIdle) + )); + // simulate relay block number jumping 10 blocks + sp_io::storage::set(&RELAY_BLOCK_KEY, &10_u32.encode()); + assert_eq!(IdleScheduler::on_idle(System::block_number(), u64::MAX), u64::MAX); + + System::set_block_number(1); + IdleScheduler::on_initialize(1); + // On_initialize is called it will execute, as now relay block number is the same + assert_eq!( + IdleScheduler::on_idle(System::block_number(), u64::MAX), + BASE_WEIGHT + <()>::on_idle_base() + <()>::clear_tasks() + ); + assert!(!PreviousRelayBlockNumber::::exists()); + }); +} diff --git a/modules/idle-scheduler/src/weights.rs b/modules/idle-scheduler/src/weights.rs index 3c602e101..0522a0a43 100644 --- a/modules/idle-scheduler/src/weights.rs +++ b/modules/idle-scheduler/src/weights.rs @@ -16,11 +16,11 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -//! Autogenerated weights for module_homa_lite +//! Autogenerated weights for module_idle_scheduler //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2021-10-03, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 +//! DATE: 2022-04-04, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: // target/release/acala @@ -28,14 +28,13 @@ // --chain=dev // --steps=50 // --repeat=20 -// --pallet=module-homa-lite +// --pallet=module_idle_scheduler // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 +// --output=./modules/idle-scheduler/src/weights.rs // --template=./templates/module-weight-template.hbs -// --output=./modules/homa-lite/src/weights.rs - #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -45,26 +44,62 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; -/// Weight functions needed for module_homa_lite. +/// Weight functions needed for module_idle_scheduler. pub trait WeightInfo { + fn on_initialize() -> Weight; + fn on_idle_base() -> Weight; + fn clear_tasks() -> Weight; fn schedule_task() -> Weight; } -/// Weights for module_homa_lite using the Acala node and recommended hardware. +/// Weights for module_idle_scheduler using the Acala node and recommended hardware. pub struct AcalaWeight(PhantomData); impl WeightInfo for AcalaWeight { + // Storage: ParachainSystem ValidationData (r:1 w:0) + // Storage: IdleScheduler PreviousRelayBlockNumber (r:0 w:1) + fn on_initialize() -> Weight { + (2_545_000 as Weight) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: ParachainSystem ValidationData (r:1 w:0) + // Storage: IdleScheduler PreviousRelayBlockNumber (r:1 w:0) + fn on_idle_base() -> Weight { + (3_627_000 as Weight) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + } + // Storage: IdleScheduler Tasks (r:0 w:1) + fn clear_tasks() -> Weight { + (9_181_000 as Weight) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + // Storage: IdleScheduler NextTaskId (r:1 w:1) + // Storage: IdleScheduler Tasks (r:0 w:1) fn schedule_task() -> Weight { - (34_000_000 as Weight) - .saturating_add(T::DbWeight::get().reads(8 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) + (4_103_000 as Weight) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) } } // For backwards compatibility and tests impl WeightInfo for () { + fn on_initialize() -> Weight { + (2_545_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + fn on_idle_base() -> Weight { + (3_627_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + } + fn clear_tasks() -> Weight { + (9_181_000 as Weight) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } fn schedule_task() -> Weight { - (34_000_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(8 as Weight)) - .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + (4_103_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } } diff --git a/runtime/acala/src/benchmarking/mod.rs b/runtime/acala/src/benchmarking/mod.rs index 851b72513..b78de0a42 100644 --- a/runtime/acala/src/benchmarking/mod.rs +++ b/runtime/acala/src/benchmarking/mod.rs @@ -60,6 +60,9 @@ pub mod homa { pub mod honzon { include!("../../../mandala/src/benchmarking/honzon.rs"); } +pub mod idle_scheduler { + include!("../../../mandala/src/benchmarking/idle_scheduler.rs"); +} pub mod incentives { include!("../../../mandala/src/benchmarking/incentives.rs"); } diff --git a/runtime/acala/src/lib.rs b/runtime/acala/src/lib.rs index 489a5d693..286d84a16 100644 --- a/runtime/acala/src/lib.rs +++ b/runtime/acala/src/lib.rs @@ -58,6 +58,7 @@ use module_relaychain::RelayChainCallBuilder; use module_support::{AssetIdMapping, DispatchableTask}; use module_transaction_payment::{Multiplier, TargetedFeeAdjustment, TransactionFeePoolTrader}; +use cumulus_pallet_parachain_system::RelaychainBlockNumberProvider; use orml_traits::{ create_median_value_data_provider, parameter_type_with_key, DataFeeder, DataProviderExtended, GetByKey, }; @@ -98,9 +99,8 @@ pub use runtime_common::{ FinancialCouncilInstance, FinancialCouncilMembershipInstance, GasToWeight, GeneralCouncilInstance, GeneralCouncilMembershipInstance, HomaCouncilInstance, HomaCouncilMembershipInstance, MaxTipsOfPriority, OffchainSolutionWeightLimit, OperationalFeeMultiplier, OperatorMembershipInstanceAcala, Price, ProxyType, Rate, - Ratio, RelayChainBlockNumberProvider, RuntimeBlockLength, RuntimeBlockWeights, SystemContractsFilter, - TechnicalCommitteeInstance, TechnicalCommitteeMembershipInstance, TimeStampedPrice, TipPerWeightStep, ACA, AUSD, - DOT, LCDOT, LDOT, RENBTC, + Ratio, RuntimeBlockLength, RuntimeBlockWeights, SystemContractsFilter, TechnicalCommitteeInstance, + TechnicalCommitteeMembershipInstance, TimeStampedPrice, TipPerWeightStep, ACA, AUSD, DOT, LCDOT, LDOT, RENBTC, }; pub use xcm::latest::prelude::*; @@ -846,7 +846,7 @@ impl module_prices::Config for Runtime { type Currency = Currencies; type Erc20InfoMapping = EvmErc20InfoMapping; type LiquidCrowdloanLeaseBlockNumber = LiquidCrowdloanLeaseBlockNumber; - type RelayChainBlockNumber = RelayChainBlockNumberProvider; + type RelayChainBlockNumber = RelaychainBlockNumberProvider; type RewardRatePerRelaychainBlock = RewardRatePerRelaychainBlock; type PricingPegged = PricingPegged; type WeightInfo = weights::module_prices::WeightInfo; @@ -918,7 +918,7 @@ impl orml_vesting::Config for Runtime { type VestedTransferOrigin = EnsureAcalaFoundation; type WeightInfo = weights::orml_vesting::WeightInfo; type MaxVestingSchedules = MaxVestingSchedules; - type BlockNumberProvider = RelayChainBlockNumberProvider; + type BlockNumberProvider = RelaychainBlockNumberProvider; } parameter_types! { @@ -1473,7 +1473,7 @@ impl module_homa::Config for Runtime { type BondingDuration = BondingDuration; type MintThreshold = MintThreshold; type RedeemThreshold = RedeemThreshold; - type RelayChainBlockNumber = RelayChainBlockNumberProvider; + type RelayChainBlockNumber = RelaychainBlockNumberProvider; type XcmInterface = XcmInterface; type WeightInfo = weights::module_homa::WeightInfo; } @@ -1530,6 +1530,9 @@ define_combined_task! { parameter_types!( // At least 2% of max block weight should remain before idle tasks are dispatched. pub MinimumWeightRemainInBlock: Weight = RuntimeBlockWeights::get().max_block / 50; + // Number of relay chain blocks produced with no parachain blocks finalized, + // once this number is reached idle scheduler is disabled as block production is slow + pub DisableBlockThreshold: BlockNumber = 6; ); impl module_idle_scheduler::Config for Runtime { @@ -1537,6 +1540,8 @@ impl module_idle_scheduler::Config for Runtime { type WeightInfo = (); type Task = ScheduledTasks; type MinimumWeightRemainInBlock = MinimumWeightRemainInBlock; + type RelayChainBlockNumberProvider = RelaychainBlockNumberProvider; + type DisableBlockThreshold = DisableBlockThreshold; } construct_runtime!( @@ -1553,6 +1558,7 @@ construct_runtime!( Multisig: pallet_multisig = 4, Proxy: pallet_proxy = 5, TransactionPause: module_transaction_pause = 6, + // NOTE: IdleScheduler must be put before ParachainSystem in order to read relaychain blocknumber IdleScheduler: module_idle_scheduler = 7, Preimage: pallet_preimage = 8, @@ -1736,6 +1742,7 @@ mod benches { [orml_auction, benchmarking::auction] [orml_authority, benchmarking::authority] [orml_oracle, benchmarking::oracle] + [module_idle_scheduler, benchmarking::idle_scheduler] ); } diff --git a/runtime/common/src/lib.rs b/runtime/common/src/lib.rs index 749decbfe..9ac50680e 100644 --- a/runtime/common/src/lib.rs +++ b/runtime/common/src/lib.rs @@ -33,14 +33,10 @@ use frame_support::{ }; use frame_system::{limits, EnsureRoot}; pub use module_support::{ExchangeRate, PrecompileCallerFilter, Price, Rate, Ratio}; -use primitives::{evm::is_system_contract, Balance, BlockNumber, CurrencyId, Nonce}; +use primitives::{evm::is_system_contract, Balance, CurrencyId, Nonce}; use scale_info::TypeInfo; use sp_core::{Bytes, H160}; -use sp_runtime::{ - traits::{BlockNumberProvider, Convert}, - transaction_validity::TransactionPriority, - FixedPointNumber, Perbill, -}; +use sp_runtime::{traits::Convert, transaction_validity::TransactionPriority, FixedPointNumber, Perbill}; use sp_std::collections::btree_map::BTreeMap; use static_assertions::const_assert; @@ -197,18 +193,6 @@ pub fn calculate_asset_ratio(foreign_asset: (AssetId, u128), native_asset: (Asse Ratio::saturating_from_rational(foreign_asset.1, native_asset.1) } -pub struct RelayChainBlockNumberProvider(sp_std::marker::PhantomData); - -impl BlockNumberProvider for RelayChainBlockNumberProvider { - type BlockNumber = BlockNumber; - - fn current_block_number() -> Self::BlockNumber { - cumulus_pallet_parachain_system::Pallet::::validation_data() - .map(|d| d.relay_parent_number) - .unwrap_or_default() - } -} - pub type GeneralCouncilInstance = pallet_collective::Instance1; pub type FinancialCouncilInstance = pallet_collective::Instance2; pub type HomaCouncilInstance = pallet_collective::Instance3; diff --git a/runtime/common/src/mock.rs b/runtime/common/src/mock.rs index c76e683d8..46b7e7155 100644 --- a/runtime/common/src/mock.rs +++ b/runtime/common/src/mock.rs @@ -37,7 +37,7 @@ use sp_runtime::traits::Convert; pub use sp_runtime::AccountId32; use sp_runtime::{ testing::Header, - traits::{BlakeTwo256, IdentityLookup}, + traits::{BlakeTwo256, BlockNumberProvider, IdentityLookup, Zero}, }; use std::str::FromStr; @@ -148,13 +148,26 @@ define_combined_task! { parameter_types!( pub MinimumWeightRemainInBlock: Weight = u64::MIN; + pub DisableBlockThreshold: BlockNumber = u32::MAX; ); +pub struct MockBlockNumberProvider; + +impl BlockNumberProvider for MockBlockNumberProvider { + type BlockNumber = u32; + + fn current_block_number() -> Self::BlockNumber { + Zero::zero() + } +} + impl module_idle_scheduler::Config for TestRuntime { type Event = Event; type WeightInfo = (); type Task = ScheduledTasks; type MinimumWeightRemainInBlock = MinimumWeightRemainInBlock; + type RelayChainBlockNumberProvider = MockBlockNumberProvider; + type DisableBlockThreshold = DisableBlockThreshold; } pub struct GasToWeight; diff --git a/runtime/common/src/precompile/mock.rs b/runtime/common/src/precompile/mock.rs index 3c5623627..cdff8991f 100644 --- a/runtime/common/src/precompile/mock.rs +++ b/runtime/common/src/precompile/mock.rs @@ -199,13 +199,26 @@ define_combined_task! { parameter_types!( pub MinimumWeightRemainInBlock: Weight = u64::MIN; + pub DisableBlockThreshold: BlockNumber = u32::MAX; ); +pub struct MockBlockNumberProvider; + +impl BlockNumberProvider for MockBlockNumberProvider { + type BlockNumber = u32; + + fn current_block_number() -> Self::BlockNumber { + Zero::zero() + } +} + impl module_idle_scheduler::Config for Test { type Event = Event; type WeightInfo = (); type Task = ScheduledTasks; type MinimumWeightRemainInBlock = MinimumWeightRemainInBlock; + type RelayChainBlockNumberProvider = MockBlockNumberProvider; + type DisableBlockThreshold = DisableBlockThreshold; } parameter_types! { diff --git a/runtime/integration-tests/src/homa_lite.rs b/runtime/integration-tests/src/homa_lite.rs index 2420ca27a..406d687b8 100644 --- a/runtime/integration-tests/src/homa_lite.rs +++ b/runtime/integration-tests/src/homa_lite.rs @@ -638,7 +638,7 @@ mod karura_only_tests { set_relaychain_block_number(101_000); run_to_block(5); assert_eq!( - RelayChainBlockNumberProvider::::current_block_number(), + RelaychainBlockNumberProvider::::current_block_number(), 101_000 ); HomaLite::on_idle(5, 1_000_000_000); diff --git a/runtime/integration-tests/src/setup.rs b/runtime/integration-tests/src/setup.rs index f043acf6f..015a79de2 100644 --- a/runtime/integration-tests/src/setup.rs +++ b/runtime/integration-tests/src/setup.rs @@ -27,6 +27,7 @@ pub use module_support::{ mocks::MockAddressMapping, AddressMapping, CDPTreasury, DEXManager, Price, Rate, Ratio, RiskManager, }; +pub use cumulus_pallet_parachain_system::RelaychainBlockNumberProvider; pub use orml_traits::{location::RelativeLocations, Change, GetByKey, MultiCurrency}; pub use primitives::currency::*; @@ -93,9 +94,9 @@ mod karura_imports { FinancialCouncil, Get, GetNativeCurrencyId, Homa, Honzon, IdleScheduler, KaruraFoundationAccounts, Loans, MaxTipsOfPriority, MinimumDebitValue, MultiLocation, NativeTokenExistentialDeposit, NetworkId, NftPalletId, OneDay, Origin, OriginCaller, ParachainAccount, ParachainInfo, ParachainSystem, PolkadotXcm, Proxy, ProxyType, - Ratio, RelayChainBlockNumberProvider, Runtime, Scheduler, Session, SessionManager, SevenDays, System, - Timestamp, TipPerWeightStep, TokenSymbol, Tokens, TransactionPayment, TransactionPaymentPalletId, - TreasuryPalletId, Utility, Vesting, XTokens, XcmInterface, EVM, NFT, + Ratio, Runtime, Scheduler, Session, SessionManager, SevenDays, System, Timestamp, TipPerWeightStep, + TokenSymbol, Tokens, TransactionPayment, TransactionPaymentPalletId, TreasuryPalletId, Utility, Vesting, + XTokens, XcmInterface, EVM, NFT, }; pub use primitives::TradingPair; pub use runtime_common::{calculate_asset_ratio, cent, dollar, millicent, KAR, KSM, KUSD, LKSM}; @@ -141,10 +142,10 @@ mod acala_imports { DataDepositPerByte, DefaultExchangeRate, Dex, EmergencyShutdown, Event, EvmAccounts, ExistentialDeposits, FinancialCouncil, Get, GetNativeCurrencyId, Homa, Honzon, IdleScheduler, Loans, MaxTipsOfPriority, MinimumDebitValue, MultiLocation, NativeTokenExistentialDeposit, NetworkId, NftPalletId, OneDay, Origin, - OriginCaller, ParachainAccount, ParachainInfo, ParachainSystem, PolkadotXcm, Proxy, ProxyType, Ratio, - RelayChainBlockNumberProvider, Runtime, Scheduler, Session, SessionManager, SevenDays, System, Timestamp, - TipPerWeightStep, TokenSymbol, Tokens, TransactionPayment, TransactionPaymentPalletId, TreasuryPalletId, - Utility, Vesting, XTokens, XcmInterface, EVM, LCDOT, NFT, + OriginCaller, ParachainAccount, ParachainInfo, ParachainSystem, PolkadotXcm, Proxy, ProxyType, Ratio, Runtime, + Scheduler, Session, SessionManager, SevenDays, System, Timestamp, TipPerWeightStep, TokenSymbol, Tokens, + TransactionPayment, TransactionPaymentPalletId, TreasuryPalletId, Utility, Vesting, XTokens, XcmInterface, EVM, + LCDOT, NFT, }; pub use frame_support::parameter_types; pub use primitives::TradingPair; diff --git a/runtime/karura/src/benchmarking/mod.rs b/runtime/karura/src/benchmarking/mod.rs index 702a844b6..15ff498b7 100644 --- a/runtime/karura/src/benchmarking/mod.rs +++ b/runtime/karura/src/benchmarking/mod.rs @@ -60,6 +60,9 @@ pub mod homa { pub mod honzon { include!("../../../mandala/src/benchmarking/honzon.rs"); } +pub mod idle_scheduler { + include!("../../../mandala/src/benchmarking/idle_scheduler.rs"); +} pub mod incentives { include!("../../../mandala/src/benchmarking/incentives.rs"); } diff --git a/runtime/karura/src/lib.rs b/runtime/karura/src/lib.rs index 8f4076ca5..ce8e7d5a5 100644 --- a/runtime/karura/src/lib.rs +++ b/runtime/karura/src/lib.rs @@ -58,6 +58,7 @@ use module_relaychain::RelayChainCallBuilder; use module_support::{AssetIdMapping, DispatchableTask, ExchangeRateProvider}; use module_transaction_payment::{Multiplier, TargetedFeeAdjustment, TransactionFeePoolTrader}; +use cumulus_pallet_parachain_system::RelaychainBlockNumberProvider; use orml_traits::{ create_median_value_data_provider, parameter_type_with_key, DataFeeder, DataProviderExtended, GetByKey, }; @@ -97,10 +98,9 @@ pub use runtime_common::{ EnsureRootOrTwoThirdsGeneralCouncil, EnsureRootOrTwoThirdsTechnicalCommittee, ExchangeRate, FinancialCouncilInstance, FinancialCouncilMembershipInstance, GasToWeight, GeneralCouncilInstance, GeneralCouncilMembershipInstance, HomaCouncilInstance, HomaCouncilMembershipInstance, MaxTipsOfPriority, - OperationalFeeMultiplier, OperatorMembershipInstanceAcala, Price, ProxyType, Rate, Ratio, - RelayChainBlockNumberProvider, RuntimeBlockLength, RuntimeBlockWeights, SystemContractsFilter, - TechnicalCommitteeInstance, TechnicalCommitteeMembershipInstance, TimeStampedPrice, TipPerWeightStep, BNC, KAR, - KBTC, KINT, KSM, KUSD, LKSM, PHA, RENBTC, VSKSM, + OperationalFeeMultiplier, OperatorMembershipInstanceAcala, Price, ProxyType, Rate, Ratio, RuntimeBlockLength, + RuntimeBlockWeights, SystemContractsFilter, TechnicalCommitteeInstance, TechnicalCommitteeMembershipInstance, + TimeStampedPrice, TipPerWeightStep, BNC, KAR, KBTC, KINT, KSM, KUSD, LKSM, PHA, RENBTC, VSKSM, }; pub use xcm::latest::prelude::*; @@ -860,7 +860,7 @@ impl module_prices::Config for Runtime { type Currency = Currencies; type Erc20InfoMapping = EvmErc20InfoMapping; type LiquidCrowdloanLeaseBlockNumber = LiquidCrowdloanLeaseBlockNumber; - type RelayChainBlockNumber = RelayChainBlockNumberProvider; + type RelayChainBlockNumber = RelaychainBlockNumberProvider; type RewardRatePerRelaychainBlock = RewardRatePerRelaychainBlock; type PricingPegged = PricingPegged; type WeightInfo = weights::module_prices::WeightInfo; @@ -932,7 +932,7 @@ impl orml_vesting::Config for Runtime { type VestedTransferOrigin = EnsureKaruraFoundation; type WeightInfo = weights::orml_vesting::WeightInfo; type MaxVestingSchedules = MaxVestingSchedules; - type BlockNumberProvider = RelayChainBlockNumberProvider; + type BlockNumberProvider = RelaychainBlockNumberProvider; } parameter_types! { @@ -1489,7 +1489,7 @@ impl module_homa::Config for Runtime { type BondingDuration = BondingDuration; type MintThreshold = MintThreshold; type RedeemThreshold = RedeemThreshold; - type RelayChainBlockNumber = RelayChainBlockNumberProvider; + type RelayChainBlockNumber = RelaychainBlockNumberProvider; type XcmInterface = XcmInterface; type WeightInfo = weights::module_homa::WeightInfo; } @@ -1546,6 +1546,9 @@ define_combined_task! { parameter_types!( // At least 2% of max block weight should remain before idle tasks are dispatched. pub MinimumWeightRemainInBlock: Weight = RuntimeBlockWeights::get().max_block / 50; + // Number of relay chain blocks produced with no parachain blocks finalized, + // once this number is reached idle scheduler is disabled as block production is slow + pub DisableBlockThreshold: BlockNumber = 6; ); impl module_idle_scheduler::Config for Runtime { @@ -1553,6 +1556,8 @@ impl module_idle_scheduler::Config for Runtime { type WeightInfo = (); type Task = ScheduledTasks; type MinimumWeightRemainInBlock = MinimumWeightRemainInBlock; + type RelayChainBlockNumberProvider = RelaychainBlockNumberProvider; + type DisableBlockThreshold = DisableBlockThreshold; } parameter_types! { @@ -1650,6 +1655,7 @@ construct_runtime!( Multisig: pallet_multisig = 4, Proxy: pallet_proxy = 5, TransactionPause: module_transaction_pause = 6, + // NOTE: IdleScheduler must be put before ParachainSystem in order to read relaychain blocknumber IdleScheduler: module_idle_scheduler = 7, Preimage: pallet_preimage = 8, @@ -1841,6 +1847,7 @@ mod benches { [orml_authority, benchmarking::authority] [orml_oracle, benchmarking::oracle] [nutsfinance_stable_asset, benchmarking::nutsfinance_stable_asset] + [module_idle_scheduler, benchmarking::idle_scheduler] ); } diff --git a/runtime/mandala/src/benchmarking/idle_scheduler.rs b/runtime/mandala/src/benchmarking/idle_scheduler.rs new file mode 100644 index 000000000..a1bae1212 --- /dev/null +++ b/runtime/mandala/src/benchmarking/idle_scheduler.rs @@ -0,0 +1,59 @@ +// This file is part of Acala. + +// Copyright (C) 2020-2022 Acala Foundation. +// 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 . + +use crate::{EvmTask, IdleScheduler, Origin, Runtime, ScheduledTasks, H160}; +use frame_support::traits::{OnIdle, OnInitialize}; +use orml_benchmarking::runtime_benchmarks; +use primitives::task::TaskResult; + +runtime_benchmarks! { + { Runtime, module_idle_scheduler} + + on_initialize { + }: { + IdleScheduler::on_initialize(1); + } + + on_idle_base { + }: { + IdleScheduler::on_idle(0, 1_000_000_000); + } + + clear_tasks { + let dummy_hash = [0; 20]; + let call = ScheduledTasks::EvmTask(EvmTask::Remove{caller: H160::from(&dummy_hash), contract: H160::from(&dummy_hash), maintainer: H160::from(&dummy_hash)}); + IdleScheduler::schedule_task(Origin::root(), call)?; + let completed_tasks = vec![(0, TaskResult{ result: Ok(()), used_weight: 0, finished: true })]; + }: { + IdleScheduler::remove_completed_tasks(completed_tasks); + } + + schedule_task { + let dummy_hash = [0; 20]; + let call = ScheduledTasks::EvmTask(EvmTask::Remove{caller: H160::from(&dummy_hash), contract: H160::from(&dummy_hash), maintainer: H160::from(&dummy_hash)}); + }: _(Origin::root(), call) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::benchmarking::utils::tests::new_test_ext; + use orml_benchmarking::impl_benchmark_test_suite; + + impl_benchmark_test_suite!(new_test_ext(),); +} diff --git a/runtime/mandala/src/benchmarking/mod.rs b/runtime/mandala/src/benchmarking/mod.rs index c474d2e46..b17701429 100644 --- a/runtime/mandala/src/benchmarking/mod.rs +++ b/runtime/mandala/src/benchmarking/mod.rs @@ -37,6 +37,7 @@ pub mod evm; pub mod evm_accounts; pub mod homa; pub mod honzon; +pub mod idle_scheduler; pub mod incentives; pub mod nominees_election; pub mod nutsfinance_stable_asset; diff --git a/runtime/mandala/src/lib.rs b/runtime/mandala/src/lib.rs index 43a98e7e4..f2a20698b 100644 --- a/runtime/mandala/src/lib.rs +++ b/runtime/mandala/src/lib.rs @@ -31,6 +31,7 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); use codec::{Decode, Encode}; +use cumulus_pallet_parachain_system::RelaychainBlockNumberProvider; use frame_support::pallet_prelude::InvalidTransaction; pub use frame_support::{ construct_runtime, log, parameter_types, @@ -106,9 +107,8 @@ pub use runtime_common::{ FinancialCouncilInstance, FinancialCouncilMembershipInstance, GasToWeight, GeneralCouncilInstance, GeneralCouncilMembershipInstance, HomaCouncilInstance, HomaCouncilMembershipInstance, MaxTipsOfPriority, OffchainSolutionWeightLimit, OperationalFeeMultiplier, OperatorMembershipInstanceAcala, Price, ProxyType, Rate, - Ratio, RelayChainBlockNumberProvider, RuntimeBlockLength, RuntimeBlockWeights, SystemContractsFilter, - TechnicalCommitteeInstance, TechnicalCommitteeMembershipInstance, TimeStampedPrice, TipPerWeightStep, ACA, AUSD, - DOT, KSM, LDOT, RENBTC, + Ratio, RuntimeBlockLength, RuntimeBlockWeights, SystemContractsFilter, TechnicalCommitteeInstance, + TechnicalCommitteeMembershipInstance, TimeStampedPrice, TipPerWeightStep, ACA, AUSD, DOT, KSM, LDOT, RENBTC, }; pub use xcm::latest::prelude::*; @@ -866,7 +866,7 @@ impl module_prices::Config for Runtime { type Currency = Currencies; type Erc20InfoMapping = EvmErc20InfoMapping; type LiquidCrowdloanLeaseBlockNumber = LiquidCrowdloanLeaseBlockNumber; - type RelayChainBlockNumber = RelayChainBlockNumberProvider; + type RelayChainBlockNumber = RelaychainBlockNumberProvider; type RewardRatePerRelaychainBlock = RewardRatePerRelaychainBlock; type PricingPegged = PricingPegged; type WeightInfo = weights::module_prices::WeightInfo; @@ -927,7 +927,7 @@ impl orml_vesting::Config for Runtime { type VestedTransferOrigin = EnsureRootOrTreasury; type WeightInfo = weights::orml_vesting::WeightInfo; type MaxVestingSchedules = MaxVestingSchedules; - type BlockNumberProvider = RelayChainBlockNumberProvider; + type BlockNumberProvider = RelaychainBlockNumberProvider; } parameter_types! { @@ -1328,7 +1328,7 @@ impl module_homa::Config for Runtime { type BondingDuration = RelayChainBondingDuration; type MintThreshold = MintThreshold; type RedeemThreshold = RedeemThreshold; - type RelayChainBlockNumber = RelayChainBlockNumberProvider; + type RelayChainBlockNumber = RelaychainBlockNumberProvider; type XcmInterface = XcmInterface; type WeightInfo = weights::module_homa::WeightInfo; } @@ -1722,6 +1722,9 @@ define_combined_task! { parameter_types!( // At least 2% of max block weight should remain before idle tasks are dispatched. pub MinimumWeightRemainInBlock: Weight = RuntimeBlockWeights::get().max_block / 50; + // Number of relay chain blocks produced with no parachain blocks finalized, + // once this number is reached idle scheduler is disabled as block production is slow + pub DisableBlockThreshold: BlockNumber = 6; ); impl module_idle_scheduler::Config for Runtime { @@ -1729,6 +1732,8 @@ impl module_idle_scheduler::Config for Runtime { type WeightInfo = (); type Task = ScheduledTasks; type MinimumWeightRemainInBlock = MinimumWeightRemainInBlock; + type RelayChainBlockNumberProvider = RelaychainBlockNumberProvider; + type DisableBlockThreshold = DisableBlockThreshold; } impl cumulus_pallet_aura_ext::Config for Runtime {} @@ -1882,6 +1887,7 @@ construct_runtime!( Multisig: pallet_multisig = 31, Recovery: pallet_recovery = 32, Proxy: pallet_proxy = 33, + // NOTE: IdleScheduler must be put before ParachainSystem in order to read relaychain blocknumber IdleScheduler: module_idle_scheduler = 34, Indices: pallet_indices = 40, @@ -2011,6 +2017,7 @@ mod benches { [orml_authority, benchmarking::authority] [orml_oracle, benchmarking::oracle] [nutsfinance_stable_asset, benchmarking::nutsfinance_stable_asset] + [module_idle_scheduler, benchmarking::idle_scheduler] ); }