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