Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Drop region #232

Merged
merged 10 commits into from
Aug 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions pallets/market/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ impl pallet_regions::Config for Test {
type IsmpDispatcher = MockDispatcher<Self>;
type StateMachineHeightProvider = MockStateMachineHeightProvider;
type Timeout = ConstU64<1000>;
type RCBlockNumberProvider = RelayBlockNumberProvider;
type TimeslicePeriod = ConstU64<80>;
type UnsignedPriority = RegionsUnsignedPriority;
type WeightInfo = ();
}
Expand Down
26 changes: 14 additions & 12 deletions pallets/processor/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,18 @@ parameter_types! {
pub const RegionsUnsignedPriority: TransactionPriority = TransactionPriority::max_value();
}

parameter_types! {
pub static RelayBlockNumber: u64 = 0;
}

pub struct RelayBlockNumberProvider;
impl BlockNumberProvider for RelayBlockNumberProvider {
type BlockNumber = u64;
fn current_block_number() -> Self::BlockNumber {
RelayBlockNumber::get()
}
}

impl pallet_regions::Config for Test {
type RuntimeEvent = RuntimeEvent;
type Currency = Balances;
Expand All @@ -175,6 +187,8 @@ impl pallet_regions::Config for Test {
type StateMachineHeightProvider = MockStateMachineHeightProvider;
type Timeout = ConstU64<1000>;
type UnsignedPriority = RegionsUnsignedPriority;
type RCBlockNumberProvider = RelayBlockNumberProvider;
type TimeslicePeriod = ConstU64<80>;
type WeightInfo = ();
}

Expand All @@ -191,18 +205,6 @@ impl FeeHandler<AccountId, u64> for OrderCreationFeeHandler {
}
}

parameter_types! {
pub static RelayBlockNumber: u64 = 0;
}

pub struct RelayBlockNumberProvider;
impl BlockNumberProvider for RelayBlockNumberProvider {
type BlockNumber = u64;
fn current_block_number() -> Self::BlockNumber {
RelayBlockNumber::get()
}
}

