1use std::{collections::BTreeMap, time::Duration};
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::{ErrorCategory, IotaError},
21 messages_checkpoint::CheckpointSequenceNumber,
22 object::Object,
23 transaction::{Transaction, VerifiedTransaction},
24};
25
26pub type TransactionDriverResult = Result<TransactionDriverResponse, TransactionSubmissionError>;
27
28pub type TransactionDriverEffectsQueueResult = Result<
29 (Transaction, TransactionDriverResponse),
30 (TransactionDigest, TransactionSubmissionError),
31>;
32
33pub const NON_RECOVERABLE_ERROR_MSG: &str =
34 "Transaction has non recoverable errors from at least 1/3 of validators";
35
36#[derive(Eq, PartialEq, Clone, Debug, Error, Hash, AsRefStr)]
40pub enum TransactionSubmissionError {
41 #[error("TransactionDriver internal error: {0}.")]
42 TransactionDriverInternalError(IotaError),
43 #[error("Invalid user signature: {0}.")]
44 InvalidUserSignature(IotaError),
45 #[error(
46 "Failed to sign transaction by a quorum of validators because of locked objects: {conflicting_txes:?}"
47 )]
48 ObjectsDoubleUsed {
49 conflicting_txes: BTreeMap<TransactionDigest, (Vec<(AuthorityName, ObjectRef)>, StakeUnit)>,
50 },
51 #[error("Transaction timed out before reaching finality")]
52 TimeoutBeforeFinality,
53 #[error(
54 "Transaction timed out before reaching finality. Last recorded retriable error: {last_error}"
55 )]
56 TimeoutBeforeFinalityWithErrors {
57 last_error: String,
58 attempts: u32,
59 timeout: Duration,
60 },
61 #[error(
62 "Transaction failed to reach finality with transient error after {total_attempts} attempts."
63 )]
64 FailedWithTransientErrorAfterMaximumAttempts { total_attempts: u32 },
65 #[error("{NON_RECOVERABLE_ERROR_MSG}: {errors:?}.")]
66 NonRecoverableTransactionError { errors: GroupedErrors },
67 #[error(
68 "Transaction is not processed because {overloaded_stake} of validators by stake are overloaded with certificates pending execution."
69 )]
70 SystemOverload {
71 overloaded_stake: StakeUnit,
72 errors: GroupedErrors,
73 },
74 #[error(
75 "Transaction is not processed because {overload_stake} of validators are overloaded and asked client to retry after {retry_after_secs}."
76 )]
77 SystemOverloadRetryAfter {
78 overload_stake: StakeUnit,
79 errors: GroupedErrors,
80 retry_after_secs: u64,
81 },
82 #[error("Transaction is already finalized but with different user signatures")]
83 TxAlreadyFinalizedWithDifferentUserSignatures,
84
85 #[error("Transaction processing failed. Details: {details}")]
86 TransactionFailed {
87 category: ErrorCategory,
88 details: String,
89 },
90}
91
92impl TransactionSubmissionError {
93 pub fn is_retriable(&self) -> bool {
94 match self {
95 Self::TransactionDriverInternalError { .. } => false,
96 Self::InvalidUserSignature { .. } => false,
97 Self::ObjectsDoubleUsed { .. } => false,
98 Self::TimeoutBeforeFinality => true,
99 Self::TimeoutBeforeFinalityWithErrors { .. } => true,
100 Self::FailedWithTransientErrorAfterMaximumAttempts { .. } => true,
101 Self::NonRecoverableTransactionError { .. } => false,
102 Self::SystemOverload { .. } => true,
103 Self::SystemOverloadRetryAfter { .. } => true,
104 Self::TxAlreadyFinalizedWithDifferentUserSignatures => false,
105 Self::TransactionFailed { category, .. } => category.is_submission_retriable(),
106 }
107 }
108}
109
110pub type GroupedErrors = Vec<(IotaError, StakeUnit, Vec<ConciseAuthorityPublicKeyBytes>)>;
111
112#[derive(Debug)]
113pub enum TransactionType {
114 SingleWriter, SharedObject, }
117
118#[derive(Clone, Debug)]
119pub struct TransactionDriverRequest {
120 pub transaction: VerifiedTransaction,
121}
122
123#[derive(Debug, Clone)]
124pub struct TransactionDriverResponse {
125 pub effects_cert: VerifiedCertifiedTransactionEffects,
126 pub events: Option<TransactionEvents>,
127 pub input_objects: Option<Vec<Object>>,
129 pub output_objects: Option<Vec<Object>>,
131 pub auxiliary_data: Option<Vec<u8>>,
132}
133
134#[derive(Serialize, Deserialize, Clone, Debug)]
136pub enum EffectsFinalityInfo {
137 Certified(AuthorityStrongQuorumSignInfo),
139
140 Checkpointed(EpochId, CheckpointSequenceNumber),
142
143 QuorumExecuted(EpochId),
145
146 UncertifiedSingleValidator(EpochId),
150}
151
152#[derive(Serialize, Deserialize, Clone, Debug)]
153pub struct FinalizedEffects {
154 pub effects: TransactionEffects,
155 pub finality_info: EffectsFinalityInfo,
156}
157
158impl FinalizedEffects {
159 pub fn new_from_effects_cert(effects_cert: CertifiedTransactionEffects) -> Self {
160 let (data, sig) = effects_cert.into_data_and_sig();
161 Self {
162 effects: data,
163 finality_info: EffectsFinalityInfo::Certified(sig),
164 }
165 }
166
167 pub fn epoch(&self) -> EpochId {
168 match &self.finality_info {
169 EffectsFinalityInfo::Certified(cert) => cert.epoch,
170 EffectsFinalityInfo::Checkpointed(epoch, _)
171 | EffectsFinalityInfo::QuorumExecuted(epoch)
172 | EffectsFinalityInfo::UncertifiedSingleValidator(epoch) => *epoch,
173 }
174 }
175
176 pub fn data(&self) -> &TransactionEffects {
177 &self.effects
178 }
179}