polkadot_subsystem_bench/disputes/
test_state.rs1use 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 pub config: TestConfiguration,
48 pub test_authorities: TestAuthorities,
50 pub block_infos: Vec<BlockInfo>,
52 pub candidate_receipts: HashMap<Hash, Vec<CandidateReceiptV2>>,
54 pub candidate_events: HashMap<Hash, Vec<CandidateEvent>>,
56 pub dispute_requests: HashMap<CandidateHash, DisputeRequest>,
58 pub block_headers: HashMap<Hash, Header>,
60 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}