referrerpolicy=no-referrer-when-downgrade

pallet_bridge_messages/
proofs.rs

1// Copyright 2019-2021 Parity Technologies (UK) Ltd.
2// This file is part of Parity Bridges Common.
3
4// Parity Bridges Common 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// Parity Bridges Common 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 Parity Bridges Common.  If not, see <http://www.gnu.org/licenses/>.
16
17//! Tools for messages and delivery proof verification.
18
19use 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
34/// 'Parsed' message delivery proof - inbound lane id and its state.
35pub(crate) type ParsedMessagesDeliveryProofFromBridgedChain<T, I> =
36	(<T as Config<I>>::LaneId, InboundLaneData<<T as frame_system::Config>::AccountId>);
37
38/// Verify proof of Bridged -> This chain messages.
39///
40/// This function is used when Bridged chain is directly using GRANDPA finality. For Bridged
41/// parachains, please use the `verify_messages_proof_from_parachain`.
42///
43/// The `messages_count` argument verification (sane limits) is supposed to be made
44/// outside of this function. This function only verifies that the proof declares exactly
45/// `messages_count` messages.
46pub 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	// receiving proofs where end < begin is ok (if proof includes outbound lane state)
66	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	// Read messages first. All messages that are claimed to be in the proof must
72	// be in the proof. So any error in `read_value`, or even missing value is fatal.
73	//
74	// Mind that we allow proofs with no messages if outbound lane state is proved.
75	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	// Now let's check if proof contains outbound lane state proof. It is optional, so
85	// we simply ignore `read_value` errors and missing value.
86	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	// Now we may actually check if the proof is empty or not.
94	if proved_lane_messages.lane_state.is_none() && proved_lane_messages.messages.is_empty() {
95		return Err(VerificationError::EmptyMessageProof)
96	}
97
98	// Check that the storage proof doesn't have any untouched keys.
99	parser.ensure_no_unused_keys().map_err(VerificationError::StorageProof)?;
100
101	Ok((lane, proved_lane_messages))
102}
103
104/// Verify proof of This -> Bridged chain messages delivery.
105pub 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	// Messages delivery proof is just proof of single storage key read => any error
116	// is fatal.
117	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	// check that the storage proof doesn't have any untouched trie nodes
126	parser.ensure_no_unused_keys().map_err(VerificationError::StorageProof)?;
127
128	Ok((lane, inbound_lane_data))
129}
130
131/// Abstraction over storage proof manipulation, hiding implementation details of actual storage
132/// proofs.
133trait 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
168/// Actual storage proof adapter for messages proofs.
169type MessagesStorageProofAdapter<T, I> = StorageProofCheckerAdapter<T, I>;
170
171/// A `StorageProofAdapter` implementation for raw storage proofs.
172struct 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}