1
// Copyright (C) Parity Technologies (UK) Ltd.
2
// This file is part of Polkadot.
3

            
4
// Polkadot 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
// Polkadot 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 Polkadot.  If not, see <http://www.gnu.org/licenses/>.
16

            
17
//! Utilities that don't belong to any particular module but may draw
18
//! on all modules.
19

            
20
use alloc::{collections::btree_set::BTreeSet, vec::Vec};
21
use frame_system::pallet_prelude::BlockNumberFor;
22
use polkadot_primitives::{HeadData, Id as ParaId, PersistedValidationData, ValidatorIndex};
23

            
24
use crate::{configuration, hrmp, paras};
25

            
26
/// Make the persisted validation data for a particular parachain, a specified relay-parent and it's
27
/// storage root.
28
///
29
/// This ties together the storage of several modules.
30
pub fn make_persisted_validation_data<T: paras::Config + hrmp::Config>(
31
	para_id: ParaId,
32
	relay_parent_number: BlockNumberFor<T>,
33
	relay_parent_storage_root: T::Hash,
34
) -> Option<PersistedValidationData<T::Hash, BlockNumberFor<T>>> {
35
	let config = configuration::ActiveConfig::<T>::get();
36

            
37
	Some(PersistedValidationData {
38
		parent_head: paras::Heads::<T>::get(&para_id)?,
39
		relay_parent_number,
40
		relay_parent_storage_root,
41
		max_pov_size: config.max_pov_size,
42
	})
43
}
44

            
45
/// Make the persisted validation data for a particular parachain, a specified relay-parent, its
46
/// storage root and parent head data.
47
pub fn make_persisted_validation_data_with_parent<T: configuration::Config>(
48
	relay_parent_number: BlockNumberFor<T>,
49
	relay_parent_storage_root: T::Hash,
50
	parent_head: HeadData,
51
) -> PersistedValidationData<T::Hash, BlockNumberFor<T>> {
52
	let config = configuration::ActiveConfig::<T>::get();
53

            
54
	PersistedValidationData {
55
		parent_head,
56
		relay_parent_number,
57
		relay_parent_storage_root,
58
		max_pov_size: config.max_pov_size,
59
	}
60
}
61

            
62
/// Take an active subset of a set containing all validators.
63
///
64
/// First item in pair will be all items in set have indices found in the `active` indices set (in
65
/// the order of the `active` vec, the second item will contain the rest, in the original order.
66
///
67
/// ```ignore
68
/// 		split_active_subset(active, all).0 == take_active_subset(active, all)
69
/// ```
70
135234
pub fn split_active_subset<T: Clone>(active: &[ValidatorIndex], all: &[T]) -> (Vec<T>, Vec<T>) {
71
135234
	let active_set: BTreeSet<_> = active.iter().cloned().collect();
72
135234
	// active result has ordering of active set.
73
135234
	let active_result = take_active_subset(active, all);
74
135234
	// inactive result preserves original ordering of `all`.
75
135234
	let inactive_result = all
76
135234
		.iter()
77
135234
		.enumerate()
78
135234
		.filter(|(i, _)| !active_set.contains(&ValidatorIndex(*i as _)))
79
135234
		.map(|(_, v)| v)
80
135234
		.cloned()
81
135234
		.collect();
82
135234

            
83
135234
	if active_result.len() != active.len() {
84
		log::warn!(
85
			target: "runtime::parachains",
86
			"Took active validators from set with wrong size.",
87
		);
88
135234
	}
89

            
90
135234
	(active_result, inactive_result)
91
135234
}
92

            
93
/// Uses `split_active_subset` and concatenates the inactive to the active vec.
94
///
95
/// ```ignore
96
/// 		split_active_subset(active, all)[0..active.len()]) == take_active_subset(active, all)
97
/// ```
98
135234
pub fn take_active_subset_and_inactive<T: Clone>(active: &[ValidatorIndex], all: &[T]) -> Vec<T> {
99
135234
	let (mut a, mut i) = split_active_subset(active, all);
100
135234
	a.append(&mut i);
101
135234
	a
102
135234
}
103

            
104
/// Take the active subset of a set containing all validators.
105
540936
pub fn take_active_subset<T: Clone>(active: &[ValidatorIndex], set: &[T]) -> Vec<T> {
106
540936
	let subset: Vec<_> = active.iter().filter_map(|i| set.get(i.0 as usize)).cloned().collect();
107
540936

            
108
540936
	if subset.len() != active.len() {
109
		log::warn!(
110
			target: "runtime::parachains",
111
			"Took active validators from set with wrong size",
112
		);
113
540936
	}
114

            
115
540936
	subset
116
540936
}
117

            
118
#[cfg(test)]
119
mod tests {
120

            
121
	use alloc::vec::Vec;
122

            
123
	use crate::util::{split_active_subset, take_active_subset};
124
	use polkadot_primitives::ValidatorIndex;
125

            
126
	#[test]
127
	fn take_active_subset_is_compatible_with_split_active_subset() {
128
		let active: Vec<_> = vec![ValidatorIndex(1), ValidatorIndex(7), ValidatorIndex(3)];
129
		let validators = vec![9, 1, 6, 7, 4, 5, 2, 3, 0, 8];
130
		let (selected, unselected) = split_active_subset(&active, &validators);
131
		let selected2 = take_active_subset(&active, &validators);
132
		assert_eq!(selected, selected2);
133
		assert_eq!(unselected, vec![9, 6, 4, 5, 2, 0, 8]);
134
		assert_eq!(selected, vec![1, 3, 7]);
135
	}
136
}