cumulus_pallet_aura_ext/
consensus_hook.rs1use super::{pallet, Aura};
20use core::{marker::PhantomData, num::NonZeroU32};
21use cumulus_pallet_parachain_system::{
22 self as parachain_system,
23 consensus_hook::{ConsensusHook, UnincludedSegmentCapacity},
24 relay_state_snapshot::RelayChainStateProof,
25};
26use frame_support::pallet_prelude::*;
27use sp_consensus_aura::{Slot, SlotDuration};
28
29pub struct FixedVelocityConsensusHook<
49 T,
50 const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32,
51 const V: u32,
52 const C: u32,
53>(PhantomData<T>);
54
55impl<
56 T: pallet::Config,
57 const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32,
58 const V: u32,
59 const C: u32,
60 > ConsensusHook for FixedVelocityConsensusHook<T, RELAY_CHAIN_SLOT_DURATION_MILLIS, V, C>
61where
62 <T as pallet_timestamp::Config>::Moment: Into<u64>,
63{
64 fn on_state_proof(state_proof: &RelayChainStateProof) -> (Weight, UnincludedSegmentCapacity) {
74 let velocity = V.max(1);
76 let relay_chain_slot = state_proof.read_slot().expect("failed to read relay chain slot");
77
78 let (relay_chain_slot, authored_in_relay) = match pallet::RelaySlotInfo::<T>::get() {
79 Some((slot, authored)) if slot == relay_chain_slot => (slot, authored),
80 Some((slot, _)) if slot < relay_chain_slot => (relay_chain_slot, 0),
81 Some((slot, _)) => {
82 panic!("Slot moved backwards: stored_slot={slot:?}, relay_chain_slot={relay_chain_slot:?}")
83 },
84 None => (relay_chain_slot, 0),
85 };
86
87 if authored_in_relay > velocity {
89 panic!("authored blocks limit is reached for the slot: relay_chain_slot={relay_chain_slot:?}, authored={authored_in_relay:?}, velocity={velocity:?}");
90 }
91
92 pallet::RelaySlotInfo::<T>::put((relay_chain_slot, authored_in_relay + 1));
93
94 let para_slot = pallet_aura::CurrentSlot::<T>::get();
95
96 let relay_chain_timestamp =
98 u64::from(RELAY_CHAIN_SLOT_DURATION_MILLIS).saturating_mul(*relay_chain_slot);
99
100 let para_slot_duration = SlotDuration::from_millis(Aura::<T>::slot_duration().into());
101 let para_slot_from_relay =
102 Slot::from_timestamp(relay_chain_timestamp.into(), para_slot_duration);
103
104 if *para_slot > *para_slot_from_relay {
105 panic!(
106 "Parachain slot is too far in the future: parachain_slot={:?}, derived_from_relay_slot={:?} velocity={:?}, relay_chain_slot={:?}",
107 para_slot,
108 para_slot_from_relay,
109 velocity,
110 relay_chain_slot
111 );
112 }
113
114 let weight = T::DbWeight::get().reads(1);
115
116 (
117 weight,
118 NonZeroU32::new(core::cmp::max(C, 1))
119 .expect("1 is the minimum value and non-zero; qed")
120 .into(),
121 )
122 }
123}
124
125impl<
126 T: pallet::Config + parachain_system::Config,
127 const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32,
128 const V: u32,
129 const C: u32,
130 > FixedVelocityConsensusHook<T, RELAY_CHAIN_SLOT_DURATION_MILLIS, V, C>
131{
132 pub fn can_build_upon(included_hash: T::Hash, new_slot: Slot) -> bool {
143 let velocity = V.max(1);
144 let (last_slot, authored_so_far) = match pallet::RelaySlotInfo::<T>::get() {
145 None => return true,
146 Some(x) => x,
147 };
148
149 let size_after_included =
150 parachain_system::Pallet::<T>::unincluded_segment_size_after(included_hash);
151
152 if size_after_included >= C {
154 return false
155 }
156
157 if last_slot == new_slot {
160 authored_so_far < velocity + 1
161 } else {
162 last_slot < new_slot
164 }
165 }
166}