partner_chains_mock_data_sources/
candidate.rs1use crate::Result;
2use async_trait::async_trait;
3use authority_selection_inherents::authority_selection_inputs::*;
4use hex_literal::hex;
5use log::{debug, info};
6use serde::*;
7use sidechain_domain::byte_string::*;
8use sidechain_domain::mainchain_epoch::MainchainEpochConfig;
9use sidechain_domain::*;
10
11#[derive(Deserialize, Debug, Clone)]
12pub struct MockRegistration {
13 pub name: Option<String>,
14 pub sidechain_pub_key: ByteString,
15 pub mainchain_pub_key: ByteString,
16 pub mainchain_signature: ByteString,
17 pub sidechain_signature: ByteString,
18 pub registration_utxo: UtxoId,
19 pub status: MockRegistrationStatus,
20 pub aura_pub_key: ByteString,
21 pub grandpa_pub_key: ByteString,
22}
23
24impl MockRegistration {
25 pub fn info_string(&self) -> String {
27 let name = self.name.clone().unwrap_or("<Unnamed>".into());
28 let status = match self.status {
29 MockRegistrationStatus::Active => "active".to_string(),
30 MockRegistrationStatus::PendingActivation { effective_at } => {
31 format!("active at {effective_at}")
32 },
33 MockRegistrationStatus::PendingDeregistration { effective_at } => {
34 format!("active until {effective_at}")
35 },
36 };
37 let mut short_addr = self.sidechain_pub_key.to_hex_string();
38 short_addr.replace_range(5..(short_addr.len() - 4), "...");
39 format!("{name}({short_addr}, {status})")
40 }
41}
42
43impl From<MockRegistration> for CandidateRegistrations {
44 fn from(mock: MockRegistration) -> Self {
45 let stake_pool_public_key = StakePoolPublicKey(mock.mainchain_pub_key.0.try_into().expect(
46 "Invalid mock configuration. 'mainchain_pub_key' public key should be 32 bytes.",
47 ));
48 let registrations = vec![RegistrationData {
49 registration_utxo: mock.registration_utxo,
50 sidechain_signature: SidechainSignature(mock.sidechain_signature.0.clone()),
51 mainchain_signature: MainchainSignature(
52 mock.mainchain_signature.0.try_into().expect("Mainchain signature is 64 bytes"),
53 ),
54 cross_chain_signature: CrossChainSignature(mock.sidechain_signature.0.clone()),
55 sidechain_pub_key: SidechainPublicKey(mock.sidechain_pub_key.0.clone()),
56 cross_chain_pub_key: CrossChainPublicKey(mock.sidechain_pub_key.0.clone()),
57 utxo_info: UtxoInfo {
58 utxo_id: UtxoId {
59 tx_hash: McTxHash(hex!(
60 "5a9b57731df0e008c5aa7296482c033212b71a3c1796ff00c10db7150c1f3d1d"
61 )),
62 index: UtxoIndex(9),
63 },
64 epoch_number: McEpochNumber(123),
65 block_number: McBlockNumber(12345),
66 slot_number: McSlotNumber(123456),
67 tx_index_within_block: McTxIndexInBlock(12),
68 },
69 tx_inputs: vec![mock.registration_utxo],
70 aura_pub_key: AuraPublicKey(mock.aura_pub_key.0),
71 grandpa_pub_key: GrandpaPublicKey(mock.grandpa_pub_key.0),
72 }];
73 let stake_delegation = Some(StakeDelegation(333));
74 CandidateRegistrations { stake_pool_public_key, registrations, stake_delegation }
75 }
76}
77
78#[derive(Deserialize, Debug, Clone)]
79pub enum MockRegistrationStatus {
80 Active,
81 PendingActivation { effective_at: u64 },
82 PendingDeregistration { effective_at: u64 },
83}
84
85#[derive(Deserialize, Debug, Clone)]
86pub struct MockPermissionedCandidate {
87 name: Option<String>,
88 sidechain_pub_key: ByteString,
89 aura_pub_key: ByteString,
90 grandpa_pub_key: ByteString,
91}
92
93impl MockPermissionedCandidate {
94 pub fn info_string(&self) -> String {
96 let name = self.clone().name.unwrap_or("<unnamed>".into());
97 let mut short_addr = self.sidechain_pub_key.to_hex_string();
98 short_addr.replace_range(5..(short_addr.len() - 4), "...");
99 format!("{}({})", name, short_addr)
100 }
101}
102
103impl From<MockPermissionedCandidate> for RawPermissionedCandidateData {
104 fn from(
105 MockPermissionedCandidate {
106 name: _,
107 sidechain_pub_key,
108 aura_pub_key,
109 grandpa_pub_key,
110 }: MockPermissionedCandidate,
111 ) -> Self {
112 Self {
113 sidechain_public_key: SidechainPublicKey(sidechain_pub_key.0),
114 aura_public_key: AuraPublicKey(aura_pub_key.0),
115 grandpa_public_key: GrandpaPublicKey(grandpa_pub_key.0),
116 }
117 }
118}
119
120#[derive(Deserialize, Clone, Debug)]
121pub struct MockDParam {
122 permissioned: u16,
123 registered: u16,
124}
125
126impl MockDParam {
127 pub fn info_string(&self) -> String {
128 format!("permissioned: {}, registered: {}", self.permissioned, self.registered)
129 }
130}
131
132impl From<MockDParam> for DParameter {
133 fn from(MockDParam { permissioned, registered }: MockDParam) -> Self {
134 Self { num_permissioned_candidates: permissioned, num_registered_candidates: registered }
135 }
136}
137
138#[derive(Deserialize, Clone, Debug)]
139pub struct MockEpochCandidates {
140 pub permissioned: Vec<MockPermissionedCandidate>,
141 pub registrations: Vec<MockRegistration>,
142 pub nonce: ByteString,
143 pub d_parameter: MockDParam,
144}
145
146pub struct MockRegistrationsConfig {
147 pub epoch_rotation: Vec<MockEpochCandidates>,
150}
151
152impl MockRegistrationsConfig {
153 pub fn read() -> Result<MockRegistrationsConfig> {
154 let registrations_file_path = std::env::var("MOCK_REGISTRATIONS_FILE")?;
155 let registrations_config = Self::read_registrations(registrations_file_path)?;
156 Ok(registrations_config)
157 }
158 pub fn read_registrations(path: String) -> Result<MockRegistrationsConfig> {
159 info!("Reading registrations from: {path}");
160 let file = std::fs::File::open(path)?;
161 let epoch_rotation: Vec<MockEpochCandidates> = serde_json::from_reader(file)?;
162 info!("Loaded {} registration rotations", epoch_rotation.len());
163 Ok(MockRegistrationsConfig { epoch_rotation })
164 }
165}
166
167pub struct AuthoritySelectionDataSourceMock {
168 pub registrations_data: MockRegistrationsConfig,
169 pub mc_epoch_config: MainchainEpochConfig,
170}
171
172impl AuthoritySelectionDataSourceMock {
173 pub fn epoch_data(&self, epoch_number: u32) -> MockEpochCandidates {
174 let rotation_no: usize =
175 epoch_number as usize % (self.registrations_data.epoch_rotation.len());
176 self.registrations_data.epoch_rotation[rotation_no].clone()
177 }
178
179 pub fn new_from_env() -> Result<Self> {
180 let registrations_data = MockRegistrationsConfig::read()?;
181 let mc_epoch_config = MainchainEpochConfig::read_from_env()?;
182 Ok(AuthoritySelectionDataSourceMock { registrations_data, mc_epoch_config })
183 }
184}
185
186#[async_trait]
187impl AuthoritySelectionDataSource for AuthoritySelectionDataSourceMock {
188 async fn get_ariadne_parameters(
189 &self,
190 epoch_number: McEpochNumber,
191 _d_parameter_validator: PolicyId,
192 _permissioned_candidates_validator: PolicyId,
193 ) -> Result<AriadneParameters> {
194 let epoch_number = epoch_number.0;
195 debug!("Received get_d_parameter_for_epoch({epoch_number}) request");
196
197 let d_parameter = self.epoch_data(epoch_number).d_parameter;
198 debug!(" Responding with: {}", d_parameter.info_string());
199
200 debug!("Received get_permissioned_candidates_for_epoch({epoch_number}) request");
201
202 let candidates = self.epoch_data(epoch_number).permissioned;
203
204 debug!(
205 " Responding with: {:?}",
206 candidates.iter().cloned().map(|c| c.info_string()).collect::<Vec<_>>()
207 );
208
209 let permissioned_candidates: Option<Vec<RawPermissionedCandidateData>> =
210 Some(candidates.into_iter().map(|p| p.into()).collect());
211
212 Ok(AriadneParameters { d_parameter: d_parameter.into(), permissioned_candidates })
213 }
214
215 async fn get_candidates(
216 &self,
217 epoch: McEpochNumber,
218 _committee_candidate_address: MainchainAddress,
219 ) -> Result<Vec<CandidateRegistrations>> {
220 let epoch_number = epoch.0;
221 debug!("Received get_candidates({epoch_number}) request");
222
223 let epoch_conf = self.epoch_data(epoch_number);
224 let registrations = epoch_conf.registrations;
225
226 debug!(
227 " Responding with:
228 Registrations: {:?}",
229 registrations.iter().cloned().map(|r| r.info_string()).collect::<Vec<_>>()
230 );
231 Ok(registrations.into_iter().map(CandidateRegistrations::from).collect())
232 }
233
234 async fn get_epoch_nonce(&self, epoch_number: McEpochNumber) -> Result<Option<EpochNonce>> {
235 let epoch_number = epoch_number.0;
236 debug!("Received get_epoch_nonce({epoch_number}) request");
237 let epoch_conf = self.epoch_data(epoch_number);
238 debug!(
239 " Responding with:
240 Nonce: {}",
241 epoch_conf.nonce.to_hex_string(),
242 );
243 Ok(Some(EpochNonce(epoch_conf.nonce.clone().0)))
244 }
245
246 async fn data_epoch(&self, for_epoch: McEpochNumber) -> Result<McEpochNumber> {
247 Ok(McEpochNumber(for_epoch.0 - 2))
248 }
249}