1
// Copyright Moonsong Labs
2
// This file is part of Moonkit.
3

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

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

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

            
17
#![cfg_attr(not(feature = "std"), no_std)]
18

            
19
pub mod consensus_hook;
20

            
21
#[cfg(test)]
22
mod mock;
23
#[cfg(test)]
24
mod tests;
25

            
26
pub use pallet::*;
27

            
28
use frame_support::pallet_prelude::*;
29
use sp_consensus_slots::{Slot, SlotDuration};
30

            
31
/// The InherentIdentifier for nimbus's extension inherent
32
pub const INHERENT_IDENTIFIER: InherentIdentifier = *b"nimb-ext";
33

            
34
/// A way to get the current parachain slot and verify it's validity against the relay slot.
35
/// If you don't need to have slots at parachain level, you can use the `RelaySlot` implementation.
36
pub trait GetAndVerifySlot {
37
	/// Get the current slot
38
	fn get_and_verify_slot(relay_chain_slot: &Slot) -> Result<Slot, ()>;
39
}
40

            
41
/// Parachain slot implementation that use the relay chain slot directly
42
pub struct RelaySlot;
43
impl GetAndVerifySlot for RelaySlot {
44
	fn get_and_verify_slot(relay_chain_slot: &Slot) -> Result<Slot, ()> {
45
		Ok(*relay_chain_slot)
46
	}
47
}
48

            
49
/// Parachain slot implementation that use a slot provider
50
pub struct ParaSlot<const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32, SlotProvider>(
51
	PhantomData<SlotProvider>,
52
);
53

            
54
impl<const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32, SlotProvider> GetAndVerifySlot
55
	for ParaSlot<RELAY_CHAIN_SLOT_DURATION_MILLIS, SlotProvider>
56
where
57
	SlotProvider: Get<(Slot, SlotDuration)>,
58
{
59
	fn get_and_verify_slot(relay_chain_slot: &Slot) -> Result<Slot, ()> {
60
		// Convert relay chain timestamp.
61
		let relay_chain_timestamp =
62
			u64::from(RELAY_CHAIN_SLOT_DURATION_MILLIS).saturating_mul((*relay_chain_slot).into());
63

            
64
		let (new_slot, para_slot_duration) = SlotProvider::get();
65

            
66
		let para_slot_from_relay =
67
			Slot::from_timestamp(relay_chain_timestamp.into(), para_slot_duration);
68

            
69
		if new_slot == para_slot_from_relay {
70
			Ok(new_slot)
71
		} else {
72
			Err(())
73
		}
74
	}
75
}
76

            
77
#[frame_support::pallet]
78
pub mod pallet {
79
	use super::*;
80

            
81
	/// The current storage version.
82
	const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
83

            
84
	#[pallet::pallet]
85
	#[pallet::storage_version(STORAGE_VERSION)]
86
	pub struct Pallet<T>(PhantomData<T>);
87

            
88
	/// The configuration trait.
89
	#[pallet::config]
90
	pub trait Config: pallet_timestamp::Config + frame_system::Config {
91
		/// Whether or not to allow more than one block per slot.
92
		/// Setting it to 'true' will enable async-backing compatibility.
93
		type AllowMultipleBlocksPerSlot: Get<bool>;
94

            
95
		/// A way to get the current parachain slot and verify it's validity against the relay slot.
96
		type GetAndVerifySlot: GetAndVerifySlot;
97

            
98
		/// Purely informative, but used by mocking tools like chospticks to allow knowing how to mock
99
		/// blocks
100
		#[pallet::constant]
101
		type ExpectedBlockTime: Get<Self::Moment>;
102
	}
103

            
104
	/// First tuple element is the highest slot that has been seen in the history of this chain.
105
	/// Second tuple element is the number of authored blocks so far.
106
	/// This is a strictly-increasing value if T::AllowMultipleBlocksPerSlot = false.
107
	#[pallet::storage]
108
	#[pallet::getter(fn slot_info)]
109
	pub type SlotInfo<T: Config> = StorageValue<_, (Slot, u32), OptionQuery>;
110
}