diff --git a/polkadot/Cargo.lock b/polkadot/Cargo.lock index 41b498d789..ab5343f2d0 100644 --- a/polkadot/Cargo.lock +++ b/polkadot/Cargo.lock @@ -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", diff --git a/polkadot/runtime/common/slot_range_helper/Cargo.toml b/polkadot/runtime/common/slot_range_helper/Cargo.toml index eff28d19c9..932cd81aa3 100644 --- a/polkadot/runtime/common/slot_range_helper/Cargo.toml +++ b/polkadot/runtime/common/slot_range_helper/Cargo.toml @@ -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 } diff --git a/polkadot/runtime/common/slot_range_helper/src/lib.rs b/polkadot/runtime/common/slot_range_helper/src/lib.rs index ffad684b33..ec680c87d7 100644 --- a/polkadot/runtime/common/slot_range_helper/src/lib.rs +++ b/polkadot/runtime/common/slot_range_helper/src/lib.rs @@ -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 ),* } }; diff --git a/polkadot/runtime/common/src/auctions.rs b/polkadot/runtime/common/src/auctions.rs index a3abc5e11c..f608b5ab06 100644 --- a/polkadot/runtime/common/src/auctions.rs +++ b/polkadot/runtime/common/src/auctions.rs @@ -192,6 +192,8 @@ decl_module! { type Error = Error; 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::::get) - .unwrap_or_default(); + .unwrap_or([Self::EMPTY; SlotRange::SLOT_RANGE_COUNT]); Winning::::insert(offset, winning_data); } } @@ -344,6 +346,9 @@ impl Auctioneer for Module { } impl Module { + // A trick to allow me to initialize large arrays with nothing in them. + const EMPTY: Option<(::AccountId, ParaId, BalanceOf)> = None; + /// True if an auction is in progress. pub fn is_in_progress() -> bool { AuctionInfo::::get().map_or(false, |(_, early_end)| { @@ -416,7 +421,7 @@ impl Module { // The current winning ranges. let mut current_winning = Winning::::get(offset) .or_else(|| offset.checked_sub(&One::one()).and_then(Winning::::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 Module { let auction_counter = AuctionCounter::get(); Self::deposit_event(RawEvent::WinningOffset(auction_counter, offset)); - let res = Winning::::get(offset).unwrap_or_default(); + let res = Winning::::get(offset).unwrap_or([Self::EMPTY; SlotRange::SLOT_RANGE_COUNT]); let mut i = T::BlockNumber::zero(); while i < ending_period { Winning::::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::::make_free_balance_be(&bidder, BalanceOf::::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::::bid( RawOrigin::Signed(bidder).into(), diff --git a/polkadot/runtime/common/src/crowdloan.rs b/polkadot/runtime/common/src/crowdloan.rs index d505d65b47..6ead470aef 100644 --- a/polkadot/runtime/common/src/crowdloan.rs +++ b/polkadot/runtime/common/src/crowdloan.rs @@ -1056,7 +1056,7 @@ mod tests { let e = Error::::LastPeriodBeforeFirstPeriod; assert_noop!(Crowdloan::create(Origin::signed(1), para, 1000, 4, 1, 9, None), e); let e = Error::::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::::register(1337, ParaId::from(1234), Default::default(), Default::default())); diff --git a/polkadot/runtime/common/src/integration_tests.rs b/polkadot/runtime/common/src/integration_tests.rs index 83bbe3b466..899b74e4cc 100644 --- a/polkadot/runtime/common/src/integration_tests.rs +++ b/polkadot/runtime/common/src/integration_tests.rs @@ -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::::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)); }) } diff --git a/polkadot/runtime/common/src/slot_range.rs b/polkadot/runtime/common/src/slot_range.rs index 31480a6aab..3dcda158dd 100644 --- a/polkadot/runtime/common/src/slot_range.rs +++ b/polkadot/runtime/common/src/slot_range.rs @@ -14,7 +14,47 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! 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 +// }