partner_chains_mock_data_sources/
candidate.rs

1use 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	/// Returns an info string like: "Bob(0x039...1f27, active)"
26	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	/// Returns an info string like: Bob(0x039...1f27)
95	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	/// List of epoch configurations
148	/// These are returned for each epoch in a round-robin fashion
149	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}