sui_types/
transaction_driver_types.rs

1// Copyright (c) 2021, Facebook, Inc. and its affiliates
2// Copyright (c) Mysten Labs, Inc.
3// SPDX-License-Identifier: Apache-2.0
4
5use 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/// Client facing errors regarding transaction submission via Transaction Driver.
34/// Every invariant needs detailed documents to instruct client handling.
35#[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, // Txes that only use owned objects and/or immutable objects
117    SharedObject, // Txes that use at least one shared object
118}
119
120/// Proof of finality of transaction effects.
121#[derive(Serialize, Deserialize, Clone, Debug)]
122pub enum EffectsFinalityInfo {
123    /// Effects are certified by a quorum of validators.
124    Certified(AuthorityStrongQuorumSignInfo),
125
126    /// Effects are included in a checkpoint.
127    Checkpointed(EpochId, CheckpointSequenceNumber),
128
129    /// A quorum of validators have acknowledged effects.
130    QuorumExecuted(EpochId),
131}
132
133/// When requested to execute a transaction with WaitForLocalExecution,
134/// TransactionOrchestrator attempts to execute this transaction locally
135/// after it is finalized. This value represents whether the transaction
136/// is confirmed to be executed on this node before the response returns.
137pub 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    // Input objects will only be populated in the happy path
160    pub input_objects: Option<Vec<Object>>,
161    // Output objects will only be populated in the happy path
162    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    // Input objects will only be populated in the happy path
194    pub input_objects: Option<Vec<Object>>,
195    // Output objects will only be populated in the happy path
196    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}