sui_rpc/proto/sui/rpc/v2/
checkpoint.rs

1use super::*;
2use crate::field::FieldMaskTree;
3use crate::merge::Merge;
4use crate::proto::TryFromProtoError;
5use tap::Pipe;
6
7//
8// CheckpointSummary
9//
10
11impl From<sui_sdk_types::CheckpointSummary> for CheckpointSummary {
12    fn from(summary: sui_sdk_types::CheckpointSummary) -> Self {
13        Self::merge_from(summary, &FieldMaskTree::new_wildcard())
14    }
15}
16
17impl Merge<sui_sdk_types::CheckpointSummary> for CheckpointSummary {
18    fn merge(&mut self, source: sui_sdk_types::CheckpointSummary, mask: &FieldMaskTree) {
19        if mask.contains(Self::BCS_FIELD.name) {
20            let mut bcs = Bcs::serialize(&source).unwrap();
21            bcs.name = Some("CheckpointSummary".to_owned());
22            self.bcs = Some(bcs);
23        }
24
25        if mask.contains(Self::DIGEST_FIELD.name) {
26            self.digest = Some(source.digest().to_string());
27        }
28
29        let sui_sdk_types::CheckpointSummary {
30            epoch,
31            sequence_number,
32            network_total_transactions,
33            content_digest,
34            previous_digest,
35            epoch_rolling_gas_cost_summary,
36            timestamp_ms,
37            checkpoint_commitments,
38            end_of_epoch_data,
39            version_specific_data,
40        } = source;
41
42        if mask.contains(Self::EPOCH_FIELD.name) {
43            self.epoch = Some(epoch);
44        }
45
46        if mask.contains(Self::SEQUENCE_NUMBER_FIELD.name) {
47            self.sequence_number = Some(sequence_number);
48        }
49
50        if mask.contains(Self::TOTAL_NETWORK_TRANSACTIONS_FIELD.name) {
51            self.total_network_transactions = Some(network_total_transactions);
52        }
53
54        if mask.contains(Self::CONTENT_DIGEST_FIELD.name) {
55            self.content_digest = Some(content_digest.to_string());
56        }
57
58        if mask.contains(Self::PREVIOUS_DIGEST_FIELD.name) {
59            self.previous_digest = previous_digest.map(|d| d.to_string());
60        }
61
62        if mask.contains(Self::EPOCH_ROLLING_GAS_COST_SUMMARY_FIELD.name) {
63            self.epoch_rolling_gas_cost_summary = Some(epoch_rolling_gas_cost_summary.into());
64        }
65
66        if mask.contains(Self::TIMESTAMP_FIELD.name) {
67            self.timestamp = Some(crate::proto::timestamp_ms_to_proto(timestamp_ms));
68        }
69
70        if mask.contains(Self::COMMITMENTS_FIELD.name) {
71            self.commitments = checkpoint_commitments.into_iter().map(Into::into).collect();
72        }
73
74        if mask.contains(Self::END_OF_EPOCH_DATA_FIELD.name) {
75            self.end_of_epoch_data = end_of_epoch_data.map(Into::into);
76        }
77
78        if mask.contains(Self::VERSION_SPECIFIC_DATA_FIELD.name) {
79            self.version_specific_data = Some(version_specific_data.into());
80        }
81    }
82}
83
84impl Merge<&CheckpointSummary> for CheckpointSummary {
85    fn merge(&mut self, source: &CheckpointSummary, mask: &FieldMaskTree) {
86        let CheckpointSummary {
87            bcs,
88            digest,
89            epoch,
90            sequence_number,
91            total_network_transactions,
92            content_digest,
93            previous_digest,
94            epoch_rolling_gas_cost_summary,
95            timestamp,
96            commitments,
97            end_of_epoch_data,
98            version_specific_data,
99        } = source;
100
101        if mask.contains(Self::BCS_FIELD.name) {
102            self.bcs = bcs.clone();
103        }
104
105        if mask.contains(Self::DIGEST_FIELD.name) {
106            self.digest = digest.clone();
107        }
108
109        if mask.contains(Self::EPOCH_FIELD.name) {
110            self.epoch = *epoch;
111        }
112
113        if mask.contains(Self::SEQUENCE_NUMBER_FIELD.name) {
114            self.sequence_number = *sequence_number;
115        }
116
117        if mask.contains(Self::TOTAL_NETWORK_TRANSACTIONS_FIELD.name) {
118            self.total_network_transactions = *total_network_transactions;
119        }
120
121        if mask.contains(Self::CONTENT_DIGEST_FIELD.name) {
122            self.content_digest = content_digest.clone();
123        }
124
125        if mask.contains(Self::PREVIOUS_DIGEST_FIELD.name) {
126            self.previous_digest = previous_digest.clone();
127        }
128
129        if mask.contains(Self::EPOCH_ROLLING_GAS_COST_SUMMARY_FIELD.name) {
130            self.epoch_rolling_gas_cost_summary = *epoch_rolling_gas_cost_summary;
131        }
132
133        if mask.contains(Self::TIMESTAMP_FIELD.name) {
134            self.timestamp = *timestamp;
135        }
136
137        if mask.contains(Self::COMMITMENTS_FIELD.name) {
138            self.commitments = commitments.clone();
139        }
140
141        if mask.contains(Self::END_OF_EPOCH_DATA_FIELD.name) {
142            self.end_of_epoch_data = end_of_epoch_data.clone();
143        }
144
145        if mask.contains(Self::VERSION_SPECIFIC_DATA_FIELD.name) {
146            self.version_specific_data = version_specific_data.clone();
147        }
148    }
149}
150
151impl TryFrom<&CheckpointSummary> for sui_sdk_types::CheckpointSummary {
152    type Error = TryFromProtoError;
153
154    fn try_from(
155        CheckpointSummary {
156            bcs: _,
157            digest: _,
158            epoch,
159            sequence_number,
160            total_network_transactions,
161            content_digest,
162            previous_digest,
163            epoch_rolling_gas_cost_summary,
164            timestamp,
165            commitments,
166            end_of_epoch_data,
167            version_specific_data,
168        }: &CheckpointSummary,
169    ) -> Result<Self, Self::Error> {
170        let epoch = epoch.ok_or_else(|| TryFromProtoError::missing("epoch"))?;
171        let sequence_number =
172            sequence_number.ok_or_else(|| TryFromProtoError::missing("sequence_number"))?;
173        let network_total_transactions = total_network_transactions
174            .ok_or_else(|| TryFromProtoError::missing("total_network_transactions"))?;
175        let content_digest = content_digest
176            .as_ref()
177            .ok_or_else(|| TryFromProtoError::missing("content_digest"))?
178            .parse()
179            .map_err(|e| TryFromProtoError::invalid(CheckpointSummary::CONTENT_DIGEST_FIELD, e))?;
180        let previous_digest = previous_digest
181            .as_ref()
182            .map(|s| {
183                s.parse().map_err(|e| {
184                    TryFromProtoError::invalid(CheckpointSummary::PREVIOUS_DIGEST_FIELD, e)
185                })
186            })
187            .transpose()?;
188        let epoch_rolling_gas_cost_summary = epoch_rolling_gas_cost_summary
189            .as_ref()
190            .ok_or_else(|| TryFromProtoError::missing("epoch_rolling_gas_cost_summary"))?
191            .try_into()?;
192
193        let timestamp_ms = timestamp
194            .ok_or_else(|| TryFromProtoError::missing("timestamp_ms"))?
195            .pipe(crate::proto::proto_to_timestamp_ms)?;
196
197        let checkpoint_commitments = commitments
198            .iter()
199            .map(TryInto::try_into)
200            .collect::<Result<_, _>>()?;
201
202        let end_of_epoch_data = end_of_epoch_data
203            .as_ref()
204            .map(TryInto::try_into)
205            .transpose()?;
206
207        let version_specific_data = version_specific_data
208            .as_ref()
209            .ok_or_else(|| TryFromProtoError::missing("version_specific_data"))?
210            .to_vec();
211
212        Ok(Self {
213            epoch,
214            sequence_number,
215            network_total_transactions,
216            content_digest,
217            previous_digest,
218            epoch_rolling_gas_cost_summary,
219            timestamp_ms,
220            checkpoint_commitments,
221            end_of_epoch_data,
222            version_specific_data,
223        })
224    }
225}
226
227//
228// GasCostSummary
229//
230
231impl From<sui_sdk_types::GasCostSummary> for GasCostSummary {
232    fn from(
233        sui_sdk_types::GasCostSummary {
234            computation_cost,
235            storage_cost,
236            storage_rebate,
237            non_refundable_storage_fee,
238        }: sui_sdk_types::GasCostSummary,
239    ) -> Self {
240        Self {
241            computation_cost: Some(computation_cost),
242            storage_cost: Some(storage_cost),
243            storage_rebate: Some(storage_rebate),
244            non_refundable_storage_fee: Some(non_refundable_storage_fee),
245        }
246    }
247}
248
249impl TryFrom<&GasCostSummary> for sui_sdk_types::GasCostSummary {
250    type Error = TryFromProtoError;
251
252    fn try_from(
253        GasCostSummary {
254            computation_cost,
255            storage_cost,
256            storage_rebate,
257            non_refundable_storage_fee,
258        }: &GasCostSummary,
259    ) -> Result<Self, Self::Error> {
260        let computation_cost =
261            computation_cost.ok_or_else(|| TryFromProtoError::missing("computation_cost"))?;
262        let storage_cost =
263            storage_cost.ok_or_else(|| TryFromProtoError::missing("storage_cost"))?;
264        let storage_rebate =
265            storage_rebate.ok_or_else(|| TryFromProtoError::missing("storage_rebate"))?;
266        let non_refundable_storage_fee = non_refundable_storage_fee
267            .ok_or_else(|| TryFromProtoError::missing("non_refundable_storage_fee"))?;
268        Ok(Self {
269            computation_cost,
270            storage_cost,
271            storage_rebate,
272            non_refundable_storage_fee,
273        })
274    }
275}
276
277//
278// CheckpointCommitment
279//
280
281impl From<sui_sdk_types::CheckpointCommitment> for CheckpointCommitment {
282    fn from(value: sui_sdk_types::CheckpointCommitment) -> Self {
283        use checkpoint_commitment::CheckpointCommitmentKind;
284
285        let mut message = Self::default();
286
287        let kind = match value {
288            sui_sdk_types::CheckpointCommitment::EcmhLiveObjectSet { digest } => {
289                message.digest = Some(digest.to_string());
290                CheckpointCommitmentKind::EcmhLiveObjectSet
291            }
292            sui_sdk_types::CheckpointCommitment::CheckpointArtifacts { digest } => {
293                message.digest = Some(digest.to_string());
294                CheckpointCommitmentKind::CheckpointArtifacts
295            }
296            _ => CheckpointCommitmentKind::Unknown,
297        };
298
299        message.set_kind(kind);
300        message
301    }
302}
303
304impl TryFrom<&CheckpointCommitment> for sui_sdk_types::CheckpointCommitment {
305    type Error = TryFromProtoError;
306
307    fn try_from(value: &CheckpointCommitment) -> Result<Self, Self::Error> {
308        use checkpoint_commitment::CheckpointCommitmentKind;
309
310        match value.kind() {
311            CheckpointCommitmentKind::Unknown => {
312                return Err(TryFromProtoError::invalid(
313                    CheckpointCommitment::KIND_FIELD,
314                    "unknown CheckpointCommitmentKind",
315                ))
316            }
317            CheckpointCommitmentKind::EcmhLiveObjectSet => Self::EcmhLiveObjectSet {
318                digest: value.digest().parse().map_err(|e| {
319                    TryFromProtoError::invalid(CheckpointCommitment::DIGEST_FIELD, e)
320                })?,
321            },
322            CheckpointCommitmentKind::CheckpointArtifacts => Self::CheckpointArtifacts {
323                digest: value.digest().parse().map_err(|e| {
324                    TryFromProtoError::invalid(CheckpointCommitment::DIGEST_FIELD, e)
325                })?,
326            },
327        }
328        .pipe(Ok)
329    }
330}
331
332//
333// EndOfEpochData
334//
335
336impl From<sui_sdk_types::EndOfEpochData> for EndOfEpochData {
337    fn from(
338        sui_sdk_types::EndOfEpochData {
339            next_epoch_committee,
340            next_epoch_protocol_version,
341            epoch_commitments,
342        }: sui_sdk_types::EndOfEpochData,
343    ) -> Self {
344        Self {
345            next_epoch_committee: next_epoch_committee.into_iter().map(Into::into).collect(),
346            next_epoch_protocol_version: Some(next_epoch_protocol_version),
347            epoch_commitments: epoch_commitments.into_iter().map(Into::into).collect(),
348        }
349    }
350}
351
352impl TryFrom<&EndOfEpochData> for sui_sdk_types::EndOfEpochData {
353    type Error = TryFromProtoError;
354
355    fn try_from(
356        EndOfEpochData {
357            next_epoch_committee,
358            next_epoch_protocol_version,
359            epoch_commitments,
360        }: &EndOfEpochData,
361    ) -> Result<Self, Self::Error> {
362        let next_epoch_protocol_version = next_epoch_protocol_version
363            .ok_or_else(|| TryFromProtoError::missing("next_epoch_protocol_version"))?;
364
365        Ok(Self {
366            next_epoch_committee: next_epoch_committee
367                .iter()
368                .map(TryInto::try_into)
369                .collect::<Result<_, _>>()?,
370            next_epoch_protocol_version,
371            epoch_commitments: epoch_commitments
372                .iter()
373                .map(TryInto::try_into)
374                .collect::<Result<_, _>>()?,
375        })
376    }
377}
378
379//
380// CheckpointedTransactionInfo
381//
382
383impl From<sui_sdk_types::CheckpointTransactionInfo> for CheckpointedTransactionInfo {
384    fn from(value: sui_sdk_types::CheckpointTransactionInfo) -> Self {
385        Self {
386            transaction: Some(value.transaction.to_string()),
387            effects: Some(value.effects.to_string()),
388            signatures: value.signatures.into_iter().map(Into::into).collect(),
389        }
390    }
391}
392
393impl TryFrom<&CheckpointedTransactionInfo> for sui_sdk_types::CheckpointTransactionInfo {
394    type Error = TryFromProtoError;
395
396    fn try_from(value: &CheckpointedTransactionInfo) -> Result<Self, Self::Error> {
397        let transaction = value
398            .transaction
399            .as_ref()
400            .ok_or_else(|| TryFromProtoError::missing("transaction"))?
401            .parse()
402            .map_err(|e| {
403                TryFromProtoError::invalid(CheckpointedTransactionInfo::TRANSACTION_FIELD, e)
404            })?;
405
406        let effects = value
407            .effects
408            .as_ref()
409            .ok_or_else(|| TryFromProtoError::missing("effects"))?
410            .parse()
411            .map_err(|e| {
412                TryFromProtoError::invalid(CheckpointedTransactionInfo::EFFECTS_FIELD, e)
413            })?;
414
415        let signatures = value
416            .signatures
417            .iter()
418            .map(TryInto::try_into)
419            .collect::<Result<_, _>>()?;
420
421        Ok(Self {
422            transaction,
423            effects,
424            signatures,
425        })
426    }
427}
428
429//
430// CheckpointContents
431//
432
433impl From<sui_sdk_types::CheckpointContents> for CheckpointContents {
434    fn from(value: sui_sdk_types::CheckpointContents) -> Self {
435        Self::merge_from(value, &FieldMaskTree::new_wildcard())
436    }
437}
438
439impl Merge<sui_sdk_types::CheckpointContents> for CheckpointContents {
440    fn merge(&mut self, source: sui_sdk_types::CheckpointContents, mask: &FieldMaskTree) {
441        if mask.contains(Self::BCS_FIELD.name) {
442            let mut bcs = Bcs::serialize(&source).unwrap();
443            bcs.name = Some("CheckpointContents".to_owned());
444            self.bcs = Some(bcs);
445        }
446
447        if mask.contains(Self::DIGEST_FIELD.name) {
448            self.digest = Some(source.digest().to_string());
449        }
450
451        if mask.contains(Self::VERSION_FIELD.name) {
452            self.version = Some(1);
453        }
454
455        if mask.contains(Self::TRANSACTIONS_FIELD.name) {
456            self.transactions = source.into_v1().into_iter().map(Into::into).collect();
457        }
458    }
459}
460
461impl Merge<&CheckpointContents> for CheckpointContents {
462    fn merge(&mut self, source: &CheckpointContents, mask: &FieldMaskTree) {
463        let CheckpointContents {
464            bcs,
465            digest,
466            version,
467            transactions,
468        } = source;
469
470        if mask.contains(Self::BCS_FIELD.name) {
471            self.bcs = bcs.clone();
472        }
473
474        if mask.contains(Self::DIGEST_FIELD.name) {
475            self.digest = digest.clone();
476        }
477
478        if mask.contains(Self::VERSION_FIELD.name) {
479            self.version = *version;
480        }
481
482        if mask.contains(Self::TRANSACTIONS_FIELD.name) {
483            self.transactions = transactions.clone();
484        }
485    }
486}
487
488impl TryFrom<&CheckpointContents> for sui_sdk_types::CheckpointContents {
489    type Error = TryFromProtoError;
490
491    fn try_from(value: &CheckpointContents) -> Result<Self, Self::Error> {
492        match value.version {
493            Some(1) => {}
494            v => {
495                return Err(TryFromProtoError::invalid(
496                    CheckpointContents::VERSION_FIELD,
497                    format!("unknown type version {v:?}"),
498                ));
499            }
500        }
501
502        Ok(Self::new(
503            value
504                .transactions
505                .iter()
506                .map(TryInto::try_into)
507                .collect::<Result<_, _>>()?,
508        ))
509    }
510}
511
512//
513// Checkpoint
514//
515
516impl Merge<&sui_sdk_types::CheckpointSummary> for Checkpoint {
517    fn merge(&mut self, source: &sui_sdk_types::CheckpointSummary, mask: &FieldMaskTree) {
518        if mask.contains(Self::SEQUENCE_NUMBER_FIELD.name) {
519            self.sequence_number = Some(source.sequence_number);
520        }
521
522        if mask.contains(Self::DIGEST_FIELD.name) {
523            self.digest = Some(source.digest().to_string());
524        }
525
526        if let Some(submask) = mask.subtree(Self::SUMMARY_FIELD.name) {
527            self.summary = Some(CheckpointSummary::merge_from(source.clone(), &submask));
528        }
529    }
530}
531
532impl Merge<sui_sdk_types::ValidatorAggregatedSignature> for Checkpoint {
533    fn merge(&mut self, source: sui_sdk_types::ValidatorAggregatedSignature, mask: &FieldMaskTree) {
534        if mask.contains(Self::SIGNATURE_FIELD.name) {
535            self.signature = Some(source.into());
536        }
537    }
538}
539
540impl Merge<sui_sdk_types::CheckpointContents> for Checkpoint {
541    fn merge(&mut self, source: sui_sdk_types::CheckpointContents, mask: &FieldMaskTree) {
542        if let Some(submask) = mask.subtree(Self::CONTENTS_FIELD.name) {
543            self.contents = Some(CheckpointContents::merge_from(source, &submask));
544        }
545    }
546}
547
548impl Merge<&Checkpoint> for Checkpoint {
549    fn merge(&mut self, source: &Checkpoint, mask: &FieldMaskTree) {
550        let Checkpoint {
551            sequence_number,
552            digest,
553            summary,
554            signature,
555            contents,
556            transactions,
557            objects,
558        } = source;
559
560        if mask.contains(Self::SEQUENCE_NUMBER_FIELD.name) {
561            self.sequence_number = *sequence_number;
562        }
563
564        if mask.contains(Self::DIGEST_FIELD.name) {
565            self.digest = digest.clone();
566        }
567
568        if let Some(submask) = mask.subtree(Self::SUMMARY_FIELD.name) {
569            self.summary = summary
570                .as_ref()
571                .map(|summary| CheckpointSummary::merge_from(summary, &submask));
572        }
573
574        if mask.contains(Self::SIGNATURE_FIELD.name) {
575            self.signature = signature.clone();
576        }
577
578        if let Some(submask) = mask.subtree(Self::CONTENTS_FIELD.name) {
579            self.contents = contents
580                .as_ref()
581                .map(|contents| CheckpointContents::merge_from(contents, &submask));
582        }
583
584        if let Some(submask) = mask.subtree(Self::TRANSACTIONS_FIELD.name) {
585            self.transactions = transactions
586                .iter()
587                .map(|transaction| ExecutedTransaction::merge_from(transaction, &submask))
588                .collect();
589        }
590
591        if let Some(submask) = mask.subtree(Self::OBJECTS_FIELD) {
592            self.objects = objects
593                .as_ref()
594                .map(|objects| ObjectSet::merge_from(objects, &submask));
595        }
596    }
597}