sui_types/
quorum_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 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/// Client facing errors regarding transaction submission via Quorum Driver.
32/// Every invariant needs detailed documents to instruct client handling.
33#[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("Transaction is already finalized but with different user signatures")]
69    TxAlreadyFinalizedWithDifferentUserSignatures,
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
79    // Wrapped error from Transaction Driver.
80    #[error("Transaction processing failed. Details: {details}")]
81    TransactionFailed {
82        category: ErrorCategory,
83        details: String,
84    },
85
86    #[error(
87        "Transaction is already being processed in transaction orchestrator (most likely by quorum driver), wait for results"
88    )]
89    PendingExecutionInTransactionOrchestrator,
90}
91
92pub type GroupedErrors = Vec<(SuiError, StakeUnit, Vec<ConciseAuthorityPublicKeyBytes>)>;
93
94#[derive(Serialize, Deserialize, Clone, Debug, schemars::JsonSchema)]
95pub enum ExecuteTransactionRequestType {
96    WaitForEffectsCert,
97    WaitForLocalExecution,
98}
99
100#[derive(Debug)]
101pub enum TransactionType {
102    SingleWriter, // Txes that only use owned objects and/or immutable objects
103    SharedObject, // Txes that use at least one shared object
104}
105
106/// Proof of finality of transaction effects.
107#[derive(Serialize, Deserialize, Clone, Debug)]
108pub enum EffectsFinalityInfo {
109    /// Effects are certified by a quorum of validators.
110    Certified(AuthorityStrongQuorumSignInfo),
111
112    /// Effects are included in a checkpoint.
113    Checkpointed(EpochId, CheckpointSequenceNumber),
114
115    /// A quorum of validators have acknowledged effects.
116    QuorumExecuted(EpochId),
117}
118
119/// When requested to execute a transaction with WaitForLocalExecution,
120/// TransactionOrchestrator attempts to execute this transaction locally
121/// after it is finalized. This value represents whether the transaction
122/// is confirmed to be executed on this node before the response returns.
123pub type IsTransactionExecutedLocally = bool;
124
125#[derive(Serialize, Deserialize, Clone, Debug)]
126pub enum ExecuteTransactionResponse {
127    EffectsCert(
128        Box<(
129            FinalizedEffects,
130            TransactionEvents,
131            IsTransactionExecutedLocally,
132        )>,
133    ),
134}
135
136#[derive(Clone, Debug)]
137pub struct QuorumDriverRequest {
138    pub transaction: VerifiedTransaction,
139}
140
141#[derive(Debug, Clone)]
142pub struct QuorumDriverResponse {
143    pub effects_cert: VerifiedCertifiedTransactionEffects,
144    // pub events: TransactionEvents,
145    pub events: Option<TransactionEvents>,
146    // Input objects will only be populated in the happy path
147    pub input_objects: Option<Vec<Object>>,
148    // Output objects will only be populated in the happy path
149    pub output_objects: Option<Vec<Object>>,
150    pub auxiliary_data: Option<Vec<u8>>,
151}
152
153#[derive(Serialize, Deserialize, Clone, Debug)]
154pub struct ExecuteTransactionRequestV3 {
155    pub transaction: Transaction,
156
157    pub include_events: bool,
158    pub include_input_objects: bool,
159    pub include_output_objects: bool,
160    pub include_auxiliary_data: bool,
161}
162
163impl ExecuteTransactionRequestV3 {
164    pub fn new_v2<T: Into<Transaction>>(transaction: T) -> Self {
165        Self {
166            transaction: transaction.into(),
167            include_events: true,
168            include_input_objects: false,
169            include_output_objects: false,
170            include_auxiliary_data: false,
171        }
172    }
173}
174
175#[derive(Serialize, Deserialize, Clone, Debug)]
176pub struct ExecuteTransactionResponseV3 {
177    pub effects: FinalizedEffects,
178
179    pub events: Option<TransactionEvents>,
180    // Input objects will only be populated in the happy path
181    pub input_objects: Option<Vec<Object>>,
182    // Output objects will only be populated in the happy path
183    pub output_objects: Option<Vec<Object>>,
184    pub auxiliary_data: Option<Vec<u8>>,
185}
186
187#[derive(Serialize, Deserialize, Clone, Debug)]
188pub struct FinalizedEffects {
189    pub effects: TransactionEffects,
190    pub finality_info: EffectsFinalityInfo,
191}
192
193impl FinalizedEffects {
194    pub fn new_from_effects_cert(effects_cert: CertifiedTransactionEffects) -> Self {
195        let (data, sig) = effects_cert.into_data_and_sig();
196        Self {
197            effects: data,
198            finality_info: EffectsFinalityInfo::Certified(sig),
199        }
200    }
201
202    pub fn epoch(&self) -> EpochId {
203        match &self.finality_info {
204            EffectsFinalityInfo::Certified(cert) => cert.epoch,
205            EffectsFinalityInfo::Checkpointed(epoch, _) => *epoch,
206            EffectsFinalityInfo::QuorumExecuted(epoch) => *epoch,
207        }
208    }
209
210    pub fn data(&self) -> &TransactionEffects {
211        &self.effects
212    }
213}