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