cumulus_pallet_parachain_system/
relay_state_snapshot.rs1use alloc::vec::Vec;
20use codec::{Decode, Encode};
21use cumulus_primitives_core::{
22 relay_chain, AbridgedHostConfiguration, AbridgedHrmpChannel, ParaId,
23};
24use scale_info::TypeInfo;
25use sp_runtime::traits::HashingFor;
26use sp_state_machine::{Backend, TrieBackend, TrieBackendBuilder};
27use sp_trie::{HashDBT, MemoryDB, StorageProof, EMPTY_PREFIX};
28
29#[derive(Clone, Encode, Decode, TypeInfo, Default)]
33pub struct RelayDispatchQueueRemainingCapacity {
34 pub remaining_count: u32,
36 pub remaining_size: u32,
38}
39
40#[derive(Clone, Encode, Decode, TypeInfo)]
46pub struct MessagingStateSnapshot {
47 pub dmq_mqc_head: relay_chain::Hash,
51
52 pub relay_dispatch_queue_remaining_capacity: RelayDispatchQueueRemainingCapacity,
55
56 pub ingress_channels: Vec<(ParaId, AbridgedHrmpChannel)>,
63
64 pub egress_channels: Vec<(ParaId, AbridgedHrmpChannel)>,
71}
72
73#[derive(Debug)]
74pub enum Error {
75 RootMismatch,
77 ReadEntry(ReadEntryErr),
79 ReadOptionalEntry(ReadEntryErr),
81 Slot(ReadEntryErr),
83 UpgradeGoAhead(ReadEntryErr),
85 UpgradeRestriction(ReadEntryErr),
87 Config(ReadEntryErr),
89 DmqMqcHead(ReadEntryErr),
91 RelayDispatchQueueRemainingCapacity(ReadEntryErr),
93 HrmpIngressChannelIndex(ReadEntryErr),
95 HrmpEgressChannelIndex(ReadEntryErr),
97 HrmpChannel(ParaId, ParaId, ReadEntryErr),
99 ParaHead(ReadEntryErr),
101 Authorities(ReadEntryErr),
103 NextAuthorities(ReadEntryErr),
105}
106
107#[derive(Debug)]
108pub enum ReadEntryErr {
109 Proof,
111 Decode,
113 Absent,
115}
116
117fn read_entry<T, B>(backend: &B, key: &[u8], fallback: Option<T>) -> Result<T, ReadEntryErr>
124where
125 T: Decode,
126 B: Backend<HashingFor<relay_chain::Block>>,
127{
128 backend
129 .storage(key)
130 .map_err(|_| ReadEntryErr::Proof)?
131 .map(|raw_entry| T::decode(&mut &raw_entry[..]).map_err(|_| ReadEntryErr::Decode))
132 .transpose()?
133 .or(fallback)
134 .ok_or(ReadEntryErr::Absent)
135}
136
137fn read_optional_entry<T, B>(backend: &B, key: &[u8]) -> Result<Option<T>, ReadEntryErr>
143where
144 T: Decode,
145 B: Backend<HashingFor<relay_chain::Block>>,
146{
147 match read_entry(backend, key, None) {
148 Ok(v) => Ok(Some(v)),
149 Err(ReadEntryErr::Absent) => Ok(None),
150 Err(err) => Err(err),
151 }
152}
153
154pub struct RelayChainStateProof {
158 para_id: ParaId,
159 trie_backend:
160 TrieBackend<MemoryDB<HashingFor<relay_chain::Block>>, HashingFor<relay_chain::Block>>,
161}
162
163impl RelayChainStateProof {
164 pub fn new(
169 para_id: ParaId,
170 relay_parent_storage_root: relay_chain::Hash,
171 proof: StorageProof,
172 ) -> Result<Self, Error> {
173 let db = proof.into_memory_db::<HashingFor<relay_chain::Block>>();
174 if !db.contains(&relay_parent_storage_root, EMPTY_PREFIX) {
175 return Err(Error::RootMismatch)
176 }
177 let trie_backend = TrieBackendBuilder::new(db, relay_parent_storage_root).build();
178
179 Ok(Self { para_id, trie_backend })
180 }
181
182 pub fn read_messaging_state_snapshot(
186 &self,
187 host_config: &AbridgedHostConfiguration,
188 ) -> Result<MessagingStateSnapshot, Error> {
189 let dmq_mqc_head: relay_chain::Hash = read_entry(
190 &self.trie_backend,
191 &relay_chain::well_known_keys::dmq_mqc_head(self.para_id),
192 Some(Default::default()),
193 )
194 .map_err(Error::DmqMqcHead)?;
195
196 let relay_dispatch_queue_remaining_capacity = read_optional_entry::<
197 RelayDispatchQueueRemainingCapacity,
198 _,
199 >(
200 &self.trie_backend,
201 &relay_chain::well_known_keys::relay_dispatch_queue_remaining_capacity(self.para_id)
202 .key,
203 );
204
205 let relay_dispatch_queue_remaining_capacity = match relay_dispatch_queue_remaining_capacity
216 {
217 Ok(Some(r)) => r,
218 Ok(None) => {
219 let res = read_entry::<(u32, u32), _>(
220 &self.trie_backend,
221 #[allow(deprecated)]
222 &relay_chain::well_known_keys::relay_dispatch_queue_size(self.para_id),
223 Some((0, 0)),
224 )
225 .map_err(Error::RelayDispatchQueueRemainingCapacity)?;
226
227 let remaining_count = host_config.max_upward_queue_count.saturating_sub(res.0);
228 let remaining_size = host_config.max_upward_queue_size.saturating_sub(res.1);
229 RelayDispatchQueueRemainingCapacity { remaining_count, remaining_size }
230 },
231 Err(e) => return Err(Error::RelayDispatchQueueRemainingCapacity(e)),
232 };
233
234 let ingress_channel_index: Vec<ParaId> = read_entry(
235 &self.trie_backend,
236 &relay_chain::well_known_keys::hrmp_ingress_channel_index(self.para_id),
237 Some(Vec::new()),
238 )
239 .map_err(Error::HrmpIngressChannelIndex)?;
240
241 let egress_channel_index: Vec<ParaId> = read_entry(
242 &self.trie_backend,
243 &relay_chain::well_known_keys::hrmp_egress_channel_index(self.para_id),
244 Some(Vec::new()),
245 )
246 .map_err(Error::HrmpEgressChannelIndex)?;
247
248 let mut ingress_channels = Vec::with_capacity(ingress_channel_index.len());
249 for sender in ingress_channel_index {
250 let channel_id = relay_chain::HrmpChannelId { sender, recipient: self.para_id };
251 let hrmp_channel: AbridgedHrmpChannel = read_entry(
252 &self.trie_backend,
253 &relay_chain::well_known_keys::hrmp_channels(channel_id),
254 None,
255 )
256 .map_err(|read_err| Error::HrmpChannel(sender, self.para_id, read_err))?;
257 ingress_channels.push((sender, hrmp_channel));
258 }
259
260 let mut egress_channels = Vec::with_capacity(egress_channel_index.len());
261 for recipient in egress_channel_index {
262 let channel_id = relay_chain::HrmpChannelId { sender: self.para_id, recipient };
263 let hrmp_channel: AbridgedHrmpChannel = read_entry(
264 &self.trie_backend,
265 &relay_chain::well_known_keys::hrmp_channels(channel_id),
266 None,
267 )
268 .map_err(|read_err| Error::HrmpChannel(self.para_id, recipient, read_err))?;
269 egress_channels.push((recipient, hrmp_channel));
270 }
271
272 Ok(MessagingStateSnapshot {
276 dmq_mqc_head,
277 relay_dispatch_queue_remaining_capacity,
278 ingress_channels,
279 egress_channels,
280 })
281 }
282
283 pub fn read_abridged_host_configuration(&self) -> Result<AbridgedHostConfiguration, Error> {
287 read_entry(&self.trie_backend, relay_chain::well_known_keys::ACTIVE_CONFIG, None)
288 .map_err(Error::Config)
289 }
290
291 pub fn read_included_para_head(&self) -> Result<relay_chain::HeadData, Error> {
296 read_entry(&self.trie_backend, &relay_chain::well_known_keys::para_head(self.para_id), None)
297 .map_err(Error::ParaHead)
298 }
299
300 pub fn read_authorities(
302 &self,
303 ) -> Result<Vec<(sp_consensus_babe::AuthorityId, sp_consensus_babe::BabeAuthorityWeight)>, Error>
304 {
305 read_entry(&self.trie_backend, &relay_chain::well_known_keys::AUTHORITIES, None)
306 .map_err(Error::Authorities)
307 }
308
309 pub fn read_next_authorities(
311 &self,
312 ) -> Result<
313 Option<Vec<(sp_consensus_babe::AuthorityId, sp_consensus_babe::BabeAuthorityWeight)>>,
314 Error,
315 > {
316 read_optional_entry(&self.trie_backend, &relay_chain::well_known_keys::NEXT_AUTHORITIES)
317 .map_err(Error::NextAuthorities)
318 }
319
320 pub fn read_slot(&self) -> Result<relay_chain::Slot, Error> {
326 read_entry(&self.trie_backend, relay_chain::well_known_keys::CURRENT_SLOT, None)
327 .map_err(Error::Slot)
328 }
329
330 pub fn read_upgrade_go_ahead_signal(
338 &self,
339 ) -> Result<Option<relay_chain::UpgradeGoAhead>, Error> {
340 read_optional_entry(
341 &self.trie_backend,
342 &relay_chain::well_known_keys::upgrade_go_ahead_signal(self.para_id),
343 )
344 .map_err(Error::UpgradeGoAhead)
345 }
346
347 pub fn read_upgrade_restriction_signal(
354 &self,
355 ) -> Result<Option<relay_chain::UpgradeRestriction>, Error> {
356 read_optional_entry(
357 &self.trie_backend,
358 &relay_chain::well_known_keys::upgrade_restriction_signal(self.para_id),
359 )
360 .map_err(Error::UpgradeRestriction)
361 }
362
363 pub fn read_entry<T>(&self, key: &[u8], fallback: Option<T>) -> Result<T, Error>
370 where
371 T: Decode,
372 {
373 read_entry(&self.trie_backend, key, fallback).map_err(Error::ReadEntry)
374 }
375
376 pub fn read_optional_entry<T>(&self, key: &[u8]) -> Result<Option<T>, Error>
381 where
382 T: Decode,
383 {
384 read_optional_entry(&self.trie_backend, key).map_err(Error::ReadOptionalEntry)
385 }
386}