polkadot_subsystem_bench/availability/
test_state.rs1use crate::{
18 configuration::{TestAuthorities, TestConfiguration},
19 environment::GENESIS_HASH,
20 mock::runtime_api::default_node_features,
21};
22use bitvec::bitvec;
23use codec::Encode;
24use colored::Colorize;
25use itertools::Itertools;
26use polkadot_node_network_protocol::{
27 request_response::{v2::ChunkFetchingRequest, ReqProtocolNames},
28 ValidationProtocols, VersionedValidationProtocol,
29};
30use polkadot_node_primitives::{AvailableData, BlockData, ErasureChunk, PoV};
31use polkadot_node_subsystem_test_helpers::{
32 derive_erasure_chunks_with_proofs_and_root, mock::new_block_import_info,
33};
34use polkadot_node_subsystem_util::availability_chunks::availability_chunk_indices;
35use polkadot_overseer::BlockInfo;
36use polkadot_primitives::{
37 AvailabilityBitfield, BlockNumber, CandidateHash, CandidateReceiptV2 as CandidateReceipt,
38 ChunkIndex, CoreIndex, Hash, HeadData, Header, PersistedValidationData, Signed, SigningContext,
39 ValidatorIndex,
40};
41use polkadot_primitives_test_helpers::{dummy_candidate_receipt_v2, dummy_hash};
42use sp_core::H256;
43use std::{collections::HashMap, iter::Cycle, sync::Arc};
44
45const LOG_TARGET: &str = "subsystem-bench::availability::test_state";
46
47#[derive(Clone)]
48pub struct TestState {
49 pub config: TestConfiguration,
51 pub pov_sizes: Cycle<std::vec::IntoIter<usize>>,
53 pub candidates: Cycle<std::vec::IntoIter<CandidateReceipt>>,
55 pub pov_size_to_candidate: HashMap<usize, usize>,
57 pub candidate_hashes: HashMap<CandidateHash, usize>,
59 pub candidate_hash_to_core_index: HashMap<CandidateHash, CoreIndex>,
61 pub candidate_receipt_templates: Vec<CandidateReceipt>,
63 pub available_data: Vec<AvailableData>,
65 pub chunks: Vec<Vec<ErasureChunk>>,
67 pub chunk_indices: Vec<Vec<ChunkIndex>>,
69 pub backed_candidates: Vec<CandidateReceipt>,
71 pub req_protocol_names: ReqProtocolNames,
73 pub block_infos: Vec<BlockInfo>,
75 pub chunk_fetching_requests: Vec<Vec<Vec<u8>>>,
77 pub signed_bitfields: HashMap<H256, Vec<VersionedValidationProtocol>>,
79 pub block_headers: HashMap<H256, Header>,
81 pub test_authorities: TestAuthorities,
83 pub candidate_receipts: HashMap<H256, Vec<CandidateReceipt>>,
85}
86
87impl TestState {
88 pub fn new(config: &TestConfiguration) -> Self {
89 use polkadot_primitives::MutateDescriptorV2;
90 let mut test_state = Self {
91 available_data: Default::default(),
92 candidate_receipt_templates: Default::default(),
93 chunks: Default::default(),
94 pov_size_to_candidate: Default::default(),
95 pov_sizes: Vec::from(config.pov_sizes()).into_iter().cycle(),
96 candidate_hashes: HashMap::new(),
97 candidates: Vec::new().into_iter().cycle(),
98 backed_candidates: Vec::new(),
99 config: config.clone(),
100 block_infos: Default::default(),
101 chunk_fetching_requests: Default::default(),
102 signed_bitfields: Default::default(),
103 candidate_receipts: Default::default(),
104 block_headers: Default::default(),
105 test_authorities: config.generate_authorities(),
106 req_protocol_names: ReqProtocolNames::new(GENESIS_HASH, None),
107 chunk_indices: Default::default(),
108 candidate_hash_to_core_index: Default::default(),
109 };
110
111 let persisted_validation_data = PersistedValidationData {
113 parent_head: HeadData(vec![7, 8, 9]),
114 relay_parent_number: Default::default(),
115 max_pov_size: 1024,
116 relay_parent_storage_root: Default::default(),
117 };
118
119 test_state.chunk_indices = (0..config.n_cores)
120 .map(|core_index| {
121 availability_chunk_indices(
122 &default_node_features(),
123 config.n_validators,
124 CoreIndex(core_index as u32),
125 )
126 .unwrap()
127 })
128 .collect();
129
130 for (index, pov_size) in config.pov_sizes().iter().cloned().unique().enumerate() {
132 gum::info!(target: LOG_TARGET, index, pov_size, "{}", "Generating template candidate".bright_blue());
133
134 let mut candidate_receipt = dummy_candidate_receipt_v2(dummy_hash());
135 let pov = PoV { block_data: BlockData(vec![index as u8; pov_size]) };
136
137 let new_available_data = AvailableData {
138 validation_data: persisted_validation_data.clone(),
139 pov: Arc::new(pov),
140 };
141
142 let (new_chunks, erasure_root) = derive_erasure_chunks_with_proofs_and_root(
143 config.n_validators,
144 &new_available_data,
145 |_, _| {},
146 );
147
148 candidate_receipt.descriptor.set_erasure_root(erasure_root);
149
150 test_state.chunks.push(new_chunks);
151 test_state.available_data.push(new_available_data);
152 test_state.pov_size_to_candidate.insert(pov_size, index);
153 test_state.candidate_receipt_templates.push(CandidateReceipt {
154 descriptor: candidate_receipt.descriptor,
155 commitments_hash: candidate_receipt.commitments_hash,
156 });
157 }
158
159 test_state.block_infos = (1..=config.num_blocks)
160 .map(|block_num| {
161 let relay_block_hash = Hash::repeat_byte(block_num as u8);
162 new_block_import_info(relay_block_hash, block_num as BlockNumber)
163 })
164 .collect();
165
166 test_state.block_headers = test_state
167 .block_infos
168 .iter()
169 .map(|info| {
170 (
171 info.hash,
172 Header {
173 digest: Default::default(),
174 number: info.number,
175 parent_hash: info.parent_hash,
176 extrinsics_root: Default::default(),
177 state_root: Default::default(),
178 },
179 )
180 })
181 .collect::<HashMap<_, _>>();
182
183 let candidates_count = config.n_cores * config.num_blocks;
185 gum::info!(target: LOG_TARGET,"{}", format!("Pre-generating {candidates_count} candidates.").bright_blue());
186 test_state.candidates = (0..candidates_count)
187 .map(|index| {
188 let pov_size = test_state.pov_sizes.next().expect("This is a cycle; qed");
189 let candidate_index = *test_state
190 .pov_size_to_candidate
191 .get(&pov_size)
192 .expect("pov_size always exists; qed");
193 let mut candidate_receipt =
194 test_state.candidate_receipt_templates[candidate_index].clone();
195
196 candidate_receipt
198 .descriptor
199 .set_relay_parent(Hash::from_low_u64_be(index as u64));
200 test_state.candidate_hashes.insert(candidate_receipt.hash(), candidate_index);
202
203 let core_index = (index % config.n_cores) as u32;
204 test_state
205 .candidate_hash_to_core_index
206 .insert(candidate_receipt.hash(), core_index.into());
207
208 gum::debug!(target: LOG_TARGET, candidate_hash = ?candidate_receipt.hash(), "new candidate");
209
210 candidate_receipt
211 })
212 .collect::<Vec<_>>()
213 .into_iter()
214 .cycle();
215
216 for info in test_state.block_infos.iter() {
219 for _ in 0..config.n_cores {
220 let receipt = test_state.candidates.next().expect("Cycle iterator");
221 test_state.candidate_receipts.entry(info.hash).or_default().push(receipt);
222 }
223
224 test_state.backed_candidates.push(
226 test_state
227 .candidate_receipts
228 .get(&info.hash)
229 .expect("just inserted above")
230 .first()
231 .expect("just inserted above")
232 .clone(),
233 );
234 }
235
236 test_state.chunk_fetching_requests = test_state
237 .backed_candidates
238 .iter()
239 .map(|candidate| {
240 (0..config.n_validators)
241 .map(|index| {
242 ChunkFetchingRequest {
243 candidate_hash: candidate.hash(),
244 index: ValidatorIndex(index as u32),
245 }
246 .encode()
247 })
248 .collect::<Vec<_>>()
249 })
250 .collect::<Vec<_>>();
251
252 test_state.signed_bitfields = test_state
253 .block_infos
254 .iter()
255 .map(|block_info| {
256 let signing_context =
257 SigningContext { session_index: 0, parent_hash: block_info.hash };
258 let messages = (0..config.n_validators)
259 .map(|index| {
260 let validator_public = test_state
261 .test_authorities
262 .validator_public
263 .get(index)
264 .expect("All validator keys are known");
265
266 let payload: AvailabilityBitfield =
268 AvailabilityBitfield(bitvec![u8, bitvec::order::Lsb0; 1u8; 32]);
269 let signed_bitfield = Signed::<AvailabilityBitfield>::sign(
270 &test_state.test_authorities.keyring.keystore(),
271 payload,
272 &signing_context,
273 ValidatorIndex(index as u32),
274 validator_public,
275 )
276 .ok()
277 .flatten()
278 .expect("should be signed");
279
280 peer_bitfield_message_v3(block_info.hash, signed_bitfield)
281 })
282 .collect::<Vec<_>>();
283
284 (block_info.hash, messages)
285 })
286 .collect();
287
288 gum::info!(target: LOG_TARGET, "{}","Created test environment.".bright_blue());
289
290 test_state
291 }
292}
293
294fn peer_bitfield_message_v3(
295 relay_hash: H256,
296 signed_bitfield: Signed<AvailabilityBitfield>,
297) -> VersionedValidationProtocol {
298 let bitfield = polkadot_node_network_protocol::v3::BitfieldDistributionMessage::Bitfield(
299 relay_hash,
300 signed_bitfield.into(),
301 );
302
303 ValidationProtocols::V3(
304 polkadot_node_network_protocol::v3::ValidationProtocol::BitfieldDistribution(bitfield),
305 )
306}