Skip to content

Commit

Permalink
Store randomness from previous relay block in pallet storage
Browse files Browse the repository at this point in the history
Because since #288 collator rotation is handled in on_initialize, and we
can only read the relay randomness after the set_validation_data
inherent, which happens after on_initialize.

The solution is to read the randomness on the on_finalize hook of the
previous block, store it in pallet_collator_assignment, and delete it
when reading it.
  • Loading branch information
tmpolaczyk committed Oct 17, 2023
1 parent f6bcc37 commit 1223f9b
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 33 deletions.
38 changes: 37 additions & 1 deletion pallets/collator-assignment/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ pub use pallet::*;
use {
crate::weights::WeightInfo,
frame_support::pallet_prelude::*,
frame_system::pallet_prelude::BlockNumberFor,
rand::{seq::SliceRandom, SeedableRng},
rand_chacha::ChaCha20Rng,
sp_runtime::{
Expand Down Expand Up @@ -93,6 +94,7 @@ pub mod pallet {
type HostConfiguration: GetHostConfiguration<Self::SessionIndex>;
type ContainerChains: GetSessionContainerChains<Self::SessionIndex>;
type ShouldRotateAllCollators: ShouldRotateAllCollators<Self::SessionIndex>;
type GetRandomnessForNextBlock: GetRandomnessForNextBlock<BlockNumberFor<Self>>;
/// The weight information of this pallet.
type WeightInfo: WeightInfo;
}
Expand Down Expand Up @@ -124,6 +126,13 @@ pub mod pallet {
pub(crate) type PendingCollatorContainerChain<T: Config> =
StorageValue<_, Option<AssignedCollators<T::AccountId>>, ValueQuery>;

/// Randomness from previous block. Used to shuffle collators on session change.
/// Should only be set on the last block of each session and should be killed on the on_initialize of the next block.
/// The default value of [0; 32] disables randomness in the pallet.
#[pallet::storage]
#[pallet::getter(fn randomness)]
pub(crate) type Randomness<T: Config> = StorageValue<_, [u8; 32], ValueQuery>;

#[pallet::call]
impl<T: Config> Pallet<T> {}

Expand Down Expand Up @@ -371,9 +380,9 @@ pub mod pallet {

pub fn initializer_on_new_session(
session_index: &T::SessionIndex,
random_seed: [u8; 32],
collators: Vec<T::AccountId>,
) -> SessionChangeOutcome<T> {
let random_seed = Randomness::<T>::take();
let num_collators = collators.len();
let assigned_collators = Self::assign_collators(session_index, random_seed, collators);
let num_parachains = assigned_collators.next_assignment.container_chains.len();
Expand Down Expand Up @@ -406,6 +415,28 @@ pub mod pallet {
CollatorContainerChain::<T>::put(assigned_collators);
}
}

#[pallet::hooks]
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
fn on_initialize(n: BlockNumberFor<T>) -> Weight {
let mut weight = Weight::zero();

// Account reads and writes for on_finalize
if T::GetRandomnessForNextBlock::should_end_session(n.saturating_add(One::one())) {
weight += T::DbWeight::get().reads_writes(1, 1);
}

weight
}

fn on_finalize(n: BlockNumberFor<T>) {
// If the next block is a session change, read randomness and store in pallet storage
if T::GetRandomnessForNextBlock::should_end_session(n.saturating_add(One::one())) {
let random_seed = T::GetRandomnessForNextBlock::get_randomness();
Randomness::<T>::put(random_seed);
}
}
}
}

pub struct RotateCollatorsEveryNSessions<Period>(PhantomData<Period>);
Expand All @@ -418,3 +449,8 @@ where
session_index % Period::get() == 0
}
}

pub trait GetRandomnessForNextBlock<BlockNumber> {
fn should_end_session(block_number: BlockNumber) -> bool;
fn get_randomness() -> [u8; 32];
}
25 changes: 22 additions & 3 deletions pallets/collator-assignment/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,13 @@
// You should have received a copy of the GNU General Public License
// along with Tanssi. If not, see <http://www.gnu.org/licenses/>

use frame_support::traits::Hooks;

