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