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::{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/// Client facing errors regarding transaction submission via Transaction Driver.
24/// Every invariant needs detailed documents to instruct client handling.
25#[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/// Proof of finality of transaction effects.
105#[derive(Serialize, Deserialize, Clone, Debug)]
106pub enum EffectsFinalityInfo {
107    /// Effects are certified by a quorum of validators.
108    Certified(AuthorityStrongQuorumSignInfo),
109
110    /// Effects are included in a checkpoint.
111    Checkpointed(EpochId, CheckpointSequenceNumber),
112
113    /// A quorum of validators have acknowledged effects.
114    QuorumExecuted(EpochId),
115}
116
117/// When requested to execute a transaction with WaitForLocalExecution,
118/// TransactionOrchestrator attempts to execute this transaction locally
119/// after it is finalized. This value represents whether the transaction
120/// is confirmed to be executed on this node before the response returns.
121pub 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    // Input objects will only be populated in the happy path
162    pub input_objects: Option<Vec<Object>>,
163    // Output objects will only be populated in the happy path
164    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}