Unverified Commit 302b2c09 authored by Shawn Tabrizi's avatar Shawn Tabrizi Committed by GitHub
Browse files

Change Auctions to Eight Lease Periods Per Slot (#2862)



* initial patch

* fix tests

* fix benchmarks

* expose `SlotRange` consts

* Update Cargo.lock

* fix tests

Co-authored-by: asynchronous rob's avatarRobert Habermeier <rphmeier@gmail.com>
parent 028d4b65
Pipeline #133973 failed with stages
in 21 minutes and 3 seconds
......@@ -1537,6 +1537,17 @@ dependencies = [
"syn",
]
[[package]]
name = "enumn"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e58b112d5099aa0857c5d05f0eacab86406dd8c0f85fe5d320a13256d29ecf4"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "env_logger"
version = "0.7.1"
......@@ -8796,6 +8807,7 @@ checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
name = "slot-range-helper"
version = "0.8.30"
dependencies = [
"enumn",
"parity-scale-codec",
"paste 1.0.4",
"sp-runtime",
......
......@@ -6,6 +6,7 @@ edition = "2018"
[dependencies]
paste = "1.0"
enumn = "0.1.3"
parity-scale-codec = { version = "2.0.0", default-features = false, features = ["derive"] }
sp-std = { package = "sp-std", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
......
......@@ -22,6 +22,7 @@ pub use sp_std::{result, ops::Add, convert::TryInto};
pub use sp_runtime::traits::CheckedSub;
pub use parity_scale_codec::{Encode, Decode};
pub use paste;
pub use enumn::N;
/// This macro generates a `SlotRange` enum of arbitrary length for use in the Slot Auction
/// mechanism on Polkadot.
......@@ -106,7 +107,7 @@ macro_rules! generate_slot_range_enum {
$( $parsed:ident )*
) => {
/// A compactly represented sub-range from the series.
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, $crate::Encode, $crate::Decode)]
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, $crate::Encode, $crate::Decode, $crate::N)]
#[repr(u8)]
pub enum SlotRange { $( $parsed ),* }
};
......
......@@ -192,6 +192,8 @@ decl_module! {
type Error = Error<T>;
const EndingPeriod: T::BlockNumber = T::EndingPeriod::get();
const SlotRangeCount: u32 = SlotRange::SLOT_RANGE_COUNT as u32;
const LeasePeriodsPerSlot: u32 = SlotRange::LEASE_PERIODS_PER_SLOT as u32;
fn deposit_event() = default;
......@@ -207,7 +209,7 @@ decl_module! {
weight = weight.saturating_add(T::DbWeight::get().writes(1));
let winning_data = offset.checked_sub(&One::one())
.and_then(Winning::<T>::get)
.unwrap_or_default();
.unwrap_or([Self::EMPTY; SlotRange::SLOT_RANGE_COUNT]);
Winning::<T>::insert(offset, winning_data);
}
}
......@@ -344,6 +346,9 @@ impl<T: Config> Auctioneer for Module<T> {
}
impl<T: Config> Module<T> {
// A trick to allow me to initialize large arrays with nothing in them.
const EMPTY: Option<(<T as frame_system::Config>::AccountId, ParaId, BalanceOf<T>)> = None;
/// True if an auction is in progress.
pub fn is_in_progress() -> bool {
AuctionInfo::<T>::get().map_or(false, |(_, early_end)| {
......@@ -416,7 +421,7 @@ impl<T: Config> Module<T> {
// The current winning ranges.
let mut current_winning = Winning::<T>::get(offset)
.or_else(|| offset.checked_sub(&One::one()).and_then(Winning::<T>::get))
.unwrap_or_default();
.unwrap_or([Self::EMPTY; SlotRange::SLOT_RANGE_COUNT]);
// If this bid beat the previous winner of our range.
if current_winning[range_index].as_ref().map_or(true, |last| amount > last.2) {
......@@ -497,7 +502,7 @@ impl<T: Config> Module<T> {
let auction_counter = AuctionCounter::get();
Self::deposit_event(RawEvent::WinningOffset(auction_counter, offset));
let res = Winning::<T>::get(offset).unwrap_or_default();
let res = Winning::<T>::get(offset).unwrap_or([Self::EMPTY; SlotRange::SLOT_RANGE_COUNT]);
let mut i = T::BlockNumber::zero();
while i < ending_period {
Winning::<T>::remove(i);
......@@ -1188,18 +1193,9 @@ mod tests {
#[test]
fn incomplete_calculate_winners_works() {
let winning = [
None,
None,
None,
None,
None,
None,
None,
None,
None,
Some((1, 0.into(), 1)),
];
let mut winning = [None; SlotRange::SLOT_RANGE_COUNT];
winning[SlotRange::ThreeThree as u8 as usize] = Some((1, 0.into(), 1));
let winners = vec![
(1, 0.into(), 1, SlotRange::ThreeThree)
];
......@@ -1209,18 +1205,9 @@ mod tests {
#[test]
fn first_incomplete_calculate_winners_works() {
let winning = [
Some((1, 0.into(), 1)),
None,
None,
None,
None,
None,
None,
None,
None,
None,
];
let mut winning = [None; SlotRange::SLOT_RANGE_COUNT];
winning[0] = Some((1, 0.into(), 1));
let winners = vec![
(1, 0.into(), 1, SlotRange::ZeroZero)
];
......@@ -1230,28 +1217,13 @@ mod tests {
#[test]
fn calculate_winners_works() {
let mut winning = [
/*0..0*/
Some((2, 0.into(), 2)),
/*0..1*/
None,
/*0..2*/
None,
/*0..3*/
Some((1, 100.into(), 1)),
/*1..1*/
Some((3, 1.into(), 1)),
/*1..2*/
None,
/*1..3*/
None,
/*2..2*/
Some((1, 2.into(), 53)),
/*2..3*/
None,
/*3..3*/
Some((5, 3.into(), 1)),
];
let mut winning = [None; SlotRange::SLOT_RANGE_COUNT];
winning[SlotRange::ZeroZero as u8 as usize] = Some((2, 0.into(), 2));
winning[SlotRange::ZeroThree as u8 as usize] = Some((1, 100.into(), 1));
winning[SlotRange::OneOne as u8 as usize] = Some((3, 1.into(), 1));
winning[SlotRange::TwoTwo as u8 as usize] = Some((1, 2.into(), 53));
winning[SlotRange::ThreeThree as u8 as usize] = Some((5, 3.into(), 1));
let winners = vec![
(2, 0.into(), 2, SlotRange::ZeroZero),
(3, 1.into(), 1, SlotRange::OneOne),
......@@ -1313,67 +1285,27 @@ mod tests {
assert_ok!(Auctions::bid(Origin::signed(2), para_2, 1, 3, 4, 20));
assert_eq!(Auctions::is_ending(System::block_number()), None);
assert_eq!(Auctions::winning(0), Some([
None,
None,
None,
Some((1, para_1, 10)),
None,
None,
None,
None,
Some((2, para_2, 20)),
None,
]));
let mut winning = [None; SlotRange::SLOT_RANGE_COUNT];
winning[SlotRange::ZeroThree as u8 as usize] = Some((1, para_1, 10));
winning[SlotRange::TwoThree as u8 as usize] = Some((2, para_2, 20));
assert_eq!(Auctions::winning(0), Some(winning));
run_to_block(9);
assert_eq!(Auctions::is_ending(System::block_number()), None);
run_to_block(10);
assert_eq!(Auctions::is_ending(System::block_number()), Some(0));
assert_eq!(Auctions::winning(0), Some([
None,
None,
None,
Some((1, para_1, 10)),
None,
None,
None,
None,
Some((2, para_2, 20)),
None,
]));
assert_eq!(Auctions::winning(0), Some(winning));
run_to_block(11);
assert_eq!(Auctions::is_ending(System::block_number()), Some(1));
assert_eq!(Auctions::winning(1), Some([
None,
None,
None,
Some((1, para_1, 10)),
None,
None,
None,
None,
Some((2, para_2, 20)),
None,
]));
assert_eq!(Auctions::winning(1), Some(winning));
assert_ok!(Auctions::bid(Origin::signed(3), para_3, 1, 3, 4, 30));
run_to_block(12);
assert_eq!(Auctions::is_ending(System::block_number()), Some(2));
assert_eq!(Auctions::winning(2), Some([
None,
None,
None,
Some((1, para_1, 10)),
None,
None,
None,
None,
Some((3, para_3, 30)),
None,
]));
winning[SlotRange::TwoThree as u8 as usize] = Some((3, para_3, 30));
assert_eq!(Auctions::winning(2), Some(winning));
});
}
......@@ -1406,96 +1338,35 @@ mod tests {
assert_ok!(Auctions::bid(Origin::signed(2), para_2, 1, 13, 14, 20));
assert_eq!(Auctions::is_ending(System::block_number()), None);
assert_eq!(Auctions::winning(0), Some([
None,
None,
None,
Some((1, para_1, 10)),
None,
None,
None,
None,
Some((2, para_2, 20)),
None,
]));
let mut winning = [None; SlotRange::SLOT_RANGE_COUNT];
winning[SlotRange::ZeroThree as u8 as usize] = Some((1, para_1, 10));
winning[SlotRange::TwoThree as u8 as usize] = Some((2, para_2, 20));
assert_eq!(Auctions::winning(0), Some(winning));
run_to_block(9);
assert_eq!(Auctions::is_ending(System::block_number()), None);
run_to_block(10);
assert_eq!(Auctions::is_ending(System::block_number()), Some(0));
assert_eq!(Auctions::winning(0), Some([
None,
None,
None,
Some((1, para_1, 10)),
None,
None,
None,
None,
Some((2, para_2, 20)),
None,
]));
assert_eq!(Auctions::winning(0), Some(winning));
// New bids update the current winning
assert_ok!(Auctions::bid(Origin::signed(3), para_3, 1, 14, 14, 30));
assert_eq!(Auctions::winning(0), Some([
None,
None,
None,
Some((1, para_1, 10)),
None,
None,
None,
None,
Some((2, para_2, 20)),
Some((3, para_3, 30)),
]));
winning[SlotRange::ThreeThree as u8 as usize] = Some((3, para_3, 30));
assert_eq!(Auctions::winning(0), Some(winning));
run_to_block(20);
assert_eq!(Auctions::is_ending(System::block_number()), Some(1));
assert_eq!(Auctions::winning(1), Some([
None,
None,
None,
Some((1, para_1, 10)),
None,
None,
None,
None,
Some((2, para_2, 20)),
Some((3, para_3, 30)),
]));
assert_eq!(Auctions::winning(1), Some(winning));
run_to_block(25);
// Overbid mid sample
assert_ok!(Auctions::bid(Origin::signed(3), para_3, 1, 13, 14, 30));
assert_eq!(Auctions::winning(1), Some([
None,
None,
None,
Some((1, para_1, 10)),
None,
None,
None,
None,
Some((3, para_3, 30)),
Some((3, para_3, 30)),
]));
winning[SlotRange::TwoThree as u8 as usize] = Some((3, para_3, 30));
assert_eq!(Auctions::winning(1), Some(winning));
run_to_block(30);
assert_eq!(Auctions::is_ending(System::block_number()), Some(2));
assert_eq!(Auctions::winning(2), Some([
None,
None,
None,
Some((1, para_1, 10)),
None,
None,
None,
None,
Some((3, para_3, 30)),
Some((3, para_3, 30)),
]));
assert_eq!(Auctions::winning(2), Some(winning));
set_last_random(H256::from([254; 32]), 40);
run_to_block(40);
......@@ -1569,19 +1440,8 @@ mod benchmarking {
let bidder = account("bidder", n, 0);
CurrencyOf::<T>::make_free_balance_be(&bidder, BalanceOf::<T>::max_value());
let (start, end) = match n {
1 => (0u32, 0u32),
2 => (0, 1),
3 => (0, 2),
4 => (0, 3),
5 => (1, 1),
6 => (1, 2),
7 => (1, 3),
8 => (2, 2),
9 => (2, 3),
10 => (3, 3),
_ => panic!("test not meant for this"),
};
let slot_range = SlotRange::n((n - 1) as u8).unwrap();
let (start, end) = slot_range.as_pair();
assert!(Auctions::<T>::bid(
RawOrigin::Signed(bidder).into(),
......
......@@ -1056,7 +1056,7 @@ mod tests {
let e = Error::<Test>::LastPeriodBeforeFirstPeriod;
assert_noop!(Crowdloan::create(Origin::signed(1), para, 1000, 4, 1, 9, None), e);
let e = Error::<Test>::LastPeriodTooFarInFuture;
assert_noop!(Crowdloan::create(Origin::signed(1), para, 1000, 1, 5, 9, None), e);
assert_noop!(Crowdloan::create(Origin::signed(1), para, 1000, 1, 9, 9, None), e);
// Cannot create a crowdloan without some deposit funds
assert_ok!(TestRegistrar::<Test>::register(1337, ParaId::from(1234), Default::default(), Default::default()));
......
......@@ -39,6 +39,7 @@ use runtime_parachains::{
use frame_support_test::TestRandomness;
use crate::{
auctions, crowdloan, slots, paras_registrar,
slot_range::SlotRange,
traits::{
Registrar as RegistrarT, Auctioneer,
},
......@@ -531,11 +532,6 @@ fn competing_slots() {
));
}
// All winner slots are filled by bids
for winner in &auctions::Winning::<Test>::get(0).unwrap() {
assert!(winner.is_some());
}
// Auction should be done after ending period
run_to_block(160);
......@@ -846,21 +842,11 @@ fn crowdloan_ending_period_bid() {
run_to_block(100);
assert_eq!(Auctions::is_ending(100), Some(0));
let mut winning = [None; SlotRange::SLOT_RANGE_COUNT];
winning[SlotRange::ZeroOne as u8 as usize] = Some((2, ParaId::from(1002), 900));
winning[SlotRange::ZeroThree as u8 as usize] = Some((crowdloan_account, ParaId::from(1001), total));
assert_eq!(Auctions::winning(0), Some(
[
None, // 0-0
Some((2, ParaId::from(1002), 900)), // 0-1
None, // 0-2
Some((crowdloan_account, ParaId::from(1001), total)), // 0-3
None, // 1-1
None, // 1-2
None, // 1-3
None, // 2-2
None, // 2-3
None, // 3-3
]
));
assert_eq!(Auctions::winning(0), Some(winning));
run_to_block(101);
......@@ -869,20 +855,10 @@ fn crowdloan_ending_period_bid() {
// Data propagates correctly
run_to_block(102);
assert_eq!(Auctions::winning(2), Some(
[
None, // 0-0
Some((2, ParaId::from(1002), 900)), // 0-1
None, // 0-2
Some((crowdloan_account, ParaId::from(1001), total + 900)), // 0-3
None, // 1-1
None, // 1-2
None, // 1-3
None, // 2-2
None, // 2-3
None, // 3-3
]
));
let mut winning = [None; SlotRange::SLOT_RANGE_COUNT];
winning[SlotRange::ZeroOne as u8 as usize] = Some((2, ParaId::from(1002), 900));
winning[SlotRange::ZeroThree as u8 as usize] = Some((crowdloan_account, ParaId::from(1001), total + 900));
assert_eq!(Auctions::winning(2), Some(winning));
})
}
......
......@@ -14,7 +14,47 @@
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
//! The SlotRange struct which succinctly handles the ten values that
//! represent all sub ranges between 0 and 3 inclusive.
//! The SlotRange struct which succinctly handles the 36 values that
//! represent all sub ranges between 0 and 7 inclusive.
slot_range_helper::generate_slot_range!(Zero(0), One(1), Two(2), Three(3));
slot_range_helper::generate_slot_range!(Zero(0), One(1), Two(2), Three(3), Four(4), Five(5), Six(6), Seven(7));
// Will generate:
// pub enum SlotRange {
// ZeroZero, 0
// ZeroOne, 1
// ZeroTwo, 2
// ZeroThree, 3
// ZeroFour, 4
// ZeroFive, 5
// ZeroSix, 6
// ZeroSeven, 7
// OneOne, 8
// OneTwo, 9
// OneThree, 10
// OneFour, 11
// OneFive, 12
// OneSix, 13
// OneSeven, 14
// TwoTwo, 15
// TwoThree, 16
// TwoFour, 17
// TwoFive, 18
// TwoSix, 19
// TwoSeven, 20
// ThreeThree, 21
// ThreeFour, 22
// ThreeFive, 23
// ThreeSix, 24
// ThreeSeven, 25
// FourFour, 26
// FourFive, 27
// FourSix, 28
// FourSeven, 29
// FiveFive, 30
// FiveSix, 31
// FiveSeven, 32
// SixSix, 33
// SixSeven, 34
// SevenSeven, 35
// }
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment