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::{
12 CertifiedTransactionEffects, TransactionEffects, TransactionEvents,
13 VerifiedCertifiedTransactionEffects,
14};
15use crate::error::{ErrorCategory, SuiError};
16use crate::messages_checkpoint::CheckpointSequenceNumber;
17use crate::object::Object;
18use crate::transaction::{Transaction, VerifiedTransaction};
19use serde::{Deserialize, Serialize};
20use strum::AsRefStr;
21use thiserror::Error;
22
23pub type TransactionDriverResult = Result<TransactionDriverResponse, TransactionSubmissionError>;
24
25pub type TransactionDriverEffectsQueueResult = Result<
26 (Transaction, TransactionDriverResponse),
27 (TransactionDigest, TransactionSubmissionError),
28>;
29
30pub const NON_RECOVERABLE_ERROR_MSG: &str =
31 "Transaction has non recoverable errors from at least 1/3 of validators";
32
33#[derive(Eq, PartialEq, Clone, Debug, Error, Hash, AsRefStr)]
36pub enum TransactionSubmissionError {
37 #[error("TransactionDriver internal error: {0}.")]
38 TransactionDriverInternalError(SuiError),
39 #[error("Invalid user signature: {0}.")]
40 InvalidUserSignature(SuiError),
41 #[error(
42 "Failed to sign transaction by a quorum of validators because of locked objects: {conflicting_txes:?}"
43 )]
44 ObjectsDoubleUsed {
45 conflicting_txes: BTreeMap<TransactionDigest, (Vec<(AuthorityName, ObjectRef)>, StakeUnit)>,
46 },
47 #[error("Transaction timed out before reaching finality")]
48 TimeoutBeforeFinality,
49 #[error(
50 "Transaction timed out before reaching finality. Last recorded retriable error: {last_error}"
51 )]
52 TimeoutBeforeFinalityWithErrors {
53 last_error: String,
54 attempts: u32,
55 timeout: Duration,
56 },
57 #[error(
58 "Transaction failed to reach finality with transient error after {total_attempts} attempts."
59 )]
60 FailedWithTransientErrorAfterMaximumAttempts { total_attempts: u32 },
61 #[error("{NON_RECOVERABLE_ERROR_MSG}: {errors:?}.")]
62 NonRecoverableTransactionError { errors: GroupedErrors },
63 #[error(
64 "Transaction is not processed because {overloaded_stake} of validators by stake are overloaded with certificates pending execution."
65 )]
66 SystemOverload {
67 overloaded_stake: StakeUnit,
68 errors: GroupedErrors,
69 },
70 #[error(
71 "Transaction is not processed because {overload_stake} of validators are overloaded and asked client to retry after {retry_after_secs}."
72 )]
73 SystemOverloadRetryAfter {
74 overload_stake: StakeUnit,
75 errors: GroupedErrors,
76 retry_after_secs: u64,
77 },
78 #[error("Transaction is already finalized but with different user signatures")]
79 TxAlreadyFinalizedWithDifferentUserSignatures,
80
81 #[error("Transaction processing failed. Details: {details}")]
82 TransactionFailed {
83 category: ErrorCategory,
84 details: String,
85 },
86}
87
88impl TransactionSubmissionError {
89 pub fn is_retriable(&self) -> bool {
90 match self {
91 Self::TransactionDriverInternalError { .. } => false,
92 Self::InvalidUserSignature { .. } => false,
93 Self::ObjectsDoubleUsed { .. } => false,
94 Self::TimeoutBeforeFinality => true,
95 Self::TimeoutBeforeFinalityWithErrors { .. } => true,
96 Self::FailedWithTransientErrorAfterMaximumAttempts { .. } => true,
97 Self::NonRecoverableTransactionError { .. } => false,
98 Self::SystemOverload { .. } => true,
99 Self::SystemOverloadRetryAfter { .. } => true,
100 Self::TxAlreadyFinalizedWithDifferentUserSignatures => false,
101 Self::TransactionFailed { category, .. } => category.is_submission_retriable(),
102 }
103 }
104}
105
106pub type GroupedErrors = Vec<(SuiError, StakeUnit, Vec<ConciseAuthorityPublicKeyBytes>)>;
107
108#[derive(Serialize, Deserialize, Clone, Debug, schemars::JsonSchema)]
109pub enum ExecuteTransactionRequestType {
110 WaitForEffectsCert,
111 WaitForLocalExecution,
112}
113
114#[derive(Debug)]
115pub enum TransactionType {
116 SingleWriter, SharedObject, }
119
120#[derive(Serialize, Deserialize, Clone, Debug)]
122pub enum EffectsFinalityInfo {
123 Certified(AuthorityStrongQuorumSignInfo),
125
126 Checkpointed(EpochId, CheckpointSequenceNumber),
128
129 QuorumExecuted(EpochId),
131}
132
133pub type IsTransactionExecutedLocally = bool;
138
139#[derive(Serialize, Deserialize, Clone, Debug)]
140pub enum ExecuteTransactionResponse {
141 EffectsCert(
142 Box<(
143 FinalizedEffects,
144 TransactionEvents,
145 IsTransactionExecutedLocally,
146 )>,
147 ),
148}
149
150#[derive(Clone, Debug)]
151pub struct TransactionDriverRequest {
152 pub transaction: VerifiedTransaction,
153}
154
155#[derive(Debug, Clone)]
156pub struct TransactionDriverResponse {
157 pub effects_cert: VerifiedCertifiedTransactionEffects,
158 pub events: Option<TransactionEvents>,
159 pub input_objects: Option<Vec<Object>>,
161 pub output_objects: Option<Vec<Object>>,
163 pub auxiliary_data: Option<Vec<u8>>,
164}
165
166#[derive(Serialize, Deserialize, Clone, Debug)]
167pub struct ExecuteTransactionRequestV3 {
168 pub transaction: Transaction,
169
170 pub include_events: bool,
171 pub include_input_objects: bool,
172 pub include_output_objects: bool,
173 pub include_auxiliary_data: bool,
174}
175
176impl ExecuteTransactionRequestV3 {
177 pub fn new_v2<T: Into<Transaction>>(transaction: T) -> Self {
178 Self {
179 transaction: transaction.into(),
180 include_events: true,
181 include_input_objects: false,
182 include_output_objects: false,
183 include_auxiliary_data: false,
184 }
185 }
186}
187
188#[derive(Serialize, Deserialize, Clone, Debug)]
189pub struct ExecuteTransactionResponseV3 {
190 pub effects: FinalizedEffects,
191
192 pub events: Option<TransactionEvents>,
193 pub input_objects: Option<Vec<Object>>,
195 pub output_objects: Option<Vec<Object>>,
197 pub auxiliary_data: Option<Vec<u8>>,
198}
199
200#[derive(Serialize, Deserialize, Clone, Debug)]
201pub struct FinalizedEffects {
202 pub effects: TransactionEffects,
203 pub finality_info: EffectsFinalityInfo,
204}
205
206impl FinalizedEffects {
207 pub fn new_from_effects_cert(effects_cert: CertifiedTransactionEffects) -> Self {
208 let (data, sig) = effects_cert.into_data_and_sig();
209 Self {
210 effects: data,
211 finality_info: EffectsFinalityInfo::Certified(sig),
212 }
213 }
214
215 pub fn epoch(&self) -> EpochId {
216 match &self.finality_info {
217 EffectsFinalityInfo::Certified(cert) => cert.epoch,
218 EffectsFinalityInfo::Checkpointed(epoch, _) => *epoch,
219 EffectsFinalityInfo::QuorumExecuted(epoch) => *epoch,
220 }
221 }
222
223 pub fn data(&self) -> &TransactionEffects {
224 &self.effects
225 }
226}