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

pallet_broker: Support renewing leases expired in a previous period #4089

Merged
merged 8 commits into from
Apr 15, 2024
Merged
Show file tree
Hide file tree
Changes from 4 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
1 change: 1 addition & 0 deletions Cargo.lock

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

11 changes: 11 additions & 0 deletions prdoc/pr_4089.prdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
title: "pallet_broker: Support renewing leases expired in a previous period"

doc:
- audience: Runtime User
description: |
Allow renewals of leases that ended before `start_sales` or in the first period after calling `start_sales`.
This ensures that everyone has a smooth experience when migrating to coretime and the timing of
`start_sales` isn't that important.

crates:
- name: pallet-broker
1 change: 1 addition & 0 deletions substrate/frame/broker/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ frame-system = { path = "../system", default-features = false }

[dev-dependencies]
sp-io = { path = "../../primitives/io" }
pretty_assertions = "1.3.0"

[features]
default = ["std"]
Expand Down
11 changes: 10 additions & 1 deletion substrate/frame/broker/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use frame_support::{
};
use frame_system::{EnsureRoot, EnsureSignedBy};
use sp_arithmetic::Perbill;
use sp_core::{ConstU32, ConstU64};
use sp_core::{ConstU32, ConstU64, Get};
use sp_runtime::{
traits::{BlockNumberProvider, Identity},
BuildStorage, Saturating,
Expand Down Expand Up @@ -210,6 +210,15 @@ pub fn advance_to(b: u64) {
}
}

pub fn advance_sale_period() {
seadanda marked this conversation as resolved.
Show resolved Hide resolved
let sale = SaleInfo::<Test>::get().unwrap();

let target_block_number =
sale.region_begin as u64 * <<Test as crate::Config>::TimeslicePeriod as Get<u64>>::get();

advance_to(target_block_number)
}

pub fn pot() -> u64 {
balance(Broker::account_id())
}
Expand Down
139 changes: 139 additions & 0 deletions substrate/frame/broker/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use frame_support::{
BoundedVec,
};
use frame_system::RawOrigin::Root;
use pretty_assertions::assert_eq;
use sp_runtime::{traits::Get, TokenError};
use CoreAssignment::*;
use CoretimeTraceItem::*;
Expand Down Expand Up @@ -1092,3 +1093,141 @@ fn config_works() {
assert_noop!(Broker::configure(Root.into(), cfg), Error::<Test>::InvalidConfig);
});
}

/// Ensure that a lease that ended before `start_sales` was called can be renewed.
#[test]
fn renewal_works_leases_ended_before_start_sales() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

more like renewal_works_for_leases_ended_before_period_1() ?

And description:

Bootstrapping: Ensure that leases that end right in the first sale period can still be renewed, despite the fact that renewal rights are determined one period before the corresponding sale period.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I mean this lease ends before start_sales :P

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, but the issue is wider than that. Even leases after start_sales would not have renewal rights, without your fix.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

haha I just called them short_leases in mine

TestExt::new().endow(1, 1000).execute_with(|| {
let config = Configuration::<Test>::get().unwrap();

// This lease is ended before `start_stales` was called.
assert_ok!(Broker::do_set_lease(1, 1));

// Go to some block to ensure that the lease of task 1 already ended.
advance_to(5);

// This lease will end three sale periods in.
assert_ok!(Broker::do_set_lease(
2,
Broker::latest_timeslice_ready_to_commit(&config) + config.region_length * 3
));

// This intializes the first sale and the period 0.
assert_ok!(Broker::do_start_sales(100, 2));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really want those newtypes.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean wtf. We can also start coding binary directly:

000111011110000011111000111

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At that stage we could rewrite it all in VHDL and run it on FPGAs

assert_noop!(Broker::do_renew(1, 1), Error::<Test>::Unavailable);
assert_noop!(Broker::do_renew(1, 0), Error::<Test>::Unavailable);

// Lease for task 1 should have been dropped.
assert!(Leases::<Test>::get().iter().any(|l| l.task == 2));

// This intializes the second and the period 1.
advance_sale_period();

// Now we can finally renew the core 0 of task 1.
let new_core = Broker::do_renew(1, 0).unwrap();
// Renewing the active lease doesn't work.
assert_noop!(Broker::do_renew(1, 1), Error::<Test>::SoldOut);
assert_eq!(balance(1), 900);

// This intializes the third sale and the period 2.
advance_sale_period();
let new_core = Broker::do_renew(1, new_core).unwrap();

// Renewing the active lease doesn't work.
assert_noop!(Broker::do_renew(1, 0), Error::<Test>::SoldOut);
assert_eq!(balance(1), 800);

// All leases should have ended
assert!(Leases::<Test>::get().is_empty());

// This intializes the fourth sale and the period 3.
advance_sale_period();

// Renew again
assert_eq!(0, Broker::do_renew(1, new_core).unwrap());
// Renew the task 2.
assert_eq!(1, Broker::do_renew(1, 0).unwrap());
assert_eq!(balance(1), 600);

// This intializes the fifth sale and the period 4.
advance_sale_period();

assert_eq!(
CoretimeTrace::get(),
vec![
(
10,
AssignCore {
core: 0,
begin: 12,
assignment: vec![(Task(1), 57600)],
end_hint: None
}
),
(
10,
AssignCore {
core: 1,
begin: 12,
assignment: vec![(Task(2), 57600)],
end_hint: None
}
),
(
16,
AssignCore {
core: 0,
begin: 18,
assignment: vec![(Task(2), 57600)],
end_hint: None
}
),
(
16,
AssignCore {
core: 1,
begin: 18,
assignment: vec![(Task(1), 57600)],
end_hint: None
}
),
(
22,
AssignCore {
core: 0,
begin: 24,
assignment: vec![(Task(2), 57600)],
end_hint: None,
},
),
(
22,
AssignCore {
core: 1,
begin: 24,
assignment: vec![(Task(1), 57600)],
end_hint: None,
},
),
(
28,
AssignCore {
core: 0,
begin: 30,
assignment: vec![(Task(1), 57600)],
end_hint: None,
},
),
(
28,
AssignCore {
core: 1,
begin: 30,
assignment: vec![(Task(2), 57600)],
end_hint: None,
},
),
]
);
});
}
13 changes: 7 additions & 6 deletions substrate/frame/broker/src/tick_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,11 +216,10 @@ impl<T: Config> Pallet<T> {
let assignment = CoreAssignment::Task(task);
let schedule = BoundedVec::truncate_from(vec![ScheduleItem { mask, assignment }]);
Workplan::<T>::insert((region_begin, first_core), &schedule);
// Separate these to avoid missed expired leases hanging around forever.
let expired = until < region_end;
let expiring = until >= region_begin && expired;
if expiring {
// last time for this one - make it renewable.
// Will the lease expire at the end of the period?
let expire = until < region_end;
if expire {
// last time for this one - make it renewable in this sale.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for the next sale actually.

bkchr marked this conversation as resolved.
Show resolved Hide resolved
let renewal_id = AllowedRenewalId { core: first_core, when: region_end };
let record = AllowedRenewalRecord { price, completion: Complete(schedule) };
AllowedRenewals::<T>::insert(renewal_id, &record);
Expand All @@ -232,8 +231,10 @@ impl<T: Config> Pallet<T> {
});
Self::deposit_event(Event::LeaseEnding { when: region_end, task });
}

first_core.saturating_inc();
!expired

!expire
});
Leases::<T>::put(&leases);

Expand Down
Loading