diff --git a/pallets/aura-ext/Cargo.toml b/pallets/aura-ext/Cargo.toml
index 1db43697511..df145aad522 100644
--- a/pallets/aura-ext/Cargo.toml
+++ b/pallets/aura-ext/Cargo.toml
@@ -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
@@ -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"]
diff --git a/pallets/aura-ext/src/consensus_hook.rs b/pallets/aura-ext/src/consensus_hook.rs
new file mode 100644
index 00000000000..c8806b1f4cb
--- /dev/null
+++ b/pallets/aura-ext/src/consensus_hook.rs
@@ -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 .
+
+//! 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(PhantomData);
+
+impl ConsensusHook
+ for FixedVelocityConsensusHook
+{
+ // 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::::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(),
+ )
+ }
+}
diff --git a/pallets/aura-ext/src/lib.rs b/pallets/aura-ext/src/lib.rs
index 15e82edeefe..5605e2f2ac5 100644
--- a/pallets/aura-ext/src/lib.rs
+++ b/pallets/aura-ext/src/lib.rs
@@ -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 = pallet_aura::Pallet;
pub use pallet::*;
@@ -68,6 +71,19 @@ pub mod pallet {
// Fetch the authorities once to get them into the storage proof of the PoV.
Authorities::::get();
+ let new_slot = Aura::::current_slot();
+
+ let (new_slot, authored) = match SlotInfo::::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::::put((new_slot, authored));
+
T::DbWeight::get().reads_writes(2, 1)
}
}
@@ -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 = StorageValue<_, (Slot, u32), OptionQuery>;
+
#[pallet::genesis_config]
#[derive(Default)]
pub struct GenesisConfig;
diff --git a/pallets/parachain-system/src/consensus_hook.rs b/pallets/parachain-system/src/consensus_hook.rs
index 8d3606d14b8..bdf590a0fd5 100644
--- a/pallets/parachain-system/src/consensus_hook.rs
+++ b/pallets/parachain-system/src/consensus_hook.rs
@@ -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.
@@ -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,
@@ -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),
+ )
}
}
@@ -88,10 +92,13 @@ impl ConsensusHook for ExpectParentIncluded {
pub struct FixedCapacityUnincludedSegment;
impl ConsensusHook for FixedCapacityUnincludedSegment {
- 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(),
+ )
}
}
diff --git a/pallets/parachain-system/src/lib.rs b/pallets/parachain-system/src/lib.rs
index 50df5e8ba59..5601bcdd17d 100644
--- a/pallets/parachain-system/src/lib.rs
+++ b/pallets/parachain-system/src/lib.rs
@@ -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;
@@ -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
@@ -543,7 +544,7 @@ pub mod pallet {
// ancestor was included, the MQC heads wouldn't match and the block would be invalid.
//
//
- 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,
diff --git a/pallets/parachain-system/src/relay_state_snapshot.rs b/pallets/parachain-system/src/relay_state_snapshot.rs
index 9da5a03ce83..ead077f527d 100644
--- a/pallets/parachain-system/src/relay_state_snapshot.rs
+++ b/pallets/parachain-system/src/relay_state_snapshot.rs
@@ -14,6 +14,8 @@
// You should have received a copy of the GNU General Public License
// along with Cumulus. If not, see .
+//! 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,
diff --git a/pallets/parachain-system/src/tests.rs b/pallets/parachain-system/src/tests.rs
index e1010f89be0..574ab43078d 100755
--- a/pallets/parachain-system/src/tests.rs
+++ b/pallets/parachain-system/src/tests.rs
@@ -121,14 +121,14 @@ std::thread_local! {
static HANDLED_DMP_MESSAGES: RefCell)>> = RefCell::new(Vec::new());
static HANDLED_XCMP_MESSAGES: RefCell)>> = RefCell::new(Vec::new());
static SENT_MESSAGES: RefCell)>> = RefCell::new(Vec::new());
- static CONSENSUS_HOOK: RefCell UnincludedSegmentCapacity>>
- = RefCell::new(Box::new(|_| NonZeroU32::new(1).unwrap().into()));
+ static CONSENSUS_HOOK: RefCell (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))
}
}
@@ -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)
@@ -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)