1use crate::{BridgedChainOf, BridgedHeaderChainOf, Config};
20
21use bp_header_chain::{HeaderChain, HeaderChainError};
22use bp_messages::{
23 source_chain::FromBridgedChainMessagesDeliveryProof,
24 target_chain::{FromBridgedChainMessagesProof, ProvedLaneMessages, ProvedMessages},
25 ChainWithMessages, InboundLaneData, Message, MessageKey, MessageNonce, MessagePayload,
26 OutboundLaneData, VerificationError,
27};
28use bp_runtime::{
29 HashOf, HasherOf, RangeInclusiveExt, RawStorageProof, StorageProofChecker, StorageProofError,
30};
31use codec::Decode;
32use sp_std::vec::Vec;
33
34pub(crate) type ParsedMessagesDeliveryProofFromBridgedChain<T, I> =
36 (<T as Config<I>>::LaneId, InboundLaneData<<T as frame_system::Config>::AccountId>);
37
38pub fn verify_messages_proof<T: Config<I>, I: 'static>(
47 proof: FromBridgedChainMessagesProof<HashOf<BridgedChainOf<T, I>>, T::LaneId>,
48 messages_count: u32,
49) -> Result<ProvedMessages<T::LaneId, Message<T::LaneId>>, VerificationError> {
50 let FromBridgedChainMessagesProof {
51 bridged_header_hash,
52 storage_proof,
53 lane,
54 nonces_start,
55 nonces_end,
56 } = proof;
57 let mut parser: MessagesStorageProofAdapter<T, I> =
58 MessagesStorageProofAdapter::try_new_with_verified_storage_proof(
59 bridged_header_hash,
60 storage_proof,
61 )
62 .map_err(VerificationError::HeaderChain)?;
63 let nonces_range = nonces_start..=nonces_end;
64
65 let messages_in_the_proof = nonces_range.saturating_len();
67 if messages_in_the_proof != MessageNonce::from(messages_count) {
68 return Err(VerificationError::MessagesCountMismatch)
69 }
70
71 let mut messages = Vec::with_capacity(messages_in_the_proof as _);
76 for nonce in nonces_range {
77 let message_key = MessageKey { lane_id: lane, nonce };
78 let message_payload = parser
79 .read_and_decode_message_payload(&message_key)
80 .map_err(VerificationError::MessageStorage)?;
81 messages.push(Message { key: message_key, payload: message_payload });
82 }
83
84 let proved_lane_messages = ProvedLaneMessages {
87 lane_state: parser
88 .read_and_decode_outbound_lane_data(&lane)
89 .map_err(VerificationError::OutboundLaneStorage)?,
90 messages,
91 };
92
93 if proved_lane_messages.lane_state.is_none() && proved_lane_messages.messages.is_empty() {
95 return Err(VerificationError::EmptyMessageProof)
96 }
97
98 parser.ensure_no_unused_keys().map_err(VerificationError::StorageProof)?;
100
101 Ok((lane, proved_lane_messages))
102}
103
104pub fn verify_messages_delivery_proof<T: Config<I>, I: 'static>(
106 proof: FromBridgedChainMessagesDeliveryProof<HashOf<BridgedChainOf<T, I>>, T::LaneId>,
107) -> Result<ParsedMessagesDeliveryProofFromBridgedChain<T, I>, VerificationError> {
108 let FromBridgedChainMessagesDeliveryProof { bridged_header_hash, storage_proof, lane } = proof;
109 let mut parser: MessagesStorageProofAdapter<T, I> =
110 MessagesStorageProofAdapter::try_new_with_verified_storage_proof(
111 bridged_header_hash,
112 storage_proof,
113 )
114 .map_err(VerificationError::HeaderChain)?;
115 let storage_inbound_lane_data_key = bp_messages::storage_keys::inbound_lane_data_key(
118 T::ThisChain::WITH_CHAIN_MESSAGES_PALLET_NAME,
119 &lane,
120 );
121 let inbound_lane_data = parser
122 .read_and_decode_mandatory_value(&storage_inbound_lane_data_key)
123 .map_err(VerificationError::InboundLaneStorage)?;
124
125 parser.ensure_no_unused_keys().map_err(VerificationError::StorageProof)?;
127
128 Ok((lane, inbound_lane_data))
129}
130
131trait StorageProofAdapter<T: Config<I>, I: 'static> {
134 fn read_and_decode_mandatory_value<D: Decode>(
135 &mut self,
136 key: &impl AsRef<[u8]>,
137 ) -> Result<D, StorageProofError>;
138 fn read_and_decode_optional_value<D: Decode>(
139 &mut self,
140 key: &impl AsRef<[u8]>,
141 ) -> Result<Option<D>, StorageProofError>;
142 fn ensure_no_unused_keys(self) -> Result<(), StorageProofError>;
143
144 fn read_and_decode_outbound_lane_data(
145 &mut self,
146 lane_id: &T::LaneId,
147 ) -> Result<Option<OutboundLaneData>, StorageProofError> {
148 let storage_outbound_lane_data_key = bp_messages::storage_keys::outbound_lane_data_key(
149 T::ThisChain::WITH_CHAIN_MESSAGES_PALLET_NAME,
150 lane_id,
151 );
152 self.read_and_decode_optional_value(&storage_outbound_lane_data_key)
153 }
154
155 fn read_and_decode_message_payload(
156 &mut self,
157 message_key: &MessageKey<T::LaneId>,
158 ) -> Result<MessagePayload, StorageProofError> {
159 let storage_message_key = bp_messages::storage_keys::message_key(
160 T::ThisChain::WITH_CHAIN_MESSAGES_PALLET_NAME,
161 &message_key.lane_id,
162 message_key.nonce,
163 );
164 self.read_and_decode_mandatory_value(&storage_message_key)
165 }
166}
167
168type MessagesStorageProofAdapter<T, I> = StorageProofCheckerAdapter<T, I>;
170
171struct StorageProofCheckerAdapter<T: Config<I>, I: 'static> {
173 storage: StorageProofChecker<HasherOf<BridgedChainOf<T, I>>>,
174 _dummy: sp_std::marker::PhantomData<(T, I)>,
175}
176
177impl<T: Config<I>, I: 'static> StorageProofCheckerAdapter<T, I> {
178 fn try_new_with_verified_storage_proof(
179 bridged_header_hash: HashOf<BridgedChainOf<T, I>>,
180 storage_proof: RawStorageProof,
181 ) -> Result<Self, HeaderChainError> {
182 BridgedHeaderChainOf::<T, I>::verify_storage_proof(bridged_header_hash, storage_proof).map(
183 |storage| StorageProofCheckerAdapter::<T, I> { storage, _dummy: Default::default() },
184 )
185 }
186}
187
188impl<T: Config<I>, I: 'static> StorageProofAdapter<T, I> for StorageProofCheckerAdapter<T, I> {
189 fn read_and_decode_optional_value<D: Decode>(
190 &mut self,
191 key: &impl AsRef<[u8]>,
192 ) -> Result<Option<D>, StorageProofError> {
193 self.storage.read_and_decode_opt_value(key.as_ref())
194 }
195
196 fn read_and_decode_mandatory_value<D: Decode>(
197 &mut self,
198 key: &impl AsRef<[u8]>,
199 ) -> Result<D, StorageProofError> {
200 self.storage.read_and_decode_mandatory_value(key.as_ref())
201 }
202
203 fn ensure_no_unused_keys(self) -> Result<(), StorageProofError> {
204 self.storage.ensure_no_unused_nodes()
205 }
206}
207
208#[cfg(test)]
209mod tests {
210 use super::*;
211 use crate::tests::{
212 messages_generation::{
213 encode_all_messages, encode_lane_data, generate_dummy_message,
214 prepare_messages_storage_proof,
215 },
216 mock::*,
217 };
218
219 use bp_header_chain::{HeaderChainError, StoredHeaderDataBuilder};
220 use bp_messages::LaneState;
221 use bp_runtime::{HeaderId, StorageProofError};
222 use codec::Encode;
223 use sp_runtime::traits::Header;
224
225 fn using_messages_proof<R>(
226 nonces_end: MessageNonce,
227 outbound_lane_data: Option<OutboundLaneData>,
228 encode_message: impl Fn(MessageNonce, &MessagePayload) -> Option<Vec<u8>>,
229 encode_outbound_lane_data: impl Fn(&OutboundLaneData) -> Vec<u8>,
230 add_duplicate_key: bool,
231 add_unused_key: bool,
232 test: impl Fn(FromBridgedChainMessagesProof<BridgedHeaderHash, TestLaneIdType>) -> R,
233 ) -> R {
234 let (state_root, storage_proof) =
235 prepare_messages_storage_proof::<BridgedChain, ThisChain, TestLaneIdType>(
236 test_lane_id(),
237 1..=nonces_end,
238 outbound_lane_data,
239 bp_runtime::UnverifiedStorageProofParams::default(),
240 generate_dummy_message,
241 encode_message,
242 encode_outbound_lane_data,
243 add_duplicate_key,
244 add_unused_key,
245 );
246
247 sp_io::TestExternalities::new(Default::default()).execute_with(move || {
248 let bridged_header = BridgedChainHeader::new(
249 0,
250 Default::default(),
251 state_root,
252 Default::default(),
253 Default::default(),
254 );
255 let bridged_header_hash = bridged_header.hash();
256
257 pallet_bridge_grandpa::BestFinalized::<TestRuntime>::put(HeaderId(
258 0,
259 bridged_header_hash,
260 ));
261 pallet_bridge_grandpa::ImportedHeaders::<TestRuntime>::insert(
262 bridged_header_hash,
263 bridged_header.build(),
264 );
265 test(FromBridgedChainMessagesProof {
266 bridged_header_hash,
267 storage_proof,
268 lane: test_lane_id(),
269 nonces_start: 1,
270 nonces_end,
271 })
272 })
273 }
274
275 #[test]
276 fn messages_proof_is_rejected_if_declared_less_than_actual_number_of_messages() {
277 assert_eq!(
278 using_messages_proof(
279 10,
280 None,
281 encode_all_messages,
282 encode_lane_data,
283 false,
284 false,
285 |proof| { verify_messages_proof::<TestRuntime, ()>(proof, 5) }
286 ),
287 Err(VerificationError::MessagesCountMismatch),
288 );
289 }
290
291 #[test]
292 fn messages_proof_is_rejected_if_declared_more_than_actual_number_of_messages() {
293 assert_eq!(
294 using_messages_proof(
295 10,
296 None,
297 encode_all_messages,
298 encode_lane_data,
299 false,
300 false,
301 |proof| { verify_messages_proof::<TestRuntime, ()>(proof, 15) }
302 ),
303 Err(VerificationError::MessagesCountMismatch),
304 );
305 }
306
307 #[test]
308 fn message_proof_is_rejected_if_header_is_missing_from_the_chain() {
309 assert_eq!(
310 using_messages_proof(
311 10,
312 None,
313 encode_all_messages,
314 encode_lane_data,
315 false,
316 false,
317 |proof| {
318 let bridged_header_hash =
319 pallet_bridge_grandpa::BestFinalized::<TestRuntime>::get().unwrap().1;
320 pallet_bridge_grandpa::ImportedHeaders::<TestRuntime>::remove(
321 bridged_header_hash,
322 );
323 verify_messages_proof::<TestRuntime, ()>(proof, 10)
324 }
325 ),
326 Err(VerificationError::HeaderChain(HeaderChainError::UnknownHeader)),
327 );
328 }
329
330 #[test]
331 fn message_proof_is_rejected_if_header_state_root_mismatches() {
332 assert_eq!(
333 using_messages_proof(
334 10,
335 None,
336 encode_all_messages,
337 encode_lane_data,
338 false,
339 false,
340 |proof| {
341 let bridged_header_hash =
342 pallet_bridge_grandpa::BestFinalized::<TestRuntime>::get().unwrap().1;
343 pallet_bridge_grandpa::ImportedHeaders::<TestRuntime>::insert(
344 bridged_header_hash,
345 BridgedChainHeader::new(
346 0,
347 Default::default(),
348 Default::default(),
349 Default::default(),
350 Default::default(),
351 )
352 .build(),
353 );
354 verify_messages_proof::<TestRuntime, ()>(proof, 10)
355 }
356 ),
357 Err(VerificationError::HeaderChain(HeaderChainError::StorageProof(
358 StorageProofError::StorageRootMismatch
359 ))),
360 );
361 }
362
363 #[test]
364 fn message_proof_is_rejected_if_it_has_duplicate_trie_nodes() {
365 assert_eq!(
366 using_messages_proof(
367 10,
368 None,
369 encode_all_messages,
370 encode_lane_data,
371 true,
372 false,
373 |proof| { verify_messages_proof::<TestRuntime, ()>(proof, 10) },
374 ),
375 Err(VerificationError::HeaderChain(HeaderChainError::StorageProof(
376 StorageProofError::DuplicateNodes
377 ))),
378 );
379 }
380
381 #[test]
382 fn message_proof_is_rejected_if_it_has_unused_trie_nodes() {
383 assert_eq!(
384 using_messages_proof(
385 10,
386 None,
387 encode_all_messages,
388 encode_lane_data,
389 false,
390 true,
391 |proof| { verify_messages_proof::<TestRuntime, ()>(proof, 10) },
392 ),
393 Err(VerificationError::StorageProof(StorageProofError::UnusedKey)),
394 );
395 }
396
397 #[test]
398 fn message_proof_is_rejected_if_required_message_is_missing() {
399 matches!(
400 using_messages_proof(
401 10,
402 None,
403 |n, m| if n != 5 { Some(m.encode()) } else { None },
404 encode_lane_data,
405 false,
406 false,
407 |proof| verify_messages_proof::<TestRuntime, ()>(proof, 10)
408 ),
409 Err(VerificationError::MessageStorage(StorageProofError::EmptyVal)),
410 );
411 }
412
413 #[test]
414 fn message_proof_is_rejected_if_message_decode_fails() {
415 matches!(
416 using_messages_proof(
417 10,
418 None,
419 |n, m| {
420 let mut m = m.encode();
421 if n == 5 {
422 m = vec![42]
423 }
424 Some(m)
425 },
426 encode_lane_data,
427 false,
428 false,
429 |proof| verify_messages_proof::<TestRuntime, ()>(proof, 10),
430 ),
431 Err(VerificationError::MessageStorage(StorageProofError::DecodeError)),
432 );
433 }
434
435 #[test]
436 fn message_proof_is_rejected_if_outbound_lane_state_decode_fails() {
437 matches!(
438 using_messages_proof(
439 10,
440 Some(OutboundLaneData {
441 state: LaneState::Opened,
442 oldest_unpruned_nonce: 1,
443 latest_received_nonce: 1,
444 latest_generated_nonce: 1,
445 }),
446 encode_all_messages,
447 |d| {
448 let mut d = d.encode();
449 d.truncate(1);
450 d
451 },
452 false,
453 false,
454 |proof| verify_messages_proof::<TestRuntime, ()>(proof, 10),
455 ),
456 Err(VerificationError::OutboundLaneStorage(StorageProofError::DecodeError)),
457 );
458 }
459
460 #[test]
461 fn message_proof_is_rejected_if_it_is_empty() {
462 assert_eq!(
463 using_messages_proof(
464 0,
465 None,
466 encode_all_messages,
467 encode_lane_data,
468 false,
469 false,
470 |proof| { verify_messages_proof::<TestRuntime, ()>(proof, 0) },
471 ),
472 Err(VerificationError::EmptyMessageProof),
473 );
474 }
475
476 #[test]
477 fn non_empty_message_proof_without_messages_is_accepted() {
478 assert_eq!(
479 using_messages_proof(
480 0,
481 Some(OutboundLaneData {
482 state: LaneState::Opened,
483 oldest_unpruned_nonce: 1,
484 latest_received_nonce: 1,
485 latest_generated_nonce: 1,
486 }),
487 encode_all_messages,
488 encode_lane_data,
489 false,
490 false,
491 |proof| verify_messages_proof::<TestRuntime, ()>(proof, 0),
492 ),
493 Ok((
494 test_lane_id(),
495 ProvedLaneMessages {
496 lane_state: Some(OutboundLaneData {
497 state: LaneState::Opened,
498 oldest_unpruned_nonce: 1,
499 latest_received_nonce: 1,
500 latest_generated_nonce: 1,
501 }),
502 messages: Vec::new(),
503 },
504 )),
505 );
506 }
507
508 #[test]
509 fn non_empty_message_proof_is_accepted() {
510 assert_eq!(
511 using_messages_proof(
512 1,
513 Some(OutboundLaneData {
514 state: LaneState::Opened,
515 oldest_unpruned_nonce: 1,
516 latest_received_nonce: 1,
517 latest_generated_nonce: 1,
518 }),
519 encode_all_messages,
520 encode_lane_data,
521 false,
522 false,
523 |proof| verify_messages_proof::<TestRuntime, ()>(proof, 1),
524 ),
525 Ok((
526 test_lane_id(),
527 ProvedLaneMessages {
528 lane_state: Some(OutboundLaneData {
529 state: LaneState::Opened,
530 oldest_unpruned_nonce: 1,
531 latest_received_nonce: 1,
532 latest_generated_nonce: 1,
533 }),
534 messages: vec![Message {
535 key: MessageKey { lane_id: test_lane_id(), nonce: 1 },
536 payload: vec![42],
537 }],
538 },
539 ))
540 );
541 }
542
543 #[test]
544 fn verify_messages_proof_does_not_panic_if_messages_count_mismatches() {
545 assert_eq!(
546 using_messages_proof(
547 1,
548 None,
549 encode_all_messages,
550 encode_lane_data,
551 false,
552 false,
553 |mut proof| {
554 proof.nonces_end = u64::MAX;
555 verify_messages_proof::<TestRuntime, ()>(proof, u32::MAX)
556 },
557 ),
558 Err(VerificationError::MessagesCountMismatch),
559 );
560 }
561}