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