1use std::{collections::HashMap, sync::Arc};
6
7use iota_config::genesis::Genesis;
8use iota_sdk_types::crypto::{Intent, IntentMessage, IntentScope};
9use iota_types::{
10 base_types::{AuthorityName, ExecutionData},
11 committee::{Committee, EpochId, StakeUnit},
12 crypto::{
13 AuthorityKeyPair, AuthoritySignInfo, AuthoritySignature, IotaAuthoritySignature,
14 KeypairTraits,
15 },
16 messages_checkpoint::{
17 CertifiedCheckpointSummary, CheckpointDigest, CheckpointSequenceNumber, CheckpointSummary,
18 CheckpointVersionSpecificData, EndOfEpochData, FullCheckpointContents, VerifiedCheckpoint,
19 VerifiedCheckpointContents,
20 },
21};
22
23use crate::network_config::NetworkConfig;
24
25pub struct CommitteeFixture {
26 epoch: EpochId,
27 validators: HashMap<AuthorityName, (AuthorityKeyPair, StakeUnit)>,
28 committee: Committee,
29 genesis: Option<Arc<Genesis>>,
30}
31
32type MakeCheckpointResults = (
33 Vec<VerifiedCheckpoint>,
34 Vec<VerifiedCheckpointContents>,
35 HashMap<CheckpointSequenceNumber, CheckpointDigest>,
36 HashMap<CheckpointDigest, VerifiedCheckpoint>,
37);
38
39impl CommitteeFixture {
40 pub fn generate<R: ::rand::RngCore + ::rand::CryptoRng>(
41 mut rng: R,
42 epoch: EpochId,
43 committee_size: usize,
44 ) -> Self {
45 let validators = (0..committee_size)
46 .map(|_| iota_types::crypto::get_key_pair_from_rng::<AuthorityKeyPair, _>(&mut rng).1)
47 .map(|keypair| (keypair.public().into(), (keypair, 1)))
48 .collect::<HashMap<_, _>>();
49
50 let committee = Committee::new_for_testing_with_normalized_voting_power(
51 epoch,
52 validators
53 .iter()
54 .map(|(name, (_, stake))| (*name, *stake))
55 .collect(),
56 );
57
58 Self {
59 epoch,
60 validators,
61 committee,
62 genesis: None,
63 }
64 }
65
66 pub fn from_network_config(network_config: &NetworkConfig) -> Self {
67 let committee = network_config.genesis.committee().unwrap();
68 Self {
69 epoch: committee.epoch,
70 validators: committee
71 .members()
72 .map(|(name, stake)| {
73 (
74 *name,
75 (
76 network_config
77 .validator_configs()
78 .iter()
79 .find(|config| config.authority_public_key() == *name)
80 .unwrap()
81 .authority_key_pair()
82 .copy(),
83 *stake,
84 ),
85 )
86 })
87 .collect(),
88 committee,
89 genesis: Some(Arc::new(network_config.genesis.clone())),
90 }
91 }
92
93 pub fn committee(&self) -> &Committee {
94 &self.committee
95 }
96
97 fn create_root_checkpoint(&self) -> (VerifiedCheckpoint, VerifiedCheckpointContents) {
98 assert_eq!(self.epoch, 0, "root checkpoint must be epoch 0");
99
100 let mut contents = empty_contents();
101 if let Some(genesis) = &self.genesis {
102 let tx = genesis.transaction().clone();
105 let effects = genesis.effects().clone();
106 let execution_data = ExecutionData::new(tx, effects);
107
108 contents = VerifiedCheckpointContents::new_unchecked(
109 FullCheckpointContents::new_with_causally_ordered_transactions(std::iter::once(
110 execution_data,
111 )),
112 );
113 }
114
115 let content_digest = *contents
116 .clone()
117 .into_inner()
118 .into_checkpoint_contents()
119 .digest();
120
121 let checkpoint = CheckpointSummary {
122 epoch: 0,
123 sequence_number: 0,
124 network_total_transactions: contents.num_of_transactions() as u64,
125 content_digest,
126 previous_digest: None,
127 epoch_rolling_gas_cost_summary: Default::default(),
128 end_of_epoch_data: None,
129 timestamp_ms: 0,
130 version_specific_data: bcs::to_bytes(&CheckpointVersionSpecificData::empty_for_tests())
131 .unwrap(),
132 checkpoint_commitments: Default::default(),
133 };
134
135 (self.create_certified_checkpoint(checkpoint), contents)
136 }
137
138 fn create_certified_checkpoint(&self, checkpoint: CheckpointSummary) -> VerifiedCheckpoint {
139 let signatures = self
140 .validators
141 .iter()
142 .map(|(name, (key, _))| {
143 let intent_msg = IntentMessage::new(
144 Intent::iota_app(IntentScope::CheckpointSummary),
145 checkpoint.clone(),
146 );
147 let signature = AuthoritySignature::new_secure(&intent_msg, &checkpoint.epoch, key);
148 AuthoritySignInfo {
149 epoch: checkpoint.epoch,
150 authority: *name,
151 signature,
152 }
153 })
154 .collect();
155
156 let checkpoint = CertifiedCheckpointSummary::new(checkpoint, signatures, self.committee())
157 .unwrap()
158 .try_into_verified(self.committee())
159 .unwrap();
160
161 checkpoint
162 }
163
164 pub fn make_random_checkpoints(
165 &self,
166 number_of_checkpoints: usize,
167 previous_checkpoint: Option<VerifiedCheckpoint>,
168 ) -> MakeCheckpointResults {
169 self.make_checkpoints(number_of_checkpoints, previous_checkpoint, random_contents)
170 }
171
172 pub fn make_empty_checkpoints(
173 &self,
174 number_of_checkpoints: usize,
175 previous_checkpoint: Option<VerifiedCheckpoint>,
176 ) -> MakeCheckpointResults {
177 self.make_checkpoints(number_of_checkpoints, previous_checkpoint, empty_contents)
178 }
179
180 fn make_checkpoints<F: Fn() -> VerifiedCheckpointContents>(
181 &self,
182 number_of_checkpoints: usize,
183 previous_checkpoint: Option<VerifiedCheckpoint>,
184 content_generator: F,
185 ) -> MakeCheckpointResults {
186 let skip = previous_checkpoint.is_some() as usize;
188 let first = previous_checkpoint
189 .map(|c| (c, empty_contents()))
190 .unwrap_or_else(|| self.create_root_checkpoint());
191
192 let (ordered_checkpoints, contents): (Vec<_>, Vec<_>) =
193 std::iter::successors(Some(first), |prev| {
194 let contents = content_generator();
195 let contents_digest = *contents
196 .clone()
197 .into_inner()
198 .into_checkpoint_contents()
199 .digest();
200 let summary = CheckpointSummary {
201 epoch: self.epoch,
202 sequence_number: prev.0.sequence_number + 1,
203 network_total_transactions: prev.0.network_total_transactions
204 + contents.num_of_transactions() as u64,
205 content_digest: contents_digest,
206 previous_digest: Some(*prev.0.digest()),
207 epoch_rolling_gas_cost_summary: Default::default(),
208 end_of_epoch_data: None,
209 timestamp_ms: 0,
210 version_specific_data: bcs::to_bytes(
211 &CheckpointVersionSpecificData::empty_for_tests(),
212 )
213 .unwrap(),
214 checkpoint_commitments: Default::default(),
215 };
216
217 let checkpoint = self.create_certified_checkpoint(summary);
218
219 Some((checkpoint, contents))
220 })
221 .skip(skip)
222 .take(number_of_checkpoints)
223 .unzip();
224
225 let (sequence_number_to_digest, checkpoints) = ordered_checkpoints
226 .iter()
227 .cloned()
228 .map(|checkpoint| {
229 let digest = *checkpoint.digest();
230 ((checkpoint.sequence_number, digest), (digest, checkpoint))
231 })
232 .unzip();
233
234 (
235 ordered_checkpoints,
236 contents,
237 sequence_number_to_digest,
238 checkpoints,
239 )
240 }
241
242 pub fn make_end_of_epoch_checkpoint(
243 &self,
244 previous_checkpoint: VerifiedCheckpoint,
245 end_of_epoch_data: Option<EndOfEpochData>,
246 ) -> (
247 CheckpointSequenceNumber,
248 CheckpointDigest,
249 VerifiedCheckpoint,
250 ) {
251 let summary = CheckpointSummary {
252 epoch: self.epoch,
253 sequence_number: previous_checkpoint.sequence_number + 1,
254 network_total_transactions: 0,
255 content_digest: *empty_contents()
256 .into_inner()
257 .into_checkpoint_contents()
258 .digest(),
259 previous_digest: Some(*previous_checkpoint.digest()),
260 epoch_rolling_gas_cost_summary: Default::default(),
261 end_of_epoch_data,
262 timestamp_ms: 0,
263 version_specific_data: bcs::to_bytes(&CheckpointVersionSpecificData::empty_for_tests())
264 .unwrap(),
265 checkpoint_commitments: Default::default(),
266 };
267
268 let checkpoint = self.create_certified_checkpoint(summary);
269
270 (checkpoint.sequence_number, *checkpoint.digest(), checkpoint)
271 }
272}
273
274pub fn empty_contents() -> VerifiedCheckpointContents {
275 VerifiedCheckpointContents::new_unchecked(
276 FullCheckpointContents::new_with_causally_ordered_transactions(std::iter::empty()),
277 )
278}
279
280pub fn random_contents() -> VerifiedCheckpointContents {
281 VerifiedCheckpointContents::new_unchecked(FullCheckpointContents::random_for_testing())
282}