1use std::collections::BTreeMap;
6use std::time::Duration;
7
8use crate::base_types::{AuthorityName, EpochId, ObjectRef, TransactionDigest};
9use crate::committee::StakeUnit;
10use crate::crypto::{AuthorityStrongQuorumSignInfo, ConciseAuthorityPublicKeyBytes};
11use crate::effects::{TransactionEffects, TransactionEvents};
12use crate::error::{ErrorCategory, SuiError};
13use crate::messages_checkpoint::CheckpointSequenceNumber;
14use crate::object::Object;
15use crate::transaction::Transaction;
16use serde::{Deserialize, Serialize};
17use strum::AsRefStr;
18use thiserror::Error;
19
20pub const NON_RECOVERABLE_ERROR_MSG: &str =
21 "Transaction has non recoverable errors from at least 1/3 of validators";
22
23#[derive(Eq, PartialEq, Clone, Debug, Error, Hash, AsRefStr)]
26pub enum TransactionSubmissionError {
27 #[error("TransactionDriver internal error: {0}.")]
28 TransactionDriverInternalError(SuiError),
29 #[error("Invalid user signature: {0}.")]
30 InvalidUserSignature(SuiError),
31 #[error(
32 "Failed to sign transaction by a quorum of validators because of locked objects: {conflicting_txes:?}"
33 )]
34 ObjectsDoubleUsed {
35 conflicting_txes: BTreeMap<TransactionDigest, (Vec<(AuthorityName, ObjectRef)>, StakeUnit)>,
36 },
37 #[error("Transaction timed out before reaching finality")]
38 TimeoutBeforeFinality,
39 #[error(
40 "Transaction timed out before reaching finality. Last recorded retriable error: {last_error}"
41 )]
42 TimeoutBeforeFinalityWithErrors {
43 last_error: String,
44 attempts: u32,
45 timeout: Duration,
46 },
47 #[error(
48 "Transaction failed to reach finality with transient error after {total_attempts} attempts."
49 )]
50 FailedWithTransientErrorAfterMaximumAttempts { total_attempts: u32 },
51 #[error("{NON_RECOVERABLE_ERROR_MSG}: {errors:?}.")]
52 NonRecoverableTransactionError { errors: GroupedErrors },
53 #[error(
54 "Transaction is not processed because {overloaded_stake} of validators by stake are overloaded with certificates pending execution."
55 )]
56 SystemOverload {
57 overloaded_stake: StakeUnit,
58 errors: GroupedErrors,
59 },
60 #[error(
61 "Transaction is not processed because {overload_stake} of validators are overloaded and asked client to retry after {retry_after_secs}."
62 )]
63 SystemOverloadRetryAfter {
64 overload_stake: StakeUnit,
65 errors: GroupedErrors,
66 retry_after_secs: u64,
67 },
68 #[error("Transaction is already finalized but with different user signatures")]
69 TxAlreadyFinalizedWithDifferentUserSignatures,
70
71 #[error("Transaction processing failed. Details: {details}")]
72 TransactionFailed {
73 category: ErrorCategory,
74 details: String,
75 },
76}
77
78impl TransactionSubmissionError {
79 pub fn is_retriable(&self) -> bool {
80 match self {
81 Self::TransactionDriverInternalError { .. } => false,
82 Self::InvalidUserSignature { .. } => false,
83 Self::ObjectsDoubleUsed { .. } => false,
84 Self::TimeoutBeforeFinality => true,
85 Self::TimeoutBeforeFinalityWithErrors { .. } => true,
86 Self::FailedWithTransientErrorAfterMaximumAttempts { .. } => true,
87 Self::NonRecoverableTransactionError { .. } => false,
88 Self::SystemOverload { .. } => true,
89 Self::SystemOverloadRetryAfter { .. } => true,
90 Self::TxAlreadyFinalizedWithDifferentUserSignatures => false,
91 Self::TransactionFailed { category, .. } => category.is_submission_retriable(),
92 }
93 }
94}
95
96pub type GroupedErrors = Vec<(SuiError, StakeUnit, Vec<ConciseAuthorityPublicKeyBytes>)>;
97
98#[derive(Serialize, Deserialize, Clone, Debug, schemars::JsonSchema)]
99pub enum ExecuteTransactionRequestType {
100 WaitForEffectsCert,
101 WaitForLocalExecution,
102}
103
104#[derive(Serialize, Deserialize, Clone, Debug)]
106pub enum EffectsFinalityInfo {
107 Certified(AuthorityStrongQuorumSignInfo),
109
110 Checkpointed(EpochId, CheckpointSequenceNumber),
112
113 QuorumExecuted(EpochId),
115}
116
117pub type IsTransactionExecutedLocally = bool;
122
123#[derive(Serialize, Deserialize, Clone, Debug)]
124pub enum ExecuteTransactionResponse {
125 EffectsCert(
126 Box<(
127 FinalizedEffects,
128 TransactionEvents,
129 IsTransactionExecutedLocally,
130 )>,
131 ),
132}
133
134#[derive(Serialize, Deserialize, Clone, Debug)]
135pub struct ExecuteTransactionRequestV3 {
136 pub transaction: Transaction,
137
138 pub include_events: bool,
139 pub include_input_objects: bool,
140 pub include_output_objects: bool,
141 pub include_auxiliary_data: bool,
142}
143
144impl ExecuteTransactionRequestV3 {
145 pub fn new_v2<T: Into<Transaction>>(transaction: T) -> Self {
146 Self {
147 transaction: transaction.into(),
148 include_events: true,
149 include_input_objects: false,
150 include_output_objects: false,
151 include_auxiliary_data: false,
152 }
153 }
154}
155
156#[derive(Serialize, Deserialize, Clone, Debug)]
157pub struct ExecuteTransactionResponseV3 {
158 pub effects: FinalizedEffects,
159
160 pub events: Option<TransactionEvents>,
161 pub input_objects: Option<Vec<Object>>,
163 pub output_objects: Option<Vec<Object>>,
165 pub auxiliary_data: Option<Vec<u8>>,
166}
167
168#[derive(Serialize, Deserialize, Clone, Debug)]
169pub struct FinalizedEffects {
170 pub effects: TransactionEffects,
171 pub finality_info: EffectsFinalityInfo,
172}
173
174impl FinalizedEffects {
175 pub fn epoch(&self) -> EpochId {
176 match &self.finality_info {
177 EffectsFinalityInfo::Certified(cert) => cert.epoch,
178 EffectsFinalityInfo::Checkpointed(epoch, _) => *epoch,
179 EffectsFinalityInfo::QuorumExecuted(epoch) => *epoch,
180 }
181 }
182
183 pub fn data(&self) -> &TransactionEffects {
184 &self.effects
185 }
186}