1use fastcrypto::traits::Signer;
5use std::mem;
6use sui_protocol_config::ProtocolConfig;
7use sui_types::base_types::{AuthorityName, VerifiedExecutionData};
8use sui_types::committee::Committee;
9use sui_types::crypto::{AuthoritySignInfo, AuthoritySignature, SuiAuthoritySignature};
10use sui_types::effects::{TransactionEffects, TransactionEffectsAPI};
11use sui_types::gas::GasCostSummary;
12use sui_types::messages_checkpoint::{
13 CertifiedCheckpointSummary, CheckpointContents, CheckpointSummary,
14 CheckpointVersionSpecificData, EndOfEpochData, FullCheckpointContents, VerifiedCheckpoint,
15 VerifiedCheckpointContents, VersionedFullCheckpointContents,
16};
17use sui_types::object::OBJECT_START_VERSION;
18use sui_types::transaction::{Transaction, VerifiedTransaction};
19
20use crate::accumulators::{self, AccumulatorSettlementTxBuilder};
21use crate::checkpoints::CheckpointHeight;
22
23pub trait ValidatorKeypairProvider {
24 fn get_validator_key(&self, name: &AuthorityName) -> &dyn Signer<AuthoritySignature>;
25 fn get_committee(&self) -> &Committee;
26}
27
28#[derive(Debug)]
31pub struct MockCheckpointBuilder {
32 previous_checkpoint: Option<VerifiedCheckpoint>,
33 transactions: Vec<VerifiedExecutionData>,
34 epoch_rolling_gas_cost_summary: GasCostSummary,
35 epoch: u64,
36}
37
38impl MockCheckpointBuilder {
39 pub fn new(previous_checkpoint: VerifiedCheckpoint) -> Self {
40 let epoch_rolling_gas_cost_summary =
41 previous_checkpoint.epoch_rolling_gas_cost_summary.clone();
42 let epoch = previous_checkpoint.epoch;
43
44 Self {
45 previous_checkpoint: Some(previous_checkpoint),
46 transactions: Vec::new(),
47 epoch_rolling_gas_cost_summary,
48 epoch,
49 }
50 }
51
52 pub fn size(&self) -> usize {
53 self.transactions.len()
54 }
55
56 pub fn epoch_rolling_gas_cost_summary(&self) -> &GasCostSummary {
57 &self.epoch_rolling_gas_cost_summary
58 }
59
60 pub fn push_transaction(
61 &mut self,
62 transaction: VerifiedTransaction,
63 effects: TransactionEffects,
64 ) {
65 self.epoch_rolling_gas_cost_summary += effects.gas_cost_summary();
66
67 self.transactions
68 .push(VerifiedExecutionData::new(transaction, effects))
69 }
70
71 pub fn get_next_checkpoint_number(&self) -> u64 {
72 self.previous_checkpoint
73 .as_ref()
74 .map(|c| c.sequence_number + 1)
75 .unwrap_or_default()
76 }
77
78 pub fn override_next_checkpoint_number(
81 &mut self,
82 checkpoint_number: u64,
83 validator_keys: &impl ValidatorKeypairProvider,
84 ) {
85 if checkpoint_number > 0 {
86 let mut summary = self.previous_checkpoint.as_ref().unwrap().data().clone();
87 summary.sequence_number = checkpoint_number - 1;
88 let checkpoint = Self::create_certified_checkpoint(validator_keys, summary);
89 self.previous_checkpoint = Some(checkpoint);
90 } else {
91 self.previous_checkpoint = None;
92 }
93 }
94
95 pub fn build(
97 &mut self,
98 validator_keys: &impl ValidatorKeypairProvider,
99 timestamp_ms: u64,
100 ) -> (
101 VerifiedCheckpoint,
102 CheckpointContents,
103 VerifiedCheckpointContents,
104 ) {
105 self.build_internal(validator_keys, timestamp_ms, None)
106 }
107
108 pub fn build_end_of_epoch(
109 &mut self,
110 validator_keys: &impl ValidatorKeypairProvider,
111 timestamp_ms: u64,
112 new_epoch: u64,
113 end_of_epoch_data: EndOfEpochData,
114 ) -> (
115 VerifiedCheckpoint,
116 CheckpointContents,
117 VerifiedCheckpointContents,
118 ) {
119 self.build_internal(
120 validator_keys,
121 timestamp_ms,
122 Some((new_epoch, end_of_epoch_data)),
123 )
124 }
125
126 pub fn get_settlement_txns(
128 &self,
129 protocol_config: &ProtocolConfig,
130 ) -> (Vec<Transaction>, CheckpointHeight) {
131 let effects: Vec<_> = self
132 .transactions
133 .iter()
134 .map(|e| e.effects.clone())
135 .collect();
136
137 let checkpoint_height = self.get_next_checkpoint_number();
138 let checkpoint_seq = checkpoint_height;
139
140 let builder = AccumulatorSettlementTxBuilder::new(None, &effects, checkpoint_seq, 0);
141
142 let settlement_txns = builder.build_tx(
143 protocol_config,
144 self.epoch,
145 OBJECT_START_VERSION,
146 checkpoint_height,
147 checkpoint_seq,
148 );
149
150 let txns = settlement_txns
151 .into_iter()
152 .map(|tx| VerifiedTransaction::new_system_transaction(tx).into_inner())
153 .collect();
154
155 (txns, checkpoint_height)
156 }
157
158 pub fn get_barrier_tx(
160 &self,
161 checkpoint_height: CheckpointHeight,
162 settlement_effects: &[TransactionEffects],
163 ) -> Transaction {
164 let barrier_tx = accumulators::build_accumulator_barrier_tx(
165 self.epoch,
166 OBJECT_START_VERSION,
167 checkpoint_height,
168 settlement_effects,
169 );
170
171 VerifiedTransaction::new_system_transaction(barrier_tx).into_inner()
172 }
173
174 fn build_internal(
175 &mut self,
176 validator_keys: &impl ValidatorKeypairProvider,
177 timestamp_ms: u64,
178 new_epoch_data: Option<(u64, EndOfEpochData)>,
179 ) -> (
180 VerifiedCheckpoint,
181 CheckpointContents,
182 VerifiedCheckpointContents,
183 ) {
184 let contents =
185 CheckpointContents::new_with_causally_ordered_execution_data(self.transactions.iter());
186 let full_contents =
187 VerifiedCheckpointContents::new_unchecked(VersionedFullCheckpointContents::V1(
188 FullCheckpointContents::new_with_causally_ordered_transactions(
189 mem::take(&mut self.transactions)
190 .into_iter()
191 .map(|e| e.into_inner()),
192 ),
193 ));
194
195 let (epoch, epoch_rolling_gas_cost_summary, end_of_epoch_data) =
196 if let Some((next_epoch, end_of_epoch_data)) = new_epoch_data {
197 let epoch = std::mem::replace(&mut self.epoch, next_epoch);
198 assert_eq!(next_epoch, epoch + 1);
199 let epoch_rolling_gas_cost_summary =
200 std::mem::take(&mut self.epoch_rolling_gas_cost_summary);
201
202 (
203 epoch,
204 epoch_rolling_gas_cost_summary,
205 Some(end_of_epoch_data),
206 )
207 } else {
208 (
209 self.epoch,
210 self.epoch_rolling_gas_cost_summary.clone(),
211 None,
212 )
213 };
214
215 let summary = CheckpointSummary {
216 epoch,
217 sequence_number: self
218 .previous_checkpoint
219 .as_ref()
220 .map(|c| c.sequence_number + 1)
221 .unwrap_or_default(),
222 network_total_transactions: self
223 .previous_checkpoint
224 .as_ref()
225 .map(|c| c.network_total_transactions)
226 .unwrap_or_default()
227 + contents.size() as u64,
228 content_digest: *contents.digest(),
229 previous_digest: self.previous_checkpoint.as_ref().map(|c| *c.digest()),
230 epoch_rolling_gas_cost_summary,
231 end_of_epoch_data,
232 timestamp_ms,
233 version_specific_data: bcs::to_bytes(&CheckpointVersionSpecificData::empty_for_tests())
234 .unwrap(),
235 checkpoint_commitments: Default::default(),
236 };
237
238 let checkpoint = Self::create_certified_checkpoint(validator_keys, summary);
239 self.previous_checkpoint = Some(checkpoint.clone());
240 (checkpoint, contents, full_contents)
241 }
242
243 fn create_certified_checkpoint(
244 validator_keys: &impl ValidatorKeypairProvider,
245 checkpoint: CheckpointSummary,
246 ) -> VerifiedCheckpoint {
247 let signatures = validator_keys
248 .get_committee()
249 .voting_rights
250 .iter()
251 .map(|(name, _)| {
252 let intent_msg = shared_crypto::intent::IntentMessage::new(
253 shared_crypto::intent::Intent::sui_app(
254 shared_crypto::intent::IntentScope::CheckpointSummary,
255 ),
256 &checkpoint,
257 );
258 let key = validator_keys.get_validator_key(name);
259 let signature = AuthoritySignature::new_secure(&intent_msg, &checkpoint.epoch, key);
260 AuthoritySignInfo {
261 epoch: checkpoint.epoch,
262 authority: *name,
263 signature,
264 }
265 })
266 .collect();
267
268 let checkpoint_cert =
269 CertifiedCheckpointSummary::new(checkpoint, signatures, validator_keys.get_committee())
270 .unwrap();
271 VerifiedCheckpoint::new_unchecked(checkpoint_cert)
272 }
273}