diff --git a/Cargo.lock b/Cargo.lock index ff27769df..ac8baa58e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3194,6 +3194,7 @@ dependencies = [ "pallet-democracy", "pallet-identity", "pallet-insecure-randomness-collective-flip", + "pallet-mock-skip-blocks", "pallet-multisig", "pallet-preimage", "pallet-proxy", @@ -6987,6 +6988,22 @@ dependencies = [ "syn 2.0.65", ] +[[package]] +name = "pallet-contracts-test" +version = "0.1.0" +dependencies = [ + "frame-support", + "frame-system", + "pallet-contracts", + "pallet-contracts-primitives", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-runtime", +] + [[package]] name = "pallet-conviction-voting" version = "4.0.0-dev" @@ -7218,6 +7235,20 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-mock-skip-blocks" +version = "0.1.0" +dependencies = [ + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-runtime", +] + [[package]] name = "pallet-multisig" version = "4.0.0-dev" diff --git a/Cargo.toml b/Cargo.toml index dc0ab9f75..576207876 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,7 @@ members = [ "runtime/integration-tests", "chain-extensions/token", "chain-extensions/price", - "chain-extensions/common", + "chain-extensions/common", "pallets/pallet-mock-skip-blocks", ] # need this because of bifrost farming dependency in runtime diff --git a/node/Cargo.toml b/node/Cargo.toml index 09f12c5c2..3d60349c5 100644 --- a/node/Cargo.toml +++ b/node/Cargo.toml @@ -113,3 +113,5 @@ try-runtime = [ "pendulum-runtime/try-runtime", "try-runtime-cli/try-runtime" ] + +instant-seal = ["foucoco-runtime/instant-seal"] diff --git a/pallets/pallet-mock-skip-blocks/Cargo.toml b/pallets/pallet-mock-skip-blocks/Cargo.toml new file mode 100644 index 000000000..373dc25cd --- /dev/null +++ b/pallets/pallet-mock-skip-blocks/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "pallet-mock-skip-blocks" +version = "0.1.0" +edition = "2021" + +[features] +default = ["std"] +std = [ + "frame-system/std", + "frame-support/std", +] + +instant-seal = [] + +[dependencies] +# hex-literal = { version = "0.3.4", optional = true } +codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive", "max-encoded-len"] } +scale-info = { version = "2.2.0", default-features = false, features = ["derive"] } +serde = { version = "1.0.130", default-features = false, features = ["derive"], optional = true } +frame-support = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42", default-features = false } +frame-system = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42", default-features = false } +sp-io = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42", default-features = false } + +[dev-dependencies] +sp-core = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42", default-features = false } +sp-io = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42", default-features = false } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42", default-features = false } \ No newline at end of file diff --git a/pallets/pallet-mock-skip-blocks/src/lib.rs b/pallets/pallet-mock-skip-blocks/src/lib.rs new file mode 100644 index 000000000..18bc3f839 --- /dev/null +++ b/pallets/pallet-mock-skip-blocks/src/lib.rs @@ -0,0 +1,124 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +// #[cfg(not(feature = "instant-seal"))] +// pub use dummy as pallet; + +pub use pallet::*; + +// #[cfg(not(feature = "instant-seal"))] +// #[frame_support::pallet] +// pub mod dummy { +// use frame_support::pallet_prelude::*; +// +// #[pallet::pallet] +// pub struct Pallet(_); +// +// #[pallet::event] +// #[pallet::generate_deposit(pub(super) fn deposit_event)] +// pub enum Event { +// /// Dummy event +// DummyEvent, +// } +// +// #[pallet::config] +// pub trait Config: frame_system::Config { +// /// Overarching event type +// type RuntimeEvent: From> + IsType<::RuntimeEvent>; +// } +// +// #[pallet::call] +// impl Pallet {} +// } + +//#[cfg(feature = "instant-seal")] +#[cfg(test)] +mod mock; + +//#[cfg(feature = "instant-seal")] +#[cfg(test)] +mod tests; + +//#[cfg(feature = "instant-seal")] +#[frame_support::pallet] +pub mod pallet { + use frame_support::{dispatch::DispatchResult, pallet_prelude::*}; + use frame_system::pallet_prelude::*; + + #[pallet::pallet] + pub struct Pallet(PhantomData); + + #[pallet::error] + pub enum Error { + InvalidBlockNumber, + } + + //const ENCODED_KEY: &[u8] = &hex_literal::hex!("0x26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac"); + + const ENCODED_KEY: &[u8] = &[ + 0x26, 0xaa, 0x39, 0x4e, 0xea, 0x56, 0x30, 0xe0, 0x7c, 0x48, 0xae, 0x0c, + 0x95, 0x58, 0xce, 0xf7, 0x02, 0xa5, 0xc1, 0xb1, 0x9a, 0xb7, 0xa0, 0x4f, + 0x53, 0x6c, 0x51, 0x9a, 0xca, 0x49, 0x83, 0xac, + ]; + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// Desired block number stored + DesiredBlockStored { n: BlockNumberFor }, + /// Desired block number set + BlockSet { n: BlockNumberFor }, + /// Original block number restored + BlockReverted { n: BlockNumberFor }, + } + + #[pallet::hooks] + impl Hooks> for Pallet { + fn on_initialize(n: T::BlockNumber) -> Weight { + let desired_block_number = DesiredBlockNumber::::get(); + OriginalBlockNumber::::put(n); + //frame_system::Pallet::::set_block_number(desired_block_number); + sp_io::storage::set(ENCODED_KEY, &*desired_block_number.encode()); + Self::deposit_event(Event::::BlockSet { n: desired_block_number }); + Weight::from_ref_time(0) + } + + fn on_finalize(_: T::BlockNumber) { + let original_block_number = OriginalBlockNumber::::get(); + //frame_system::Pallet::::set_block_number(original_block_number); + sp_io::storage::set(ENCODED_KEY, &*original_block_number.encode()); + Self::deposit_event(Event::::BlockReverted { n: original_block_number }); + } + } + + #[pallet::storage] + pub type DesiredBlockNumber = StorageValue<_, T::BlockNumber, ValueQuery>; + + #[pallet::storage] + pub type OriginalBlockNumber = StorageValue<_, T::BlockNumber, ValueQuery>; + + #[pallet::config] + pub trait Config: frame_system::Config { + /// Overarching event type + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + } + + #[pallet::call] + impl Pallet { + #[pallet::call_index(0)] + #[pallet::weight((0, Pays::No))] + pub fn set_block_number( + origin: OriginFor, + block_number: T::BlockNumber, + ) -> DispatchResult { + ensure_root(origin)?; + + let current_block_number = frame_system::Pallet::::block_number(); + ensure!(block_number >= current_block_number, Error::::InvalidBlockNumber); + + DesiredBlockNumber::::put(block_number); + Self::deposit_event(Event::::DesiredBlockStored { n: block_number }); + + Ok(()) + } + } +} diff --git a/pallets/pallet-mock-skip-blocks/src/mock.rs b/pallets/pallet-mock-skip-blocks/src/mock.rs new file mode 100644 index 000000000..b6902e1b1 --- /dev/null +++ b/pallets/pallet-mock-skip-blocks/src/mock.rs @@ -0,0 +1,83 @@ +use crate::{self as pallet_mock_skip_blocks, Config}; +use frame_support::{parameter_types, traits::Everything}; +use sp_core::H256; +use sp_runtime::{ + testing::Header, + traits::{BlakeTwo256, IdentityLookup}, +}; + +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlock; + +// Configure a mock runtime to test the pallet. +frame_support::construct_runtime!( + pub enum Test where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system::{Pallet, Call, Storage, Config, Event}, + MockSkipBlocks: pallet_mock_skip_blocks::{Pallet, Storage, Call, Event}, + } +); + +pub type AccountId = u64; +pub type BlockNumber = u64; +pub type Index = u64; + +parameter_types! { + pub const BlockHashCount: u64 = 250; + pub const SS58Prefix: u8 = 42; +} + +pub type TestEvent = RuntimeEvent; + +impl frame_system::Config for Test { + type BaseCallFilter = Everything; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type Index = Index; + type BlockNumber = BlockNumber; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type Header = Header; + type RuntimeEvent = TestEvent; + type BlockHashCount = BlockHashCount; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = (); + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = SS58Prefix; + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + +impl Config for Test { + type RuntimeEvent = RuntimeEvent; +} + +pub struct ExtBuilder; + +impl ExtBuilder { + pub fn build() -> sp_io::TestExternalities { + let storage = frame_system::GenesisConfig::default().build_storage::().unwrap(); + sp_io::TestExternalities::from(storage) + } +} + +pub fn run_test(test: T) +where + T: FnOnce(), +{ + ExtBuilder::build().execute_with(|| { + System::set_block_number(1); + test(); + }); +} diff --git a/pallets/pallet-mock-skip-blocks/src/tests.rs b/pallets/pallet-mock-skip-blocks/src/tests.rs new file mode 100644 index 000000000..f101a1fef --- /dev/null +++ b/pallets/pallet-mock-skip-blocks/src/tests.rs @@ -0,0 +1,54 @@ +#![cfg(test)] +use crate::{mock::*, Error}; +use frame_support::{assert_noop, assert_ok, traits::Hooks}; + +#[test] +fn sets_and_reverts_block_number_success() { + run_test(|| { + // Initial block number + assert_eq!(System::block_number(), 1); + + // Set desired block number + let desired_block_number = 95; + assert_ok!(crate::Pallet::::set_block_number( + RuntimeOrigin::root(), + desired_block_number + )); + + // Simulate block production + System::on_initialize(1); + crate::Pallet::::on_initialize(1); + assert_eq!(System::block_number(), desired_block_number); + + crate::Pallet::::on_finalize(1); + System::on_finalize(1); + assert_eq!(System::block_number(), 1); + + // Advance to the next block + System::set_block_number(2); + System::on_initialize(2); + crate::Pallet::::on_initialize(2); + assert_eq!(System::block_number(), desired_block_number); + + crate::Pallet::::on_finalize(2); + System::on_finalize(2); + assert_eq!(System::block_number(), 2); + }); +} + +#[test] +fn setting_block_number_to_less_than_current_fails() { + run_test(|| { + // Initial block number + assert_eq!(System::block_number(), 1); + + // Attempt to set desired block number to a value less than the current block number + assert_noop!( + crate::Pallet::::set_block_number(RuntimeOrigin::root(), 0), + Error::::InvalidBlockNumber + ); + + // Block number should remain unchanged + assert_eq!(System::block_number(), 1); + }); +} diff --git a/runtime/foucoco/Cargo.toml b/runtime/foucoco/Cargo.toml index 816f8d5fb..5971d302e 100644 --- a/runtime/foucoco/Cargo.toml +++ b/runtime/foucoco/Cargo.toml @@ -110,6 +110,7 @@ parachain-staking = { path = "../../pallets/parachain-staking", default-features orml-currencies-allowance-extension = { path = "../../pallets/orml-currencies-allowance-extension", default-features = false } orml-tokens-management-extension = { path = "../../pallets/orml-tokens-management-extension", default-features = false } treasury-buyout-extension = { path = "../../pallets/treasury-buyout-extension", default-features = false } +pallet-mock-skip-blocks = { path = "../../pallets/pallet-mock-skip-blocks", default-features = false } # DIA dia-oracle = { git = "https://github.com/pendulum-chain/oracle-pallet", default-features = false, branch = "polkadot-v0.9.42" } @@ -338,3 +339,7 @@ try-runtime = [ "bifrost-farming/try-runtime", "zenlink-protocol/try-runtime", ] + +instant-seal = [ + "pallet-mock-skip-blocks/instant-seal", +] diff --git a/runtime/foucoco/src/lib.rs b/runtime/foucoco/src/lib.rs index 039a0c3fc..a92f573f8 100644 --- a/runtime/foucoco/src/lib.rs +++ b/runtime/foucoco/src/lib.rs @@ -374,6 +374,7 @@ impl Contains for BaseFilter { | RuntimeCall::Proxy(_) | RuntimeCall::OrmlExtension(_) | RuntimeCall::TreasuryBuyoutExtension(_) + | RuntimeCall::MockSkipBlocks(_) | RuntimeCall::RewardDistribution(_) => true, // All pallets are allowed, but exhaustive match is defensive // in the case of adding new pallets. } @@ -1413,6 +1414,28 @@ impl pallet_proxy::Config for Runtime { type AnnouncementDepositFactor = AnnouncementDepositFactor; } +// cfg_if::cfg_if! { +// if #[cfg(feature = "instant-seal")] { +// impl pallet_mock_skip_blocks::Config for Runtime { +// type RuntimeEvent = RuntimeEvent; +// } +// } else { +// impl pallet_mock_skip_blocks::dummy::Config for Runtime { +// type RuntimeEvent = RuntimeEvent; +// } +// } +// } + +//#[cfg(feature = "instant-seal")] +impl pallet_mock_skip_blocks::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} + +// #[cfg(not(feature = "instant-seal"))] +// impl pallet_mock_skip_blocks::dummy::Config for Runtime { +// type RuntimeEvent = RuntimeEvent; +// } + impl frame_system::offchain::SendTransactionTypes for Runtime where RuntimeCall: From, @@ -1507,6 +1530,7 @@ construct_runtime!( // Asset Metadata AssetRegistry: orml_asset_registry::{Pallet, Storage, Call, Event, Config} = 91, + MockSkipBlocks: pallet_mock_skip_blocks::{Pallet, Call, Storage, Event} = 92, } );