1use std::fmt::Debug;
6
7use iota_json_rpc_types::{IotaEvent, IotaTransactionBlockEffects};
8use iota_protocol_config::{Chain, ProtocolVersion};
9use iota_sdk::error::Error as IotaRpcError;
10use iota_types::{
11 base_types::{IotaAddress, ObjectID, ObjectRef, SequenceNumber, VersionNumber},
12 digests::{ObjectDigest, TransactionDigest},
13 error::{IotaError, IotaObjectResponseError, IotaResult, UserInputError},
14 object::Object,
15 transaction::{InputObjectKind, SenderSignedData, TransactionKind},
16};
17use jsonrpsee::core::ClientError as JsonRpseeError;
18use move_binary_format::CompiledModule;
19use move_core_types::{
20 account_address::AccountAddress,
21 language_storage::{ModuleId, StructTag},
22};
23use serde::{Deserialize, Serialize};
24use thiserror::Error;
25use tokio::time::Duration;
26use tracing::{error, warn};
27
28use crate::config::ReplayableNetworkConfigSet;
29
30pub(crate) const RPC_TIMEOUT_ERR_SLEEP_RETRY_PERIOD: Duration = Duration::from_millis(100_000);
32pub(crate) const RPC_TIMEOUT_ERR_NUM_RETRIES: u32 = 3;
33pub(crate) const MAX_CONCURRENT_REQUESTS: usize = 1_000;
34
35pub(crate) const EPOCH_CHANGE_STRUCT_TAG: &str =
37 "0x3::iota_system_state_inner::SystemEpochInfoEventV1";
38
39#[derive(Clone, Debug, Serialize, Deserialize)]
42pub struct OnChainTransactionInfo {
43 pub tx_digest: TransactionDigest,
44 pub sender_signed_data: SenderSignedData,
45 pub sender: IotaAddress,
46 pub input_objects: Vec<InputObjectKind>,
47 pub kind: TransactionKind,
48 pub modified_at_versions: Vec<(ObjectID, SequenceNumber)>,
49 pub shared_object_refs: Vec<ObjectRef>,
50 pub gas: Vec<(ObjectID, SequenceNumber, ObjectDigest)>,
51 pub gas_budget: u64,
52 pub gas_price: u64,
53 pub executed_epoch: u64,
54 pub dependencies: Vec<TransactionDigest>,
55 #[serde(skip)]
56 pub receiving_objs: Vec<(ObjectID, SequenceNumber)>,
57 #[serde(skip)]
58 pub config_objects: Vec<(ObjectID, SequenceNumber)>,
59 pub effects: IotaTransactionBlockEffects,
66 pub protocol_version: ProtocolVersion,
67 pub epoch_start_timestamp: u64,
68 pub reference_gas_price: u64,
69 #[serde(default = "unspecified_chain")]
70 pub chain: Chain,
71}
72
73fn unspecified_chain() -> Chain {
74 warn!("Unable to determine chain id. Defaulting to unknown");
75 Chain::Unknown
76}
77
78#[derive(Debug, Error, Clone)]
79pub enum ReplayEngineError {
80 #[error("IotaError: {:#?}", err)]
81 IotaError { err: IotaError },
82
83 #[error("IotaRpcError: {:#?}", err)]
84 IotaRpcError { err: String },
85
86 #[error("IotaObjectResponseError: {:#?}", err)]
87 IotaObjectResponseError { err: IotaObjectResponseError },
88
89 #[error("UserInputError: {:#?}", err)]
90 UserInputError { err: UserInputError },
91
92 #[error("GeneralError: {:#?}", err)]
93 GeneralError { err: String },
94
95 #[error("IotaRpcRequestTimeout")]
96 IotaRpcRequestTimeout,
97
98 #[error("ObjectNotExist: {:#?}", id)]
99 ObjectNotExist { id: ObjectID },
100
101 #[error("ObjectVersionNotFound: {:#?} version {}", id, version)]
102 ObjectVersionNotFound {
103 id: ObjectID,
104 version: SequenceNumber,
105 },
106
107 #[error(
108 "ObjectVersionTooHigh: {:#?}, requested version {}, latest version found {}",
109 id,
110 asked_version,
111 latest_version
112 )]
113 ObjectVersionTooHigh {
114 id: ObjectID,
115 asked_version: SequenceNumber,
116 latest_version: SequenceNumber,
117 },
118
119 #[error(
120 "ObjectDeleted: {:#?} at version {:#?} digest {:#?}",
121 id,
122 version,
123 digest
124 )]
125 ObjectDeleted {
126 id: ObjectID,
127 version: SequenceNumber,
128 digest: ObjectDigest,
129 },
130
131 #[error(
132 "EffectsForked: Effects for digest {} forked with diff {}",
133 digest,
134 diff
135 )]
136 EffectsForked {
137 digest: TransactionDigest,
138 diff: String,
139 on_chain: Box<IotaTransactionBlockEffects>,
140 local: Box<IotaTransactionBlockEffects>,
141 },
142
143 #[error(
144 "Transaction {:#?} not supported by replay. Reason: {:?}",
145 digest,
146 reason
147 )]
148 TransactionNotSupported {
149 digest: TransactionDigest,
150 reason: String,
151 },
152
153 #[error(
154 "Fatal! No framework versions for protocol version {protocol_version}. Make sure version tables are populated"
155 )]
156 FrameworkObjectVersionTableNotPopulated { protocol_version: u64 },
157
158 #[error("Protocol version not found for epoch {epoch}")]
159 ProtocolVersionNotFound { epoch: u64 },
160
161 #[error("Error querying system events for epoch {epoch}")]
162 ErrorQueryingSystemEvents { epoch: u64 },
163
164 #[error("Invalid epoch change transaction in events for epoch {epoch}")]
165 InvalidEpochChangeTx { epoch: u64 },
166
167 #[error("Unexpected event format {:#?}", event)]
168 UnexpectedEventFormat { event: Box<IotaEvent> },
169
170 #[error("Unable to find event for epoch {epoch}")]
171 EventNotFound { epoch: u64 },
172
173 #[error("Unable to find checkpoints for epoch {epoch}")]
174 UnableToDetermineCheckpoint { epoch: u64 },
175
176 #[error("Unable to query system events; {}", rpc_err)]
177 UnableToQuerySystemEvents { rpc_err: String },
178
179 #[error("Internal error or cache corrupted! Object {id}{} should be in cache.", version.map(|q| format!(" version {:#?}", q)).unwrap_or_default()
180 )]
181 InternalCacheInvariantViolation {
182 id: ObjectID,
183 version: Option<SequenceNumber>,
184 },
185
186 #[error("Error getting dynamic fields loaded objects: {}", rpc_err)]
187 UnableToGetDynamicFieldLoadedObjects { rpc_err: String },
188
189 #[error("Unable to open yaml cfg file at {}: {}", path, err)]
190 UnableToOpenYamlFile { path: String, err: String },
191
192 #[error("Unable to write yaml file at {}: {}", path, err)]
193 UnableToWriteYamlFile { path: String, err: String },
194
195 #[error("Unable to convert string {} to URL {}", url, err)]
196 InvalidUrl { url: String, err: String },
197
198 #[error(
199 "Unable to execute transaction with existing network configs {:#?}",
200 cfgs
201 )]
202 UnableToExecuteWithNetworkConfigs { cfgs: ReplayableNetworkConfigSet },
203
204 #[error("Unable to get chain id: {}", err)]
205 UnableToGetChainId { err: String },
206}
207
208impl From<IotaObjectResponseError> for ReplayEngineError {
209 fn from(err: IotaObjectResponseError) -> Self {
210 match err {
211 IotaObjectResponseError::NotExists { object_id } => {
212 ReplayEngineError::ObjectNotExist { id: object_id }
213 }
214 IotaObjectResponseError::Deleted {
215 object_id,
216 digest,
217 version,
218 } => ReplayEngineError::ObjectDeleted {
219 id: object_id,
220 version,
221 digest,
222 },
223 _ => ReplayEngineError::IotaObjectResponseError { err },
224 }
225 }
226}
227
228impl From<ReplayEngineError> for IotaError {
229 fn from(err: ReplayEngineError) -> Self {
230 IotaError::Unknown(format!("{:#?}", err))
231 }
232}
233
234impl From<IotaError> for ReplayEngineError {
235 fn from(err: IotaError) -> Self {
236 ReplayEngineError::IotaError { err }
237 }
238}
239impl From<IotaRpcError> for ReplayEngineError {
240 fn from(err: IotaRpcError) -> Self {
241 match err {
242 IotaRpcError::Rpc(JsonRpseeError::RequestTimeout) => {
243 ReplayEngineError::IotaRpcRequestTimeout
244 }
245 _ => ReplayEngineError::IotaRpcError {
246 err: format!("{:?}", err),
247 },
248 }
249 }
250}
251
252impl From<UserInputError> for ReplayEngineError {
253 fn from(err: UserInputError) -> Self {
254 ReplayEngineError::UserInputError { err }
255 }
256}
257
258impl From<anyhow::Error> for ReplayEngineError {
259 fn from(err: anyhow::Error) -> Self {
260 ReplayEngineError::GeneralError {
261 err: format!("{:#?}", err),
262 }
263 }
264}
265
266#[derive(Debug)]
268pub enum ExecutionStoreEvent {
269 BackingPackageGetPackageObject {
270 package_id: ObjectID,
271 result: IotaResult<Option<Object>>,
272 },
273 ChildObjectResolverStoreReadChildObject {
274 parent: ObjectID,
275 child: ObjectID,
276 result: IotaResult<Option<Object>>,
277 },
278 ResourceResolverGetResource {
279 address: AccountAddress,
280 typ: StructTag,
281 result: IotaResult<Option<Vec<u8>>>,
282 },
283 ModuleResolverGetModule {
284 module_id: ModuleId,
285 result: IotaResult<Option<Vec<u8>>>,
286 },
287 ObjectStoreGetObject {
288 object_id: ObjectID,
289 result: IotaResult<Option<Object>>,
290 },
291 ObjectStoreGetObjectByKey {
292 object_id: ObjectID,
293 version: VersionNumber,
294 result: IotaResult<Option<Object>>,
295 },
296 GetModuleGetModuleByModuleId {
297 id: ModuleId,
298 result: IotaResult<Option<CompiledModule>>,
299 },
300 ReceiveObject {
301 owner: ObjectID,
302 receive: ObjectID,
303 receive_at_version: SequenceNumber,
304 result: IotaResult<Option<Object>>,
305 },
306}