1
// Copyright 2019-2025 PureStake Inc.
2
// This file is part of Moonbeam.
3

            
4
// Moonbeam 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
// Moonbeam 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 Moonbeam.  If not, see <http://www.gnu.org/licenses/>.
16

            
17
//! A way to get a relyable timestamp
18

            
19
use cumulus_pallet_parachain_system::{
20
	consensus_hook::UnincludedSegmentCapacity,
21
	relay_state_snapshot::{self, ReadEntryErr},
22
	ConsensusHook, RelayChainStateProof,
23
};
24
use frame_support::pallet_prelude::*;
25
use frame_support::storage::types::{StorageValue, ValueQuery};
26
use frame_support::traits::{StorageInstance, Time};
27
pub use moonbeam_core_primitives::well_known_relay_keys;
28

            
29
/// Get the relay timestamp.
30
/// Noe that the relay timestamp is populated at the parachain system inherent.
31
/// If you fetch the timestamp before, you will get the timestamp of the parent block.
32
pub struct RelayTimestamp;
33
impl Time for RelayTimestamp {
34
	type Moment = u64;
35

            
36
562951
	fn now() -> Self::Moment {
37
562951
		RelayTimestampNow::get()
38
562951
	}
39
}
40

            
41
/// A wrapper around the consensus hook to get the relay timestamp from the relay storage proof
42
pub struct ConsensusHookWrapperForRelayTimestamp<Runtime, Inner>(
43
	core::marker::PhantomData<(Runtime, Inner)>,
44
);
45
impl<Runtime, Inner> ConsensusHook for ConsensusHookWrapperForRelayTimestamp<Runtime, Inner>
46
where
47
	Runtime: frame_system::Config,
48
	Inner: ConsensusHook,
49
{
50
237
	fn on_state_proof(state_proof: &RelayChainStateProof) -> (Weight, UnincludedSegmentCapacity) {
51
237
		let relay_timestamp: u64 =
52
237
			match state_proof.read_entry(well_known_relay_keys::TIMESTAMP_NOW, None) {
53
237
				Ok(relay_timestamp) => relay_timestamp,
54
				// Log the read entry error
55
				Err(relay_state_snapshot::Error::ReadEntry(ReadEntryErr::Proof)) => {
56
					log::error!("Invalid relay storage proof: fail to read key TIMESTAMP_NOW");
57
					panic!("Invalid realy storage proof: fail to read key TIMESTAMP_NOW");
58
				}
59
				Err(relay_state_snapshot::Error::ReadEntry(ReadEntryErr::Decode)) => {
60
					log::error!("Corrupted relay storage: fail to decode value TIMESTAMP_NOW");
61
					panic!("Corrupted relay storage: fail to decode value TIMESTAMP_NOW");
62
				}
63
				Err(relay_state_snapshot::Error::ReadEntry(ReadEntryErr::Absent)) => {
64
					log::error!("Corrupted relay storage: value TIMESTAMP_NOW is absent!");
65
					panic!("Corrupted relay storage: value TIMESTAMP_NOW is absent!");
66
				}
67
				// Can't return another kind of error, the blokc is invalid anyway, so we should panic
68
				_ => unreachable!(),
69
			};
70

            
71
237
		let wrapper_weight = <Runtime as frame_system::Config>::DbWeight::get().writes(1);
72
237

            
73
237
		RelayTimestampNow::put(relay_timestamp);
74
237

            
75
237
		let (weight, capacity) = Inner::on_state_proof(state_proof);
76
237

            
77
237
		(weight.saturating_add(wrapper_weight), capacity)
78
237
	}
79
}
80

            
81
// Prefix for storage value RelayTimestampNow
82
struct RelayTimestampNowPrefix;
83
impl StorageInstance for RelayTimestampNowPrefix {
84
	const STORAGE_PREFIX: &'static str = "RelayTimestampNow";
85

            
86
563635
	fn pallet_prefix() -> &'static str {
87
563635
		"runtime"
88
563635
	}
89
}
90

            
91
// Storage type used to store the last current relay timestamp
92
type RelayTimestampNow = StorageValue<RelayTimestampNowPrefix, u64, ValueQuery>;