1use crate::base_types::{ObjectID, SequenceNumber, TransactionDigest};
5use crate::crypto::{AuthoritySignInfo, AuthorityStrongQuorumSignInfo};
6use crate::effects::{
7 SignedTransactionEffects, TransactionEvents, VerifiedSignedTransactionEffects,
8};
9use crate::error::{SuiError, SuiErrorKind};
10use crate::object::Object;
11use crate::transaction::{CertifiedTransaction, SenderSignedData, SignedTransaction, Transaction};
12
13use bytes::Bytes;
14use move_core_types::annotated_value::MoveStructLayout;
15use serde::{Deserialize, Serialize};
16
17use mysten_metrics::TX_TYPE_SHARED_OBJ_TX;
18use mysten_metrics::TX_TYPE_SINGLE_WRITER_TX;
19
20use strum::EnumIter;
21
22#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
23pub enum ObjectInfoRequestKind {
24 LatestObjectInfo,
26 PastObjectInfoDebug(SequenceNumber),
31}
32
33#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
35pub enum LayoutGenerationOption {
36 Generate,
37 None,
38}
39
40#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
43pub struct ObjectInfoRequest {
44 pub object_id: ObjectID,
46 pub generate_layout: LayoutGenerationOption,
48 pub request_kind: ObjectInfoRequestKind,
50}
51
52impl ObjectInfoRequest {
53 pub fn past_object_info_debug_request(
54 object_id: ObjectID,
55 version: SequenceNumber,
56 generate_layout: LayoutGenerationOption,
57 ) -> Self {
58 ObjectInfoRequest {
59 object_id,
60 generate_layout,
61 request_kind: ObjectInfoRequestKind::PastObjectInfoDebug(version),
62 }
63 }
64
65 pub fn latest_object_info_request(
66 object_id: ObjectID,
67 generate_layout: LayoutGenerationOption,
68 ) -> Self {
69 ObjectInfoRequest {
70 object_id,
71 generate_layout,
72 request_kind: ObjectInfoRequestKind::LatestObjectInfo,
73 }
74 }
75}
76
77#[derive(Debug, Clone, Serialize, Deserialize)]
79pub struct ObjectInfoResponse {
80 pub object: Object,
82 pub layout: Option<MoveStructLayout>,
85 pub lock_for_debugging: Option<SignedTransaction>,
90}
91
92#[derive(Debug, Clone)]
95pub struct VerifiedObjectInfoResponse {
96 pub object: Object,
98}
99
100#[derive(Clone, Debug, Serialize, Deserialize)]
101pub struct TransactionInfoRequest {
102 pub transaction_digest: TransactionDigest,
103}
104
105#[derive(Clone, Debug, Serialize, Deserialize)]
106#[allow(clippy::large_enum_variant)]
107pub enum TransactionStatus {
108 Signed(AuthoritySignInfo),
110 Executed(
115 Option<AuthorityStrongQuorumSignInfo>,
116 SignedTransactionEffects,
117 TransactionEvents,
118 ),
119}
120
121impl TransactionStatus {
122 pub fn into_signed_for_testing(self) -> AuthoritySignInfo {
123 match self {
124 Self::Signed(s) => s,
125 _ => unreachable!("Incorrect response type"),
126 }
127 }
128
129 pub fn into_effects_for_testing(self) -> SignedTransactionEffects {
130 match self {
131 Self::Executed(_, e, _) => e,
132 _ => unreachable!("Incorrect response type"),
133 }
134 }
135}
136
137impl PartialEq for TransactionStatus {
138 fn eq(&self, other: &Self) -> bool {
139 match self {
140 Self::Signed(s1) => match other {
141 Self::Signed(s2) => s1.epoch == s2.epoch,
142 _ => false,
143 },
144 Self::Executed(c1, e1, ev1) => match other {
145 Self::Executed(c2, e2, ev2) => {
146 c1.as_ref().map(|a| a.epoch) == c2.as_ref().map(|a| a.epoch)
147 && e1.epoch() == e2.epoch()
148 && e1.digest() == e2.digest()
149 && ev1.digest() == ev2.digest()
150 }
151 _ => false,
152 },
153 }
154 }
155}
156
157#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
158pub struct HandleTransactionResponse {
159 pub status: TransactionStatus,
160}
161
162#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
163pub struct TransactionInfoResponse {
164 pub transaction: SenderSignedData,
165 pub status: TransactionStatus,
166}
167
168#[derive(Clone, Debug, Serialize, Deserialize)]
169pub struct HandleCertificateResponseV2 {
170 pub signed_effects: SignedTransactionEffects,
171 pub events: TransactionEvents,
172 pub fastpath_input_objects: Vec<Object>,
174}
175
176#[derive(Clone, Debug, Serialize, Deserialize)]
177pub struct SubmitCertificateResponse {
178 pub executed: Option<HandleCertificateResponseV2>,
180}
181
182#[derive(Clone, Debug)]
183pub struct VerifiedHandleCertificateResponse {
184 pub signed_effects: VerifiedSignedTransactionEffects,
185 pub events: TransactionEvents,
186}
187
188#[derive(Serialize, Deserialize, Clone, Debug)]
189pub struct SystemStateRequest {
190 pub _unused: bool,
192}
193
194#[derive(Clone, Debug, Serialize, Deserialize)]
202pub struct HandleCertificateResponseV3 {
203 pub effects: SignedTransactionEffects,
204 pub events: Option<TransactionEvents>,
205
206 pub input_objects: Option<Vec<Object>>,
213
214 pub output_objects: Option<Vec<Object>>,
218 pub auxiliary_data: Option<Vec<u8>>,
219}
220
221#[derive(Clone, Debug, Serialize, Deserialize)]
222pub struct HandleCertificateRequestV3 {
223 pub certificate: CertifiedTransaction,
224
225 pub include_events: bool,
226 pub include_input_objects: bool,
227 pub include_output_objects: bool,
228 pub include_auxiliary_data: bool,
229}
230
231impl From<HandleCertificateResponseV3> for HandleCertificateResponseV2 {
232 fn from(value: HandleCertificateResponseV3) -> Self {
233 Self {
234 signed_effects: value.effects,
235 events: value.events.unwrap_or_default(),
236 fastpath_input_objects: Vec::new(),
237 }
238 }
239}
240
241#[derive(Clone, Debug, Serialize, Deserialize)]
248pub struct HandleSoftBundleCertificatesResponseV3 {
249 pub responses: Vec<HandleCertificateResponseV3>,
250}
251
252#[derive(Clone, Debug, Serialize, Deserialize)]
254pub struct HandleSoftBundleCertificatesRequestV3 {
255 pub certificates: Vec<CertifiedTransaction>,
256
257 pub wait_for_effects: bool,
258 pub include_events: bool,
259 pub include_input_objects: bool,
260 pub include_output_objects: bool,
261 pub include_auxiliary_data: bool,
262}
263
264#[derive(Default, Clone)]
267pub struct ExecutedData {
268 pub effects: crate::effects::TransactionEffects,
269 pub events: Option<crate::effects::TransactionEvents>,
270 pub input_objects: Vec<crate::object::Object>,
271 pub output_objects: Vec<crate::object::Object>,
272}
273
274#[derive(Clone, prost::Message)]
275pub struct RawExecutedData {
276 #[prost(bytes = "bytes", tag = "1")]
277 pub effects: Bytes,
278 #[prost(bytes = "bytes", optional, tag = "2")]
279 pub events: Option<Bytes>,
280 #[prost(bytes = "bytes", repeated, tag = "3")]
281 pub input_objects: Vec<Bytes>,
282 #[prost(bytes = "bytes", repeated, tag = "4")]
283 pub output_objects: Vec<Bytes>,
284}
285
286#[derive(Clone, Debug)]
290pub struct SubmitTxRequest {
291 pub transaction: Option<Transaction>,
292 pub ping_type: Option<PingType>,
293}
294
295impl From<Transaction> for SubmitTxRequest {
296 fn from(transaction: Transaction) -> Self {
297 Self::new_transaction(transaction)
298 }
299}
300
301impl SubmitTxRequest {
302 pub fn new_transaction(transaction: Transaction) -> Self {
303 Self {
304 transaction: Some(transaction),
305 ping_type: None,
306 }
307 }
308
309 pub fn new_ping() -> Self {
310 Self {
311 transaction: None,
312 ping_type: Some(PingType::Consensus),
313 }
314 }
315
316 pub fn tx_type(&self) -> TxType {
317 if self.ping_type.is_some() {
318 return TxType::SharedObject;
319 }
320 let transaction = self.transaction.as_ref().unwrap();
321 if transaction.is_consensus_tx() {
322 TxType::SharedObject
323 } else {
324 TxType::SingleWriter
325 }
326 }
327
328 pub fn tx_digest(&self) -> Option<TransactionDigest> {
331 self.transaction.as_ref().map(|t| *t.digest())
332 }
333}
334
335#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EnumIter)]
336pub enum TxType {
337 SingleWriter,
338 SharedObject,
339}
340
341impl TxType {
342 pub fn as_str(&self) -> &str {
343 match self {
344 TxType::SingleWriter => TX_TYPE_SINGLE_WRITER_TX,
345 TxType::SharedObject => TX_TYPE_SHARED_OBJ_TX,
346 }
347 }
348}
349
350impl SubmitTxRequest {
351 pub fn into_raw(&self) -> Result<RawSubmitTxRequest, SuiError> {
352 let transactions = if let Some(transaction) = &self.transaction {
353 vec![
354 bcs::to_bytes(&transaction)
355 .map_err(|e| SuiErrorKind::TransactionSerializationError {
356 error: e.to_string(),
357 })?
358 .into(),
359 ]
360 } else {
361 vec![]
362 };
363
364 let submit_type = if self.ping_type.is_some() {
365 SubmitTxType::Ping
366 } else {
367 SubmitTxType::Default
368 };
369
370 Ok(RawSubmitTxRequest {
371 transactions,
372 submit_type: submit_type.into(),
373 })
374 }
375}
376
377#[derive(Clone)]
378pub enum SubmitTxResult {
379 Submitted {
380 consensus_position: crate::messages_consensus::ConsensusPosition,
381 },
382 Executed {
383 effects_digest: crate::digests::TransactionEffectsDigest,
384 details: Option<Box<ExecutedData>>,
387 },
388 Rejected {
389 error: crate::error::SuiError,
390 },
391}
392
393impl std::fmt::Debug for SubmitTxResult {
394 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
395 match self {
396 Self::Submitted { consensus_position } => f
397 .debug_struct("Submitted")
398 .field("consensus_position", consensus_position)
399 .finish(),
400 Self::Executed { effects_digest, .. } => f
401 .debug_struct("Executed")
402 .field("effects_digest", &format_args!("{}", effects_digest))
403 .finish(),
404 Self::Rejected { error } => f.debug_struct("Rejected").field("error", &error).finish(),
405 }
406 }
407}
408
409#[derive(Clone, Debug)]
410pub struct SubmitTxResponse {
411 pub results: Vec<SubmitTxResult>,
412}
413
414#[derive(Clone, prost::Message)]
415pub struct RawSubmitTxRequest {
416 #[prost(bytes = "bytes", repeated, tag = "1")]
418 pub transactions: Vec<Bytes>,
419
420 #[prost(enumeration = "SubmitTxType", tag = "2")]
422 pub submit_type: i32,
423}
424
425#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, prost::Enumeration)]
426#[repr(i32)]
427pub enum SubmitTxType {
428 Default = 0,
432 Ping = 1,
434 SoftBundle = 2,
437}
438
439#[derive(Clone, prost::Message)]
440pub struct RawSubmitTxResponse {
441 #[prost(message, repeated, tag = "1")]
443 pub results: Vec<RawSubmitTxResult>,
444}
445
446#[derive(Clone, prost::Message)]
447pub struct RawSubmitTxResult {
448 #[prost(oneof = "RawValidatorSubmitStatus", tags = "1, 2, 3")]
449 pub inner: Option<RawValidatorSubmitStatus>,
450}
451
452#[derive(Clone, prost::Oneof)]
453pub enum RawValidatorSubmitStatus {
454 #[prost(bytes = "bytes", tag = "1")]
456 Submitted(Bytes),
457
458 #[prost(message, tag = "2")]
460 Executed(RawExecutedStatus),
461
462 #[prost(message, tag = "3")]
464 Rejected(RawRejectedStatus),
465}
466
467#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, prost::Enumeration)]
468#[repr(i32)]
469pub enum PingType {
470 Consensus = 0,
473}
474
475impl PingType {
476 pub fn as_str(&self) -> &str {
477 match self {
478 PingType::Consensus => "consensus",
479 }
480 }
481}
482
483pub struct WaitForEffectsRequest {
486 pub transaction_digest: Option<crate::digests::TransactionDigest>,
487 pub consensus_position: Option<crate::messages_consensus::ConsensusPosition>,
492 pub include_details: bool,
495 pub ping_type: Option<PingType>,
497}
498
499#[derive(Clone)]
500pub enum WaitForEffectsResponse {
501 Executed {
502 effects_digest: crate::digests::TransactionEffectsDigest,
503 details: Option<Box<ExecutedData>>,
504 },
505 Rejected {
507 error: Option<crate::error::SuiError>,
510 },
511 Expired {
514 epoch: u64,
515 round: Option<u32>,
516 },
517}
518
519impl std::fmt::Debug for WaitForEffectsResponse {
520 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
521 match self {
522 Self::Executed { effects_digest, .. } => f
523 .debug_struct("Executed")
524 .field("effects_digest", effects_digest)
525 .finish(),
526 Self::Rejected { error } => f.debug_struct("Rejected").field("error", error).finish(),
527 Self::Expired { epoch, round } => f
528 .debug_struct("Expired")
529 .field("epoch", epoch)
530 .field("round", round)
531 .finish(),
532 }
533 }
534}
535
536#[derive(Clone, prost::Message)]
537pub struct RawWaitForEffectsRequest {
538 #[prost(bytes = "bytes", optional, tag = "1")]
540 pub transaction_digest: Option<Bytes>,
541
542 #[prost(bytes = "bytes", optional, tag = "2")]
546 pub consensus_position: Option<Bytes>,
547
548 #[prost(bool, tag = "3")]
551 pub include_details: bool,
552
553 #[prost(enumeration = "PingType", optional, tag = "4")]
555 pub ping_type: Option<i32>,
556}
557
558impl RawWaitForEffectsRequest {
559 pub fn get_ping_type(&self) -> Option<PingType> {
560 self.ping_type
561 .map(|p| PingType::try_from(p).expect("Invalid ping type"))
562 }
563}
564
565#[derive(Clone, prost::Message)]
566pub struct RawWaitForEffectsResponse {
567 #[prost(oneof = "RawValidatorTransactionStatus", tags = "1, 2, 3")]
572 pub inner: Option<RawValidatorTransactionStatus>,
573}
574
575#[derive(Clone, prost::Oneof)]
576pub enum RawValidatorTransactionStatus {
577 #[prost(message, tag = "1")]
578 Executed(RawExecutedStatus),
579 #[prost(message, tag = "2")]
580 Rejected(RawRejectedStatus),
581 #[prost(message, tag = "3")]
582 Expired(RawExpiredStatus),
583}
584
585#[derive(Clone, prost::Message)]
586pub struct RawExecutedStatus {
587 #[prost(bytes = "bytes", tag = "1")]
588 pub effects_digest: Bytes,
589 #[prost(message, optional, tag = "2")]
590 pub details: Option<RawExecutedData>,
591}
592
593#[derive(Clone, prost::Message)]
594pub struct RawRejectedStatus {
595 #[prost(bytes = "bytes", optional, tag = "1")]
596 pub error: Option<Bytes>,
597}
598
599#[derive(Clone, prost::Message)]
600pub struct RawExpiredStatus {
601 #[prost(uint64, tag = "1")]
603 pub epoch: u64,
604 #[prost(uint32, optional, tag = "2")]
606 pub round: Option<u32>,
607}
608
609#[derive(Clone, Debug, Default)]
613pub struct ValidatorHealthRequest {}
614
615#[derive(Clone, Debug, Default)]
617pub struct ValidatorHealthResponse {
618 pub num_inflight_execution_transactions: u64,
620 pub num_inflight_consensus_transactions: u64,
622 pub last_committed_leader_round: u32,
624 pub last_locally_built_checkpoint: u64,
626}
627
628#[derive(Clone, prost::Message)]
630pub struct RawValidatorHealthRequest {}
631
632#[derive(Clone, prost::Message)]
634pub struct RawValidatorHealthResponse {
635 #[prost(uint64, optional, tag = "1")]
637 pub pending_certificates: Option<u64>,
638 #[prost(uint64, optional, tag = "2")]
640 pub inflight_consensus_messages: Option<u64>,
641 #[prost(uint64, optional, tag = "3")]
643 pub consensus_round: Option<u64>,
644 #[prost(uint64, optional, tag = "4")]
646 pub checkpoint_sequence: Option<u64>,
647}
648
649impl TryFrom<ExecutedData> for RawExecutedData {
652 type Error = crate::error::SuiError;
653
654 fn try_from(value: ExecutedData) -> Result<Self, Self::Error> {
655 let effects = bcs::to_bytes(&value.effects)
656 .map_err(
657 |err| crate::error::SuiErrorKind::GrpcMessageSerializeError {
658 type_info: "ExecutedData.effects".to_string(),
659 error: err.to_string(),
660 },
661 )?
662 .into();
663 let events = if let Some(events) = &value.events {
664 Some(
665 bcs::to_bytes(events)
666 .map_err(
667 |err| crate::error::SuiErrorKind::GrpcMessageSerializeError {
668 type_info: "ExecutedData.events".to_string(),
669 error: err.to_string(),
670 },
671 )?
672 .into(),
673 )
674 } else {
675 None
676 };
677 let mut input_objects = Vec::with_capacity(value.input_objects.len());
678 for object in value.input_objects {
679 input_objects.push(
680 bcs::to_bytes(&object)
681 .map_err(
682 |err| crate::error::SuiErrorKind::GrpcMessageSerializeError {
683 type_info: "ExecutedData.input_objects".to_string(),
684 error: err.to_string(),
685 },
686 )?
687 .into(),
688 );
689 }
690 let mut output_objects = Vec::with_capacity(value.output_objects.len());
691 for object in value.output_objects {
692 output_objects.push(
693 bcs::to_bytes(&object)
694 .map_err(
695 |err| crate::error::SuiErrorKind::GrpcMessageSerializeError {
696 type_info: "ExecutedData.output_objects".to_string(),
697 error: err.to_string(),
698 },
699 )?
700 .into(),
701 );
702 }
703 Ok(RawExecutedData {
704 effects,
705 events,
706 input_objects,
707 output_objects,
708 })
709 }
710}
711
712impl TryFrom<RawExecutedData> for ExecutedData {
713 type Error = crate::error::SuiError;
714
715 fn try_from(value: RawExecutedData) -> Result<Self, Self::Error> {
716 let effects = bcs::from_bytes(&value.effects).map_err(|err| {
717 crate::error::SuiErrorKind::GrpcMessageDeserializeError {
718 type_info: "RawExecutedData.effects".to_string(),
719 error: err.to_string(),
720 }
721 })?;
722 let events = if let Some(events) = value.events {
723 Some(bcs::from_bytes(&events).map_err(|err| {
724 crate::error::SuiErrorKind::GrpcMessageDeserializeError {
725 type_info: "RawExecutedData.events".to_string(),
726 error: err.to_string(),
727 }
728 })?)
729 } else {
730 None
731 };
732 let mut input_objects = Vec::with_capacity(value.input_objects.len());
733 for object in value.input_objects {
734 input_objects.push(bcs::from_bytes(&object).map_err(|err| {
735 crate::error::SuiErrorKind::GrpcMessageDeserializeError {
736 type_info: "RawExecutedData.input_objects".to_string(),
737 error: err.to_string(),
738 }
739 })?);
740 }
741 let mut output_objects = Vec::with_capacity(value.output_objects.len());
742 for object in value.output_objects {
743 output_objects.push(bcs::from_bytes(&object).map_err(|err| {
744 crate::error::SuiErrorKind::GrpcMessageDeserializeError {
745 type_info: "RawExecutedData.output_objects".to_string(),
746 error: err.to_string(),
747 }
748 })?);
749 }
750 Ok(ExecutedData {
751 effects,
752 events,
753 input_objects,
754 output_objects,
755 })
756 }
757}
758
759impl TryFrom<SubmitTxResult> for RawSubmitTxResult {
760 type Error = crate::error::SuiError;
761
762 fn try_from(value: SubmitTxResult) -> Result<Self, Self::Error> {
763 let inner = match value {
764 SubmitTxResult::Submitted { consensus_position } => {
765 let consensus_position = consensus_position.into_raw()?;
766 RawValidatorSubmitStatus::Submitted(consensus_position)
767 }
768 SubmitTxResult::Executed {
769 effects_digest,
770 details,
771 } => {
772 let raw_executed = try_from_response_executed(effects_digest, details)?;
773 RawValidatorSubmitStatus::Executed(raw_executed)
774 }
775 SubmitTxResult::Rejected { error } => {
776 RawValidatorSubmitStatus::Rejected(try_from_response_rejected(Some(error))?)
777 }
778 };
779 Ok(RawSubmitTxResult { inner: Some(inner) })
780 }
781}
782
783impl TryFrom<RawSubmitTxResult> for SubmitTxResult {
784 type Error = crate::error::SuiError;
785
786 fn try_from(value: RawSubmitTxResult) -> Result<Self, Self::Error> {
787 match value.inner {
788 Some(RawValidatorSubmitStatus::Submitted(consensus_position)) => {
789 Ok(SubmitTxResult::Submitted {
790 consensus_position: consensus_position.as_ref().try_into()?,
791 })
792 }
793 Some(RawValidatorSubmitStatus::Executed(executed)) => {
794 let (effects_digest, details) = try_from_raw_executed_status(executed)?;
795 Ok(SubmitTxResult::Executed {
796 effects_digest,
797 details,
798 })
799 }
800 Some(RawValidatorSubmitStatus::Rejected(error)) => {
801 let error = try_from_raw_rejected_status(error)?.unwrap_or(
802 crate::error::SuiErrorKind::GrpcMessageDeserializeError {
803 type_info: "RawSubmitTxResult.inner.Error".to_string(),
804 error: "RawSubmitTxResult.inner.Error is None".to_string(),
805 }
806 .into(),
807 );
808 Ok(SubmitTxResult::Rejected { error })
809 }
810 None => Err(crate::error::SuiErrorKind::GrpcMessageDeserializeError {
811 type_info: "RawSubmitTxResult.inner".to_string(),
812 error: "RawSubmitTxResult.inner is None".to_string(),
813 }
814 .into()),
815 }
816 }
817}
818
819impl TryFrom<RawSubmitTxResponse> for SubmitTxResponse {
820 type Error = crate::error::SuiError;
821
822 fn try_from(value: RawSubmitTxResponse) -> Result<Self, Self::Error> {
823 if value.results.len() != 1 {
825 return Err(crate::error::SuiErrorKind::GrpcMessageDeserializeError {
826 type_info: "RawSubmitTxResponse.results".to_string(),
827 error: format!("Expected exactly 1 result, got {}", value.results.len()),
828 }
829 .into());
830 }
831
832 let results = value
833 .results
834 .into_iter()
835 .map(|result| result.try_into())
836 .collect::<Result<Vec<SubmitTxResult>, crate::error::SuiError>>()?;
837
838 Ok(Self { results })
839 }
840}
841
842fn try_from_raw_executed_status(
843 executed: RawExecutedStatus,
844) -> Result<
845 (
846 crate::digests::TransactionEffectsDigest,
847 Option<Box<ExecutedData>>,
848 ),
849 crate::error::SuiError,
850> {
851 let effects_digest = bcs::from_bytes(&executed.effects_digest).map_err(|err| {
852 crate::error::SuiErrorKind::GrpcMessageDeserializeError {
853 type_info: "RawWaitForEffectsResponse.effects_digest".to_string(),
854 error: err.to_string(),
855 }
856 })?;
857 let executed_data = if let Some(details) = executed.details {
858 Some(Box::new(details.try_into()?))
859 } else {
860 None
861 };
862 Ok((effects_digest, executed_data))
863}
864
865fn try_from_raw_rejected_status(
866 rejected: RawRejectedStatus,
867) -> Result<Option<crate::error::SuiError>, crate::error::SuiError> {
868 match rejected.error {
869 Some(error_bytes) => {
870 let error = bcs::from_bytes(&error_bytes).map_err(|err| {
871 crate::error::SuiErrorKind::GrpcMessageDeserializeError {
872 type_info: "RawWaitForEffectsResponse.rejected.reason".to_string(),
873 error: err.to_string(),
874 }
875 })?;
876 Ok(Some(error))
877 }
878 None => Ok(None),
879 }
880}
881
882fn try_from_response_rejected(
883 error: Option<crate::error::SuiError>,
884) -> Result<RawRejectedStatus, crate::error::SuiError> {
885 let error = match error {
886 Some(e) => Some(
887 bcs::to_bytes(&e)
888 .map_err(
889 |err| crate::error::SuiErrorKind::GrpcMessageSerializeError {
890 type_info: "RawRejectedStatus.error".to_string(),
891 error: err.to_string(),
892 },
893 )?
894 .into(),
895 ),
896 None => None,
897 };
898 Ok(RawRejectedStatus { error })
899}
900
901fn try_from_response_executed(
902 effects_digest: crate::digests::TransactionEffectsDigest,
903 details: Option<Box<ExecutedData>>,
904) -> Result<RawExecutedStatus, crate::error::SuiError> {
905 let effects_digest = bcs::to_bytes(&effects_digest)
906 .map_err(
907 |err| crate::error::SuiErrorKind::GrpcMessageSerializeError {
908 type_info: "RawWaitForEffectsResponse.effects_digest".to_string(),
909 error: err.to_string(),
910 },
911 )?
912 .into();
913 let details = if let Some(details) = details {
914 Some((*details).try_into()?)
915 } else {
916 None
917 };
918 Ok(RawExecutedStatus {
919 effects_digest,
920 details,
921 })
922}
923
924impl TryFrom<RawWaitForEffectsRequest> for WaitForEffectsRequest {
925 type Error = crate::error::SuiError;
926
927 fn try_from(value: RawWaitForEffectsRequest) -> Result<Self, Self::Error> {
928 let transaction_digest = match value.transaction_digest {
929 Some(digest) => Some(bcs::from_bytes(&digest).map_err(|err| {
930 crate::error::SuiErrorKind::GrpcMessageDeserializeError {
931 type_info: "RawWaitForEffectsRequest.transaction_digest".to_string(),
932 error: err.to_string(),
933 }
934 })?),
935 None => None,
936 };
937 let consensus_position = match value.consensus_position {
938 Some(cp) => Some(cp.as_ref().try_into()?),
939 None => None,
940 };
941 let ping_type = value
942 .ping_type
943 .map(|p| {
944 PingType::try_from(p).map_err(|e| SuiErrorKind::GrpcMessageDeserializeError {
945 type_info: "RawWaitForEffectsRequest.ping_type".to_string(),
946 error: e.to_string(),
947 })
948 })
949 .transpose()?;
950 Ok(Self {
951 consensus_position,
952 transaction_digest,
953 include_details: value.include_details,
954 ping_type,
955 })
956 }
957}
958
959impl TryFrom<WaitForEffectsRequest> for RawWaitForEffectsRequest {
960 type Error = crate::error::SuiError;
961
962 fn try_from(value: WaitForEffectsRequest) -> Result<Self, Self::Error> {
963 let transaction_digest = match value.transaction_digest {
964 Some(digest) => Some(
965 bcs::to_bytes(&digest)
966 .map_err(
967 |err| crate::error::SuiErrorKind::GrpcMessageSerializeError {
968 type_info: "RawWaitForEffectsRequest.transaction_digest".to_string(),
969 error: err.to_string(),
970 },
971 )?
972 .into(),
973 ),
974 None => None,
975 };
976 let consensus_position = match value.consensus_position {
977 Some(cp) => Some(cp.into_raw()?),
978 None => None,
979 };
980 let ping_type = value.ping_type.map(|p| p.into());
981 Ok(Self {
982 consensus_position,
983 transaction_digest,
984 include_details: value.include_details,
985 ping_type,
986 })
987 }
988}
989
990impl TryFrom<RawWaitForEffectsResponse> for WaitForEffectsResponse {
991 type Error = crate::error::SuiError;
992
993 fn try_from(value: RawWaitForEffectsResponse) -> Result<Self, Self::Error> {
994 match value.inner {
995 Some(RawValidatorTransactionStatus::Executed(executed)) => {
996 let (effects_digest, details) = try_from_raw_executed_status(executed)?;
997 Ok(Self::Executed {
998 effects_digest,
999 details,
1000 })
1001 }
1002 Some(RawValidatorTransactionStatus::Rejected(rejected)) => {
1003 let error = try_from_raw_rejected_status(rejected)?;
1004 Ok(Self::Rejected { error })
1005 }
1006 Some(RawValidatorTransactionStatus::Expired(expired)) => Ok(Self::Expired {
1007 epoch: expired.epoch,
1008 round: expired.round,
1009 }),
1010 None => Err(crate::error::SuiErrorKind::GrpcMessageDeserializeError {
1011 type_info: "RawWaitForEffectsResponse.inner".to_string(),
1012 error: "RawWaitForEffectsResponse.inner is None".to_string(),
1013 }
1014 .into()),
1015 }
1016 }
1017}
1018
1019impl TryFrom<WaitForEffectsResponse> for RawWaitForEffectsResponse {
1020 type Error = crate::error::SuiError;
1021
1022 fn try_from(value: WaitForEffectsResponse) -> Result<Self, Self::Error> {
1023 let inner = match value {
1024 WaitForEffectsResponse::Executed {
1025 effects_digest,
1026 details,
1027 } => {
1028 let raw_executed = try_from_response_executed(effects_digest, details)?;
1029 RawValidatorTransactionStatus::Executed(raw_executed)
1030 }
1031 WaitForEffectsResponse::Rejected { error } => {
1032 let raw_rejected = try_from_response_rejected(error)?;
1033 RawValidatorTransactionStatus::Rejected(raw_rejected)
1034 }
1035 WaitForEffectsResponse::Expired { epoch, round } => {
1036 RawValidatorTransactionStatus::Expired(RawExpiredStatus { epoch, round })
1037 }
1038 };
1039 Ok(RawWaitForEffectsResponse { inner: Some(inner) })
1040 }
1041}
1042
1043impl TryFrom<ValidatorHealthRequest> for RawValidatorHealthRequest {
1044 type Error = crate::error::SuiError;
1045
1046 fn try_from(_value: ValidatorHealthRequest) -> Result<Self, Self::Error> {
1047 Ok(Self {})
1048 }
1049}
1050
1051impl TryFrom<RawValidatorHealthRequest> for ValidatorHealthRequest {
1052 type Error = crate::error::SuiError;
1053
1054 fn try_from(_value: RawValidatorHealthRequest) -> Result<Self, Self::Error> {
1055 Ok(Self {})
1057 }
1058}
1059
1060impl TryFrom<ValidatorHealthResponse> for RawValidatorHealthResponse {
1061 type Error = crate::error::SuiError;
1062
1063 fn try_from(value: ValidatorHealthResponse) -> Result<Self, Self::Error> {
1064 Ok(Self {
1065 pending_certificates: Some(value.num_inflight_execution_transactions),
1066 inflight_consensus_messages: Some(value.num_inflight_consensus_transactions),
1067 consensus_round: Some(value.last_committed_leader_round as u64),
1068 checkpoint_sequence: Some(value.last_locally_built_checkpoint),
1069 })
1070 }
1071}
1072
1073impl TryFrom<RawValidatorHealthResponse> for ValidatorHealthResponse {
1074 type Error = crate::error::SuiError;
1075
1076 fn try_from(value: RawValidatorHealthResponse) -> Result<Self, Self::Error> {
1077 Ok(Self {
1078 num_inflight_consensus_transactions: value.inflight_consensus_messages.unwrap_or(0),
1079 num_inflight_execution_transactions: value.pending_certificates.unwrap_or(0),
1080 last_locally_built_checkpoint: value.checkpoint_sequence.unwrap_or(0),
1081 last_committed_leader_round: value.consensus_round.unwrap_or(0) as u32,
1082 })
1083 }
1084}
1085
1086#[cfg(test)]
1087mod tests {
1088 use crate::{
1089 messages_grpc::{SubmitTxRequest, SubmitTxType},
1090 transaction::{Transaction, TransactionData},
1091 };
1092
1093 #[tokio::test]
1094 async fn test_submit_tx_request_into_raw() {
1095 println!(
1096 "Case 1. SubmitTxRequest::new_ping should be converted to RawSubmitTxRequest with submit_type set to Ping."
1097 );
1098 {
1099 let request = SubmitTxRequest::new_ping();
1100 let raw_request = request.into_raw().unwrap();
1101
1102 let submit_type = SubmitTxType::try_from(raw_request.submit_type).unwrap();
1103 assert_eq!(submit_type, SubmitTxType::Ping);
1104 }
1105
1106 println!(
1107 "Case 2. SubmitTxRequest::new_transaction should be converted to RawSubmitTxRequest with submit_type set to Default."
1108 );
1109 {
1110 let sender = crate::base_types::SuiAddress::random_for_testing_only();
1112 let recipient = crate::base_types::SuiAddress::random_for_testing_only();
1113 let gas_object_ref = crate::base_types::random_object_ref();
1114
1115 let tx_data = TransactionData::new_transfer_sui(
1116 recipient,
1117 sender,
1118 None,
1119 gas_object_ref,
1120 1000,
1121 1000,
1122 );
1123
1124 let (_, keypair) = crate::crypto::get_account_key_pair();
1125 let transaction = Transaction::from_data_and_signer(tx_data, vec![&keypair]);
1126
1127 let request = SubmitTxRequest::new_transaction(transaction);
1128 let raw_request = request.into_raw().unwrap();
1129
1130 let submit_type = SubmitTxType::try_from(raw_request.submit_type).unwrap();
1131 assert_eq!(submit_type, SubmitTxType::Default);
1132 assert_eq!(raw_request.transactions.len(), 1);
1133 }
1134 }
1135}