partner_chains_mock_data_sources/
candidate.rs1use crate::Result;
2use async_trait::async_trait;
3use authority_selection_inherents::*;
4use hex_literal::hex;
5use log::{debug, info};
6use serde::*;
7use sidechain_domain::byte_string::*;
8use sidechain_domain::*;
9
10#[derive(Deserialize, Debug, Clone)]
11pub struct MockRegistration {
12 pub name: Option<String>,
13 pub sidechain_pub_key: ByteString,
14 pub mainchain_pub_key: ByteString,
15 pub mainchain_signature: ByteString,
16 pub sidechain_signature: ByteString,
17 pub registration_utxo: UtxoId,
18 pub status: MockRegistrationStatus,
19 pub aura_pub_key: ByteString,
20 pub grandpa_pub_key: ByteString,
21}
22
23impl MockRegistration {
24 pub fn info_string(&self) -> String {
26 let name = self.name.clone().unwrap_or("<Unnamed>".into());
27 let status = match self.status {
28 MockRegistrationStatus::Active => "active".to_string(),
29 MockRegistrationStatus::PendingActivation { effective_at } => {
30 format!("active at {effective_at}")
31 },
32 MockRegistrationStatus::PendingDeregistration { effective_at } => {
33 format!("active until {effective_at}")
34 },
35 };
36 let mut short_addr = self.sidechain_pub_key.to_hex_string();
37 short_addr.replace_range(5..(short_addr.len() - 4), "...");
38 format!("{name}({short_addr}, {status})")
39 }
40}
41
42impl From<MockRegistration> for CandidateRegistrations {
43 fn from(mock: MockRegistration) -> Self {
44 let stake_pool_public_key = StakePoolPublicKey(mock.mainchain_pub_key.0.try_into().expect(
45 "Invalid mock configuration. 'mainchain_pub_key' public key should be 32 bytes.",
46 ));
47 let registrations = vec![RegistrationData {
48 registration_utxo: mock.registration_utxo,
49 sidechain_signature: SidechainSignature(mock.sidechain_signature.0.clone()),
50 mainchain_signature: MainchainSignature(
51 mock.mainchain_signature.0.try_into().expect("Mainchain signature is 64 bytes"),
52 ),
53 cross_chain_signature: CrossChainSignature(mock.sidechain_signature.0.clone()),
54 sidechain_pub_key: SidechainPublicKey(mock.sidechain_pub_key.0.clone()),
55 cross_chain_pub_key: CrossChainPublicKey(mock.sidechain_pub_key.0.clone()),
56 utxo_info: UtxoInfo {
57 utxo_id: UtxoId {
58 tx_hash: McTxHash(hex!(
59 "5a9b57731df0e008c5aa7296482c033212b71a3c1796ff00c10db7150c1f3d1d"
60 )),
61 index: UtxoIndex(9),
62 },
63 epoch_number: McEpochNumber(123),
64 block_number: McBlockNumber(12345),
65 slot_number: McSlotNumber(123456),
66 tx_index_within_block: McTxIndexInBlock(12),
67 },
68 tx_inputs: vec![mock.registration_utxo],
69 keys: CandidateKeys(vec![
70 AuraPublicKey(mock.aura_pub_key.0).into(),
71 GrandpaPublicKey(mock.grandpa_pub_key.0).into(),
72 ]),
73 }];
74 let stake_delegation = Some(StakeDelegation(333));
75 CandidateRegistrations { stake_pool_public_key, registrations, stake_delegation }
76 }
77}
78
79#[derive(Deserialize, Debug, Clone)]
80pub enum MockRegistrationStatus {
81 Active,
82 PendingActivation { effective_at: u64 },
83 PendingDeregistration { effective_at: u64 },
84}
85
86#[derive(Deserialize, Debug, Clone)]
87pub struct MockPermissionedCandidate {
88 name: Option<String>,
89 sidechain_pub_key: ByteString,
90 aura_pub_key: ByteString,
91 grandpa_pub_key: ByteString,
92}
93
94impl MockPermissionedCandidate {
95 pub fn info_string(&self) -> String {
97 let name = self.clone().name.unwrap_or("<unnamed>".into());
98 let mut short_addr = self.sidechain_pub_key.to_hex_string();
99 short_addr.replace_range(5..(short_addr.len() - 4), "...");
100 format!("{}({})", name, short_addr)
101 }
102}
103
104impl From<MockPermissionedCandidate> for PermissionedCandidateData {
105 fn from(
106 MockPermissionedCandidate {
107 name: _,
108 sidechain_pub_key,
109 aura_pub_key,
110 grandpa_pub_key,
111 }: MockPermissionedCandidate,
112 ) -> Self {
113 Self {
114 sidechain_public_key: SidechainPublicKey(sidechain_pub_key.0),
115 keys: CandidateKeys(vec![
116 AuraPublicKey(aura_pub_key.0).into(),
117 GrandpaPublicKey(grandpa_pub_key.0).into(),
118 ]),
119 }
120 }
121}
122
123#[derive(Deserialize, Clone, Debug)]
124pub struct MockDParam {
125 permissioned: u16,
126 registered: u16,
127}
128
129impl MockDParam {
130 pub fn info_string(&self) -> String {
131 format!("permissioned: {}, registered: {}", self.permissioned, self.registered)
132 }
133}
134
135impl From<MockDParam> for DParameter {
136 fn from(MockDParam { permissioned, registered }: MockDParam) -> Self {
137 Self { num_permissioned_candidates: permissioned, num_registered_candidates: registered }
138 }
139}
140
141#[derive(Deserialize, Clone, Debug)]
143pub struct MockEpochCandidates {
144 pub permissioned: Vec<MockPermissionedCandidate>,
146 pub registrations: Vec<MockRegistration>,
148 pub nonce: ByteString,
150 pub d_parameter: MockDParam,
152}
153
154pub struct MockRegistrationsConfig {
156 pub epoch_rotation: Vec<MockEpochCandidates>,
159}
160
161impl MockRegistrationsConfig {
162 pub fn read() -> Result<MockRegistrationsConfig> {
165 let registrations_file_path = std::env::var("MOCK_REGISTRATIONS_FILE")?;
166 let registrations_config = Self::read_registrations(®istrations_file_path)?;
167 Ok(registrations_config)
168 }
169
170 pub fn read_registrations(path: &str) -> Result<MockRegistrationsConfig> {
172 info!("Reading registrations from: {path}");
173 let file = std::fs::File::open(path)?;
174 let epoch_rotation: Vec<MockEpochCandidates> = serde_json::from_reader(file)?;
175 info!("Loaded {} registration rotations", epoch_rotation.len());
176 Ok(MockRegistrationsConfig { epoch_rotation })
177 }
178}
179
180#[doc = include_str!("../examples/registrations.json")]
191pub struct AuthoritySelectionDataSourceMock {
220 pub registrations_data: MockRegistrationsConfig,
222}
223
224impl AuthoritySelectionDataSourceMock {
225 pub(crate) fn epoch_data(&self, epoch_number: u32) -> MockEpochCandidates {
226 let rotation_no: usize =
227 epoch_number as usize % (self.registrations_data.epoch_rotation.len());
228 self.registrations_data.epoch_rotation[rotation_no].clone()
229 }
230
231 pub fn new_from_env() -> Result<Self> {
234 let registrations_data = MockRegistrationsConfig::read()?;
235 Ok(AuthoritySelectionDataSourceMock { registrations_data })
236 }
237}
238
239#[async_trait]
240impl AuthoritySelectionDataSource for AuthoritySelectionDataSourceMock {
241 async fn get_ariadne_parameters(
242 &self,
243 epoch_number: McEpochNumber,
244 _d_parameter_validator: PolicyId,
245 _permissioned_candidates_validator: PolicyId,
246 ) -> Result<AriadneParameters> {
247 let epoch_number = epoch_number.0;
248 debug!("Received get_d_parameter_for_epoch({epoch_number}) request");
249
250 let d_parameter = self.epoch_data(epoch_number).d_parameter;
251 debug!(" Responding with: {}", d_parameter.info_string());
252
253 debug!("Received get_permissioned_candidates_for_epoch({epoch_number}) request");
254
255 let candidates = self.epoch_data(epoch_number).permissioned;
256
257 debug!(
258 " Responding with: {:?}",
259 candidates.iter().cloned().map(|c| c.info_string()).collect::<Vec<_>>()
260 );
261
262 let permissioned_candidates: Option<Vec<PermissionedCandidateData>> =
263 Some(candidates.into_iter().map(|p| p.into()).collect());
264
265 Ok(AriadneParameters { d_parameter: d_parameter.into(), permissioned_candidates })
266 }
267
268 async fn get_candidates(
269 &self,
270 epoch: McEpochNumber,
271 _committee_candidate_address: MainchainAddress,
272 ) -> Result<Vec<CandidateRegistrations>> {
273 let epoch_number = epoch.0;
274 debug!("Received get_candidates({epoch_number}) request");
275
276 let epoch_conf = self.epoch_data(epoch_number);
277 let registrations = epoch_conf.registrations;
278
279 debug!(
280 " Responding with:
281 Registrations: {:?}",
282 registrations.iter().cloned().map(|r| r.info_string()).collect::<Vec<_>>()
283 );
284 Ok(registrations.into_iter().map(CandidateRegistrations::from).collect())
285 }
286
287 async fn get_epoch_nonce(&self, epoch_number: McEpochNumber) -> Result<Option<EpochNonce>> {
288 let epoch_number = epoch_number.0;
289 debug!("Received get_epoch_nonce({epoch_number}) request");
290 let epoch_conf = self.epoch_data(epoch_number);
291 debug!(
292 " Responding with:
293 Nonce: {}",
294 epoch_conf.nonce.to_hex_string(),
295 );
296 Ok(Some(EpochNonce(epoch_conf.nonce.clone().0)))
297 }
298
299 async fn data_epoch(&self, for_epoch: McEpochNumber) -> Result<McEpochNumber> {
300 Ok(McEpochNumber(for_epoch.0 - 2))
301 }
302}