referrerpolicy=no-referrer-when-downgrade

polkadot_subsystem_bench/disputes/
test_state.rs

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
17use crate::{
18	configuration::{TestAuthorities, TestConfiguration},
19	disputes::DisputesOptions,
20	network::{HandleNetworkMessage, NetworkMessage},
21};
22use codec::Encode;
23use polkadot_node_network_protocol::request_response::{
24	v1::{DisputeRequest, DisputeResponse},
25	ProtocolName, Requests,
26};
27use polkadot_node_primitives::{
28	InvalidDisputeVote, SignedDisputeStatement, UncheckedDisputeMessage, ValidDisputeVote,
29};
30use polkadot_node_subsystem_test_helpers::mock::new_block_import_info;
31use polkadot_overseer::BlockInfo;
32use polkadot_primitives::{
33	AuthorityDiscoveryId, BlockNumber, CandidateCommitments, CandidateEvent, CandidateHash,
34	CandidateReceiptV2, CoreIndex, GroupIndex, Hash, HeadData, Header, InvalidDisputeStatementKind,
35	SessionIndex, ValidDisputeStatementKind, ValidatorId, ValidatorIndex,
36};
37use polkadot_primitives_test_helpers::{dummy_candidate_receipt_v2_bad_sig, dummy_hash};
38use sp_keystore::KeystorePtr;
39use std::{
40	collections::{HashMap, HashSet},
41	sync::{Arc, Mutex},
42};
43
44#[derive(Clone)]
45pub struct TestState {
46	// Full test config
47	pub config: TestConfiguration,
48	// Authority keys for the network emulation.
49	pub test_authorities: TestAuthorities,
50	// Relay chain block infos
51	pub block_infos: Vec<BlockInfo>,
52	// Generated candidate receipts
53	pub candidate_receipts: HashMap<Hash, Vec<CandidateReceiptV2>>,
54	// Generated candidate events
55	pub candidate_events: HashMap<Hash, Vec<CandidateEvent>>,
56	// Generated dispute requests
57	pub dispute_requests: HashMap<CandidateHash, DisputeRequest>,
58	// Relay chain block headers
59	pub block_headers: HashMap<Hash, Header>,
60	// Map from candidate hash to authorities that have received a dispute request
61	pub requests_tracker: Arc<Mutex<HashMap<CandidateHash, HashSet<AuthorityDiscoveryId>>>>,
62}
63
64impl TestState {
65	pub fn new(config: &TestConfiguration, options: &DisputesOptions) -> Self {
66		let config = config.clone();
67		let test_authorities = config.generate_authorities();
68		let block_infos: Vec<BlockInfo> =
69			(1..=config.num_blocks).map(generate_block_info).collect();
70		let candidate_receipts: HashMap<Hash, Vec<CandidateReceiptV2>> = block_infos
71			.iter()
72			.map(|block_info| {
73				(
74					block_info.hash,
75					(0..options.n_disputes)
76						.map(|_| make_candidate_receipt(block_info.hash))
77						.collect(),
78				)
79			})
80			.collect();
81
82		let candidate_events = candidate_receipts
83			.iter()
84			.map(|(&hash, receipts)| {
85				(
86					hash,
87					receipts
88						.iter()
89						.map(|receipt| make_candidate_backed_event(receipt.clone()))
90						.collect::<Vec<_>>(),
91				)
92			})
93			.collect();
94		let dispute_requests = candidate_receipts
95			.iter()
96			.flat_map(|(_, receipts)| {
97				receipts.iter().map(|receipt| {
98					let valid = issue_explicit_statement(
99						test_authorities.keyring.local_keystore(),
100						test_authorities.validator_public[1].clone(),
101						receipt.hash(),
102						1,
103						true,
104					);
105					let invalid = issue_explicit_statement(
106						test_authorities.keyring.local_keystore(),
107						test_authorities.validator_public[3].clone(),
108						receipt.hash(),
109						1,
110						false,
111					);
112
113					(
114						receipt.hash(),
115						DisputeRequest(UncheckedDisputeMessage {
116							candidate_receipt: receipt.clone(),
117							session_index: 1,
118							valid_vote: ValidDisputeVote {
119								validator_index: ValidatorIndex(1),
120								signature: valid.validator_signature().clone(),
121								kind: ValidDisputeStatementKind::Explicit,
122							},
123							invalid_vote: InvalidDisputeVote {
124								validator_index: ValidatorIndex(3),
125								signature: invalid.validator_signature().clone(),
126								kind: InvalidDisputeStatementKind::Explicit,
127							},
128						}),
129					)
130				})
131			})
132			.collect();
133		let block_headers = block_infos.iter().map(generate_block_header).collect();
134		let requests_tracker = Arc::new(Mutex::new(HashMap::new()));
135
136		Self {
137			config,
138			test_authorities,
139			block_infos,
140			candidate_receipts,
141			candidate_events,
142			dispute_requests,
143			block_headers,
144			requests_tracker,
145		}
146	}
147}
148
149fn make_candidate_receipt(relay_parent: Hash) -> CandidateReceiptV2 {
150	let mut candidate_receipt = dummy_candidate_receipt_v2_bad_sig(relay_parent, dummy_hash());
151	candidate_receipt.commitments_hash = CandidateCommitments::default().hash();
152	candidate_receipt
153}
154
155fn make_candidate_backed_event(receipt: CandidateReceiptV2) -> CandidateEvent {
156	CandidateEvent::CandidateBacked(
157		receipt,
158		HeadData::default(),
159		CoreIndex::default(),
160		GroupIndex::default(),
161	)
162}
163
164fn generate_block_info(block_num: usize) -> BlockInfo {
165	new_block_import_info(Hash::repeat_byte(block_num as u8), block_num as BlockNumber)
166}
167
168fn generate_block_header(info: &BlockInfo) -> (Hash, Header) {
169	(
170		info.hash,
171		Header {
172			digest: Default::default(),
173			number: info.number,
174			parent_hash: info.parent_hash,
175			extrinsics_root: Default::default(),
176			state_root: Default::default(),
177		},
178	)
179}
180
181fn issue_explicit_statement(
182	keystore: KeystorePtr,
183	public: ValidatorId,
184	candidate_hash: CandidateHash,
185	session: SessionIndex,
186	valid: bool,
187) -> SignedDisputeStatement {
188	SignedDisputeStatement::sign_explicit(&keystore, valid, candidate_hash, session, public)
189		.unwrap()
190		.unwrap()
191}
192
193#[async_trait::async_trait]
194impl HandleNetworkMessage for TestState {
195	async fn handle(
196		&self,
197		message: NetworkMessage,
198		_node_sender: &mut futures::channel::mpsc::UnboundedSender<NetworkMessage>,
199	) -> Option<NetworkMessage> {
200		match message {
201			NetworkMessage::RequestFromNode(authority_id, requests) => {
202				let Requests::DisputeSendingV1(req) = *requests else {
203					todo!("Wrong requests type in message: {:?}", requests);
204				};
205				let mut tracker = self.requests_tracker.lock().unwrap();
206				tracker
207					.entry(req.payload.0.candidate_receipt.hash())
208					.or_default()
209					.insert(authority_id);
210				drop(tracker);
211
212				let _ = req
213					.pending_response
214					.send(Ok(((DisputeResponse::Confirmed).encode(), ProtocolName::from(""))));
215				None
216			},
217			_ => {
218				todo!("Wrong message type: {:?}", message);
219			},
220		}
221	}
222}