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