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().cloned().map(Into::into).collect(),
389            address_aliases_versions: value
390                .signatures_with_address_aliases_versions()
391                .map(|(_, version)| AddressAliasesVersion { version })
392                .collect(),
393        }
394    }
395}
396
397impl TryFrom<&CheckpointedTransactionInfo> for sui_sdk_types::CheckpointTransactionInfo {
398    type Error = TryFromProtoError;
399
400    fn try_from(value: &CheckpointedTransactionInfo) -> Result<Self, Self::Error> {
401        let transaction = value
402            .transaction
403            .as_ref()
404            .ok_or_else(|| TryFromProtoError::missing("transaction"))?
405            .parse()
406            .map_err(|e| {
407                TryFromProtoError::invalid(CheckpointedTransactionInfo::TRANSACTION_FIELD, e)
408            })?;
409
410        let effects = value
411            .effects
412            .as_ref()
413            .ok_or_else(|| TryFromProtoError::missing("effects"))?
414            .parse()
415            .map_err(|e| {
416                TryFromProtoError::invalid(CheckpointedTransactionInfo::EFFECTS_FIELD, e)
417            })?;
418
419        let signatures: Vec<sui_sdk_types::UserSignature> = value
420            .signatures
421            .iter()
422            .map(TryInto::try_into)
423            .collect::<Result<_, _>>()?;
424
425        let address_aliases_versions: Vec<Option<u64>> = value
426            .address_aliases_versions
427            .iter()
428            .map(|a| a.version)
429            .collect();
430
431        if signatures.len() == address_aliases_versions.len() {
432            Ok(Self::new_with_address_aliases_versions(
433                transaction,
434                effects,
435                signatures
436                    .into_iter()
437                    .zip(address_aliases_versions)
438                    .collect(),
439            ))
440        } else {
441            Ok(Self::new(transaction, effects, signatures))
442        }
443    }
444}
445
446//
447// CheckpointContents
448//
449
450impl From<sui_sdk_types::CheckpointContents> for CheckpointContents {
451    fn from(value: sui_sdk_types::CheckpointContents) -> Self {
452        Self::merge_from(value, &FieldMaskTree::new_wildcard())
453    }
454}
455
456impl Merge<sui_sdk_types::CheckpointContents> for CheckpointContents {
457    fn merge(&mut self, source: sui_sdk_types::CheckpointContents, mask: &FieldMaskTree) {
458        if mask.contains(Self::BCS_FIELD.name) {
459            let mut bcs = Bcs::serialize(&source).unwrap();
460            bcs.name = Some("CheckpointContents".to_owned());
461            self.bcs = Some(bcs);
462        }
463
464        if mask.contains(Self::DIGEST_FIELD.name) {
465            self.digest = Some(source.digest().to_string());
466        }
467
468        if mask.contains(Self::VERSION_FIELD.name) {
469            self.version = Some(source.version() as _);
470        }
471
472        if mask.contains(Self::TRANSACTIONS_FIELD.name) {
473            self.transactions = source.transactions().iter().map(Into::into).collect();
474        }
475    }
476}
477
478impl Merge<&CheckpointContents> for CheckpointContents {
479    fn merge(&mut self, source: &CheckpointContents, mask: &FieldMaskTree) {
480        let CheckpointContents {
481            bcs,
482            digest,
483            version,
484            transactions,
485        } = source;
486
487        if mask.contains(Self::BCS_FIELD.name) {
488            self.bcs = bcs.clone();
489        }
490
491        if mask.contains(Self::DIGEST_FIELD.name) {
492            self.digest = digest.clone();
493        }
494
495        if mask.contains(Self::VERSION_FIELD.name) {
496            self.version = *version;
497        }
498
499        if mask.contains(Self::TRANSACTIONS_FIELD.name) {
500            self.transactions = transactions.clone();
501        }
502    }
503}
504
505impl TryFrom<&CheckpointContents> for sui_sdk_types::CheckpointContents {
506    type Error = TryFromProtoError;
507
508    fn try_from(value: &CheckpointContents) -> Result<Self, Self::Error> {
509        match value.version {
510            Some(1) => Ok(Self::new_v1(
511                value
512                    .transactions
513                    .iter()
514                    .map(TryInto::try_into)
515                    .collect::<Result<_, _>>()?,
516            )),
517            Some(2) => Ok(Self::new_v2(
518                value
519                    .transactions
520                    .iter()
521                    .map(TryInto::try_into)
522                    .collect::<Result<_, _>>()?,
523            )),
524            v => Err(TryFromProtoError::invalid(
525                CheckpointContents::VERSION_FIELD,
526                format!("unknown type version {v:?}"),
527            )),
528        }
529    }
530}
531
532//
533// Checkpoint
534//
535
536impl Merge<&sui_sdk_types::CheckpointSummary> for Checkpoint {
537    fn merge(&mut self, source: &sui_sdk_types::CheckpointSummary, mask: &FieldMaskTree) {
538        if mask.contains(Self::SEQUENCE_NUMBER_FIELD.name) {
539            self.sequence_number = Some(source.sequence_number);
540        }
541
542        if mask.contains(Self::DIGEST_FIELD.name) {
543            self.digest = Some(source.digest().to_string());
544        }
545
546        if let Some(submask) = mask.subtree(Self::SUMMARY_FIELD.name) {
547            self.summary = Some(CheckpointSummary::merge_from(source.clone(), &submask));
548        }
549    }
550}
551
552impl Merge<sui_sdk_types::ValidatorAggregatedSignature> for Checkpoint {
553    fn merge(&mut self, source: sui_sdk_types::ValidatorAggregatedSignature, mask: &FieldMaskTree) {
554        if mask.contains(Self::SIGNATURE_FIELD.name) {
555            self.signature = Some(source.into());
556        }
557    }
558}
559
560impl Merge<sui_sdk_types::CheckpointContents> for Checkpoint {
561    fn merge(&mut self, source: sui_sdk_types::CheckpointContents, mask: &FieldMaskTree) {
562        if let Some(submask) = mask.subtree(Self::CONTENTS_FIELD.name) {
563            self.contents = Some(CheckpointContents::merge_from(source, &submask));
564        }
565    }
566}
567
568impl Merge<&Checkpoint> for Checkpoint {
569    fn merge(&mut self, source: &Checkpoint, mask: &FieldMaskTree) {
570        let Checkpoint {
571            sequence_number,
572            digest,
573            summary,
574            signature,
575            contents,
576            transactions,
577            objects,
578        } = source;
579
580        if mask.contains(Self::SEQUENCE_NUMBER_FIELD.name) {
581            self.sequence_number = *sequence_number;
582        }
583
584        if mask.contains(Self::DIGEST_FIELD.name) {
585            self.digest = digest.clone();
586        }
587
588        if let Some(submask) = mask.subtree(Self::SUMMARY_FIELD.name) {
589            self.summary = summary
590                .as_ref()
591                .map(|summary| CheckpointSummary::merge_from(summary, &submask));
592        }
593
594        if mask.contains(Self::SIGNATURE_FIELD.name) {
595            self.signature = signature.clone();
596        }
597
598        if let Some(submask) = mask.subtree(Self::CONTENTS_FIELD.name) {
599            self.contents = contents
600                .as_ref()
601                .map(|contents| CheckpointContents::merge_from(contents, &submask));
602        }
603
604        if let Some(submask) = mask.subtree(Self::TRANSACTIONS_FIELD.name) {
605            self.transactions = transactions
606                .iter()
607                .map(|transaction| ExecutedTransaction::merge_from(transaction, &submask))
608                .collect();
609        }
610
611        if let Some(submask) = mask.subtree(Self::OBJECTS_FIELD) {
612            self.objects = objects
613                .as_ref()
614                .map(|objects| ObjectSet::merge_from(objects, &submask));
615        }
616    }
617}