Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -652,4 +652,16 @@ impl<T: frame_system::Config> pallet_broker::WeightInfo for WeightInfo<T> {
.saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1))
}
/// Storage: `Broker::Regions` (r:1 w:1)
/// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(86), added: 2561, mode: `MaxEncodedLen`)
fn force_transfer() -> Weight {
// Proof Size summary in bytes:
// Measured: `358`
// Estimated: `3551`
// Minimum execution time: 22_968_000 picoseconds.
Weight::from_parts(23_878_000, 0)
.saturating_add(Weight::from_parts(0, 3551))
.saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1))
}
}
11 changes: 11 additions & 0 deletions prdoc/pr_10856.prdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
title: '[pallet-broker] add extrinsic to force transfer a region'
doc:
- audience: Runtime User
description: |-
Add an extrinsic to `pallet-broker` which allows a privileged origin (`AdminOrigin` or `Root`) to forcefully transfer a region, ignoring its current owner.
crates:
- name: pallet-broker
bump: major
- name: coretime-westend-runtime
bump: minor

35 changes: 35 additions & 0 deletions substrate/frame/broker/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1343,6 +1343,41 @@ mod benches {
Ok(())
}

#[benchmark]
fn force_transfer() -> Result<(), BenchmarkError> {
let sale_data = setup_and_start_sale::<T>()?;
advance_to::<T>(2);

let caller: T::AccountId = whitelisted_caller();
T::Currency::set_balance(
&caller.clone(),
T::Currency::minimum_balance().saturating_add(sale_data.start_price),
);

let region = Broker::<T>::do_purchase(caller.clone(), sale_data.start_price)
.expect("Offer not high enough for configuration.");

let recipient: T::AccountId = account("recipient", 0, SEED);

let origin =
T::AdminOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;

#[extrinsic_call]
_(origin, region, recipient.clone());

assert_last_event::<T>(
Event::Transferred {
region_id: region,
old_owner: Some(caller),
owner: Some(recipient),
duration: 3u32.into(),
}
.into(),
);

Ok(())
}

// Implements a test for each benchmark. Execute with:
// `cargo test -p pallet-broker --features runtime-benchmarks`.
impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test);
Expand Down
19 changes: 19 additions & 0 deletions substrate/frame/broker/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1058,6 +1058,25 @@ pub mod pallet {
Self::do_remove_potential_renewal(core, when)
}

/// Transfer a Bulk Coretime Region to a new owner, ignoring the previous owner.
///
Comment thread
mertwole marked this conversation as resolved.
/// This can also be used to recover regions that have been "burned" (e.g., from an
/// XCM reserve transfer).
///
/// - `origin`: Must be Root or pass `AdminOrigin`.
/// - `region_id`: The Region whose ownership should change.
/// - `new_owner`: The new owner for the Region.
#[pallet::call_index(28)]
pub fn force_transfer(
origin: OriginFor<T>,
region_id: RegionId,
new_owner: T::AccountId,
) -> DispatchResult {
T::AdminOrigin::ensure_origin_or_root(origin)?;
Self::do_transfer(region_id, None, new_owner)?;
Ok(())
}

#[pallet::call_index(99)]
#[pallet::weight(T::WeightInfo::swap_leases())]
pub fn swap_leases(origin: OriginFor<T>, id: TaskId, other: TaskId) -> DispatchResult {
Expand Down
121 changes: 121 additions & 0 deletions substrate/frame/broker/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2901,3 +2901,124 @@ fn remove_potential_renewal_makes_auto_renewal_die() {
assert_eq!(AutoRenewals::<Test>::get().len(), 0);
})
}

#[test]
fn force_transfer_works() {
TestExt::new().endow(1, 1000).execute_with(|| {
assert_ok!(Broker::do_start_sales(100, 4));
advance_to(2);

const OLD_OWNER: u64 = 1;
const NEW_OWNER: u64 = 222;

let region_id = Broker::do_purchase(OLD_OWNER, u64::max_value()).unwrap();
let region = Regions::<Test>::get(region_id).unwrap();

assert_noop!(
Broker::force_transfer(
RuntimeOrigin::root(),
RegionId {
begin: u32::max_value(),
core: u16::max_value(),
mask: CoreMask::void()
},
NEW_OWNER
),
Error::<Test>::UnknownRegion
);

assert_noop!(
Broker::force_transfer(RuntimeOrigin::signed(1001), region_id, NEW_OWNER),
BadOrigin
);

assert_ok!(Broker::force_transfer(RuntimeOrigin::root(), region_id, NEW_OWNER));

System::assert_last_event(
Event::Transferred {
region_id,
duration: region.end - region_id.begin,
old_owner: Some(OLD_OWNER),
owner: Some(NEW_OWNER),
}
.into(),
);

assert_noop!(
Broker::assign(RuntimeOrigin::signed(OLD_OWNER), region_id, 10, Finality::Final),
Error::<Test>::NotOwner
);

assert_ok!(Broker::assign(
RuntimeOrigin::signed(NEW_OWNER),
region_id,
10,
Finality::Final
));
});
}
Comment thread
mertwole marked this conversation as resolved.

#[test]
fn force_transfer_can_transfer_burned_region() {
TestExt::new().endow(1, 1000).execute_with(|| {
assert_ok!(Broker::do_start_sales(100, 4));
advance_to(2);

const OLD_OWNER: u64 = 1;
const NEW_OWNER: u64 = 222;

let region_id = Broker::do_purchase(OLD_OWNER, u64::max_value()).unwrap();

assert_ok!(<Broker as Mutate<u64>>::burn(&region_id.into(), None));

let region = Regions::<Test>::get(region_id).unwrap();
assert_eq!(region.owner, None);

assert_ok!(Broker::force_transfer(RuntimeOrigin::root(), region_id, NEW_OWNER));

System::assert_last_event(
Event::Transferred {
region_id,
duration: region.end - region_id.begin,
old_owner: None,
owner: Some(NEW_OWNER),
}
.into(),
);

assert_ok!(Broker::assign(
RuntimeOrigin::signed(NEW_OWNER),
region_id,
10,
Finality::Final
));
});
}

#[test]
fn force_transfer_can_transfer_provisionally_assigned_region() {
TestExt::new().endow(1, 1000).execute_with(|| {
assert_ok!(Broker::do_start_sales(100, 4));
advance_to(2);

const OLD_OWNER: u64 = 1;
const NEW_OWNER: u64 = 222;

let region_id = Broker::do_purchase(OLD_OWNER, u64::max_value()).unwrap();

assert_ok!(Broker::assign(RuntimeOrigin::signed(OLD_OWNER), region_id, 1001, Provisional));

assert_ok!(Broker::force_transfer(RuntimeOrigin::root(), region_id, NEW_OWNER));

let region = Regions::<Test>::get(region_id).unwrap();
System::assert_last_event(
Event::Transferred {
region_id,
duration: region.end - region_id.begin,
old_owner: Some(OLD_OWNER),
owner: Some(NEW_OWNER),
}
.into(),
);
});
}
23 changes: 23 additions & 0 deletions substrate/frame/broker/src/weights.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading