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