use crate::base_types::{ObjectID, SequenceNumber, TransactionDigest};
use crate::crypto::{AuthoritySignInfo, AuthorityStrongQuorumSignInfo};
use crate::effects::{
SignedTransactionEffects, TransactionEvents, VerifiedSignedTransactionEffects,
};
use crate::error::SuiError;
use crate::object::Object;
use crate::transaction::{CertifiedTransaction, SenderSignedData, SignedTransaction, Transaction};
use bytes::Bytes;
use move_core_types::annotated_value::MoveStructLayout;
use serde::{Deserialize, Serialize};
use mysten_metrics::TX_TYPE_SHARED_OBJ_TX;
use mysten_metrics::TX_TYPE_SINGLE_WRITER_TX;
use strum::EnumIter;
#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
pub enum ObjectInfoRequestKind {
LatestObjectInfo,
PastObjectInfoDebug(SequenceNumber),
}
#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
pub enum LayoutGenerationOption {
Generate,
None,
}
#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
pub struct ObjectInfoRequest {
pub object_id: ObjectID,
pub generate_layout: LayoutGenerationOption,
pub request_kind: ObjectInfoRequestKind,
}
impl ObjectInfoRequest {
pub fn past_object_info_debug_request(
object_id: ObjectID,
version: SequenceNumber,
generate_layout: LayoutGenerationOption,
) -> Self {
ObjectInfoRequest {
object_id,
generate_layout,
request_kind: ObjectInfoRequestKind::PastObjectInfoDebug(version),
}
}
pub fn latest_object_info_request(
object_id: ObjectID,
generate_layout: LayoutGenerationOption,
) -> Self {
ObjectInfoRequest {
object_id,
generate_layout,
request_kind: ObjectInfoRequestKind::LatestObjectInfo,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ObjectInfoResponse {
pub object: Object,
pub layout: Option<MoveStructLayout>,
pub lock_for_debugging: Option<SignedTransaction>,
}
#[derive(Debug, Clone)]
pub struct VerifiedObjectInfoResponse {
pub object: Object,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct TransactionInfoRequest {
pub transaction_digest: TransactionDigest,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum TransactionStatus {
Signed(AuthoritySignInfo),
Executed(
Option<AuthorityStrongQuorumSignInfo>,
SignedTransactionEffects,
TransactionEvents,
),
}
impl TransactionStatus {
pub fn into_signed_for_testing(self) -> AuthoritySignInfo {
match self {
Self::Signed(s) => s,
_ => unreachable!("Incorrect response type"),
}
}
pub fn into_effects_for_testing(self) -> SignedTransactionEffects {
match self {
Self::Executed(_, e, _) => e,
_ => unreachable!("Incorrect response type"),
}
}
}
impl PartialEq for TransactionStatus {
fn eq(&self, other: &Self) -> bool {
match self {
Self::Signed(s1) => match other {
Self::Signed(s2) => s1.epoch == s2.epoch,
_ => false,
},
Self::Executed(c1, e1, ev1) => match other {
Self::Executed(c2, e2, ev2) => {
c1.as_ref().map(|a| a.epoch) == c2.as_ref().map(|a| a.epoch)
&& e1.epoch() == e2.epoch()
&& e1.digest() == e2.digest()
&& ev1.digest() == ev2.digest()
}
_ => false,
},
}
}
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct HandleTransactionResponse {
pub status: TransactionStatus,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct TransactionInfoResponse {
pub transaction: SenderSignedData,
pub status: TransactionStatus,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct HandleCertificateResponseV2 {
pub signed_effects: SignedTransactionEffects,
pub events: TransactionEvents,
pub fastpath_input_objects: Vec<Object>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct SubmitCertificateResponse {
pub executed: Option<HandleCertificateResponseV2>,
}
#[derive(Clone, Debug)]
pub struct VerifiedHandleCertificateResponse {
pub signed_effects: VerifiedSignedTransactionEffects,
pub events: TransactionEvents,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct SystemStateRequest {
pub _unused: bool,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct HandleCertificateResponseV3 {
pub effects: SignedTransactionEffects,
pub events: Option<TransactionEvents>,
pub input_objects: Option<Vec<Object>>,
pub output_objects: Option<Vec<Object>>,
pub auxiliary_data: Option<Vec<u8>>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct HandleCertificateRequestV3 {
pub certificate: CertifiedTransaction,
pub include_events: bool,
pub include_input_objects: bool,
pub include_output_objects: bool,
pub include_auxiliary_data: bool,
}
impl From<HandleCertificateResponseV3> for HandleCertificateResponseV2 {
fn from(value: HandleCertificateResponseV3) -> Self {
Self {
signed_effects: value.effects,
events: value.events.unwrap_or_default(),
fastpath_input_objects: Vec::new(),
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct HandleSoftBundleCertificatesResponseV3 {
pub responses: Vec<HandleCertificateResponseV3>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct HandleSoftBundleCertificatesRequestV3 {
pub certificates: Vec<CertifiedTransaction>,
pub wait_for_effects: bool,
pub include_events: bool,
pub include_input_objects: bool,
pub include_output_objects: bool,
pub include_auxiliary_data: bool,
}
#[derive(Default, Clone)]
pub struct ExecutedData {
pub effects: crate::effects::TransactionEffects,
pub events: Option<crate::effects::TransactionEvents>,
pub input_objects: Vec<crate::object::Object>,
pub output_objects: Vec<crate::object::Object>,
}
#[derive(Clone, prost::Message)]
pub struct RawExecutedData {
#[prost(bytes = "bytes", tag = "1")]
pub effects: Bytes,
#[prost(bytes = "bytes", optional, tag = "2")]
pub events: Option<Bytes>,
#[prost(bytes = "bytes", repeated, tag = "3")]
pub input_objects: Vec<Bytes>,
#[prost(bytes = "bytes", repeated, tag = "4")]
pub output_objects: Vec<Bytes>,
}
#[derive(Clone, Debug)]
pub struct SubmitTxRequest {
pub transaction: Option<Transaction>,
pub ping_type: Option<PingType>,
}
impl SubmitTxRequest {
pub fn new_transaction(transaction: Transaction) -> Self {
Self {
transaction: Some(transaction),
ping_type: None,
}
}
pub fn new_ping(ping_type: PingType) -> Self {
Self {
transaction: None,
ping_type: Some(ping_type),
}
}
pub fn tx_type(&self) -> TxType {
if let Some(ping_type) = self.ping_type {
return if ping_type == PingType::FastPath {
TxType::SingleWriter
} else {
TxType::SharedObject
};
}
let transaction = self.transaction.as_ref().unwrap();
if transaction.is_consensus_tx() {
TxType::SharedObject
} else {
TxType::SingleWriter
}
}
pub fn tx_digest(&self) -> Option<TransactionDigest> {
self.transaction.as_ref().map(|t| *t.digest())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EnumIter)]
pub enum TxType {
SingleWriter,
SharedObject,
}
impl TxType {
pub fn as_str(&self) -> &str {
match self {
TxType::SingleWriter => TX_TYPE_SINGLE_WRITER_TX,
TxType::SharedObject => TX_TYPE_SHARED_OBJ_TX,
}
}
}
impl SubmitTxRequest {
pub fn into_raw(&self) -> Result<RawSubmitTxRequest, SuiError> {
let transactions = if let Some(transaction) = &self.transaction {
vec![bcs::to_bytes(&transaction)
.map_err(|e| SuiError::TransactionSerializationError {
error: e.to_string(),
})?
.into()]
} else {
vec![]
};
let submit_type = if self.ping_type.is_some() {
SubmitTxType::Ping
} else {
SubmitTxType::Default
};
Ok(RawSubmitTxRequest {
transactions,
submit_type: submit_type.into(),
})
}
}
#[derive(Clone)]
pub enum SubmitTxResult {
Submitted {
consensus_position: crate::messages_consensus::ConsensusPosition,
},
Executed {
effects_digest: crate::digests::TransactionEffectsDigest,
details: Option<Box<ExecutedData>>,
fast_path: bool,
},
Rejected {
error: crate::error::SuiError,
},
}
impl std::fmt::Debug for SubmitTxResult {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Submitted { consensus_position } => f
.debug_struct("Submitted")
.field("consensus_position", consensus_position)
.finish(),
Self::Executed {
effects_digest,
fast_path,
..
} => f
.debug_struct("Executed")
.field("effects_digest", &format_args!("{}", effects_digest))
.field("fast_path", fast_path)
.finish(),
Self::Rejected { error } => f.debug_struct("Rejected").field("error", &error).finish(),
}
}
}
#[derive(Clone, Debug)]
pub struct SubmitTxResponse {
pub results: Vec<SubmitTxResult>,
}
#[derive(Clone, prost::Message)]
pub struct RawSubmitTxRequest {
#[prost(bytes = "bytes", repeated, tag = "1")]
pub transactions: Vec<Bytes>,
#[prost(enumeration = "SubmitTxType", tag = "2")]
pub submit_type: i32,
}
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, prost::Enumeration)]
#[repr(i32)]
pub enum SubmitTxType {
Default = 0,
Ping = 1,
SoftBundle = 2,
}
#[derive(Clone, prost::Message)]
pub struct RawSubmitTxResponse {
#[prost(message, repeated, tag = "1")]
pub results: Vec<RawSubmitTxResult>,
}
#[derive(Clone, prost::Message)]
pub struct RawSubmitTxResult {
#[prost(oneof = "RawValidatorSubmitStatus", tags = "1, 2, 3")]
pub inner: Option<RawValidatorSubmitStatus>,
}
#[derive(Clone, prost::Oneof)]
pub enum RawValidatorSubmitStatus {
#[prost(bytes = "bytes", tag = "1")]
Submitted(Bytes),
#[prost(message, tag = "2")]
Executed(RawExecutedStatus),
#[prost(message, tag = "3")]
Rejected(RawRejectedStatus),
}
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, prost::Enumeration)]
#[repr(i32)]
pub enum PingType {
Consensus = 0,
FastPath = 1,
}
impl PingType {
pub fn as_str(&self) -> &str {
match self {
PingType::FastPath => "fastpath",
PingType::Consensus => "consensus",
}
}
}
pub struct WaitForEffectsRequest {
pub transaction_digest: Option<crate::digests::TransactionDigest>,
pub consensus_position: Option<crate::messages_consensus::ConsensusPosition>,
pub include_details: bool,
pub ping_type: Option<PingType>,
}
#[derive(Clone)]
pub enum WaitForEffectsResponse {
Executed {
effects_digest: crate::digests::TransactionEffectsDigest,
details: Option<Box<ExecutedData>>,
fast_path: bool,
},
Rejected {
error: Option<crate::error::SuiError>,
},
Expired {
epoch: u64,
round: Option<u32>,
},
}
impl std::fmt::Debug for WaitForEffectsResponse {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Executed {
effects_digest,
fast_path,
..
} => f
.debug_struct("Executed")
.field("effects_digest", effects_digest)
.field("fast_path", fast_path)
.finish(),
Self::Rejected { error } => f.debug_struct("Rejected").field("error", error).finish(),
Self::Expired { epoch, round } => f
.debug_struct("Expired")
.field("epoch", epoch)
.field("round", round)
.finish(),
}
}
}
#[derive(Clone, prost::Message)]
pub struct RawWaitForEffectsRequest {
#[prost(bytes = "bytes", optional, tag = "1")]
pub transaction_digest: Option<Bytes>,
#[prost(bytes = "bytes", optional, tag = "2")]
pub consensus_position: Option<Bytes>,
#[prost(bool, tag = "3")]
pub include_details: bool,
#[prost(enumeration = "PingType", optional, tag = "4")]
pub ping_type: Option<i32>,
}
impl RawWaitForEffectsRequest {
pub fn get_ping_type(&self) -> Option<PingType> {
self.ping_type
.map(|p| PingType::try_from(p).expect("Invalid ping type"))
}
}
#[derive(Clone, prost::Message)]
pub struct RawWaitForEffectsResponse {
#[prost(oneof = "RawValidatorTransactionStatus", tags = "1, 2, 3")]
pub inner: Option<RawValidatorTransactionStatus>,
}
#[derive(Clone, prost::Oneof)]
pub enum RawValidatorTransactionStatus {
#[prost(message, tag = "1")]
Executed(RawExecutedStatus),
#[prost(message, tag = "2")]
Rejected(RawRejectedStatus),
#[prost(message, tag = "3")]
Expired(RawExpiredStatus),
}
#[derive(Clone, prost::Message)]
pub struct RawExecutedStatus {
#[prost(bytes = "bytes", tag = "1")]
pub effects_digest: Bytes,
#[prost(message, optional, tag = "2")]
pub details: Option<RawExecutedData>,
#[prost(bool, tag = "3")]
pub fast_path: bool,
}
#[derive(Clone, prost::Message)]
pub struct RawRejectedStatus {
#[prost(bytes = "bytes", optional, tag = "1")]
pub error: Option<Bytes>,
}
#[derive(Clone, prost::Message)]
pub struct RawExpiredStatus {
#[prost(uint64, tag = "1")]
pub epoch: u64,
#[prost(uint32, optional, tag = "2")]
pub round: Option<u32>,
}
#[derive(Clone, Debug, Default)]
pub struct ValidatorHealthRequest {}
#[derive(Clone, Debug, Default)]
pub struct ValidatorHealthResponse {
pub num_inflight_execution_transactions: u64,
pub num_inflight_consensus_transactions: u64,
pub last_committed_leader_round: u32,
pub last_locally_built_checkpoint: u64,
}
#[derive(Clone, prost::Message)]
pub struct RawValidatorHealthRequest {}
#[derive(Clone, prost::Message)]
pub struct RawValidatorHealthResponse {
#[prost(uint64, optional, tag = "1")]
pub pending_certificates: Option<u64>,
#[prost(uint64, optional, tag = "2")]
pub inflight_consensus_messages: Option<u64>,
#[prost(uint64, optional, tag = "3")]
pub consensus_round: Option<u64>,
#[prost(uint64, optional, tag = "4")]
pub checkpoint_sequence: Option<u64>,
}
impl TryFrom<ExecutedData> for RawExecutedData {
type Error = crate::error::SuiError;
fn try_from(value: ExecutedData) -> Result<Self, Self::Error> {
let effects = bcs::to_bytes(&value.effects)
.map_err(|err| crate::error::SuiError::GrpcMessageSerializeError {
type_info: "ExecutedData.effects".to_string(),
error: err.to_string(),
})?
.into();
let events = if let Some(events) = &value.events {
Some(
bcs::to_bytes(events)
.map_err(|err| crate::error::SuiError::GrpcMessageSerializeError {
type_info: "ExecutedData.events".to_string(),
error: err.to_string(),
})?
.into(),
)
} else {
None
};
let mut input_objects = Vec::with_capacity(value.input_objects.len());
for object in value.input_objects {
input_objects.push(
bcs::to_bytes(&object)
.map_err(|err| crate::error::SuiError::GrpcMessageSerializeError {
type_info: "ExecutedData.input_objects".to_string(),
error: err.to_string(),
})?
.into(),
);
}
let mut output_objects = Vec::with_capacity(value.output_objects.len());
for object in value.output_objects {
output_objects.push(
bcs::to_bytes(&object)
.map_err(|err| crate::error::SuiError::GrpcMessageSerializeError {
type_info: "ExecutedData.output_objects".to_string(),
error: err.to_string(),
})?
.into(),
);
}
Ok(RawExecutedData {
effects,
events,
input_objects,
output_objects,
})
}
}
impl TryFrom<RawExecutedData> for ExecutedData {
type Error = crate::error::SuiError;
fn try_from(value: RawExecutedData) -> Result<Self, Self::Error> {
let effects = bcs::from_bytes(&value.effects).map_err(|err| {
crate::error::SuiError::GrpcMessageDeserializeError {
type_info: "RawExecutedData.effects".to_string(),
error: err.to_string(),
}
})?;
let events = if let Some(events) = value.events {
Some(bcs::from_bytes(&events).map_err(|err| {
crate::error::SuiError::GrpcMessageDeserializeError {
type_info: "RawExecutedData.events".to_string(),
error: err.to_string(),
}
})?)
} else {
None
};
let mut input_objects = Vec::with_capacity(value.input_objects.len());
for object in value.input_objects {
input_objects.push(bcs::from_bytes(&object).map_err(|err| {
crate::error::SuiError::GrpcMessageDeserializeError {
type_info: "RawExecutedData.input_objects".to_string(),
error: err.to_string(),
}
})?);
}
let mut output_objects = Vec::with_capacity(value.output_objects.len());
for object in value.output_objects {
output_objects.push(bcs::from_bytes(&object).map_err(|err| {
crate::error::SuiError::GrpcMessageDeserializeError {
type_info: "RawExecutedData.output_objects".to_string(),
error: err.to_string(),
}
})?);
}
Ok(ExecutedData {
effects,
events,
input_objects,
output_objects,
})
}
}
impl TryFrom<SubmitTxResult> for RawSubmitTxResult {
type Error = crate::error::SuiError;
fn try_from(value: SubmitTxResult) -> Result<Self, Self::Error> {
let inner = match value {
SubmitTxResult::Submitted { consensus_position } => {
let consensus_position = consensus_position.into_raw()?;
RawValidatorSubmitStatus::Submitted(consensus_position)
}
SubmitTxResult::Executed {
effects_digest,
details,
fast_path,
} => {
let raw_executed = try_from_response_executed(effects_digest, details, fast_path)?;
RawValidatorSubmitStatus::Executed(raw_executed)
}
SubmitTxResult::Rejected { error } => {
RawValidatorSubmitStatus::Rejected(try_from_response_rejected(Some(error))?)
}
};
Ok(RawSubmitTxResult { inner: Some(inner) })
}
}
impl TryFrom<RawSubmitTxResult> for SubmitTxResult {
type Error = crate::error::SuiError;
fn try_from(value: RawSubmitTxResult) -> Result<Self, Self::Error> {
match value.inner {
Some(RawValidatorSubmitStatus::Submitted(consensus_position)) => {
Ok(SubmitTxResult::Submitted {
consensus_position: consensus_position.as_ref().try_into()?,
})
}
Some(RawValidatorSubmitStatus::Executed(executed)) => {
let (effects_digest, details, fast_path) = try_from_raw_executed_status(executed)?;
Ok(SubmitTxResult::Executed {
effects_digest,
details,
fast_path,
})
}
Some(RawValidatorSubmitStatus::Rejected(error)) => {
let error = try_from_raw_rejected_status(error)?.unwrap_or(
crate::error::SuiError::GrpcMessageDeserializeError {
type_info: "RawSubmitTxResult.inner.Error".to_string(),
error: "RawSubmitTxResult.inner.Error is None".to_string(),
},
);
Ok(SubmitTxResult::Rejected { error })
}
None => Err(crate::error::SuiError::GrpcMessageDeserializeError {
type_info: "RawSubmitTxResult.inner".to_string(),
error: "RawSubmitTxResult.inner is None".to_string(),
}),
}
}
}
impl TryFrom<RawSubmitTxResponse> for SubmitTxResponse {
type Error = crate::error::SuiError;
fn try_from(value: RawSubmitTxResponse) -> Result<Self, Self::Error> {
if value.results.len() != 1 {
return Err(crate::error::SuiError::GrpcMessageDeserializeError {
type_info: "RawSubmitTxResponse.results".to_string(),
error: format!("Expected exactly 1 result, got {}", value.results.len()),
});
}
let results = value
.results
.into_iter()
.map(|result| result.try_into())
.collect::<Result<Vec<SubmitTxResult>, crate::error::SuiError>>()?;
Ok(Self { results })
}
}
fn try_from_raw_executed_status(
executed: RawExecutedStatus,
) -> Result<
(
crate::digests::TransactionEffectsDigest,
Option<Box<ExecutedData>>,
bool,
),
crate::error::SuiError,
> {
let effects_digest = bcs::from_bytes(&executed.effects_digest).map_err(|err| {
crate::error::SuiError::GrpcMessageDeserializeError {
type_info: "RawWaitForEffectsResponse.effects_digest".to_string(),
error: err.to_string(),
}
})?;
let executed_data = if let Some(details) = executed.details {
Some(Box::new(details.try_into()?))
} else {
None
};
Ok((effects_digest, executed_data, executed.fast_path))
}
fn try_from_raw_rejected_status(
rejected: RawRejectedStatus,
) -> Result<Option<crate::error::SuiError>, crate::error::SuiError> {
match rejected.error {
Some(error_bytes) => {
let error = bcs::from_bytes(&error_bytes).map_err(|err| {
crate::error::SuiError::GrpcMessageDeserializeError {
type_info: "RawWaitForEffectsResponse.rejected.reason".to_string(),
error: err.to_string(),
}
})?;
Ok(Some(error))
}
None => Ok(None),
}
}
fn try_from_response_rejected(
error: Option<crate::error::SuiError>,
) -> Result<RawRejectedStatus, crate::error::SuiError> {
let error = match error {
Some(e) => Some(
bcs::to_bytes(&e)
.map_err(|err| crate::error::SuiError::GrpcMessageSerializeError {
type_info: "RawRejectedStatus.error".to_string(),
error: err.to_string(),
})?
.into(),
),
None => None,
};
Ok(RawRejectedStatus { error })
}
fn try_from_response_executed(
effects_digest: crate::digests::TransactionEffectsDigest,
details: Option<Box<ExecutedData>>,
fast_path: bool,
) -> Result<RawExecutedStatus, crate::error::SuiError> {
let effects_digest = bcs::to_bytes(&effects_digest)
.map_err(|err| crate::error::SuiError::GrpcMessageSerializeError {
type_info: "RawWaitForEffectsResponse.effects_digest".to_string(),
error: err.to_string(),
})?
.into();
let details = if let Some(details) = details {
Some((*details).try_into()?)
} else {
None
};
Ok(RawExecutedStatus {
effects_digest,
details,
fast_path,
})
}
impl TryFrom<RawWaitForEffectsRequest> for WaitForEffectsRequest {
type Error = crate::error::SuiError;
fn try_from(value: RawWaitForEffectsRequest) -> Result<Self, Self::Error> {
let transaction_digest = match value.transaction_digest {
Some(digest) => Some(bcs::from_bytes(&digest).map_err(|err| {
crate::error::SuiError::GrpcMessageDeserializeError {
type_info: "RawWaitForEffectsRequest.transaction_digest".to_string(),
error: err.to_string(),
}
})?),
None => None,
};
let consensus_position = match value.consensus_position {
Some(cp) => Some(cp.as_ref().try_into()?),
None => None,
};
let ping_type = value
.ping_type
.map(|p| {
PingType::try_from(p).map_err(|e| SuiError::GrpcMessageDeserializeError {
type_info: "RawWaitForEffectsRequest.ping_type".to_string(),
error: e.to_string(),
})
})
.transpose()?;
Ok(Self {
consensus_position,
transaction_digest,
include_details: value.include_details,
ping_type,
})
}
}
impl TryFrom<WaitForEffectsRequest> for RawWaitForEffectsRequest {
type Error = crate::error::SuiError;
fn try_from(value: WaitForEffectsRequest) -> Result<Self, Self::Error> {
let transaction_digest = match value.transaction_digest {
Some(digest) => Some(
bcs::to_bytes(&digest)
.map_err(|err| crate::error::SuiError::GrpcMessageSerializeError {
type_info: "RawWaitForEffectsRequest.transaction_digest".to_string(),
error: err.to_string(),
})?
.into(),
),
None => None,
};
let consensus_position = match value.consensus_position {
Some(cp) => Some(cp.into_raw()?),
None => None,
};
let ping_type = value.ping_type.map(|p| p.into());
Ok(Self {
consensus_position,
transaction_digest,
include_details: value.include_details,
ping_type,
})
}
}
impl TryFrom<RawWaitForEffectsResponse> for WaitForEffectsResponse {
type Error = crate::error::SuiError;
fn try_from(value: RawWaitForEffectsResponse) -> Result<Self, Self::Error> {
match value.inner {
Some(RawValidatorTransactionStatus::Executed(executed)) => {
let (effects_digest, details, fast_path) = try_from_raw_executed_status(executed)?;
Ok(Self::Executed {
effects_digest,
details,
fast_path,
})
}
Some(RawValidatorTransactionStatus::Rejected(rejected)) => {
let error = try_from_raw_rejected_status(rejected)?;
Ok(Self::Rejected { error })
}
Some(RawValidatorTransactionStatus::Expired(expired)) => Ok(Self::Expired {
epoch: expired.epoch,
round: expired.round,
}),
None => Err(crate::error::SuiError::GrpcMessageDeserializeError {
type_info: "RawWaitForEffectsResponse.inner".to_string(),
error: "RawWaitForEffectsResponse.inner is None".to_string(),
}),
}
}
}
impl TryFrom<WaitForEffectsResponse> for RawWaitForEffectsResponse {
type Error = crate::error::SuiError;
fn try_from(value: WaitForEffectsResponse) -> Result<Self, Self::Error> {
let inner = match value {
WaitForEffectsResponse::Executed {
effects_digest,
details,
fast_path,
} => {
let raw_executed = try_from_response_executed(effects_digest, details, fast_path)?;
RawValidatorTransactionStatus::Executed(raw_executed)
}
WaitForEffectsResponse::Rejected { error } => {
let raw_rejected = try_from_response_rejected(error)?;
RawValidatorTransactionStatus::Rejected(raw_rejected)
}
WaitForEffectsResponse::Expired { epoch, round } => {
RawValidatorTransactionStatus::Expired(RawExpiredStatus { epoch, round })
}
};
Ok(RawWaitForEffectsResponse { inner: Some(inner) })
}
}
impl TryFrom<ValidatorHealthRequest> for RawValidatorHealthRequest {
type Error = crate::error::SuiError;
fn try_from(_value: ValidatorHealthRequest) -> Result<Self, Self::Error> {
Ok(Self {})
}
}
impl TryFrom<RawValidatorHealthRequest> for ValidatorHealthRequest {
type Error = crate::error::SuiError;
fn try_from(_value: RawValidatorHealthRequest) -> Result<Self, Self::Error> {
Ok(Self {})
}
}
impl TryFrom<ValidatorHealthResponse> for RawValidatorHealthResponse {
type Error = crate::error::SuiError;
fn try_from(value: ValidatorHealthResponse) -> Result<Self, Self::Error> {
Ok(Self {
pending_certificates: Some(value.num_inflight_execution_transactions),
inflight_consensus_messages: Some(value.num_inflight_consensus_transactions),
consensus_round: Some(value.last_committed_leader_round as u64),
checkpoint_sequence: Some(value.last_locally_built_checkpoint),
})
}
}
impl TryFrom<RawValidatorHealthResponse> for ValidatorHealthResponse {
type Error = crate::error::SuiError;
fn try_from(value: RawValidatorHealthResponse) -> Result<Self, Self::Error> {
Ok(Self {
num_inflight_consensus_transactions: value.inflight_consensus_messages.unwrap_or(0),
num_inflight_execution_transactions: value.pending_certificates.unwrap_or(0),
last_locally_built_checkpoint: value.checkpoint_sequence.unwrap_or(0),
last_committed_leader_round: value.consensus_round.unwrap_or(0) as u32,
})
}
}
#[cfg(test)]
mod tests {
use crate::{
messages_grpc::{PingType, SubmitTxRequest, SubmitTxType},
transaction::{Transaction, TransactionData},
};
#[tokio::test]
async fn test_submit_tx_request_into_raw() {
println!("Case 1. SubmitTxRequest::new_ping should be converted to RawSubmitTxRequest with submit_type set to Ping.");
{
let request = SubmitTxRequest::new_ping(PingType::Consensus);
let raw_request = request.into_raw().unwrap();
let submit_type = SubmitTxType::try_from(raw_request.submit_type).unwrap();
assert_eq!(submit_type, SubmitTxType::Ping);
}
println!("Case 2. SubmitTxRequest::new_transaction should be converted to RawSubmitTxRequest with submit_type set to Default.");
{
let sender = crate::base_types::SuiAddress::random_for_testing_only();
let recipient = crate::base_types::SuiAddress::random_for_testing_only();
let gas_object_ref = crate::base_types::random_object_ref();
let tx_data = TransactionData::new_transfer_sui(
recipient,
sender,
None,
gas_object_ref,
1000,
1000,
);
let (_, keypair) = crate::crypto::get_account_key_pair();
let transaction = Transaction::from_data_and_signer(tx_data, vec![&keypair]);
let request = SubmitTxRequest::new_transaction(transaction);
let raw_request = request.into_raw().unwrap();
let submit_type = SubmitTxType::try_from(raw_request.submit_type).unwrap();
assert_eq!(submit_type, SubmitTxType::Default);
assert_eq!(raw_request.transactions.len(), 1);
}
}
}