use {
crate::{self as pallet_collator_assignment, RotateCollatorsEveryNSessions},
crate::{
self as pallet_collator_assignment, GetRandomnessForNextBlock,
RotateCollatorsEveryNSessions,
},
frame_support::{
parameter_types,
traits::{ConstU16, ConstU64},
Expand Down Expand Up @@ -161,6 +166,18 @@ impl tp_traits::GetSessionContainerChains<u32> for ContainerChainsGetter {
}
}

pub struct MockGetRandomnessForNextBlock;

impl GetRandomnessForNextBlock<u64> for MockGetRandomnessForNextBlock {
fn should_end_session(n: u64) -> bool {
n % 5 == 0
}

fn get_randomness() -> [u8; 32] {
MockData::mock().random_seed
}
}

parameter_types! {
pub const CollatorRotationSessionPeriod: u32 = 5;
}
Expand All @@ -171,6 +188,7 @@ impl pallet_collator_assignment::Config for Test {
type HostConfiguration = HostConfigurationGetter;
type ContainerChains = ContainerChainsGetter;
type ShouldRotateAllCollators = RotateCollatorsEveryNSessions<CollatorRotationSessionPeriod>;
type GetRandomnessForNextBlock = MockGetRandomnessForNextBlock;
type WeightInfo = ();
}

Expand All @@ -193,15 +211,16 @@ pub fn run_to_block(n: u64) {
for x in (old_block_number + 1)..=n {
System::reset_events();
System::set_block_number(x);
let randomness = MockData::mock().random_seed;
CollatorAssignment::on_initialize(x);

if x % session_len == 1 {
let session_index = (x / session_len) as u32;
CollatorAssignment::initializer_on_new_session(
&session_index,
randomness,
CollatorsGetter::collators(session_index),
);
}

CollatorAssignment::on_finalize(x);
}
}
63 changes: 37 additions & 26 deletions runtime/dancebox/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ use {
EnsureRoot,
},
nimbus_primitives::NimbusId,
pallet_collator_assignment::RotateCollatorsEveryNSessions,
pallet_collator_assignment::{GetRandomnessForNextBlock, RotateCollatorsEveryNSessions},
pallet_pooled_staking::traits::{IsCandidateEligible, Timer},
pallet_registrar_runtime_api::ContainerChainGenesisData,
pallet_session::{SessionManager, ShouldEndSession},
Expand Down Expand Up @@ -507,26 +507,6 @@ impl pallet_initializer::ApplyNewSession<Runtime> for OwnApplySession {
all_validators: Vec<(AccountId, NimbusId)>,
queued: Vec<(AccountId, NimbusId)>,
) {
let random_seed = if session_index != 0 {
if let Some(random_hash) =
BabeCurrentBlockRandomnessGetter::get_block_randomness_mixed(b"CollatorAssignment")
{
// Return random_hash as a [u8; 32] instead of a Hash
let mut buf = [0u8; 32];
let len = sp_std::cmp::min(32, random_hash.as_ref().len());
buf[..len].copy_from_slice(&random_hash.as_ref()[..len]);

buf
} else {
// If there is no randomness (e.g when running in dev mode), return [0; 32]
// TODO: smoke test to ensure this never happens in a live network
[0; 32]
}
} else {
// In session 0 (genesis) there is randomness
[0; 32]
};

// We first initialize Configuration
Configuration::initializer_on_new_session(&session_index);
// Next: Registrar
Expand All @@ -537,11 +517,8 @@ impl pallet_initializer::ApplyNewSession<Runtime> for OwnApplySession {
let next_collators = queued.iter().map(|(k, _)| k.clone()).collect();

// Next: CollatorAssignment
let assignments = CollatorAssignment::initializer_on_new_session(
&session_index,
random_seed,
next_collators,
);
let assignments =
CollatorAssignment::initializer_on_new_session(&session_index, next_collators);

let queued_id_to_nimbus_map = queued.iter().cloned().collect();
AuthorityAssignment::initializer_on_new_session(
Expand Down Expand Up @@ -640,13 +617,47 @@ impl Get<u32> for ConfigurationCollatorRotationSessionPeriod {
}
}

pub struct BabeGetRandomnessForNextBlock;

impl GetRandomnessForNextBlock<u32> for BabeGetRandomnessForNextBlock {
fn should_end_session(n: u32) -> bool {
<Runtime as pallet_session::Config>::ShouldEndSession::should_end_session(n)
}

fn get_randomness() -> [u8; 32] {
let block_number = System::block_number();
let random_seed = if block_number != 0 {
if let Some(random_hash) =
BabeCurrentBlockRandomnessGetter::get_block_randomness_mixed(b"CollatorAssignment")
{
// Return random_hash as a [u8; 32] instead of a Hash
let mut buf = [0u8; 32];
let len = sp_std::cmp::min(32, random_hash.as_ref().len());
buf[..len].copy_from_slice(&random_hash.as_ref()[..len]);

buf
} else {
// If there is no randomness (e.g when running in dev mode), return [0; 32]
// TODO: smoke test to ensure this never happens in a live network
[0; 32]
}
} else {
// In block 0 (genesis) there is randomness
[0; 32]
};

random_seed
}
}

impl pallet_collator_assignment::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type HostConfiguration = Configuration;
type ContainerChains = Registrar;
type SessionIndex = u32;
type ShouldRotateAllCollators =
RotateCollatorsEveryNSessions<ConfigurationCollatorRotationSessionPeriod>;
type GetRandomnessForNextBlock = BabeGetRandomnessForNextBlock;
type WeightInfo = pallet_collator_assignment::weights::SubstrateWeight<Runtime>;
}

Expand Down
10 changes: 7 additions & 3 deletions runtime/dancebox/tests/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
use {
cumulus_primitives_core::{ParaId, PersistedValidationData},
cumulus_primitives_parachain_inherent::ParachainInherentData,
dancebox_runtime::{AuthorInherent, AuthorityAssignment, MaxLengthTokenSymbol},
dancebox_runtime::{
AuthorInherent, AuthorityAssignment, CollatorAssignment, MaxLengthTokenSymbol,
},
frame_support::{
assert_ok,
traits::{OnFinalize, OnInitialize},
Expand Down Expand Up @@ -78,16 +80,18 @@ pub fn run_to_block(n: u32) {
);

// Initialize the new block
Session::on_initialize(System::block_number());
CollatorAssignment::on_initialize(System::block_number());
Initializer::on_initialize(System::block_number());
Session::on_initialize(System::block_number());
AuthorInherent::on_initialize(System::block_number());

pallet_author_inherent::Pallet::<Runtime>::kick_off_authorship_validation(None.into())
.expect("author inherent to dispatch correctly");

// Finalize the block
Session::on_finalize(System::block_number());
CollatorAssignment::on_finalize(System::block_number());
Initializer::on_finalize(System::block_number());
Session::on_finalize(System::block_number());
AuthorInherent::on_finalize(System::block_number());
}
}
Expand Down

0 comments on commit 1223f9b

Please sign in to comment.