1use frame_support::PalletError;
2use parity_scale_codec::{Decode, DecodeWithMemTracking, Encode};
3use scale_info::TypeInfo;
4use sp_core::H256;
5use sp_core::storage::StorageKey;
6use sp_domains::bundle::OpaqueBundle;
7use sp_domains::proof_provider_and_verifier::{
8 StorageProofVerifier, VerificationError as StorageProofVerificationError,
9};
10use sp_domains::{
11 DomainAllowlistUpdates, DomainId, DomainSudoCall, EvmDomainContractCreationAllowedByCall,
12 RuntimeId, RuntimeObject,
13};
14use sp_runtime::traits::{Block as BlockT, HashingFor, Header as HeaderT, NumberFor, Zero};
15use sp_std::marker::PhantomData;
16use sp_std::vec::Vec;
17use sp_trie::StorageProof;
18use subspace_core_primitives::Randomness;
19use subspace_runtime_primitives::{Balance, Moment};
20
21#[cfg(feature = "std")]
22use sc_client_api::ProofProvider;
23
24#[cfg(feature = "std")]
25#[derive(Debug, thiserror::Error)]
26pub enum GenerationError {
27 #[error("Failed to generate storage proof")]
28 StorageProof,
29 #[error("Failed to get storage key")]
30 StorageKey,
31}
32
33#[derive(Debug, PartialEq, Eq, Encode, Decode, PalletError, TypeInfo, DecodeWithMemTracking)]
34pub enum VerificationError {
35 InvalidBundleStorageProof,
36 RuntimeCodeNotFound,
37 UnexpectedDomainRuntimeUpgrade,
38 InvalidInherentExtrinsicStorageProof(StorageProofVerificationError),
39 SuccessfulBundlesStorageProof(StorageProofVerificationError),
40 DomainAllowlistUpdatesStorageProof(StorageProofVerificationError),
41 DomainRuntimeUpgradesStorageProof(StorageProofVerificationError),
42 RuntimeRegistryStorageProof(StorageProofVerificationError),
43 DigestStorageProof(StorageProofVerificationError),
44 BlockFeesStorageProof(StorageProofVerificationError),
45 TransfersStorageProof(StorageProofVerificationError),
46 ExtrinsicStorageProof(StorageProofVerificationError),
47 DomainSudoCallStorageProof(StorageProofVerificationError),
48 EvmDomainContractCreationAllowedByCallStorageProof(StorageProofVerificationError),
49 MmrRootStorageProof(StorageProofVerificationError),
50}
51
52#[derive(Clone, Debug, Decode, Encode, Eq, PartialEq, TypeInfo)]
53pub enum FraudProofStorageKeyRequest<Number> {
54 InvalidInherentExtrinsicData,
55 SuccessfulBundles(DomainId),
56 DomainAllowlistUpdates(DomainId),
57 DomainRuntimeUpgrades,
58 RuntimeRegistry(RuntimeId),
59 DomainSudoCall(DomainId),
60 EvmDomainContractCreationAllowedByCall(DomainId),
61 MmrRoot(Number),
62}
63
64impl<Number> FraudProofStorageKeyRequest<Number> {
65 fn into_error(self, err: StorageProofVerificationError) -> VerificationError {
66 match self {
67 Self::InvalidInherentExtrinsicData => {
68 VerificationError::InvalidInherentExtrinsicStorageProof(err)
69 }
70 Self::SuccessfulBundles(_) => VerificationError::SuccessfulBundlesStorageProof(err),
71 Self::DomainAllowlistUpdates(_) => {
72 VerificationError::DomainAllowlistUpdatesStorageProof(err)
73 }
74 Self::DomainRuntimeUpgrades => {
75 VerificationError::DomainRuntimeUpgradesStorageProof(err)
76 }
77 Self::RuntimeRegistry(_) => VerificationError::RuntimeRegistryStorageProof(err),
78 FraudProofStorageKeyRequest::DomainSudoCall(_) => {
79 VerificationError::DomainSudoCallStorageProof(err)
80 }
81 FraudProofStorageKeyRequest::EvmDomainContractCreationAllowedByCall(_) => {
82 VerificationError::EvmDomainContractCreationAllowedByCallStorageProof(err)
83 }
84 Self::MmrRoot(_) => VerificationError::MmrRootStorageProof(err),
85 }
86 }
87}
88
89pub trait FraudProofStorageKeyProvider<Number> {
91 fn storage_key(req: FraudProofStorageKeyRequest<Number>) -> Vec<u8>;
92}
93
94impl<Number> FraudProofStorageKeyProvider<Number> for () {
95 fn storage_key(_req: FraudProofStorageKeyRequest<Number>) -> Vec<u8> {
96 Default::default()
97 }
98}
99
100pub trait FraudProofStorageKeyProviderInstance<Number> {
102 fn storage_key(&self, req: FraudProofStorageKeyRequest<Number>) -> Option<Vec<u8>>;
103}
104
105macro_rules! impl_storage_proof {
106 ($name:ident) => {
107 impl From<StorageProof> for $name {
108 fn from(sp: StorageProof) -> Self {
109 $name(sp)
110 }
111 }
112 impl From<$name> for StorageProof {
113 fn from(p: $name) -> StorageProof {
114 p.0
115 }
116 }
117 };
118}
119
120pub trait BasicStorageProof<Block: BlockT>:
121 Into<StorageProof> + From<StorageProof> + Clone
122{
123 type StorageValue: Decode;
124 type Key = ();
125
126 fn storage_key_request(key: Self::Key) -> FraudProofStorageKeyRequest<NumberFor<Block>>;
127
128 #[cfg(feature = "std")]
129 fn generate<
130 PP: ProofProvider<Block>,
131 SKPI: FraudProofStorageKeyProviderInstance<NumberFor<Block>>,
132 >(
133 proof_provider: &PP,
134 block_hash: Block::Hash,
135 key: Self::Key,
136 storage_key_provider: &SKPI,
137 ) -> Result<Self, GenerationError> {
138 let storage_key = storage_key_provider
139 .storage_key(Self::storage_key_request(key))
140 .ok_or(GenerationError::StorageKey)?;
141 let storage_proof = proof_provider
142 .read_proof(block_hash, &mut [storage_key.as_slice()].into_iter())
143 .map_err(|_| GenerationError::StorageProof)?;
144 Ok(storage_proof.into())
145 }
146
147 fn verify<SKP: FraudProofStorageKeyProvider<NumberFor<Block>>>(
148 self,
149 key: Self::Key,
150 state_root: &Block::Hash,
151 ) -> Result<Self::StorageValue, VerificationError> {
152 let storage_key_req = Self::storage_key_request(key);
153 let storage_key = SKP::storage_key(storage_key_req.clone());
154 StorageProofVerifier::<HashingFor<Block>>::get_decoded_value::<Self::StorageValue>(
155 state_root,
156 self.into(),
157 StorageKey(storage_key),
158 )
159 .map_err(|err| storage_key_req.into_error(err))
160 }
161}
162
163#[derive(Clone, Debug, Decode, Encode, Eq, PartialEq, TypeInfo, DecodeWithMemTracking)]
164pub struct SuccessfulBundlesProof(StorageProof);
165
166impl_storage_proof!(SuccessfulBundlesProof);
167impl<Block: BlockT> BasicStorageProof<Block> for SuccessfulBundlesProof {
168 type StorageValue = Vec<H256>;
169 type Key = DomainId;
170 fn storage_key_request(key: Self::Key) -> FraudProofStorageKeyRequest<NumberFor<Block>> {
171 FraudProofStorageKeyRequest::SuccessfulBundles(key)
172 }
173}
174
175#[derive(Clone, Debug, Decode, Encode, Eq, PartialEq, TypeInfo, DecodeWithMemTracking)]
176pub struct DomainChainsAllowlistUpdateStorageProof(StorageProof);
177
178impl_storage_proof!(DomainChainsAllowlistUpdateStorageProof);
179impl<Block: BlockT> BasicStorageProof<Block> for DomainChainsAllowlistUpdateStorageProof {
180 type StorageValue = DomainAllowlistUpdates;
181 type Key = DomainId;
182 fn storage_key_request(key: Self::Key) -> FraudProofStorageKeyRequest<NumberFor<Block>> {
183 FraudProofStorageKeyRequest::DomainAllowlistUpdates(key)
184 }
185}
186
187#[derive(Clone, Debug, Decode, Encode, Eq, PartialEq, TypeInfo, DecodeWithMemTracking)]
188pub struct DomainSudoCallStorageProof(StorageProof);
189
190impl_storage_proof!(DomainSudoCallStorageProof);
191impl<Block: BlockT> BasicStorageProof<Block> for DomainSudoCallStorageProof {
192 type StorageValue = DomainSudoCall;
193 type Key = DomainId;
194 fn storage_key_request(key: Self::Key) -> FraudProofStorageKeyRequest<NumberFor<Block>> {
195 FraudProofStorageKeyRequest::DomainSudoCall(key)
196 }
197}
198
199#[derive(Clone, Debug, Decode, Encode, Eq, PartialEq, TypeInfo, DecodeWithMemTracking)]
200pub struct EvmDomainContractCreationAllowedByCallStorageProof(StorageProof);
201
202impl_storage_proof!(EvmDomainContractCreationAllowedByCallStorageProof);
203impl<Block: BlockT> BasicStorageProof<Block>
204 for EvmDomainContractCreationAllowedByCallStorageProof
205{
206 type StorageValue = EvmDomainContractCreationAllowedByCall;
207 type Key = DomainId;
208 fn storage_key_request(key: Self::Key) -> FraudProofStorageKeyRequest<NumberFor<Block>> {
209 FraudProofStorageKeyRequest::EvmDomainContractCreationAllowedByCall(key)
210 }
211}
212
213#[derive(Clone, Debug, Decode, Encode, Eq, PartialEq, TypeInfo, DecodeWithMemTracking)]
214pub struct DomainRuntimeUpgradesProof(StorageProof);
215
216impl_storage_proof!(DomainRuntimeUpgradesProof);
217impl<Block: BlockT> BasicStorageProof<Block> for DomainRuntimeUpgradesProof {
218 type StorageValue = Vec<RuntimeId>;
219 type Key = ();
220 fn storage_key_request(_key: Self::Key) -> FraudProofStorageKeyRequest<NumberFor<Block>> {
221 FraudProofStorageKeyRequest::DomainRuntimeUpgrades
222 }
223}
224
225#[derive(Clone, Debug, Decode, Encode, Eq, PartialEq, TypeInfo, DecodeWithMemTracking)]
233pub struct DomainRuntimeCodeProof(StorageProof);
234
235impl_storage_proof!(DomainRuntimeCodeProof);
236impl<Block: BlockT> BasicStorageProof<Block> for DomainRuntimeCodeProof {
237 type StorageValue = RuntimeObject<NumberFor<Block>, Block::Hash>;
238 type Key = RuntimeId;
239 fn storage_key_request(key: Self::Key) -> FraudProofStorageKeyRequest<NumberFor<Block>> {
240 FraudProofStorageKeyRequest::RuntimeRegistry(key)
241 }
242}
243
244#[derive(Clone, Debug, Decode, Encode, Eq, PartialEq, TypeInfo, DecodeWithMemTracking)]
246pub struct OpaqueBundleWithProof<Number, Hash, DomainHeader: HeaderT, Balance> {
247 pub bundle: OpaqueBundle<Number, Hash, DomainHeader, Balance>,
248 pub bundle_index: u32,
249 pub bundle_storage_proof: SuccessfulBundlesProof,
250}
251
252impl<Number, Hash, DomainHeader, Balance> OpaqueBundleWithProof<Number, Hash, DomainHeader, Balance>
253where
254 Number: Encode + Zero,
255 Hash: Encode + Default,
256 DomainHeader: HeaderT,
257 Balance: Encode + Zero + Default,
258{
259 #[cfg(feature = "std")]
260 #[allow(clippy::let_and_return)]
261 pub fn generate<
262 Block: BlockT,
263 PP: ProofProvider<Block>,
264 SKP: FraudProofStorageKeyProviderInstance<NumberFor<Block>>,
265 >(
266 storage_key_provider: &SKP,
267 proof_provider: &PP,
268 domain_id: DomainId,
269 block_hash: Block::Hash,
270 bundle: OpaqueBundle<Number, Hash, DomainHeader, Balance>,
271 bundle_index: u32,
272 ) -> Result<Self, GenerationError> {
273 let bundle_storage_proof = SuccessfulBundlesProof::generate(
274 proof_provider,
275 block_hash,
276 domain_id,
277 storage_key_provider,
278 )?;
279
280 Ok(OpaqueBundleWithProof {
281 bundle,
282 bundle_index,
283 bundle_storage_proof,
284 })
285 }
286
287 pub fn verify<Block: BlockT, SKP: FraudProofStorageKeyProvider<NumberFor<Block>>>(
289 &self,
290 domain_id: DomainId,
291 state_root: &Block::Hash,
292 ) -> Result<(), VerificationError> {
293 let successful_bundles_at: Vec<H256> =
294 <SuccessfulBundlesProof as BasicStorageProof<Block>>::verify::<SKP>(
295 self.bundle_storage_proof.clone(),
296 domain_id,
297 state_root,
298 )?;
299
300 successful_bundles_at
301 .get(self.bundle_index as usize)
302 .filter(|b| **b == self.bundle.hash())
303 .ok_or(VerificationError::InvalidBundleStorageProof)?;
304
305 Ok(())
306 }
307}
308
309#[derive(Clone, Debug, Decode, Encode, Eq, PartialEq, TypeInfo, DecodeWithMemTracking)]
311pub struct MaybeDomainRuntimeUpgradedProof {
312 pub domain_runtime_upgrades: DomainRuntimeUpgradesProof,
314
315 pub new_domain_runtime_code: Option<DomainRuntimeCodeProof>,
317}
318
319impl MaybeDomainRuntimeUpgradedProof {
320 #[cfg(feature = "std")]
324 #[allow(clippy::let_and_return)]
325 pub fn generate<
326 Block: BlockT,
327 PP: ProofProvider<Block>,
328 SKP: FraudProofStorageKeyProviderInstance<NumberFor<Block>>,
329 >(
330 storage_key_provider: &SKP,
331 proof_provider: &PP,
332 block_hash: Block::Hash,
333 maybe_runtime_id: Option<RuntimeId>,
334 ) -> Result<Self, GenerationError> {
335 let domain_runtime_upgrades = DomainRuntimeUpgradesProof::generate(
336 proof_provider,
337 block_hash,
338 (),
339 storage_key_provider,
340 )?;
341 let new_domain_runtime_code = if let Some(runtime_id) = maybe_runtime_id {
342 Some(DomainRuntimeCodeProof::generate(
343 proof_provider,
344 block_hash,
345 runtime_id,
346 storage_key_provider,
347 )?)
348 } else {
349 None
350 };
351 Ok(MaybeDomainRuntimeUpgradedProof {
352 domain_runtime_upgrades,
353 new_domain_runtime_code,
354 })
355 }
356
357 pub fn verify<Block: BlockT, SKP: FraudProofStorageKeyProvider<NumberFor<Block>>>(
358 &self,
359 runtime_id: RuntimeId,
360 state_root: &Block::Hash,
361 ) -> Result<Option<Vec<u8>>, VerificationError> {
362 let domain_runtime_upgrades =
363 <DomainRuntimeUpgradesProof as BasicStorageProof<Block>>::verify::<SKP>(
364 self.domain_runtime_upgrades.clone(),
365 (),
366 state_root,
367 )?;
368 let runtime_upgraded = domain_runtime_upgrades.contains(&runtime_id);
369
370 match (runtime_upgraded, self.new_domain_runtime_code.as_ref()) {
371 (true, None) | (false, Some(_)) => {
372 Err(VerificationError::UnexpectedDomainRuntimeUpgrade)
373 }
374 (false, None) => Ok(None),
375 (true, Some(runtime_code_proof)) => {
376 let mut runtime_obj = <DomainRuntimeCodeProof as BasicStorageProof<Block>>::verify::<
377 SKP,
378 >(
379 runtime_code_proof.clone(), runtime_id, state_root
380 )?;
381 let code = runtime_obj
382 .raw_genesis
383 .take_runtime_code()
384 .ok_or(VerificationError::RuntimeCodeNotFound)?;
385 Ok(Some(code))
386 }
387 }
388 }
389}
390
391#[derive(Clone, Debug, Decode, Encode, Eq, PartialEq, TypeInfo)]
392pub struct InherentExtrinsicData {
393 pub extrinsics_shuffling_seed: Randomness,
395
396 pub timestamp: Moment,
398
399 pub consensus_transaction_byte_fee: Balance,
401}
402
403#[derive(Clone, Debug, Decode, Encode, Eq, PartialEq, TypeInfo, DecodeWithMemTracking)]
404pub struct InvalidInherentExtrinsicDataProof(StorageProof);
405
406impl_storage_proof!(InvalidInherentExtrinsicDataProof);
407impl<Block: BlockT> BasicStorageProof<Block> for InvalidInherentExtrinsicDataProof {
408 type StorageValue = InherentExtrinsicData;
409 fn storage_key_request(_key: Self::Key) -> FraudProofStorageKeyRequest<NumberFor<Block>> {
410 FraudProofStorageKeyRequest::InvalidInherentExtrinsicData
411 }
412}
413
414#[derive(Clone, Debug, Decode, Encode, Eq, PartialEq, TypeInfo, DecodeWithMemTracking)]
415pub struct MmrRootStorageProof<MmrHash> {
416 storage_proof: StorageProof,
417 _phantom_data: PhantomData<MmrHash>,
418}
419
420impl<MmrHash> From<StorageProof> for MmrRootStorageProof<MmrHash> {
421 fn from(storage_proof: StorageProof) -> Self {
422 MmrRootStorageProof {
423 storage_proof,
424 _phantom_data: Default::default(),
425 }
426 }
427}
428
429impl<MmrHash> From<MmrRootStorageProof<MmrHash>> for StorageProof {
430 fn from(p: MmrRootStorageProof<MmrHash>) -> StorageProof {
431 p.storage_proof
432 }
433}
434
435impl<Block: BlockT, MmrHash: Decode + Clone> BasicStorageProof<Block>
436 for MmrRootStorageProof<MmrHash>
437{
438 type StorageValue = MmrHash;
439 type Key = NumberFor<Block>;
440 fn storage_key_request(key: Self::Key) -> FraudProofStorageKeyRequest<NumberFor<Block>> {
441 FraudProofStorageKeyRequest::MmrRoot(key)
442 }
443}