Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Commit

Permalink
aura-ext: limit the number of authored blocks per slot (#2551)
Browse files Browse the repository at this point in the history
* aura_ext consensus hook

* reverse dependency

* include weight into hook

* fix tests
  • Loading branch information
slumber authored May 11, 2023
1 parent 352d556 commit 1818426
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 17 deletions.
4 changes: 4 additions & 0 deletions pallets/aura-ext/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ sp-consensus-aura = { git = "https://github.com/paritytech/substrate", default-f
sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }

# Cumulus
cumulus-pallet-parachain-system = { path = "../parachain-system", default-features = false }

[dev-dependencies]

# Cumulus
Expand All @@ -35,5 +38,6 @@ std = [
"sp-consensus-aura/std",
"sp-runtime/std",
"sp-std/std",
"cumulus-pallet-parachain-system/std",
]
try-runtime = ["frame-support/try-runtime"]
56 changes: 56 additions & 0 deletions pallets/aura-ext/src/consensus_hook.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright 2023 Parity Technologies (UK) Ltd.
// This file is part of Cumulus.

// Cumulus is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Cumulus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Cumulus. If not, see <http://www.gnu.org/licenses/>.

//! The definition of a [`FixedVelocityConsensusHook`] for consensus logic to manage
//! block velocity.
//!
//! The velocity `V` refers to the rate of block processing by the relay chain.
use super::pallet;
use cumulus_pallet_parachain_system::{
consensus_hook::{ConsensusHook, UnincludedSegmentCapacity},
relay_state_snapshot::RelayChainStateProof,
};
use frame_support::pallet_prelude::*;
use sp_std::{marker::PhantomData, num::NonZeroU32};

/// A consensus hook for a fixed block processing velocity and unincluded segment capacity.
pub struct FixedVelocityConsensusHook<T, const V: u32, const C: u32>(PhantomData<T>);

impl<T: pallet::Config, const V: u32, const C: u32> ConsensusHook
for FixedVelocityConsensusHook<T, V, C>
{
// Validates the number of authored blocks within the slot with respect to the `V + 1` limit.
fn on_state_proof(_state_proof: &RelayChainStateProof) -> (Weight, UnincludedSegmentCapacity) {
// Ensure velocity is non-zero.
let velocity = V.max(1);

let authored = pallet::Pallet::<T>::slot_info()
.map(|(_slot, authored)| authored)
.expect("slot info is inserted on block initialization");
if authored > velocity + 1 {
panic!("authored blocks limit is reached for the slot")
}
let weight = T::DbWeight::get().reads(1);

(
weight,
NonZeroU32::new(sp_std::cmp::max(C, 1))
.expect("1 is the minimum value and non-zero; qed")
.into(),
)
}
}
25 changes: 24 additions & 1 deletion pallets/aura-ext/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,12 @@

use frame_support::traits::{ExecuteBlock, FindAuthor};
use sp_application_crypto::RuntimeAppPublic;
use sp_consensus_aura::digests::CompatibleDigestItem;
use sp_consensus_aura::{digests::CompatibleDigestItem, Slot};
use sp_runtime::traits::{Block as BlockT, Header as HeaderT};

pub mod consensus_hook;
pub use consensus_hook::FixedVelocityConsensusHook;

type Aura<T> = pallet_aura::Pallet<T>;

pub use pallet::*;
Expand Down Expand Up @@ -68,6 +71,19 @@ pub mod pallet {
// Fetch the authorities once to get them into the storage proof of the PoV.
Authorities::<T>::get();

let new_slot = Aura::<T>::current_slot();

let (new_slot, authored) = match SlotInfo::<T>::get() {
Some((slot, authored)) if slot == new_slot => (slot, authored + 1),
Some((slot, _)) if slot < new_slot => (new_slot, 1),
Some(..) => {
panic!("slot moved backwards")
},
None => (new_slot, 1),
};

SlotInfo::<T>::put((new_slot, authored));

T::DbWeight::get().reads_writes(2, 1)
}
}
Expand All @@ -84,6 +100,13 @@ pub mod pallet {
ValueQuery,
>;

/// Current slot paired with a number of authored blocks.
///
/// Updated on each block initialization.
#[pallet::storage]
#[pallet::getter(fn slot_info)]
pub(crate) type SlotInfo<T: Config> = StorageValue<_, (Slot, u32), OptionQuery>;

#[pallet::genesis_config]
#[derive(Default)]
pub struct GenesisConfig;
Expand Down
23 changes: 15 additions & 8 deletions pallets/parachain-system/src/consensus_hook.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
//! of parachain blocks ready to submit to the relay chain, as well as some basic implementations.
use super::relay_state_snapshot::RelayChainStateProof;
use frame_support::weights::Weight;
use sp_std::num::NonZeroU32;

/// The possible capacity of the unincluded segment.
Expand Down Expand Up @@ -61,8 +62,8 @@ pub trait ConsensusHook {
/// This hook is called partway through the `set_validation_data` inherent in parachain-system.
///
/// The hook is allowed to panic if customized consensus rules aren't met and is required
/// to return a maximum capacity for the unincluded segment.
fn on_state_proof(state_proof: &RelayChainStateProof) -> UnincludedSegmentCapacity;
/// to return a maximum capacity for the unincluded segment with weight consumed.
fn on_state_proof(state_proof: &RelayChainStateProof) -> (Weight, UnincludedSegmentCapacity);
}

/// A special consensus hook for handling the migration to asynchronous backing gracefully,
Expand All @@ -75,8 +76,11 @@ pub trait ConsensusHook {
pub struct ExpectParentIncluded;

impl ConsensusHook for ExpectParentIncluded {
fn on_state_proof(_state_proof: &RelayChainStateProof) -> UnincludedSegmentCapacity {
UnincludedSegmentCapacity(UnincludedSegmentCapacityInner::ExpectParentIncluded)
fn on_state_proof(_state_proof: &RelayChainStateProof) -> (Weight, UnincludedSegmentCapacity) {
(
Weight::zero(),
UnincludedSegmentCapacity(UnincludedSegmentCapacityInner::ExpectParentIncluded),
)
}
}

Expand All @@ -88,10 +92,13 @@ impl ConsensusHook for ExpectParentIncluded {
pub struct FixedCapacityUnincludedSegment<const N: u32>;

impl<const N: u32> ConsensusHook for FixedCapacityUnincludedSegment<N> {
fn on_state_proof(_state_proof: &RelayChainStateProof) -> UnincludedSegmentCapacity {
NonZeroU32::new(sp_std::cmp::max(N, 1))
.expect("1 is the minimum value and non-zero; qed")
.into()
fn on_state_proof(_state_proof: &RelayChainStateProof) -> (Weight, UnincludedSegmentCapacity) {
(
Weight::zero(),
NonZeroU32::new(sp_std::cmp::max(N, 1))
.expect("1 is the minimum value and non-zero; qed")
.into(),
)
}
}

Expand Down
7 changes: 4 additions & 3 deletions pallets/parachain-system/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,12 @@ use sp_std::{cmp, collections::btree_map::BTreeMap, prelude::*};
use xcm::latest::XcmHash;

mod migration;
mod relay_state_snapshot;
#[cfg(test)]
mod tests;
mod unincluded_segment;

pub mod consensus_hook;
pub mod relay_state_snapshot;
#[macro_use]
pub mod validate_block;

Expand Down Expand Up @@ -484,7 +484,8 @@ pub mod pallet {
.expect("Invalid relay chain state proof");

// Update the desired maximum capacity according to the consensus hook.
let capacity = T::ConsensusHook::on_state_proof(&relay_state_proof);
let (consensus_hook_weight, capacity) =
T::ConsensusHook::on_state_proof(&relay_state_proof);

// initialization logic: we know that this runs exactly once every block,
// which means we can put the initialization logic here to remove the
Expand Down Expand Up @@ -543,7 +544,7 @@ pub mod pallet {
// ancestor was included, the MQC heads wouldn't match and the block would be invalid.
//
// <https://github.com/paritytech/cumulus/issues/2472>
let mut total_weight = Weight::zero();
let mut total_weight = consensus_hook_weight;
total_weight += Self::process_inbound_downward_messages(
relevant_messaging_state.dmq_mqc_head,
downward_messages,
Expand Down
2 changes: 2 additions & 0 deletions pallets/parachain-system/src/relay_state_snapshot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
// You should have received a copy of the GNU General Public License
// along with Cumulus. If not, see <http://www.gnu.org/licenses/>.

//! Relay chain state proof provides means for accessing part of relay chain storage for reads.
use codec::{Decode, Encode};
use cumulus_primitives_core::{
relay_chain, AbridgedHostConfiguration, AbridgedHrmpChannel, ParaId,
Expand Down
14 changes: 9 additions & 5 deletions pallets/parachain-system/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,14 +121,14 @@ std::thread_local! {
static HANDLED_DMP_MESSAGES: RefCell<Vec<(relay_chain::BlockNumber, Vec<u8>)>> = RefCell::new(Vec::new());
static HANDLED_XCMP_MESSAGES: RefCell<Vec<(ParaId, relay_chain::BlockNumber, Vec<u8>)>> = RefCell::new(Vec::new());
static SENT_MESSAGES: RefCell<Vec<(ParaId, Vec<u8>)>> = RefCell::new(Vec::new());
static CONSENSUS_HOOK: RefCell<Box<dyn Fn(&RelayChainStateProof) -> UnincludedSegmentCapacity>>
= RefCell::new(Box::new(|_| NonZeroU32::new(1).unwrap().into()));
static CONSENSUS_HOOK: RefCell<Box<dyn Fn(&RelayChainStateProof) -> (Weight, UnincludedSegmentCapacity)>>
= RefCell::new(Box::new(|_| (Weight::zero(), NonZeroU32::new(1).unwrap().into())));
}

pub struct TestConsensusHook;

impl ConsensusHook for TestConsensusHook {
fn on_state_proof(s: &RelayChainStateProof) -> UnincludedSegmentCapacity {
fn on_state_proof(s: &RelayChainStateProof) -> (Weight, UnincludedSegmentCapacity) {
CONSENSUS_HOOK.with(|f| f.borrow_mut()(s))
}
}
Expand Down Expand Up @@ -440,7 +440,9 @@ fn block_tests_run_on_drop() {

#[test]
fn unincluded_segment_works() {
CONSENSUS_HOOK.with(|c| *c.borrow_mut() = Box::new(|_| NonZeroU32::new(10).unwrap().into()));
CONSENSUS_HOOK.with(|c| {
*c.borrow_mut() = Box::new(|_| (Weight::zero(), NonZeroU32::new(10).unwrap().into()))
});

BlockTests::new()
.with_inclusion_delay(1)
Expand Down Expand Up @@ -475,7 +477,9 @@ fn unincluded_segment_works() {
#[test]
#[should_panic = "no space left for the block in the unincluded segment"]
fn unincluded_segment_is_limited() {
CONSENSUS_HOOK.with(|c| *c.borrow_mut() = Box::new(|_| NonZeroU32::new(1).unwrap().into()));
CONSENSUS_HOOK.with(|c| {
*c.borrow_mut() = Box::new(|_| (Weight::zero(), NonZeroU32::new(1).unwrap().into()))
});

BlockTests::new()
.with_inclusion_delay(2)
Expand Down

0 comments on commit 1818426

Please sign in to comment.