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)]
289pub struct SubmitTxRequest {
290 pub transaction: Option<Transaction>,
291 pub ping_type: Option<PingType>,
292}
293
294impl SubmitTxRequest {
295 pub fn new_transaction(transaction: Transaction) -> Self {
296 Self {
297 transaction: Some(transaction),
298 ping_type: None,
299 }
300 }
301
302 pub fn new_ping(ping_type: PingType) -> Self {
303 Self {
304 transaction: None,
305 ping_type: Some(ping_type),
306 }
307 }
308
309 pub fn tx_type(&self) -> TxType {
310 if let Some(ping_type) = self.ping_type {
311 return if ping_type == PingType::FastPath {
312 TxType::SingleWriter
313 } else {
314 TxType::SharedObject
315 };
316 }
317 let transaction = self.transaction.as_ref().unwrap();
318 if transaction.is_consensus_tx() {
319 TxType::SharedObject
320 } else {
321 TxType::SingleWriter
322 }
323 }
324
325 pub fn tx_digest(&self) -> Option<TransactionDigest> {
328 self.transaction.as_ref().map(|t| *t.digest())
329 }
330}
331
332#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EnumIter)]
333pub enum TxType {
334 SingleWriter,
335 SharedObject,
336}
337
338impl TxType {
339 pub fn as_str(&self) -> &str {
340 match self {
341 TxType::SingleWriter => TX_TYPE_SINGLE_WRITER_TX,
342 TxType::SharedObject => TX_TYPE_SHARED_OBJ_TX,
343 }
344 }
345}
346
347impl SubmitTxRequest {
348 pub fn into_raw(&self) -> Result<RawSubmitTxRequest, SuiError> {
349 let transactions = if let Some(transaction) = &self.transaction {
350 vec![
351 bcs::to_bytes(&transaction)
352 .map_err(|e| SuiErrorKind::TransactionSerializationError {
353 error: e.to_string(),
354 })?
355 .into(),
356 ]
357 } else {
358 vec![]
359 };
360
361 let submit_type = if self.ping_type.is_some() {
362 SubmitTxType::Ping
363 } else {
364 SubmitTxType::Default
365 };
366
367 Ok(RawSubmitTxRequest {
368 transactions,
369 submit_type: submit_type.into(),
370 })
371 }
372}
373
374#[derive(Clone)]
375pub enum SubmitTxResult {
376 Submitted {
377 consensus_position: crate::messages_consensus::ConsensusPosition,
378 },
379 Executed {
380 effects_digest: crate::digests::TransactionEffectsDigest,
381 details: Option<Box<ExecutedData>>,
384 fast_path: bool,
386 },
387 Rejected {
388 error: crate::error::SuiError,
389 },
390}
391
392impl std::fmt::Debug for SubmitTxResult {
393 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
394 match self {
395 Self::Submitted { consensus_position } => f
396 .debug_struct("Submitted")
397 .field("consensus_position", consensus_position)
398 .finish(),
399 Self::Executed {
400 effects_digest,
401 fast_path,
402 ..
403 } => f
404 .debug_struct("Executed")
405 .field("effects_digest", &format_args!("{}", effects_digest))
406 .field("fast_path", fast_path)
407 .finish(),
408 Self::Rejected { error } => f.debug_struct("Rejected").field("error", &error).finish(),
409 }
410 }
411}
412
413#[derive(Clone, Debug)]
414pub struct SubmitTxResponse {
415 pub results: Vec<SubmitTxResult>,
416}
417
418#[derive(Clone, prost::Message)]
419pub struct RawSubmitTxRequest {
420 #[prost(bytes = "bytes", repeated, tag = "1")]
422 pub transactions: Vec<Bytes>,
423
424 #[prost(enumeration = "SubmitTxType", tag = "2")]
426 pub submit_type: i32,
427}
428
429#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, prost::Enumeration)]
430#[repr(i32)]
431pub enum SubmitTxType {
432 Default = 0,
436 Ping = 1,
438 SoftBundle = 2,
441}
442
443#[derive(Clone, prost::Message)]
444pub struct RawSubmitTxResponse {
445 #[prost(message, repeated, tag = "1")]
447 pub results: Vec<RawSubmitTxResult>,
448}
449
450#[derive(Clone, prost::Message)]
451pub struct RawSubmitTxResult {
452 #[prost(oneof = "RawValidatorSubmitStatus", tags = "1, 2, 3")]
453 pub inner: Option<RawValidatorSubmitStatus>,
454}
455
456#[derive(Clone, prost::Oneof)]
457pub enum RawValidatorSubmitStatus {
458 #[prost(bytes = "bytes", tag = "1")]
460 Submitted(Bytes),
461
462 #[prost(message, tag = "2")]
464 Executed(RawExecutedStatus),
465
466 #[prost(message, tag = "3")]
468 Rejected(RawRejectedStatus),
469}
470
471#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, prost::Enumeration)]
472#[repr(i32)]
473pub enum PingType {
474 Consensus = 0,
477 FastPath = 1,
480}
481
482impl PingType {
483 pub fn as_str(&self) -> &str {
484 match self {
485 PingType::FastPath => "fastpath",
486 PingType::Consensus => "consensus",
487 }
488 }
489}
490
491pub struct WaitForEffectsRequest {
494 pub transaction_digest: Option<crate::digests::TransactionDigest>,
495 pub consensus_position: Option<crate::messages_consensus::ConsensusPosition>,
500 pub include_details: bool,
503 pub ping_type: Option<PingType>,
505}
506
507#[derive(Clone)]
508pub enum WaitForEffectsResponse {
509 Executed {
510 effects_digest: crate::digests::TransactionEffectsDigest,
511 details: Option<Box<ExecutedData>>,
512 fast_path: bool,
513 },
514 Rejected {
516 error: Option<crate::error::SuiError>,
519 },
520 Expired {
523 epoch: u64,
524 round: Option<u32>,
525 },
526}
527
528impl std::fmt::Debug for WaitForEffectsResponse {
529 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
530 match self {
531 Self::Executed {
532 effects_digest,
533 fast_path,
534 ..
535 } => f
536 .debug_struct("Executed")
537 .field("effects_digest", effects_digest)
538 .field("fast_path", fast_path)
539 .finish(),
540 Self::Rejected { error } => f.debug_struct("Rejected").field("error", error).finish(),
541 Self::Expired { epoch, round } => f
542 .debug_struct("Expired")
543 .field("epoch", epoch)
544 .field("round", round)
545 .finish(),
546 }
547 }
548}
549
550#[derive(Clone, prost::Message)]
551pub struct RawWaitForEffectsRequest {
552 #[prost(bytes = "bytes", optional, tag = "1")]
554 pub transaction_digest: Option<Bytes>,
555
556 #[prost(bytes = "bytes", optional, tag = "2")]
560 pub consensus_position: Option<Bytes>,
561
562 #[prost(bool, tag = "3")]
565 pub include_details: bool,
566
567 #[prost(enumeration = "PingType", optional, tag = "4")]
569 pub ping_type: Option<i32>,
570}
571
572impl RawWaitForEffectsRequest {
573 pub fn get_ping_type(&self) -> Option<PingType> {
574 self.ping_type
575 .map(|p| PingType::try_from(p).expect("Invalid ping type"))
576 }
577}
578
579#[derive(Clone, prost::Message)]
580pub struct RawWaitForEffectsResponse {
581 #[prost(oneof = "RawValidatorTransactionStatus", tags = "1, 2, 3")]
586 pub inner: Option<RawValidatorTransactionStatus>,
587}
588
589#[derive(Clone, prost::Oneof)]
590pub enum RawValidatorTransactionStatus {
591 #[prost(message, tag = "1")]
592 Executed(RawExecutedStatus),
593 #[prost(message, tag = "2")]
594 Rejected(RawRejectedStatus),
595 #[prost(message, tag = "3")]
596 Expired(RawExpiredStatus),
597}
598
599#[derive(Clone, prost::Message)]
600pub struct RawExecutedStatus {
601 #[prost(bytes = "bytes", tag = "1")]
602 pub effects_digest: Bytes,
603 #[prost(message, optional, tag = "2")]
604 pub details: Option<RawExecutedData>,
605 #[prost(bool, tag = "3")]
606 pub fast_path: bool,
607}
608
609#[derive(Clone, prost::Message)]
610pub struct RawRejectedStatus {
611 #[prost(bytes = "bytes", optional, tag = "1")]
612 pub error: Option<Bytes>,
613}
614
615#[derive(Clone, prost::Message)]
616pub struct RawExpiredStatus {
617 #[prost(uint64, tag = "1")]
619 pub epoch: u64,
620 #[prost(uint32, optional, tag = "2")]
622 pub round: Option<u32>,
623}
624
625#[derive(Clone, Debug, Default)]
629pub struct ValidatorHealthRequest {}
630
631#[derive(Clone, Debug, Default)]
633pub struct ValidatorHealthResponse {
634 pub num_inflight_execution_transactions: u64,
636 pub num_inflight_consensus_transactions: u64,
638 pub last_committed_leader_round: u32,
640 pub last_locally_built_checkpoint: u64,
642}
643
644#[derive(Clone, prost::Message)]
646pub struct RawValidatorHealthRequest {}
647
648#[derive(Clone, prost::Message)]
650pub struct RawValidatorHealthResponse {
651 #[prost(uint64, optional, tag = "1")]
653 pub pending_certificates: Option<u64>,
654 #[prost(uint64, optional, tag = "2")]
656 pub inflight_consensus_messages: Option<u64>,
657 #[prost(uint64, optional, tag = "3")]
659 pub consensus_round: Option<u64>,
660 #[prost(uint64, optional, tag = "4")]
662 pub checkpoint_sequence: Option<u64>,
663}
664
665impl TryFrom<ExecutedData> for RawExecutedData {
668 type Error = crate::error::SuiError;
669
670 fn try_from(value: ExecutedData) -> Result<Self, Self::Error> {
671 let effects = bcs::to_bytes(&value.effects)
672 .map_err(
673 |err| crate::error::SuiErrorKind::GrpcMessageSerializeError {
674 type_info: "ExecutedData.effects".to_string(),
675 error: err.to_string(),
676 },
677 )?
678 .into();
679 let events = if let Some(events) = &value.events {
680 Some(
681 bcs::to_bytes(events)
682 .map_err(
683 |err| crate::error::SuiErrorKind::GrpcMessageSerializeError {
684 type_info: "ExecutedData.events".to_string(),
685 error: err.to_string(),
686 },
687 )?
688 .into(),
689 )
690 } else {
691 None
692 };
693 let mut input_objects = Vec::with_capacity(value.input_objects.len());
694 for object in value.input_objects {
695 input_objects.push(
696 bcs::to_bytes(&object)
697 .map_err(
698 |err| crate::error::SuiErrorKind::GrpcMessageSerializeError {
699 type_info: "ExecutedData.input_objects".to_string(),
700 error: err.to_string(),
701 },
702 )?
703 .into(),
704 );
705 }
706 let mut output_objects = Vec::with_capacity(value.output_objects.len());
707 for object in value.output_objects {
708 output_objects.push(
709 bcs::to_bytes(&object)
710 .map_err(
711 |err| crate::error::SuiErrorKind::GrpcMessageSerializeError {
712 type_info: "ExecutedData.output_objects".to_string(),
713 error: err.to_string(),
714 },
715 )?
716 .into(),
717 );
718 }
719 Ok(RawExecutedData {
720 effects,
721 events,
722 input_objects,
723 output_objects,
724 })
725 }
726}
727
728impl TryFrom<RawExecutedData> for ExecutedData {
729 type Error = crate::error::SuiError;
730
731 fn try_from(value: RawExecutedData) -> Result<Self, Self::Error> {
732 let effects = bcs::from_bytes(&value.effects).map_err(|err| {
733 crate::error::SuiErrorKind::GrpcMessageDeserializeError {
734 type_info: "RawExecutedData.effects".to_string(),
735 error: err.to_string(),
736 }
737 })?;
738 let events = if let Some(events) = value.events {
739 Some(bcs::from_bytes(&events).map_err(|err| {
740 crate::error::SuiErrorKind::GrpcMessageDeserializeError {
741 type_info: "RawExecutedData.events".to_string(),
742 error: err.to_string(),
743 }
744 })?)
745 } else {
746 None
747 };
748 let mut input_objects = Vec::with_capacity(value.input_objects.len());
749 for object in value.input_objects {
750 input_objects.push(bcs::from_bytes(&object).map_err(|err| {
751 crate::error::SuiErrorKind::GrpcMessageDeserializeError {
752 type_info: "RawExecutedData.input_objects".to_string(),
753 error: err.to_string(),
754 }
755 })?);
756 }
757 let mut output_objects = Vec::with_capacity(value.output_objects.len());
758 for object in value.output_objects {
759 output_objects.push(bcs::from_bytes(&object).map_err(|err| {
760 crate::error::SuiErrorKind::GrpcMessageDeserializeError {
761 type_info: "RawExecutedData.output_objects".to_string(),
762 error: err.to_string(),
763 }
764 })?);
765 }
766 Ok(ExecutedData {
767 effects,
768 events,
769 input_objects,
770 output_objects,
771 })
772 }
773}
774
775impl TryFrom<SubmitTxResult> for RawSubmitTxResult {
776 type Error = crate::error::SuiError;
777
778 fn try_from(value: SubmitTxResult) -> Result<Self, Self::Error> {
779 let inner = match value {
780 SubmitTxResult::Submitted { consensus_position } => {
781 let consensus_position = consensus_position.into_raw()?;
782 RawValidatorSubmitStatus::Submitted(consensus_position)
783 }
784 SubmitTxResult::Executed {
785 effects_digest,
786 details,
787 fast_path,
788 } => {
789 let raw_executed = try_from_response_executed(effects_digest, details, fast_path)?;
790 RawValidatorSubmitStatus::Executed(raw_executed)
791 }
792 SubmitTxResult::Rejected { error } => {
793 RawValidatorSubmitStatus::Rejected(try_from_response_rejected(Some(error))?)
794 }
795 };
796 Ok(RawSubmitTxResult { inner: Some(inner) })
797 }
798}
799
800impl TryFrom<RawSubmitTxResult> for SubmitTxResult {
801 type Error = crate::error::SuiError;
802
803 fn try_from(value: RawSubmitTxResult) -> Result<Self, Self::Error> {
804 match value.inner {
805 Some(RawValidatorSubmitStatus::Submitted(consensus_position)) => {
806 Ok(SubmitTxResult::Submitted {
807 consensus_position: consensus_position.as_ref().try_into()?,
808 })
809 }
810 Some(RawValidatorSubmitStatus::Executed(executed)) => {
811 let (effects_digest, details, fast_path) = try_from_raw_executed_status(executed)?;
812 Ok(SubmitTxResult::Executed {
813 effects_digest,
814 details,
815 fast_path,
816 })
817 }
818 Some(RawValidatorSubmitStatus::Rejected(error)) => {
819 let error = try_from_raw_rejected_status(error)?.unwrap_or(
820 crate::error::SuiErrorKind::GrpcMessageDeserializeError {
821 type_info: "RawSubmitTxResult.inner.Error".to_string(),
822 error: "RawSubmitTxResult.inner.Error is None".to_string(),
823 }
824 .into(),
825 );
826 Ok(SubmitTxResult::Rejected { error })
827 }
828 None => Err(crate::error::SuiErrorKind::GrpcMessageDeserializeError {
829 type_info: "RawSubmitTxResult.inner".to_string(),
830 error: "RawSubmitTxResult.inner is None".to_string(),
831 }
832 .into()),
833 }
834 }
835}
836
837impl TryFrom<RawSubmitTxResponse> for SubmitTxResponse {
838 type Error = crate::error::SuiError;
839
840 fn try_from(value: RawSubmitTxResponse) -> Result<Self, Self::Error> {
841 if value.results.len() != 1 {
843 return Err(crate::error::SuiErrorKind::GrpcMessageDeserializeError {
844 type_info: "RawSubmitTxResponse.results".to_string(),
845 error: format!("Expected exactly 1 result, got {}", value.results.len()),
846 }
847 .into());
848 }
849
850 let results = value
851 .results
852 .into_iter()
853 .map(|result| result.try_into())
854 .collect::<Result<Vec<SubmitTxResult>, crate::error::SuiError>>()?;
855
856 Ok(Self { results })
857 }
858}
859
860fn try_from_raw_executed_status(
861 executed: RawExecutedStatus,
862) -> Result<
863 (
864 crate::digests::TransactionEffectsDigest,
865 Option<Box<ExecutedData>>,
866 bool,
867 ),
868 crate::error::SuiError,
869> {
870 let effects_digest = bcs::from_bytes(&executed.effects_digest).map_err(|err| {
871 crate::error::SuiErrorKind::GrpcMessageDeserializeError {
872 type_info: "RawWaitForEffectsResponse.effects_digest".to_string(),
873 error: err.to_string(),
874 }
875 })?;
876 let executed_data = if let Some(details) = executed.details {
877 Some(Box::new(details.try_into()?))
878 } else {
879 None
880 };
881 Ok((effects_digest, executed_data, executed.fast_path))
882}
883
884fn try_from_raw_rejected_status(
885 rejected: RawRejectedStatus,
886) -> Result<Option<crate::error::SuiError>, crate::error::SuiError> {
887 match rejected.error {
888 Some(error_bytes) => {
889 let error = bcs::from_bytes(&error_bytes).map_err(|err| {
890 crate::error::SuiErrorKind::GrpcMessageDeserializeError {
891 type_info: "RawWaitForEffectsResponse.rejected.reason".to_string(),
892 error: err.to_string(),
893 }
894 })?;
895 Ok(Some(error))
896 }
897 None => Ok(None),
898 }
899}
900
901fn try_from_response_rejected(
902 error: Option<crate::error::SuiError>,
903) -> Result<RawRejectedStatus, crate::error::SuiError> {
904 let error = match error {
905 Some(e) => Some(
906 bcs::to_bytes(&e)
907 .map_err(
908 |err| crate::error::SuiErrorKind::GrpcMessageSerializeError {
909 type_info: "RawRejectedStatus.error".to_string(),
910 error: err.to_string(),
911 },
912 )?
913 .into(),
914 ),
915 None => None,
916 };
917 Ok(RawRejectedStatus { error })
918}
919
920fn try_from_response_executed(
921 effects_digest: crate::digests::TransactionEffectsDigest,
922 details: Option<Box<ExecutedData>>,
923 fast_path: bool,
924) -> Result<RawExecutedStatus, crate::error::SuiError> {
925 let effects_digest = bcs::to_bytes(&effects_digest)
926 .map_err(
927 |err| crate::error::SuiErrorKind::GrpcMessageSerializeError {
928 type_info: "RawWaitForEffectsResponse.effects_digest".to_string(),
929 error: err.to_string(),
930 },
931 )?
932 .into();
933 let details = if let Some(details) = details {
934 Some((*details).try_into()?)
935 } else {
936 None
937 };
938 Ok(RawExecutedStatus {
939 effects_digest,
940 details,
941 fast_path,
942 })
943}
944
945impl TryFrom<RawWaitForEffectsRequest> for WaitForEffectsRequest {
946 type Error = crate::error::SuiError;
947
948 fn try_from(value: RawWaitForEffectsRequest) -> Result<Self, Self::Error> {
949 let transaction_digest = match value.transaction_digest {
950 Some(digest) => Some(bcs::from_bytes(&digest).map_err(|err| {
951 crate::error::SuiErrorKind::GrpcMessageDeserializeError {
952 type_info: "RawWaitForEffectsRequest.transaction_digest".to_string(),
953 error: err.to_string(),
954 }
955 })?),
956 None => None,
957 };
958 let consensus_position = match value.consensus_position {
959 Some(cp) => Some(cp.as_ref().try_into()?),
960 None => None,
961 };
962 let ping_type = value
963 .ping_type
964 .map(|p| {
965 PingType::try_from(p).map_err(|e| SuiErrorKind::GrpcMessageDeserializeError {
966 type_info: "RawWaitForEffectsRequest.ping_type".to_string(),
967 error: e.to_string(),
968 })
969 })
970 .transpose()?;
971 Ok(Self {
972 consensus_position,
973 transaction_digest,
974 include_details: value.include_details,
975 ping_type,
976 })
977 }
978}
979
980impl TryFrom<WaitForEffectsRequest> for RawWaitForEffectsRequest {
981 type Error = crate::error::SuiError;
982
983 fn try_from(value: WaitForEffectsRequest) -> Result<Self, Self::Error> {
984 let transaction_digest = match value.transaction_digest {
985 Some(digest) => Some(
986 bcs::to_bytes(&digest)
987 .map_err(
988 |err| crate::error::SuiErrorKind::GrpcMessageSerializeError {
989 type_info: "RawWaitForEffectsRequest.transaction_digest".to_string(),
990 error: err.to_string(),
991 },
992 )?
993 .into(),
994 ),
995 None => None,
996 };
997 let consensus_position = match value.consensus_position {
998 Some(cp) => Some(cp.into_raw()?),
999 None => None,
1000 };
1001 let ping_type = value.ping_type.map(|p| p.into());
1002 Ok(Self {
1003 consensus_position,
1004 transaction_digest,
1005 include_details: value.include_details,
1006 ping_type,
1007 })
1008 }
1009}
1010
1011impl TryFrom<RawWaitForEffectsResponse> for WaitForEffectsResponse {
1012 type Error = crate::error::SuiError;
1013
1014 fn try_from(value: RawWaitForEffectsResponse) -> Result<Self, Self::Error> {
1015 match value.inner {
1016 Some(RawValidatorTransactionStatus::Executed(executed)) => {
1017 let (effects_digest, details, fast_path) = try_from_raw_executed_status(executed)?;
1018 Ok(Self::Executed {
1019 effects_digest,
1020 details,
1021 fast_path,
1022 })
1023 }
1024 Some(RawValidatorTransactionStatus::Rejected(rejected)) => {
1025 let error = try_from_raw_rejected_status(rejected)?;
1026 Ok(Self::Rejected { error })
1027 }
1028 Some(RawValidatorTransactionStatus::Expired(expired)) => Ok(Self::Expired {
1029 epoch: expired.epoch,
1030 round: expired.round,
1031 }),
1032 None => Err(crate::error::SuiErrorKind::GrpcMessageDeserializeError {
1033 type_info: "RawWaitForEffectsResponse.inner".to_string(),
1034 error: "RawWaitForEffectsResponse.inner is None".to_string(),
1035 }
1036 .into()),
1037 }
1038 }
1039}
1040
1041impl TryFrom<WaitForEffectsResponse> for RawWaitForEffectsResponse {
1042 type Error = crate::error::SuiError;
1043
1044 fn try_from(value: WaitForEffectsResponse) -> Result<Self, Self::Error> {
1045 let inner = match value {
1046 WaitForEffectsResponse::Executed {
1047 effects_digest,
1048 details,
1049 fast_path,
1050 } => {
1051 let raw_executed = try_from_response_executed(effects_digest, details, fast_path)?;
1052 RawValidatorTransactionStatus::Executed(raw_executed)
1053 }
1054 WaitForEffectsResponse::Rejected { error } => {
1055 let raw_rejected = try_from_response_rejected(error)?;
1056 RawValidatorTransactionStatus::Rejected(raw_rejected)
1057 }
1058 WaitForEffectsResponse::Expired { epoch, round } => {
1059 RawValidatorTransactionStatus::Expired(RawExpiredStatus { epoch, round })
1060 }
1061 };
1062 Ok(RawWaitForEffectsResponse { inner: Some(inner) })
1063 }
1064}
1065
1066impl TryFrom<ValidatorHealthRequest> for RawValidatorHealthRequest {
1067 type Error = crate::error::SuiError;
1068
1069 fn try_from(_value: ValidatorHealthRequest) -> Result<Self, Self::Error> {
1070 Ok(Self {})
1071 }
1072}
1073
1074impl TryFrom<RawValidatorHealthRequest> for ValidatorHealthRequest {
1075 type Error = crate::error::SuiError;
1076
1077 fn try_from(_value: RawValidatorHealthRequest) -> Result<Self, Self::Error> {
1078 Ok(Self {})
1080 }
1081}
1082
1083impl TryFrom<ValidatorHealthResponse> for RawValidatorHealthResponse {
1084 type Error = crate::error::SuiError;
1085
1086 fn try_from(value: ValidatorHealthResponse) -> Result<Self, Self::Error> {
1087 Ok(Self {
1088 pending_certificates: Some(value.num_inflight_execution_transactions),
1089 inflight_consensus_messages: Some(value.num_inflight_consensus_transactions),
1090 consensus_round: Some(value.last_committed_leader_round as u64),
1091 checkpoint_sequence: Some(value.last_locally_built_checkpoint),
1092 })
1093 }
1094}
1095
1096impl TryFrom<RawValidatorHealthResponse> for ValidatorHealthResponse {
1097 type Error = crate::error::SuiError;
1098
1099 fn try_from(value: RawValidatorHealthResponse) -> Result<Self, Self::Error> {
1100 Ok(Self {
1101 num_inflight_consensus_transactions: value.inflight_consensus_messages.unwrap_or(0),
1102 num_inflight_execution_transactions: value.pending_certificates.unwrap_or(0),
1103 last_locally_built_checkpoint: value.checkpoint_sequence.unwrap_or(0),
1104 last_committed_leader_round: value.consensus_round.unwrap_or(0) as u32,
1105 })
1106 }
1107}
1108
1109#[cfg(test)]
1110mod tests {
1111 use crate::{
1112 messages_grpc::{PingType, SubmitTxRequest, SubmitTxType},
1113 transaction::{Transaction, TransactionData},
1114 };
1115
1116 #[tokio::test]
1117 async fn test_submit_tx_request_into_raw() {
1118 println!(
1119 "Case 1. SubmitTxRequest::new_ping should be converted to RawSubmitTxRequest with submit_type set to Ping."
1120 );
1121 {
1122 let request = SubmitTxRequest::new_ping(PingType::Consensus);
1123 let raw_request = request.into_raw().unwrap();
1124
1125 let submit_type = SubmitTxType::try_from(raw_request.submit_type).unwrap();
1126 assert_eq!(submit_type, SubmitTxType::Ping);
1127 }
1128
1129 println!(
1130 "Case 2. SubmitTxRequest::new_transaction should be converted to RawSubmitTxRequest with submit_type set to Default."
1131 );
1132 {
1133 let sender = crate::base_types::SuiAddress::random_for_testing_only();
1135 let recipient = crate::base_types::SuiAddress::random_for_testing_only();
1136 let gas_object_ref = crate::base_types::random_object_ref();
1137
1138 let tx_data = TransactionData::new_transfer_sui(
1139 recipient,
1140 sender,
1141 None,
1142 gas_object_ref,
1143 1000,
1144 1000,
1145 );
1146
1147 let (_, keypair) = crate::crypto::get_account_key_pair();
1148 let transaction = Transaction::from_data_and_signer(tx_data, vec![&keypair]);
1149
1150 let request = SubmitTxRequest::new_transaction(transaction);
1151 let raw_request = request.into_raw().unwrap();
1152
1153 let submit_type = SubmitTxType::try_from(raw_request.submit_type).unwrap();
1154 assert_eq!(submit_type, SubmitTxType::Default);
1155 assert_eq!(raw_request.transactions.len(), 1);
1156 }
1157 }
1158}