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