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