iota_types/
quorum_driver_types.rs

1// Copyright (c) 2021, Facebook, Inc. and its affiliates
2// Copyright (c) Mysten Labs, Inc.
3// Modifications Copyright (c) 2024 IOTA Stiftung
4// SPDX-License-Identifier: Apache-2.0
5
6use std::collections::BTreeMap;
7
8use serde::{Deserialize, Serialize};
9use strum::AsRefStr;
10use thiserror::Error;
11
12use crate::{
13    base_types::{AuthorityName, EpochId, ObjectRef, TransactionDigest},
14    committee::StakeUnit,
15    crypto::{AuthorityStrongQuorumSignInfo, ConciseAuthorityPublicKeyBytes},
16    effects::{
17        CertifiedTransactionEffects, TransactionEffects, TransactionEvents,
18        VerifiedCertifiedTransactionEffects,
19    },
20    error::IotaError,
21    messages_checkpoint::CheckpointSequenceNumber,
22    object::Object,
23    transaction::Transaction,
24};
25
26pub type QuorumDriverResult = Result<QuorumDriverResponse, QuorumDriverError>;
27
28pub type QuorumDriverEffectsQueueResult =
29    Result<(Transaction, QuorumDriverResponse), (TransactionDigest, QuorumDriverError)>;
30
31pub const NON_RECOVERABLE_ERROR_MSG: &str =
32    "Transaction has non recoverable errors from at least 1/3 of validators";
33
34/// Client facing errors regarding transaction submission via Quorum Driver.
35/// Every invariant needs detailed documents to instruct client handling.
36#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize, Error, Hash, AsRefStr)]
37pub enum QuorumDriverError {
38    #[error("QuorumDriver internal error: {0:?}.")]
39    QuorumDriverInternal(IotaError),
40    #[error("Invalid user signature: {0:?}.")]
41    InvalidUserSignature(IotaError),
42    #[error(
43        "Failed to sign transaction by a quorum of validators because of locked objects: {:?}, retried a conflicting transaction {:?}, success: {:?}",
44        conflicting_txes,
45        retried_tx,
46        retried_tx_success
47    )]
48    ObjectsDoubleUsed {
49        conflicting_txes: BTreeMap<TransactionDigest, (Vec<(AuthorityName, ObjectRef)>, StakeUnit)>,
50        retried_tx: Option<TransactionDigest>,
51        retried_tx_success: Option<bool>,
52    },
53    #[error("Transaction timed out before reaching finality")]
54    TimeoutBeforeFinality,
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
80pub type GroupedErrors = Vec<(IotaError, StakeUnit, Vec<ConciseAuthorityPublicKeyBytes>)>;
81
82#[derive(Serialize, Deserialize, Clone, Debug, schemars::JsonSchema)]
83pub enum ExecuteTransactionRequestType {
84    WaitForEffectsCert,
85    WaitForLocalExecution,
86}
87
88#[derive(Serialize, Deserialize, Clone, Debug)]
89pub enum EffectsFinalityInfo {
90    Certified(AuthorityStrongQuorumSignInfo),
91    Checkpointed(EpochId, CheckpointSequenceNumber),
92}
93
94/// When requested to execute a transaction with WaitForLocalExecution,
95/// TransactionOrchestrator attempts to execute this transaction locally
96/// after it is finalized. This value represents whether the transaction
97/// is confirmed to be executed on this node before the response returns.
98pub type IsTransactionExecutedLocally = bool;
99
100#[derive(Debug, Clone)]
101pub struct QuorumDriverResponse {
102    pub effects_cert: VerifiedCertifiedTransactionEffects,
103    // pub events: TransactionEvents,
104    pub events: Option<TransactionEvents>,
105    // Input objects will only be populated in the happy path
106    pub input_objects: Option<Vec<Object>>,
107    // Output objects will only be populated in the happy path
108    pub output_objects: Option<Vec<Object>>,
109    pub auxiliary_data: Option<Vec<u8>>,
110}
111
112#[derive(Serialize, Deserialize, Clone, Debug)]
113pub struct ExecuteTransactionRequestV1 {
114    pub transaction: Transaction,
115
116    pub include_events: bool,
117    pub include_input_objects: bool,
118    pub include_output_objects: bool,
119    pub include_auxiliary_data: bool,
120}
121
122impl ExecuteTransactionRequestV1 {
123    pub fn new<T: Into<Transaction>>(transaction: T) -> Self {
124        Self {
125            transaction: transaction.into(),
126            include_events: true,
127            include_input_objects: false,
128            include_output_objects: false,
129            include_auxiliary_data: false,
130        }
131    }
132}
133
134#[derive(Serialize, Deserialize, Clone, Debug)]
135pub struct ExecuteTransactionResponseV1 {
136    pub effects: FinalizedEffects,
137
138    pub events: Option<TransactionEvents>,
139    // Input objects will only be populated in the happy path
140    pub input_objects: Option<Vec<Object>>,
141    // Output objects will only be populated in the happy path
142    pub output_objects: Option<Vec<Object>>,
143    pub auxiliary_data: Option<Vec<u8>>,
144}
145
146#[derive(Serialize, Deserialize, Clone, Debug)]
147pub struct FinalizedEffects {
148    pub effects: TransactionEffects,
149    pub finality_info: EffectsFinalityInfo,
150}
151
152impl FinalizedEffects {
153    pub fn new_from_effects_cert(effects_cert: CertifiedTransactionEffects) -> Self {
154        let (data, sig) = effects_cert.into_data_and_sig();
155        Self {
156            effects: data,
157            finality_info: EffectsFinalityInfo::Certified(sig),
158        }
159    }
160
161    pub fn epoch(&self) -> EpochId {
162        match &self.finality_info {
163            EffectsFinalityInfo::Certified(cert) => cert.epoch,
164            EffectsFinalityInfo::Checkpointed(epoch, _) => *epoch,
165        }
166    }
167}