pub struct OrderToAccountId;
impl Convert<OrderId, AccountId> for OrderToAccountId {
fn convert(order: OrderId) -> AccountId {
Expand Down
20 changes: 20 additions & 0 deletions pallets/regions/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,26 @@ mod benchmarks {
Ok(())
}

#[benchmark]
fn drop_region() -> Result<(), BenchmarkError> {
let caller: T::AccountId = whitelisted_caller();
let owner: T::AccountId = account("alice", 0, SEED);

let region_id = RegionId { begin: 0, core: 72, mask: CoreMask::complete() };
let record: RegionRecordOf<T> = RegionRecord { end: 0, owner, paid: None };

assert_ok!(crate::Pallet::<T>::mint_into(&region_id.into(), &caller));
assert_ok!(crate::Pallet::<T>::request_region_record(RawOrigin::None.into(), region_id));
assert_ok!(crate::Pallet::<T>::set_record(region_id, record));

#[extrinsic_call]
_(RawOrigin::Signed(caller.clone()), region_id);

assert_last_event::<T>(Event::RegionDropped { region_id, who: caller }.into());

Ok(())
}

#[benchmark]
fn on_accept() -> Result<(), BenchmarkError> {
let module = IsmpModuleCallback::<T>::default();
Expand Down
77 changes: 70 additions & 7 deletions pallets/regions/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,16 @@ use ismp::{
};
use ismp_parachain::PARACHAIN_CONSENSUS_ID;
pub use pallet::*;
use pallet_broker::RegionId;
use pallet_broker::{RegionId, Timeslice};
use pallet_ismp::{weights::IsmpModuleWeight, ModuleId};
use primitives::StateMachineHeightProvider;
use region_primitives::{Record, Region, RegionFactory};
use scale_info::prelude::{format, vec, vec::Vec};
use sp_core::H256;
use sp_runtime::traits::Zero;
use sp_runtime::{
traits::{BlockNumberProvider, Zero},
SaturatedConversion,
};

#[cfg(test)]
mod mock;
Expand All @@ -53,7 +57,6 @@ mod types;
use types::*;

pub mod primitives;
use primitives::StateMachineHeightProvider;

pub mod weights;
pub use weights::WeightInfo;
Expand All @@ -67,6 +70,10 @@ pub const PALLET_ID: ModuleId = ModuleId::Pallet(PalletId(*b"regionsp"));
const REGION_NOT_FOUND: u8 = 1;
const REGION_NOT_UNAVAILABLE: u8 = 2;

/// Relay chain block number.
pub type RCBlockNumberOf<T> =
<<T as crate::Config>::RCBlockNumberProvider as BlockNumberProvider>::BlockNumber;

#[frame_support::pallet]
pub mod pallet {
use super::*;
Expand All @@ -87,6 +94,15 @@ pub mod pallet {
/// The Coretime chain from which we read region state.
type CoretimeChain: Get<StateMachine>;

/// Type for getting the current relay chain block.
///
/// This is used for determining the current timeslice.
type RCBlockNumberProvider: BlockNumberProvider;

/// Number of Relay-chain blocks per timeslice.
#[pallet::constant]
type TimeslicePeriod: Get<RCBlockNumberOf<Self>>;

/// The ISMP dispatcher.
type IsmpDispatcher: IsmpDispatcher<Account = Self::AccountId, Balance = BalanceOf<Self>>
+ Default;
Expand Down Expand Up @@ -139,23 +155,30 @@ pub mod pallet {
},
/// A region was minted via a cross chain transfer.
RegionMinted {
/// minted region id
/// id of the minted region
region_id: RegionId,
},
/// A region was burnt.
RegionBurnt {
/// burnt region id
/// id of the burnt region
region_id: RegionId,
},
/// A region was locked.
RegionLocked {
/// locked region id
/// id of the locked region
region_id: RegionId,
},
/// A region was unlocked.
RegionUnlocked {
/// unlocked region id
/// id of the unlocked region
region_id: RegionId,
},
/// An expired region was dropped.
RegionDropped {
/// id of the dropped region
region_id: RegionId,
/// the account that dropped the region
who: T::AccountId,
},
}

Expand All @@ -172,6 +195,8 @@ pub mod pallet {
IsmpDispatchError,
/// The record must be unavailable to be able to re-request it.
NotUnavailable,
/// The region record is not available.
NotAvailable,
/// The given region id is not valid.
InvalidRegionId,
/// Failed to get the latest height of the Coretime chain.
Expand All @@ -180,6 +205,8 @@ pub mod pallet {
RegionLocked,
/// Region isn't locked.
RegionNotLocked,
/// Region is not expired.
RegionNotExpired,
}

#[pallet::call]
Expand Down Expand Up @@ -215,6 +242,36 @@ pub mod pallet {

Ok(())
}

#[pallet::call_index(2)]
#[pallet::weight(T::WeightInfo::drop_region())]
pub fn drop_region(origin: OriginFor<T>, region_id: RegionId) -> DispatchResult {
let who = ensure_signed(origin)?;

let region = Regions::<T>::get(region_id).ok_or(Error::<T>::UnknownRegion)?;

ensure!(region.record.is_available(), Error::<T>::NotAvailable);

if let Record::Available(record) = region.record {
// Cannot drop a region that is not expired yet.

// Allowing region removal 1 timeslice before it truly expires makes writing
// benchmarks much easier. With this we can set the start and end to 0 and be able
// to drop the region without having to modify the current timeslice.
let current_timeslice = Self::current_timeslice();
#[cfg(feature = "runtime-benchmarks")]
ensure!(record.end <= current_timeslice, Error::<T>::RegionNotExpired);
#[cfg(not(feature = "runtime-benchmarks"))]
ensure!(record.end < current_timeslice, Error::<T>::RegionNotExpired);

Regions::<T>::remove(region_id);

Self::deposit_event(Event::RegionDropped { region_id, who });
Ok(())
} else {
Err(Error::<T>::NotAvailable.into())
}
}
}

impl<T: Config> Pallet<T> {
Expand Down Expand Up @@ -308,6 +365,12 @@ pub mod pallet {

Ok(key)
}

pub(crate) fn current_timeslice() -> Timeslice {
let latest_rc_block = T::RCBlockNumberProvider::current_block_number();
let timeslice_period = T::TimeslicePeriod::get();
(latest_rc_block / timeslice_period).saturated_into()
}
}

#[pallet::validate_unsigned]
Expand Down
16 changes: 15 additions & 1 deletion pallets/regions/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use frame_support::{pallet_prelude::*, parameter_types, traits::Everything};
use ismp::{consensus::StateMachineId, host::StateMachine};
use sp_core::{ConstU64, H256};
use sp_runtime::{
traits::{BlakeTwo256, IdentityLookup},
traits::{BlakeTwo256, BlockNumberProvider, IdentityLookup},
BuildStorage,
};

Expand Down Expand Up @@ -95,6 +95,18 @@ impl StateMachineHeightProvider for MockStateMachineHeightProvider {
}
}

parameter_types! {
pub static RelayBlockNumber: u64 = 0;
}

pub struct RelayBlockNumberProvider;
impl BlockNumberProvider for RelayBlockNumberProvider {
type BlockNumber = u64;
fn current_block_number() -> Self::BlockNumber {
RelayBlockNumber::get()
}
}

impl crate::Config for Test {
type RuntimeEvent = RuntimeEvent;
type Currency = Balances;
Expand All @@ -103,6 +115,8 @@ impl crate::Config for Test {
type StateMachineHeightProvider = MockStateMachineHeightProvider;
type Timeout = ConstU64<1000>;
type UnsignedPriority = RegionsUnsignedPriority;
type RCBlockNumberProvider = RelayBlockNumberProvider;
type TimeslicePeriod = ConstU64<80>;
type WeightInfo = ();
}

Expand Down
42 changes: 42 additions & 0 deletions pallets/regions/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -529,3 +529,45 @@ fn utils_read_value_works() {
);
});
}

#[test]
fn drop_region_works() {
new_test_ext().execute_with(|| {
let region_id = RegionId { begin: 1, core: 81, mask: CoreMask::complete() };
let record: RegionRecordOf<Test> = RegionRecord { end: 10, owner: 1, paid: None };
let who = 1u32.into();

assert_noop!(
Regions::drop_region(RuntimeOrigin::signed(who), region_id),
Error::<Test>::UnknownRegion
);

assert_ok!(Regions::mint_into(&region_id.into(), &2));
// region status = Unavailable
assert_noop!(
Regions::drop_region(RuntimeOrigin::signed(who), region_id),
Error::<Test>::NotAvailable
);

assert_ok!(Regions::request_region_record(RuntimeOrigin::none(), region_id));
// region status = Pending
assert_noop!(
Regions::drop_region(RuntimeOrigin::signed(who), region_id),
Error::<Test>::NotAvailable
);

assert_ok!(Regions::set_record(region_id, record.clone()));

assert_noop!(
Regions::drop_region(RuntimeOrigin::signed(who), region_id),
Error::<Test>::RegionNotExpired
);

RelayBlockNumber::set(11 * 80);
assert_ok!(Regions::drop_region(RuntimeOrigin::signed(who), region_id));

assert!(Regions::regions(region_id).is_none());

System::assert_last_event(Event::RegionDropped { region_id, who }.into());
})
}
31 changes: 31 additions & 0 deletions pallets/regions/src/weights.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ use core::marker::PhantomData;
pub trait WeightInfo {
fn transfer() -> Weight;
fn request_region_record() -> Weight;
fn drop_region() -> Weight;
fn on_accept() -> Weight;
fn on_response() -> Weight;
fn on_timeout() -> Weight;
Expand Down Expand Up @@ -95,6 +96,21 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
.saturating_add(T::DbWeight::get().reads(6_u64))
.saturating_add(T::DbWeight::get().writes(3_u64))
}
/// Storage: `Regions::Regions` (r:1 w:1)
/// Proof: `Regions::Regions` (`max_values`: None, `max_size`: Some(119), added: 2594, mode: `MaxEncodedLen`)
/// Storage: `ParachainSystem::ValidationData` (r:1 w:0)
/// Proof: `ParachainSystem::ValidationData` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `ParachainSystem::LastRelayChainBlockNumber` (r:1 w:0)
/// Proof: `ParachainSystem::LastRelayChainBlockNumber` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
fn drop_region() -> Weight {
// Proof Size summary in bytes:
// Measured: `249`
// Estimated: `3584`
// Minimum execution time: 19_555_000 picoseconds.
Weight::from_parts(20_101_000, 3584)
.saturating_add(T::DbWeight::get().reads(3_u64))
.saturating_add(T::DbWeight::get().writes(1_u64))
}
fn on_accept() -> Weight {
// Proof Size summary in bytes:
// Measured: `0`
Expand Down Expand Up @@ -160,6 +176,21 @@ impl WeightInfo for () {
.saturating_add(RocksDbWeight::get().reads(6_u64))
.saturating_add(RocksDbWeight::get().writes(3_u64))
}
/// Storage: `Regions::Regions` (r:1 w:1)
/// Proof: `Regions::Regions` (`max_values`: None, `max_size`: Some(119), added: 2594, mode: `MaxEncodedLen`)
/// Storage: `ParachainSystem::ValidationData` (r:1 w:0)
/// Proof: `ParachainSystem::ValidationData` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `ParachainSystem::LastRelayChainBlockNumber` (r:1 w:0)
/// Proof: `ParachainSystem::LastRelayChainBlockNumber` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
fn drop_region() -> Weight {
// Proof Size summary in bytes:
// Measured: `249`
// Estimated: `3584`
// Minimum execution time: 19_555_000 picoseconds.
Weight::from_parts(20_101_000, 3584)
.saturating_add(RocksDbWeight::get().reads(3_u64))
.saturating_add(RocksDbWeight::get().writes(1_u64))
}
fn on_accept() -> Weight {
// Proof Size summary in bytes:
// Measured: `0`
Expand Down
2 changes: 2 additions & 0 deletions runtime/cocos/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -622,6 +622,8 @@ impl pallet_regions::Config for Runtime {
type IsmpDispatcher = Ismp;
type StateMachineHeightProvider = StateMachineHeightProvider;
type Timeout = ConstU64<300>; // 5 minutes
type RCBlockNumberProvider = RelaychainDataProvider<Self>;
type TimeslicePeriod = ConstU32<80>;
type UnsignedPriority = RegionsUnsignedPriority;
type WeightInfo = weights::pallet_regions::WeightInfo<Runtime>;
}
Expand Down
Loading
Loading