referrerpolicy=no-referrer-when-downgrade

pallet_bridge_messages/tests/
messages_generation.rs

1// Copyright (C) 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//! Helpers for generating message storage proofs, that are used by tests and by benchmarks.
18
19use bp_messages::{
20	storage_keys, ChainWithMessages, InboundLaneData, MessageKey, MessageNonce, MessagePayload,
21	OutboundLaneData,
22};
23use bp_runtime::{
24	grow_storage_value, record_all_trie_keys, AccountIdOf, Chain, HashOf, HasherOf,
25	RawStorageProof, UnverifiedStorageProofParams,
26};
27use codec::Encode;
28use sp_std::{ops::RangeInclusive, prelude::*};
29use sp_trie::{trie_types::TrieDBMutBuilderV1, LayoutV1, MemoryDB, TrieMut};
30
31/// Dummy message generation function.
32pub fn generate_dummy_message(_: MessageNonce) -> MessagePayload {
33	vec![42]
34}
35
36/// Simple and correct message data encode function.
37pub fn encode_all_messages(_: MessageNonce, m: &MessagePayload) -> Option<Vec<u8>> {
38	Some(m.encode())
39}
40
41/// Simple and correct outbound lane data encode function.
42pub fn encode_lane_data(d: &OutboundLaneData) -> Vec<u8> {
43	d.encode()
44}
45
46/// Prepare storage proof of given messages.
47///
48/// Returns state trie root and nodes with prepared messages.
49#[allow(clippy::too_many_arguments)]
50pub fn prepare_messages_storage_proof<
51	BridgedChain: Chain,
52	ThisChain: ChainWithMessages,
53	LaneId: Encode + Copy,
54>(
55	lane: LaneId,
56	message_nonces: RangeInclusive<MessageNonce>,
57	outbound_lane_data: Option<OutboundLaneData>,
58	proof_params: UnverifiedStorageProofParams,
59	generate_message: impl Fn(MessageNonce) -> MessagePayload,
60	encode_message: impl Fn(MessageNonce, &MessagePayload) -> Option<Vec<u8>>,
61	encode_outbound_lane_data: impl Fn(&OutboundLaneData) -> Vec<u8>,
62	add_duplicate_key: bool,
63	add_unused_key: bool,
64) -> (HashOf<BridgedChain>, RawStorageProof)
65where
66	HashOf<BridgedChain>: Copy + Default,
67{
68	// prepare Bridged chain storage with messages and (optionally) outbound lane state
69	let message_count = message_nonces.end().saturating_sub(*message_nonces.start()) + 1;
70	let mut storage_keys = Vec::with_capacity(message_count as usize + 1);
71	let mut root = Default::default();
72	let mut mdb = MemoryDB::default();
73	{
74		let mut trie =
75			TrieDBMutBuilderV1::<HasherOf<BridgedChain>>::new(&mut mdb, &mut root).build();
76
77		// insert messages
78		for (i, nonce) in message_nonces.into_iter().enumerate() {
79			let message_key = MessageKey { lane_id: lane, nonce };
80			let message_payload = match encode_message(nonce, &generate_message(nonce)) {
81				Some(message_payload) => {
82					if i == 0 {
83						grow_storage_value(message_payload, &proof_params)
84					} else {
85						message_payload
86					}
87				},
88				None => continue,
89			};
90			let storage_key = storage_keys::message_key(
91				ThisChain::WITH_CHAIN_MESSAGES_PALLET_NAME,
92				&message_key.lane_id,
93				message_key.nonce,
94			)
95			.0;
96			trie.insert(&storage_key, &message_payload)
97				.map_err(|_| "TrieMut::insert has failed")
98				.expect("TrieMut::insert should not fail in benchmarks");
99			storage_keys.push(storage_key);
100		}
101
102		// insert outbound lane state
103		if let Some(outbound_lane_data) = outbound_lane_data.as_ref().map(encode_outbound_lane_data)
104		{
105			let storage_key = storage_keys::outbound_lane_data_key(
106				ThisChain::WITH_CHAIN_MESSAGES_PALLET_NAME,
107				&lane,
108			)
109			.0;
110			trie.insert(&storage_key, &outbound_lane_data)
111				.map_err(|_| "TrieMut::insert has failed")
112				.expect("TrieMut::insert should not fail in benchmarks");
113			storage_keys.push(storage_key);
114		}
115	}
116
117	// generate storage proof to be delivered to This chain
118	let mut storage_proof =
119		record_all_trie_keys::<LayoutV1<HasherOf<BridgedChain>>, _>(&mdb, &root)
120			.map_err(|_| "record_all_trie_keys has failed")
121			.expect("record_all_trie_keys should not fail in benchmarks");
122
123	if add_duplicate_key {
124		assert!(!storage_proof.is_empty());
125		let node = storage_proof.pop().unwrap();
126		storage_proof.push(node.clone());
127		storage_proof.push(node);
128	}
129
130	if add_unused_key {
131		storage_proof.push(b"unused_value".to_vec());
132	}
133
134	(root, storage_proof)
135}
136
137/// Prepare storage proof of given messages delivery.
138///
139/// Returns state trie root and nodes with prepared messages.
140pub fn prepare_message_delivery_storage_proof<
141	BridgedChain: Chain,
142	ThisChain: ChainWithMessages,
143	LaneId: Encode,
144>(
145	lane: LaneId,
146	inbound_lane_data: InboundLaneData<AccountIdOf<ThisChain>>,
147	proof_params: UnverifiedStorageProofParams,
148) -> (HashOf<BridgedChain>, RawStorageProof)
149where
150	HashOf<BridgedChain>: Copy + Default,
151{
152	// prepare Bridged chain storage with inbound lane state
153	let storage_key =
154		storage_keys::inbound_lane_data_key(ThisChain::WITH_CHAIN_MESSAGES_PALLET_NAME, &lane).0;
155	let mut root = Default::default();
156	let mut mdb = MemoryDB::default();
157	{
158		let mut trie =
159			TrieDBMutBuilderV1::<HasherOf<BridgedChain>>::new(&mut mdb, &mut root).build();
160		let inbound_lane_data = grow_storage_value(inbound_lane_data.encode(), &proof_params);
161		trie.insert(&storage_key, &inbound_lane_data)
162			.map_err(|_| "TrieMut::insert has failed")
163			.expect("TrieMut::insert should not fail in benchmarks");
164	}
165
166	// generate storage proof to be delivered to This chain
167	let storage_proof = record_all_trie_keys::<LayoutV1<HasherOf<BridgedChain>>, _>(&mdb, &root)
168		.map_err(|_| "record_all_trie_keys has failed")
169		.expect("record_all_trie_keys should not fail in benchmarks");
170
171	(root, storage_proof)
172}