From e5763b825fa41e05a49094bef3c67300999a52a5 Mon Sep 17 00:00:00 2001 From: asynchronous rob Date: Fri, 9 Jun 2023 16:04:37 -0500 Subject: [PATCH] pallet-aura: Allow multiple blocks per slot (#14024) * pallet-aura: Allow multiple blocks per slot * run fmt * rework as associated type * fix fallout * fmt * use constbool * fmt --- bin/node-template/runtime/src/lib.rs | 4 +- frame/aura/src/lib.rs | 21 +++++++++- frame/aura/src/mock.rs | 2 + frame/aura/src/tests.rs | 61 ++++++++++++++++++++++++++++ 4 files changed, 86 insertions(+), 2 deletions(-) diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index b32ea0d958100..22fb01b62d0f0 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -27,7 +27,8 @@ use sp_version::RuntimeVersion; pub use frame_support::{ construct_runtime, parameter_types, traits::{ - ConstU128, ConstU32, ConstU64, ConstU8, KeyOwnerProofSystem, Randomness, StorageInfo, + ConstBool, ConstU128, ConstU32, ConstU64, ConstU8, KeyOwnerProofSystem, Randomness, + StorageInfo, }, weights::{ constants::{ @@ -207,6 +208,7 @@ impl pallet_aura::Config for Runtime { type AuthorityId = AuraId; type DisabledValidators = (); type MaxAuthorities = ConstU32<32>; + type AllowMultipleBlocksPerSlot = ConstBool; } impl pallet_grandpa::Config for Runtime { diff --git a/frame/aura/src/lib.rs b/frame/aura/src/lib.rs index 12b7ee3f5fedc..3cd0e9ec2e6cc 100644 --- a/frame/aura/src/lib.rs +++ b/frame/aura/src/lib.rs @@ -81,6 +81,20 @@ pub mod pallet { /// Blocks authored by a disabled validator will lead to a panic as part of this module's /// initialization. type DisabledValidators: DisabledValidators; + + /// Whether to allow block authors to create multiple blocks per slot. + /// + /// If this is `true`, the pallet will allow slots to stay the same across sequential + /// blocks. If this is `false`, the pallet will require that subsequent blocks always have + /// higher slots than previous ones. + /// + /// Regardless of the setting of this storage value, the pallet will always enforce the + /// invariant that slots don't move backwards as the chain progresses. + /// + /// The typical value for this should be 'false' unless this pallet is being augmented by + /// another pallet which enforces some limitation on the number of blocks authors can create + /// using the same slot. + type AllowMultipleBlocksPerSlot: Get; } #[pallet::pallet] @@ -92,7 +106,12 @@ pub mod pallet { if let Some(new_slot) = Self::current_slot_from_digests() { let current_slot = CurrentSlot::::get(); - assert!(current_slot < new_slot, "Slot must increase"); + if T::AllowMultipleBlocksPerSlot::get() { + assert!(current_slot <= new_slot, "Slot must not decrease"); + } else { + assert!(current_slot < new_slot, "Slot must increase"); + } + CurrentSlot::::put(new_slot); if let Some(n_authorities) = >::decode_len() { diff --git a/frame/aura/src/mock.rs b/frame/aura/src/mock.rs index 72d11a0749933..c95b7451d0bd4 100644 --- a/frame/aura/src/mock.rs +++ b/frame/aura/src/mock.rs @@ -82,6 +82,7 @@ impl pallet_timestamp::Config for Test { parameter_types! { static DisabledValidatorTestValue: Vec = Default::default(); + pub static AllowMultipleBlocksPerSlot: bool = false; } pub struct MockDisabledValidators; @@ -106,6 +107,7 @@ impl pallet_aura::Config for Test { type AuthorityId = AuthorityId; type DisabledValidators = MockDisabledValidators; type MaxAuthorities = ConstU32<10>; + type AllowMultipleBlocksPerSlot = AllowMultipleBlocksPerSlot; } pub fn new_test_ext(authorities: Vec) -> sp_io::TestExternalities { diff --git a/frame/aura/src/tests.rs b/frame/aura/src/tests.rs index 1ed937a7745fe..d5e5f19d65ea5 100644 --- a/frame/aura/src/tests.rs +++ b/frame/aura/src/tests.rs @@ -54,3 +54,64 @@ fn disabled_validators_cannot_author_blocks() { Aura::on_initialize(42); }); } + +#[test] +#[should_panic(expected = "Slot must increase")] +fn pallet_requires_slot_to_increase_unless_allowed() { + new_test_ext(vec![0, 1, 2, 3]).execute_with(|| { + crate::mock::AllowMultipleBlocksPerSlot::set(false); + + let slot = Slot::from(1); + let pre_digest = + Digest { logs: vec![DigestItem::PreRuntime(AURA_ENGINE_ID, slot.encode())] }; + + System::reset_events(); + System::initialize(&42, &System::parent_hash(), &pre_digest); + + // and we should not be able to initialize the block with the same slot a second time. + Aura::on_initialize(42); + Aura::on_initialize(42); + }); +} + +#[test] +fn pallet_can_allow_unchanged_slot() { + new_test_ext(vec![0, 1, 2, 3]).execute_with(|| { + let slot = Slot::from(1); + let pre_digest = + Digest { logs: vec![DigestItem::PreRuntime(AURA_ENGINE_ID, slot.encode())] }; + + System::reset_events(); + System::initialize(&42, &System::parent_hash(), &pre_digest); + + crate::mock::AllowMultipleBlocksPerSlot::set(true); + + // and we should be able to initialize the block with the same slot a second time. + Aura::on_initialize(42); + Aura::on_initialize(42); + }); +} + +#[test] +#[should_panic(expected = "Slot must not decrease")] +fn pallet_always_rejects_decreasing_slot() { + new_test_ext(vec![0, 1, 2, 3]).execute_with(|| { + let slot = Slot::from(2); + let pre_digest = + Digest { logs: vec![DigestItem::PreRuntime(AURA_ENGINE_ID, slot.encode())] }; + + System::reset_events(); + System::initialize(&42, &System::parent_hash(), &pre_digest); + + crate::mock::AllowMultipleBlocksPerSlot::set(true); + + Aura::on_initialize(42); + System::finalize(); + + let earlier_slot = Slot::from(1); + let pre_digest = + Digest { logs: vec![DigestItem::PreRuntime(AURA_ENGINE_ID, earlier_slot.encode())] }; + System::initialize(&43, &System::parent_hash(), &pre_digest); + Aura::on_initialize(43); + }); +}