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>,
491 pub include_details: bool,
494 pub ping_type: Option<PingType>,
496}
497
498#[derive(Clone)]
499pub enum WaitForEffectsResponse {
500 Executed {
501 effects_digest: crate::digests::TransactionEffectsDigest,
502 details: Option<Box<ExecutedData>>,
503 },
504 Rejected {
506 error: Option<crate::error::SuiError>,
509 },
510 Expired {
513 epoch: u64,
514 round: Option<u32>,
515 },
516}
517
518impl std::fmt::Debug for WaitForEffectsResponse {
519 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
520 match self {
521 Self::Executed { effects_digest, .. } => f
522 .debug_struct("Executed")
523 .field("effects_digest", effects_digest)
524 .finish(),
525 Self::Rejected { error } => f.debug_struct("Rejected").field("error", error).finish(),
526 Self::Expired { epoch, round } => f
527 .debug_struct("Expired")
528 .field("epoch", epoch)
529 .field("round", round)
530 .finish(),
531 }
532 }
533}
534
535#[derive(Clone, prost::Message)]
536pub struct RawWaitForEffectsRequest {
537 #[prost(bytes = "bytes", optional, tag = "1")]
539 pub transaction_digest: Option<Bytes>,
540
541 #[prost(bytes = "bytes", optional, tag = "2")]
545 pub consensus_position: Option<Bytes>,
546
547 #[prost(bool, tag = "3")]
550 pub include_details: bool,
551
552 #[prost(enumeration = "PingType", optional, tag = "4")]
554 pub ping_type: Option<i32>,
555}
556
557impl RawWaitForEffectsRequest {
558 pub fn get_ping_type(&self) -> Option<PingType> {
559 self.ping_type
560 .map(|p| PingType::try_from(p).expect("Invalid ping type"))
561 }
562}
563
564#[derive(Clone, prost::Message)]
565pub struct RawWaitForEffectsResponse {
566 #[prost(oneof = "RawValidatorTransactionStatus", tags = "1, 2, 3")]
571 pub inner: Option<RawValidatorTransactionStatus>,
572}
573
574#[derive(Clone, prost::Oneof)]
575pub enum RawValidatorTransactionStatus {
576 #[prost(message, tag = "1")]
577 Executed(RawExecutedStatus),
578 #[prost(message, tag = "2")]
579 Rejected(RawRejectedStatus),
580 #[prost(message, tag = "3")]
581 Expired(RawExpiredStatus),
582}
583
584#[derive(Clone, prost::Message)]
585pub struct RawExecutedStatus {
586 #[prost(bytes = "bytes", tag = "1")]
587 pub effects_digest: Bytes,
588 #[prost(message, optional, tag = "2")]
589 pub details: Option<RawExecutedData>,
590}
591
592#[derive(Clone, prost::Message)]
593pub struct RawRejectedStatus {
594 #[prost(bytes = "bytes", optional, tag = "1")]
595 pub error: Option<Bytes>,
596}
597
598#[derive(Clone, prost::Message)]
599pub struct RawExpiredStatus {
600 #[prost(uint64, tag = "1")]
602 pub epoch: u64,
603 #[prost(uint32, optional, tag = "2")]
605 pub round: Option<u32>,
606}
607
608#[derive(Clone, Debug, Default)]
612pub struct ValidatorHealthRequest {}
613
614#[derive(Clone, Debug, Default)]
616pub struct ValidatorHealthResponse {
617 pub num_inflight_execution_transactions: u64,
619 pub num_inflight_consensus_transactions: u64,
621 pub last_committed_leader_round: u32,
623 pub last_locally_built_checkpoint: u64,
625}
626
627#[derive(Clone, prost::Message)]
629pub struct RawValidatorHealthRequest {}
630
631#[derive(Clone, prost::Message)]
633pub struct RawValidatorHealthResponse {
634 #[prost(uint64, optional, tag = "1")]
636 pub pending_certificates: Option<u64>,
637 #[prost(uint64, optional, tag = "2")]
639 pub inflight_consensus_messages: Option<u64>,
640 #[prost(uint64, optional, tag = "3")]
642 pub consensus_round: Option<u64>,
643 #[prost(uint64, optional, tag = "4")]
645 pub checkpoint_sequence: Option<u64>,
646}
647
648impl TryFrom<ExecutedData> for RawExecutedData {
651 type Error = crate::error::SuiError;
652
653 fn try_from(value: ExecutedData) -> Result<Self, Self::Error> {
654 let effects = bcs::to_bytes(&value.effects)
655 .map_err(
656 |err| crate::error::SuiErrorKind::GrpcMessageSerializeError {
657 type_info: "ExecutedData.effects".to_string(),
658 error: err.to_string(),
659 },
660 )?
661 .into();
662 let events = if let Some(events) = &value.events {
663 Some(
664 bcs::to_bytes(events)
665 .map_err(
666 |err| crate::error::SuiErrorKind::GrpcMessageSerializeError {
667 type_info: "ExecutedData.events".to_string(),
668 error: err.to_string(),
669 },
670 )?
671 .into(),
672 )
673 } else {
674 None
675 };
676 let mut input_objects = Vec::with_capacity(value.input_objects.len());
677 for object in value.input_objects {
678 input_objects.push(
679 bcs::to_bytes(&object)
680 .map_err(
681 |err| crate::error::SuiErrorKind::GrpcMessageSerializeError {
682 type_info: "ExecutedData.input_objects".to_string(),
683 error: err.to_string(),
684 },
685 )?
686 .into(),
687 );
688 }
689 let mut output_objects = Vec::with_capacity(value.output_objects.len());
690 for object in value.output_objects {
691 output_objects.push(
692 bcs::to_bytes(&object)
693 .map_err(
694 |err| crate::error::SuiErrorKind::GrpcMessageSerializeError {
695 type_info: "ExecutedData.output_objects".to_string(),
696 error: err.to_string(),
697 },
698 )?
699 .into(),
700 );
701 }
702 Ok(RawExecutedData {
703 effects,
704 events,
705 input_objects,
706 output_objects,
707 })
708 }
709}
710
711impl TryFrom<RawExecutedData> for ExecutedData {
712 type Error = crate::error::SuiError;
713
714 fn try_from(value: RawExecutedData) -> Result<Self, Self::Error> {
715 let effects = bcs::from_bytes(&value.effects).map_err(|err| {
716 crate::error::SuiErrorKind::GrpcMessageDeserializeError {
717 type_info: "RawExecutedData.effects".to_string(),
718 error: err.to_string(),
719 }
720 })?;
721 let events = if let Some(events) = value.events {
722 Some(bcs::from_bytes(&events).map_err(|err| {
723 crate::error::SuiErrorKind::GrpcMessageDeserializeError {
724 type_info: "RawExecutedData.events".to_string(),
725 error: err.to_string(),
726 }
727 })?)
728 } else {
729 None
730 };
731 let mut input_objects = Vec::with_capacity(value.input_objects.len());
732 for object in value.input_objects {
733 input_objects.push(bcs::from_bytes(&object).map_err(|err| {
734 crate::error::SuiErrorKind::GrpcMessageDeserializeError {
735 type_info: "RawExecutedData.input_objects".to_string(),
736 error: err.to_string(),
737 }
738 })?);
739 }
740 let mut output_objects = Vec::with_capacity(value.output_objects.len());
741 for object in value.output_objects {
742 output_objects.push(bcs::from_bytes(&object).map_err(|err| {
743 crate::error::SuiErrorKind::GrpcMessageDeserializeError {
744 type_info: "RawExecutedData.output_objects".to_string(),
745 error: err.to_string(),
746 }
747 })?);
748 }
749 Ok(ExecutedData {
750 effects,
751 events,
752 input_objects,
753 output_objects,
754 })
755 }
756}
757
758impl TryFrom<SubmitTxResult> for RawSubmitTxResult {
759 type Error = crate::error::SuiError;
760
761 fn try_from(value: SubmitTxResult) -> Result<Self, Self::Error> {
762 let inner = match value {
763 SubmitTxResult::Submitted { consensus_position } => {
764 let consensus_position = consensus_position.into_raw()?;
765 RawValidatorSubmitStatus::Submitted(consensus_position)
766 }
767 SubmitTxResult::Executed {
768 effects_digest,
769 details,
770 } => {
771 let raw_executed = try_from_response_executed(effects_digest, details)?;
772 RawValidatorSubmitStatus::Executed(raw_executed)
773 }
774 SubmitTxResult::Rejected { error } => {
775 RawValidatorSubmitStatus::Rejected(try_from_response_rejected(Some(error))?)
776 }
777 };
778 Ok(RawSubmitTxResult { inner: Some(inner) })
779 }
780}
781
782impl TryFrom<RawSubmitTxResult> for SubmitTxResult {
783 type Error = crate::error::SuiError;
784
785 fn try_from(value: RawSubmitTxResult) -> Result<Self, Self::Error> {
786 match value.inner {
787 Some(RawValidatorSubmitStatus::Submitted(consensus_position)) => {
788 Ok(SubmitTxResult::Submitted {
789 consensus_position: consensus_position.as_ref().try_into()?,
790 })
791 }
792 Some(RawValidatorSubmitStatus::Executed(executed)) => {
793 let (effects_digest, details) = try_from_raw_executed_status(executed)?;
794 Ok(SubmitTxResult::Executed {
795 effects_digest,
796 details,
797 })
798 }
799 Some(RawValidatorSubmitStatus::Rejected(error)) => {
800 let error = try_from_raw_rejected_status(error)?.unwrap_or(
801 crate::error::SuiErrorKind::GrpcMessageDeserializeError {
802 type_info: "RawSubmitTxResult.inner.Error".to_string(),
803 error: "RawSubmitTxResult.inner.Error is None".to_string(),
804 }
805 .into(),
806 );
807 Ok(SubmitTxResult::Rejected { error })
808 }
809 None => Err(crate::error::SuiErrorKind::GrpcMessageDeserializeError {
810 type_info: "RawSubmitTxResult.inner".to_string(),
811 error: "RawSubmitTxResult.inner is None".to_string(),
812 }
813 .into()),
814 }
815 }
816}
817
818impl TryFrom<RawSubmitTxResponse> for SubmitTxResponse {
819 type Error = crate::error::SuiError;
820
821 fn try_from(value: RawSubmitTxResponse) -> Result<Self, Self::Error> {
822 if value.results.len() != 1 {
824 return Err(crate::error::SuiErrorKind::GrpcMessageDeserializeError {
825 type_info: "RawSubmitTxResponse.results".to_string(),
826 error: format!("Expected exactly 1 result, got {}", value.results.len()),
827 }
828 .into());
829 }
830
831 let results = value
832 .results
833 .into_iter()
834 .map(|result| result.try_into())
835 .collect::<Result<Vec<SubmitTxResult>, crate::error::SuiError>>()?;
836
837 Ok(Self { results })
838 }
839}
840
841fn try_from_raw_executed_status(
842 executed: RawExecutedStatus,
843) -> Result<
844 (
845 crate::digests::TransactionEffectsDigest,
846 Option<Box<ExecutedData>>,
847 ),
848 crate::error::SuiError,
849> {
850 let effects_digest = bcs::from_bytes(&executed.effects_digest).map_err(|err| {
851 crate::error::SuiErrorKind::GrpcMessageDeserializeError {
852 type_info: "RawWaitForEffectsResponse.effects_digest".to_string(),
853 error: err.to_string(),
854 }
855 })?;
856 let executed_data = if let Some(details) = executed.details {
857 Some(Box::new(details.try_into()?))
858 } else {
859 None
860 };
861 Ok((effects_digest, executed_data))
862}
863
864fn try_from_raw_rejected_status(
865 rejected: RawRejectedStatus,
866) -> Result<Option<crate::error::SuiError>, crate::error::SuiError> {
867 match rejected.error {
868 Some(error_bytes) => {
869 let error = bcs::from_bytes(&error_bytes).map_err(|err| {
870 crate::error::SuiErrorKind::GrpcMessageDeserializeError {
871 type_info: "RawWaitForEffectsResponse.rejected.reason".to_string(),
872 error: err.to_string(),
873 }
874 })?;
875 Ok(Some(error))
876 }
877 None => Ok(None),
878 }
879}
880
881fn try_from_response_rejected(
882 error: Option<crate::error::SuiError>,
883) -> Result<RawRejectedStatus, crate::error::SuiError> {
884 let error = match error {
885 Some(e) => Some(
886 bcs::to_bytes(&e)
887 .map_err(
888 |err| crate::error::SuiErrorKind::GrpcMessageSerializeError {
889 type_info: "RawRejectedStatus.error".to_string(),
890 error: err.to_string(),
891 },
892 )?
893 .into(),
894 ),
895 None => None,
896 };
897 Ok(RawRejectedStatus { error })
898}
899
900fn try_from_response_executed(
901 effects_digest: crate::digests::TransactionEffectsDigest,
902 details: Option<Box<ExecutedData>>,
903) -> Result<RawExecutedStatus, crate::error::SuiError> {
904 let effects_digest = bcs::to_bytes(&effects_digest)
905 .map_err(
906 |err| crate::error::SuiErrorKind::GrpcMessageSerializeError {
907 type_info: "RawWaitForEffectsResponse.effects_digest".to_string(),
908 error: err.to_string(),
909 },
910 )?
911 .into();
912 let details = if let Some(details) = details {
913 Some((*details).try_into()?)
914 } else {
915 None
916 };
917 Ok(RawExecutedStatus {
918 effects_digest,
919 details,
920 })
921}
922
923impl TryFrom<RawWaitForEffectsRequest> for WaitForEffectsRequest {
924 type Error = crate::error::SuiError;
925
926 fn try_from(value: RawWaitForEffectsRequest) -> Result<Self, Self::Error> {
927 let transaction_digest = match value.transaction_digest {
928 Some(digest) => Some(bcs::from_bytes(&digest).map_err(|err| {
929 crate::error::SuiErrorKind::GrpcMessageDeserializeError {
930 type_info: "RawWaitForEffectsRequest.transaction_digest".to_string(),
931 error: err.to_string(),
932 }
933 })?),
934 None => None,
935 };
936 let consensus_position = match value.consensus_position {
937 Some(cp) => Some(cp.as_ref().try_into()?),
938 None => None,
939 };
940 let ping_type = value
941 .ping_type
942 .map(|p| {
943 PingType::try_from(p).map_err(|e| SuiErrorKind::GrpcMessageDeserializeError {
944 type_info: "RawWaitForEffectsRequest.ping_type".to_string(),
945 error: e.to_string(),
946 })
947 })
948 .transpose()?;
949 Ok(Self {
950 consensus_position,
951 transaction_digest,
952 include_details: value.include_details,
953 ping_type,
954 })
955 }
956}
957
958impl TryFrom<WaitForEffectsRequest> for RawWaitForEffectsRequest {
959 type Error = crate::error::SuiError;
960
961 fn try_from(value: WaitForEffectsRequest) -> Result<Self, Self::Error> {
962 let transaction_digest = match value.transaction_digest {
963 Some(digest) => Some(
964 bcs::to_bytes(&digest)
965 .map_err(
966 |err| crate::error::SuiErrorKind::GrpcMessageSerializeError {
967 type_info: "RawWaitForEffectsRequest.transaction_digest".to_string(),
968 error: err.to_string(),
969 },
970 )?
971 .into(),
972 ),
973 None => None,
974 };
975 let consensus_position = match value.consensus_position {
976 Some(cp) => Some(cp.into_raw()?),
977 None => None,
978 };
979 let ping_type = value.ping_type.map(|p| p.into());
980 Ok(Self {
981 consensus_position,
982 transaction_digest,
983 include_details: value.include_details,
984 ping_type,
985 })
986 }
987}
988
989impl TryFrom<RawWaitForEffectsResponse> for WaitForEffectsResponse {
990 type Error = crate::error::SuiError;
991
992 fn try_from(value: RawWaitForEffectsResponse) -> Result<Self, Self::Error> {
993 match value.inner {
994 Some(RawValidatorTransactionStatus::Executed(executed)) => {
995 let (effects_digest, details) = try_from_raw_executed_status(executed)?;
996 Ok(Self::Executed {
997 effects_digest,
998 details,
999 })
1000 }
1001 Some(RawValidatorTransactionStatus::Rejected(rejected)) => {
1002 let error = try_from_raw_rejected_status(rejected)?;
1003 Ok(Self::Rejected { error })
1004 }
1005 Some(RawValidatorTransactionStatus::Expired(expired)) => Ok(Self::Expired {
1006 epoch: expired.epoch,
1007 round: expired.round,
1008 }),
1009 None => Err(crate::error::SuiErrorKind::GrpcMessageDeserializeError {
1010 type_info: "RawWaitForEffectsResponse.inner".to_string(),
1011 error: "RawWaitForEffectsResponse.inner is None".to_string(),
1012 }
1013 .into()),
1014 }
1015 }
1016}
1017
1018impl TryFrom<WaitForEffectsResponse> for RawWaitForEffectsResponse {
1019 type Error = crate::error::SuiError;
1020
1021 fn try_from(value: WaitForEffectsResponse) -> Result<Self, Self::Error> {
1022 let inner = match value {
1023 WaitForEffectsResponse::Executed {
1024 effects_digest,
1025 details,
1026 } => {
1027 let raw_executed = try_from_response_executed(effects_digest, details)?;
1028 RawValidatorTransactionStatus::Executed(raw_executed)
1029 }
1030 WaitForEffectsResponse::Rejected { error } => {
1031 let raw_rejected = try_from_response_rejected(error)?;
1032 RawValidatorTransactionStatus::Rejected(raw_rejected)
1033 }
1034 WaitForEffectsResponse::Expired { epoch, round } => {
1035 RawValidatorTransactionStatus::Expired(RawExpiredStatus { epoch, round })
1036 }
1037 };
1038 Ok(RawWaitForEffectsResponse { inner: Some(inner) })
1039 }
1040}
1041
1042impl TryFrom<ValidatorHealthRequest> for RawValidatorHealthRequest {
1043 type Error = crate::error::SuiError;
1044
1045 fn try_from(_value: ValidatorHealthRequest) -> Result<Self, Self::Error> {
1046 Ok(Self {})
1047 }
1048}
1049
1050impl TryFrom<RawValidatorHealthRequest> for ValidatorHealthRequest {
1051 type Error = crate::error::SuiError;
1052
1053 fn try_from(_value: RawValidatorHealthRequest) -> Result<Self, Self::Error> {
1054 Ok(Self {})
1056 }
1057}
1058
1059impl TryFrom<ValidatorHealthResponse> for RawValidatorHealthResponse {
1060 type Error = crate::error::SuiError;
1061
1062 fn try_from(value: ValidatorHealthResponse) -> Result<Self, Self::Error> {
1063 Ok(Self {
1064 pending_certificates: Some(value.num_inflight_execution_transactions),
1065 inflight_consensus_messages: Some(value.num_inflight_consensus_transactions),
1066 consensus_round: Some(value.last_committed_leader_round as u64),
1067 checkpoint_sequence: Some(value.last_locally_built_checkpoint),
1068 })
1069 }
1070}
1071
1072impl TryFrom<RawValidatorHealthResponse> for ValidatorHealthResponse {
1073 type Error = crate::error::SuiError;
1074
1075 fn try_from(value: RawValidatorHealthResponse) -> Result<Self, Self::Error> {
1076 Ok(Self {
1077 num_inflight_consensus_transactions: value.inflight_consensus_messages.unwrap_or(0),
1078 num_inflight_execution_transactions: value.pending_certificates.unwrap_or(0),
1079 last_locally_built_checkpoint: value.checkpoint_sequence.unwrap_or(0),
1080 last_committed_leader_round: value.consensus_round.unwrap_or(0) as u32,
1081 })
1082 }
1083}
1084
1085#[cfg(test)]
1086mod tests {
1087 use crate::{
1088 messages_grpc::{SubmitTxRequest, SubmitTxType},
1089 transaction::{Transaction, TransactionData},
1090 };
1091
1092 #[tokio::test]
1093 async fn test_submit_tx_request_into_raw() {
1094 println!(
1095 "Case 1. SubmitTxRequest::new_ping should be converted to RawSubmitTxRequest with submit_type set to Ping."
1096 );
1097 {
1098 let request = SubmitTxRequest::new_ping();
1099 let raw_request = request.into_raw().unwrap();
1100
1101 let submit_type = SubmitTxType::try_from(raw_request.submit_type).unwrap();
1102 assert_eq!(submit_type, SubmitTxType::Ping);
1103 }
1104
1105 println!(
1106 "Case 2. SubmitTxRequest::new_transaction should be converted to RawSubmitTxRequest with submit_type set to Default."
1107 );
1108 {
1109 let sender = crate::base_types::SuiAddress::random_for_testing_only();
1111 let recipient = crate::base_types::SuiAddress::random_for_testing_only();
1112 let gas_object_ref = crate::base_types::random_object_ref();
1113
1114 let tx_data = TransactionData::new_transfer_sui(
1115 recipient,
1116 sender,
1117 None,
1118 gas_object_ref,
1119 1000,
1120 1000,
1121 );
1122
1123 let (_, keypair) = crate::crypto::get_account_key_pair();
1124 let transaction = Transaction::from_data_and_signer(tx_data, vec![&keypair]);
1125
1126 let request = SubmitTxRequest::new_transaction(transaction);
1127 let raw_request = request.into_raw().unwrap();
1128
1129 let submit_type = SubmitTxType::try_from(raw_request.submit_type).unwrap();
1130 assert_eq!(submit_type, SubmitTxType::Default);
1131 assert_eq!(raw_request.transactions.len(), 1);
1132 }
1133 }
1134}