sui_rpc/proto/sui/rpc/v2beta2/
effects.rs1use super::*;
2use crate::field::FieldMaskTree;
3use crate::merge::Merge;
4use crate::proto::TryFromProtoError;
5use tap::Pipe;
6
7impl From<sui_sdk_types::TransactionEffects> for TransactionEffects {
12 fn from(value: sui_sdk_types::TransactionEffects) -> Self {
13 Self::merge_from(&value, &FieldMaskTree::new_wildcard())
14 }
15}
16
17impl Merge<&sui_sdk_types::TransactionEffects> for TransactionEffects {
18 fn merge(&mut self, source: &sui_sdk_types::TransactionEffects, mask: &FieldMaskTree) {
19 if mask.contains(Self::BCS_FIELD.name) {
20 let mut bcs = Bcs::serialize(&source).unwrap();
21 bcs.name = Some("TransactionEffects".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 match source {
30 sui_sdk_types::TransactionEffects::V1(v1) => self.merge(v1.as_ref(), mask),
31 sui_sdk_types::TransactionEffects::V2(v2) => self.merge(v2.as_ref(), mask),
32 }
33 }
34}
35
36impl Merge<&TransactionEffects> for TransactionEffects {
37 fn merge(
38 &mut self,
39 TransactionEffects {
40 bcs,
41 digest,
42 version,
43 status,
44 epoch,
45 gas_used,
46 transaction_digest,
47 gas_object,
48 events_digest,
49 dependencies,
50 lamport_version,
51 changed_objects,
52 unchanged_consensus_objects,
53 auxiliary_data_digest,
54 }: &TransactionEffects,
55 mask: &FieldMaskTree,
56 ) {
57 if mask.contains(Self::BCS_FIELD.name) {
58 self.bcs = bcs.clone();
59 }
60
61 if mask.contains(Self::DIGEST_FIELD.name) {
62 self.digest = digest.clone();
63 }
64 if mask.contains(Self::VERSION_FIELD.name) {
65 self.version = *version;
66 }
67
68 if mask.contains(Self::STATUS_FIELD.name) {
69 self.status = status.clone();
70 }
71
72 if mask.contains(Self::EPOCH_FIELD.name) {
73 self.epoch = *epoch;
74 }
75
76 if mask.contains(Self::GAS_USED_FIELD.name) {
77 self.gas_used = *gas_used;
78 }
79
80 if mask.contains(Self::TRANSACTION_DIGEST_FIELD.name) {
81 self.transaction_digest = transaction_digest.clone();
82 }
83
84 if mask.contains(Self::GAS_OBJECT_FIELD.name) {
85 self.gas_object = gas_object.clone();
86 }
87
88 if mask.contains(Self::EVENTS_DIGEST_FIELD.name) {
89 self.events_digest = events_digest.clone();
90 }
91
92 if mask.contains(Self::DEPENDENCIES_FIELD.name) {
93 self.dependencies = dependencies.clone();
94 }
95
96 if mask.contains(Self::LAMPORT_VERSION_FIELD.name) {
97 self.lamport_version = *lamport_version;
98 }
99
100 if mask.contains(Self::CHANGED_OBJECTS_FIELD.name) {
101 self.changed_objects = changed_objects.clone();
102 }
103
104 if mask.contains(Self::UNCHANGED_CONSENSUS_OBJECTS_FIELD.name) {
105 self.unchanged_consensus_objects = unchanged_consensus_objects.clone();
106 }
107
108 if mask.contains(Self::AUXILIARY_DATA_DIGEST_FIELD.name) {
109 self.auxiliary_data_digest = auxiliary_data_digest.clone();
110 }
111 }
112}
113
114impl TryFrom<&TransactionEffects> for sui_sdk_types::TransactionEffects {
115 type Error = TryFromProtoError;
116
117 fn try_from(value: &TransactionEffects) -> Result<Self, Self::Error> {
118 value
119 .bcs
120 .as_ref()
121 .ok_or_else(|| TryFromProtoError::missing("bcs"))?
122 .deserialize()
123 .map_err(|e| TryFromProtoError::invalid(TransactionEffects::BCS_FIELD, e))
124 }
125}
126
127impl Merge<&sui_sdk_types::TransactionEffectsV1> for TransactionEffects {
132 fn merge(
133 &mut self,
134 sui_sdk_types::TransactionEffectsV1 {
135 status,
136 epoch,
137 gas_used,
138 modified_at_versions,
139 consensus_objects,
140 transaction_digest,
141 created,
142 mutated,
143 unwrapped,
144 deleted,
145 unwrapped_then_deleted,
146 wrapped,
147 gas_object,
148 events_digest,
149 dependencies,
150 }: &sui_sdk_types::TransactionEffectsV1,
151 mask: &FieldMaskTree,
152 ) {
153 if mask.contains(Self::VERSION_FIELD.name) {
154 self.version = Some(1);
155 }
156
157 if mask.contains(Self::STATUS_FIELD.name) {
158 self.status = Some(status.clone().into());
159 }
160
161 if mask.contains(Self::EPOCH_FIELD.name) {
162 self.epoch = Some(*epoch);
163 }
164
165 if mask.contains(Self::GAS_USED_FIELD.name) {
166 self.gas_used = Some(gas_used.clone().into());
167 }
168
169 if mask.contains(Self::TRANSACTION_DIGEST_FIELD.name) {
170 self.transaction_digest = Some(transaction_digest.to_string());
171 }
172
173 if mask.contains(Self::EVENTS_DIGEST_FIELD.name) {
174 self.events_digest = events_digest.map(|d| d.to_string());
175 }
176
177 if mask.contains(Self::DEPENDENCIES_FIELD.name) {
178 self.dependencies = dependencies.iter().map(ToString::to_string).collect();
179 }
180
181 if mask.contains(Self::CHANGED_OBJECTS_FIELD.name)
182 || mask.contains(Self::UNCHANGED_CONSENSUS_OBJECTS_FIELD.name)
183 || mask.contains(Self::GAS_OBJECT_FIELD.name)
184 {
185 let mut changed_objects = Vec::new();
186 let mut unchanged_consensus_objects = Vec::new();
187
188 for object in created {
189 let change = ChangedObject {
190 object_id: Some(object.reference.object_id().to_string()),
191 input_state: Some(changed_object::InputObjectState::DoesNotExist.into()),
192 input_version: None,
193 input_digest: None,
194 input_owner: None,
195 output_state: Some(changed_object::OutputObjectState::ObjectWrite.into()),
196 output_version: Some(object.reference.version()),
197 output_digest: Some(object.reference.digest().to_string()),
198 output_owner: Some(object.owner.into()),
199 id_operation: Some(changed_object::IdOperation::Created.into()),
200 object_type: None,
201 };
202
203 changed_objects.push(change);
204 }
205
206 for object in mutated {
207 let change = ChangedObject {
208 object_id: Some(object.reference.object_id().to_string()),
209 input_state: Some(changed_object::InputObjectState::Exists.into()),
210 input_version: None,
211 input_digest: None,
212 input_owner: None,
213 output_state: Some(changed_object::OutputObjectState::ObjectWrite.into()),
214 output_version: Some(object.reference.version()),
215 output_digest: Some(object.reference.digest().to_string()),
216 output_owner: Some(object.owner.into()),
217 id_operation: Some(changed_object::IdOperation::None.into()),
218 object_type: None,
219 };
220
221 changed_objects.push(change);
222 }
223
224 for object in unwrapped {
225 let change = ChangedObject {
226 object_id: Some(object.reference.object_id().to_string()),
227 input_state: Some(changed_object::InputObjectState::DoesNotExist.into()),
228 input_version: None,
229 input_digest: None,
230 input_owner: None,
231 output_state: Some(changed_object::OutputObjectState::ObjectWrite.into()),
232 output_version: Some(object.reference.version()),
233 output_digest: Some(object.reference.digest().to_string()),
234 output_owner: Some(object.owner.into()),
235 id_operation: Some(changed_object::IdOperation::None.into()),
236 object_type: None,
237 };
238
239 changed_objects.push(change);
240 }
241
242 for object in deleted {
243 let change = ChangedObject {
244 object_id: Some(object.object_id().to_string()),
245 input_state: Some(changed_object::InputObjectState::Exists.into()),
246 input_version: None,
247 input_digest: None,
248 input_owner: None,
249 output_state: Some(changed_object::OutputObjectState::DoesNotExist.into()),
250 output_version: Some(object.version()),
251 output_digest: Some(object.digest().to_string()),
252 output_owner: None,
253 id_operation: Some(changed_object::IdOperation::Deleted.into()),
254 object_type: None,
255 };
256
257 changed_objects.push(change);
258 }
259
260 for object in unwrapped_then_deleted {
261 let change = ChangedObject {
262 object_id: Some(object.object_id().to_string()),
263 input_state: Some(changed_object::InputObjectState::DoesNotExist.into()),
264 input_version: None,
265 input_digest: None,
266 input_owner: None,
267 output_state: Some(changed_object::OutputObjectState::DoesNotExist.into()),
268 output_version: Some(object.version()),
269 output_digest: Some(object.digest().to_string()),
270 output_owner: None,
271 id_operation: Some(changed_object::IdOperation::Deleted.into()),
272 object_type: None,
273 };
274
275 changed_objects.push(change);
276 }
277
278 for object in wrapped {
279 let change = ChangedObject {
280 object_id: Some(object.object_id().to_string()),
281 input_state: Some(changed_object::InputObjectState::Exists.into()),
282 input_version: None,
283 input_digest: None,
284 input_owner: None,
285 output_state: Some(changed_object::OutputObjectState::DoesNotExist.into()),
286 output_version: Some(object.version()),
287 output_digest: Some(object.digest().to_string()),
288 output_owner: None,
289 id_operation: Some(changed_object::IdOperation::Deleted.into()),
290 object_type: None,
291 };
292
293 changed_objects.push(change);
294 }
295
296 for modified_at_version in modified_at_versions {
297 let object_id = modified_at_version.object_id.to_string();
298 let version = modified_at_version.version;
299 if let Some(changed_object) = changed_objects
300 .iter_mut()
301 .find(|object| object.object_id() == object_id)
302 {
303 changed_object.input_version = Some(version);
304 }
305 }
306
307 for object in consensus_objects {
308 let object_id = object.object_id().to_string();
309 let version = object.version();
310 let digest = object.digest().to_string();
311
312 if let Some(changed_object) = changed_objects
313 .iter_mut()
314 .find(|object| object.object_id() == object_id)
315 {
316 changed_object.input_version = Some(version);
317 changed_object.input_digest = Some(digest);
318 } else {
319 let unchanged_consensus_object = UnchangedConsensusObject {
320 kind: Some(
321 unchanged_consensus_object::UnchangedConsensusObjectKind::ReadOnlyRoot
322 .into(),
323 ),
324 object_id: Some(object_id),
325 version: Some(version),
326 digest: Some(digest),
327 object_type: None,
328 };
329
330 unchanged_consensus_objects.push(unchanged_consensus_object);
331 }
332 }
333
334 if mask.contains(Self::GAS_OBJECT_FIELD.name) {
335 let gas_object_id = gas_object.reference.object_id().to_string();
336 self.gas_object = changed_objects
337 .iter()
338 .find(|object| object.object_id() == gas_object_id)
339 .cloned();
340 }
341
342 if mask.contains(Self::CHANGED_OBJECTS_FIELD.name) {
343 self.changed_objects = changed_objects;
344 }
345
346 if mask.contains(Self::UNCHANGED_CONSENSUS_OBJECTS_FIELD.name) {
347 self.unchanged_consensus_objects = unchanged_consensus_objects;
348 }
349 }
350 }
351}
352
353impl Merge<&sui_sdk_types::TransactionEffectsV2> for TransactionEffects {
358 fn merge(
359 &mut self,
360 sui_sdk_types::TransactionEffectsV2 {
361 status,
362 epoch,
363 gas_used,
364 transaction_digest,
365 gas_object_index,
366 events_digest,
367 dependencies,
368 lamport_version,
369 changed_objects,
370 unchanged_consensus_objects,
371 auxiliary_data_digest,
372 }: &sui_sdk_types::TransactionEffectsV2,
373 mask: &FieldMaskTree,
374 ) {
375 if mask.contains(Self::VERSION_FIELD.name) {
376 self.version = Some(2);
377 }
378
379 if mask.contains(Self::STATUS_FIELD.name) {
380 self.status = Some(status.clone().into());
381 }
382
383 if mask.contains(Self::EPOCH_FIELD.name) {
384 self.epoch = Some(*epoch);
385 }
386
387 if mask.contains(Self::GAS_USED_FIELD.name) {
388 self.gas_used = Some(gas_used.clone().into());
389 }
390
391 if mask.contains(Self::TRANSACTION_DIGEST_FIELD.name) {
392 self.transaction_digest = Some(transaction_digest.to_string());
393 }
394
395 if mask.contains(Self::GAS_OBJECT_FIELD.name) {
396 self.gas_object = gas_object_index
397 .map(|index| changed_objects.get(index as usize).cloned().map(Into::into))
398 .flatten();
399 }
400
401 if mask.contains(Self::EVENTS_DIGEST_FIELD.name) {
402 self.events_digest = events_digest.map(|d| d.to_string());
403 }
404
405 if mask.contains(Self::DEPENDENCIES_FIELD.name) {
406 self.dependencies = dependencies.iter().map(ToString::to_string).collect();
407 }
408
409 if mask.contains(Self::LAMPORT_VERSION_FIELD.name) {
410 self.lamport_version = Some(*lamport_version);
411 }
412
413 if mask.contains(Self::CHANGED_OBJECTS_FIELD.name) {
414 self.changed_objects = changed_objects
415 .clone()
416 .into_iter()
417 .map(Into::into)
418 .collect();
419 }
420
421 for object in self.changed_objects.iter_mut().chain(&mut self.gas_object) {
422 if object.output_digest.is_some() && object.output_version.is_none() {
423 object.output_version = Some(*lamport_version);
424 }
425 }
426
427 if mask.contains(Self::UNCHANGED_CONSENSUS_OBJECTS_FIELD.name) {
428 self.unchanged_consensus_objects = unchanged_consensus_objects
429 .clone()
430 .into_iter()
431 .map(Into::into)
432 .collect();
433 }
434
435 if mask.contains(Self::AUXILIARY_DATA_DIGEST_FIELD.name) {
436 self.auxiliary_data_digest = auxiliary_data_digest.map(|d| d.to_string());
437 }
438 }
439}
440
441impl From<sui_sdk_types::ChangedObject> for ChangedObject {
446 fn from(value: sui_sdk_types::ChangedObject) -> Self {
447 use changed_object::InputObjectState;
448 use changed_object::OutputObjectState;
449
450 let mut message = Self {
451 object_id: Some(value.object_id.to_string()),
452 ..Default::default()
453 };
454
455 let input_state = match value.input_state {
457 sui_sdk_types::ObjectIn::NotExist => InputObjectState::DoesNotExist,
458 sui_sdk_types::ObjectIn::Exist {
459 version,
460 digest,
461 owner,
462 } => {
463 message.input_version = Some(version);
464 message.input_digest = Some(digest.to_string());
465 message.input_owner = Some(owner.into());
466 InputObjectState::Exists
467 }
468 _ => InputObjectState::Unknown,
469 };
470 message.set_input_state(input_state);
471
472 let output_state = match value.output_state {
474 sui_sdk_types::ObjectOut::NotExist => OutputObjectState::DoesNotExist,
475 sui_sdk_types::ObjectOut::ObjectWrite { digest, owner } => {
476 message.output_digest = Some(digest.to_string());
477 message.output_owner = Some(owner.into());
478 OutputObjectState::ObjectWrite
479 }
480 sui_sdk_types::ObjectOut::PackageWrite { version, digest } => {
481 message.output_version = Some(version);
482 message.output_digest = Some(digest.to_string());
483 OutputObjectState::PackageWrite
484 }
485 _ => OutputObjectState::Unknown,
486 };
487 message.set_output_state(output_state);
488
489 message.set_id_operation(value.id_operation.into());
490 message
491 }
492}
493
494impl TryFrom<&ChangedObject> for sui_sdk_types::ChangedObject {
495 type Error = TryFromProtoError;
496
497 fn try_from(value: &ChangedObject) -> Result<Self, Self::Error> {
498 use changed_object::InputObjectState;
499 use changed_object::OutputObjectState;
500
501 let object_id = value
502 .object_id
503 .as_ref()
504 .ok_or_else(|| TryFromProtoError::missing("object_id"))?
505 .parse()
506 .map_err(|e| TryFromProtoError::invalid(ChangedObject::OBJECT_ID_FIELD, e))?;
507
508 let input_state = match value.input_state() {
509 InputObjectState::Unknown => {
510 return Err(TryFromProtoError::invalid(
511 ChangedObject::INPUT_STATE_FIELD,
512 "unknown InputObjectState",
513 ));
514 }
515 InputObjectState::DoesNotExist => sui_sdk_types::ObjectIn::NotExist,
516 InputObjectState::Exists => sui_sdk_types::ObjectIn::Exist {
517 version: value
518 .input_version
519 .ok_or_else(|| TryFromProtoError::missing("version"))?,
520 digest: value
521 .input_digest
522 .as_ref()
523 .ok_or_else(|| TryFromProtoError::missing("digest"))?
524 .parse()
525 .map_err(|e| {
526 TryFromProtoError::invalid(ChangedObject::INPUT_DIGEST_FIELD, e)
527 })?,
528 owner: value
529 .input_owner
530 .as_ref()
531 .ok_or_else(|| TryFromProtoError::missing("owner"))?
532 .try_into()?,
533 },
534 };
535
536 let output_state = match value.output_state() {
537 OutputObjectState::Unknown => {
538 return Err(TryFromProtoError::invalid(
539 ChangedObject::OUTPUT_STATE_FIELD,
540 "unknown OutputObjectState",
541 ))
542 }
543 OutputObjectState::DoesNotExist => sui_sdk_types::ObjectOut::NotExist,
544 OutputObjectState::ObjectWrite => sui_sdk_types::ObjectOut::ObjectWrite {
545 digest: value
546 .output_digest
547 .as_ref()
548 .ok_or_else(|| TryFromProtoError::missing("digest"))?
549 .parse()
550 .map_err(|e| {
551 TryFromProtoError::invalid(ChangedObject::OUTPUT_DIGEST_FIELD, e)
552 })?,
553
554 owner: value
555 .output_owner
556 .as_ref()
557 .ok_or_else(|| TryFromProtoError::missing("owner"))?
558 .try_into()?,
559 },
560 OutputObjectState::PackageWrite => sui_sdk_types::ObjectOut::PackageWrite {
561 version: value
562 .output_version
563 .ok_or_else(|| TryFromProtoError::missing("version"))?,
564 digest: value
565 .output_digest
566 .as_ref()
567 .ok_or_else(|| TryFromProtoError::missing("digest"))?
568 .parse()
569 .map_err(|e| {
570 TryFromProtoError::invalid(ChangedObject::OUTPUT_DIGEST_FIELD, e)
571 })?,
572 },
573 };
574
575 let id_operation = value.id_operation().try_into()?;
576
577 Ok(Self {
578 object_id,
579 input_state,
580 output_state,
581 id_operation,
582 })
583 }
584}
585
586impl From<sui_sdk_types::IdOperation> for changed_object::IdOperation {
591 fn from(value: sui_sdk_types::IdOperation) -> Self {
592 use sui_sdk_types::IdOperation::*;
593
594 match value {
595 None => Self::None,
596 Created => Self::Created,
597 Deleted => Self::Deleted,
598 _ => Self::Unknown,
599 }
600 }
601}
602
603impl TryFrom<changed_object::IdOperation> for sui_sdk_types::IdOperation {
604 type Error = TryFromProtoError;
605
606 fn try_from(value: changed_object::IdOperation) -> Result<Self, Self::Error> {
607 use changed_object::IdOperation;
608
609 match value {
610 IdOperation::Unknown => {
611 return Err(TryFromProtoError::invalid(
612 "id_operation",
613 "unknown IdOperation",
614 ))
615 }
616 IdOperation::None => Self::None,
617 IdOperation::Created => Self::Created,
618 IdOperation::Deleted => Self::Deleted,
619 }
620 .pipe(Ok)
621 }
622}
623
624impl From<sui_sdk_types::UnchangedConsensusObject> for UnchangedConsensusObject {
629 fn from(value: sui_sdk_types::UnchangedConsensusObject) -> Self {
630 use sui_sdk_types::UnchangedConsensusKind::*;
631 use unchanged_consensus_object::UnchangedConsensusObjectKind;
632
633 let mut message = Self {
634 object_id: Some(value.object_id.to_string()),
635 ..Default::default()
636 };
637
638 let kind = match value.kind {
639 ReadOnlyRoot { version, digest } => {
640 message.version = Some(version);
641 message.digest = Some(digest.to_string());
642 UnchangedConsensusObjectKind::ReadOnlyRoot
643 }
644 MutateDeleted { version } => {
645 message.version = Some(version);
646 UnchangedConsensusObjectKind::MutateConsensusStreamEnded
647 }
648 ReadDeleted { version } => {
649 message.version = Some(version);
650 UnchangedConsensusObjectKind::ReadConsensusStreamEnded
651 }
652 Canceled { version } => {
653 message.version = Some(version);
654 UnchangedConsensusObjectKind::Canceled
655 }
656 PerEpochConfig => UnchangedConsensusObjectKind::PerEpochConfig,
657 PerEpochConfigWithSequenceNumber { version } => {
658 message.version = Some(version);
659 UnchangedConsensusObjectKind::PerEpochConfig
660 }
661 _ => UnchangedConsensusObjectKind::Unknown,
662 };
663
664 message.set_kind(kind);
665 message
666 }
667}
668
669impl TryFrom<&UnchangedConsensusObject> for sui_sdk_types::UnchangedConsensusObject {
670 type Error = TryFromProtoError;
671
672 fn try_from(value: &UnchangedConsensusObject) -> Result<Self, Self::Error> {
673 use sui_sdk_types::UnchangedConsensusKind;
674 use unchanged_consensus_object::UnchangedConsensusObjectKind;
675
676 let object_id = value
677 .object_id
678 .as_ref()
679 .ok_or_else(|| TryFromProtoError::missing("object_id"))?
680 .parse()
681 .map_err(|e| {
682 TryFromProtoError::invalid(UnchangedConsensusObject::OBJECT_ID_FIELD, e)
683 })?;
684
685 let kind = match value.kind() {
686 UnchangedConsensusObjectKind::Unknown => {
687 return Err(TryFromProtoError::invalid(
688 UnchangedConsensusObject::KIND_FIELD,
689 "unknown InputKind",
690 ))
691 }
692
693 UnchangedConsensusObjectKind::ReadOnlyRoot => UnchangedConsensusKind::ReadOnlyRoot {
694 version: value
695 .version
696 .ok_or_else(|| TryFromProtoError::missing("version"))?,
697
698 digest: value
699 .digest
700 .as_ref()
701 .ok_or_else(|| TryFromProtoError::missing("digest"))?
702 .parse()
703 .map_err(|e| {
704 TryFromProtoError::invalid(UnchangedConsensusObject::DIGEST_FIELD, e)
705 })?,
706 },
707 UnchangedConsensusObjectKind::MutateConsensusStreamEnded => {
708 UnchangedConsensusKind::MutateDeleted {
709 version: value
710 .version
711 .ok_or_else(|| TryFromProtoError::missing("version"))?,
712 }
713 }
714 UnchangedConsensusObjectKind::ReadConsensusStreamEnded => {
715 UnchangedConsensusKind::ReadDeleted {
716 version: value
717 .version
718 .ok_or_else(|| TryFromProtoError::missing("version"))?,
719 }
720 }
721 UnchangedConsensusObjectKind::Canceled => UnchangedConsensusKind::Canceled {
722 version: value
723 .version
724 .ok_or_else(|| TryFromProtoError::missing("version"))?,
725 },
726 UnchangedConsensusObjectKind::PerEpochConfig => {
727 if let Some(version) = value.version {
728 UnchangedConsensusKind::PerEpochConfigWithSequenceNumber { version }
729 } else {
730 UnchangedConsensusKind::PerEpochConfig
731 }
732 }
733 };
734
735 Ok(Self { object_id, kind })
736 }
737}