1#![warn(missing_docs)]
20#![cfg_attr(not(feature = "std"), no_std)]
21
22use bp_header_chain::justification::{required_justification_precommits, GrandpaJustification};
23use bp_parachains::parachain_head_storage_key_at_source;
24use bp_polkadot_core::parachains::{ParaHash, ParaHead, ParaHeadsProof, ParaId};
25use bp_runtime::record_all_trie_keys;
26use codec::Encode;
27use sp_consensus_grandpa::{AuthorityId, AuthoritySignature, AuthorityWeight, SetId};
28use sp_runtime::traits::{Header as HeaderT, One, Zero};
29use sp_std::prelude::*;
30use sp_trie::{trie_types::TrieDBMutBuilderV1, LayoutV1, MemoryDB, TrieMut};
31
32pub use keyring::*;
34
35mod keyring;
36
37pub const TEST_GRANDPA_ROUND: u64 = 1;
39pub const TEST_GRANDPA_SET_ID: SetId = 1;
41pub const PARAS_PALLET_NAME: &str = "Paras";
43
44#[derive(Clone)]
46pub struct JustificationGeneratorParams<H> {
47 pub header: H,
49 pub round: u64,
51 pub set_id: SetId,
53 pub authorities: Vec<(Account, AuthorityWeight)>,
57 pub ancestors: u32,
61 pub forks: u32,
65}
66
67impl<H: HeaderT> Default for JustificationGeneratorParams<H> {
68 fn default() -> Self {
69 let required_signatures = required_justification_precommits(test_keyring().len() as _);
70 Self {
71 header: test_header(One::one()),
72 round: TEST_GRANDPA_ROUND,
73 set_id: TEST_GRANDPA_SET_ID,
74 authorities: test_keyring().into_iter().take(required_signatures as _).collect(),
75 ancestors: 2,
76 forks: 1,
77 }
78 }
79}
80
81pub fn make_default_justification<H: HeaderT>(header: &H) -> GrandpaJustification<H> {
83 let params = JustificationGeneratorParams::<H> { header: header.clone(), ..Default::default() };
84
85 make_justification_for_header(params)
86}
87
88pub fn make_justification_for_header<H: HeaderT>(
98 params: JustificationGeneratorParams<H>,
99) -> GrandpaJustification<H> {
100 let JustificationGeneratorParams { header, round, set_id, authorities, mut ancestors, forks } =
101 params;
102 let (target_hash, target_number) = (header.hash(), *header.number());
103 let mut votes_ancestries = vec![];
104 let mut precommits = vec![];
105
106 assert!(forks != 0, "Need at least one fork to have a chain..");
107 assert!(
108 forks as usize <= authorities.len(),
109 "If we have more forks than authorities we can't create valid pre-commits for all the forks."
110 );
111
112 let target_depth = ancestors.div_ceil(forks);
114
115 let mut unsigned_precommits = vec![];
116 for i in 0..forks {
117 let depth = if ancestors >= target_depth {
118 ancestors -= target_depth;
119 target_depth
120 } else {
121 ancestors
122 };
123
124 let chain = generate_chain(i, depth + 1, &header);
126
127 for child in &chain[1..] {
129 votes_ancestries.push(child.clone());
130 }
131
132 let precommit_candidate = chain.last().map(|h| (h.hash(), *h.number())).unwrap();
135 unsigned_precommits.push(precommit_candidate);
136 }
137
138 for (i, (id, _weight)) in authorities.iter().enumerate() {
139 let target = unsigned_precommits[i % forks as usize];
141 let precommit = signed_precommit::<H>(id, target, round, set_id);
142
143 precommits.push(precommit);
144 }
145
146 GrandpaJustification {
147 round,
148 commit: finality_grandpa::Commit { target_hash, target_number, precommits },
149 votes_ancestries,
150 }
151}
152
153fn generate_chain<H: HeaderT>(fork_id: u32, depth: u32, ancestor: &H) -> Vec<H> {
154 let mut headers = vec![ancestor.clone()];
155
156 for i in 1..depth {
157 let parent = &headers[(i - 1) as usize];
158 let (hash, num) = (parent.hash(), *parent.number());
159
160 let mut header = test_header::<H>(num + One::one());
161 header.set_parent_hash(hash);
162
163 header.digest_mut().logs.push(sp_runtime::DigestItem::Other(fork_id.encode()));
166
167 headers.push(header);
168 }
169
170 headers
171}
172
173pub fn prepare_parachain_heads_proof<H: HeaderT>(
175 heads: Vec<(u32, ParaHead)>,
176) -> (H::Hash, ParaHeadsProof, Vec<(ParaId, ParaHash)>) {
177 let mut parachains = Vec::with_capacity(heads.len());
178 let mut root = Default::default();
179 let mut mdb = MemoryDB::default();
180 let mut storage_keys = vec![];
181 {
182 let mut trie = TrieDBMutBuilderV1::<H::Hashing>::new(&mut mdb, &mut root).build();
183 for (parachain, head) in heads {
184 let storage_key =
185 parachain_head_storage_key_at_source(PARAS_PALLET_NAME, ParaId(parachain));
186 trie.insert(&storage_key.0, &head.encode())
187 .map_err(|_| "TrieMut::insert has failed")
188 .expect("TrieMut::insert should not fail in tests");
189 storage_keys.push(storage_key.0);
190 parachains.push((ParaId(parachain), head.hash()));
191 }
192 }
193
194 let storage_proof = record_all_trie_keys::<LayoutV1<H::Hashing>, _>(&mdb, &root)
196 .map_err(|_| "record_all_trie_keys has failed")
197 .expect("record_all_trie_keys should not fail in benchmarks");
198
199 (root, ParaHeadsProof { storage_proof }, parachains)
200}
201
202pub fn signed_precommit<H: HeaderT>(
204 signer: &Account,
205 target: (H::Hash, H::Number),
206 round: u64,
207 set_id: SetId,
208) -> finality_grandpa::SignedPrecommit<H::Hash, H::Number, AuthoritySignature, AuthorityId> {
209 let precommit = finality_grandpa::Precommit { target_hash: target.0, target_number: target.1 };
210
211 let encoded = sp_consensus_grandpa::localized_payload(
212 round,
213 set_id,
214 &finality_grandpa::Message::Precommit(precommit.clone()),
215 );
216
217 let signature = signer.sign(&encoded);
218 let raw_signature: Vec<u8> = signature.to_bytes().into();
219
220 let signature = AuthoritySignature::try_from(raw_signature).expect(
223 "We know our Keypair is good,
224 so our signature must also be good.",
225 );
226 let id = (*signer).into();
227
228 finality_grandpa::SignedPrecommit { precommit, signature, id }
229}
230
231pub fn test_header<H: HeaderT>(number: H::Number) -> H {
235 let default = |num| {
236 H::new(num, Default::default(), Default::default(), Default::default(), Default::default())
237 };
238
239 let mut header = default(number);
240 if number != Zero::zero() {
241 let parent_hash = default(number - One::one()).hash();
242 header.set_parent_hash(parent_hash);
243 }
244
245 header
246}
247
248pub fn test_header_with_root<H: HeaderT>(number: H::Number, state_root: H::Hash) -> H {
252 let mut header: H = test_header(number);
253 header.set_state_root(state_root);
254 header
255}
256
257pub fn header_id<H: HeaderT>(index: u8) -> (H::Hash, H::Number) {
259 (test_header::<H>(index.into()).hash(), index.into())
260}
261
262#[macro_export]
263macro_rules! generate_owned_bridge_module_tests {
272 ($normal_operating_mode: expr, $halted_operating_mode: expr) => {
273 #[test]
274 fn test_set_owner() {
275 run_test(|| {
276 PalletOwner::<TestRuntime>::put(1);
277
278 assert_ok!(Pallet::<TestRuntime>::set_owner(RuntimeOrigin::root(), Some(2)));
280 assert_eq!(PalletOwner::<TestRuntime>::get(), Some(2));
281
282 assert_ok!(Pallet::<TestRuntime>::set_owner(RuntimeOrigin::signed(2), Some(3)));
284 assert_eq!(PalletOwner::<TestRuntime>::get(), Some(3));
285
286 assert_noop!(
288 Pallet::<TestRuntime>::set_owner(RuntimeOrigin::signed(1), Some(4)),
289 DispatchError::BadOrigin
290 );
291 assert_eq!(PalletOwner::<TestRuntime>::get(), Some(3));
292 });
293 }
294
295 #[test]
296 fn test_set_operating_mode() {
297 run_test(|| {
298 PalletOwner::<TestRuntime>::put(1);
299 PalletOperatingMode::<TestRuntime>::put($normal_operating_mode);
300
301 assert_ok!(Pallet::<TestRuntime>::set_operating_mode(
303 RuntimeOrigin::root(),
304 $halted_operating_mode
305 ));
306 assert_eq!(PalletOperatingMode::<TestRuntime>::get(), $halted_operating_mode);
307 assert_ok!(Pallet::<TestRuntime>::set_operating_mode(
309 RuntimeOrigin::root(),
310 $normal_operating_mode
311 ));
312 assert_eq!(PalletOperatingMode::<TestRuntime>::get(), $normal_operating_mode);
313
314 assert_ok!(Pallet::<TestRuntime>::set_operating_mode(
316 RuntimeOrigin::signed(1),
317 $halted_operating_mode
318 ));
319 assert_eq!(PalletOperatingMode::<TestRuntime>::get(), $halted_operating_mode);
320 assert_ok!(Pallet::<TestRuntime>::set_operating_mode(
322 RuntimeOrigin::signed(1),
323 $normal_operating_mode
324 ));
325 assert_eq!(PalletOperatingMode::<TestRuntime>::get(), $normal_operating_mode);
326
327 assert_noop!(
329 Pallet::<TestRuntime>::set_operating_mode(
330 RuntimeOrigin::signed(2),
331 $halted_operating_mode
332 ),
333 DispatchError::BadOrigin
334 );
335 assert_eq!(PalletOperatingMode::<TestRuntime>::get(), $normal_operating_mode);
336 PalletOperatingMode::<TestRuntime>::put($halted_operating_mode);
338 assert_noop!(
339 Pallet::<TestRuntime>::set_operating_mode(
340 RuntimeOrigin::signed(2),
341 $normal_operating_mode
342 ),
343 DispatchError::BadOrigin
344 );
345 assert_eq!(PalletOperatingMode::<TestRuntime>::get(), $halted_operating_mode);
346 });
347 }
348 };
349}