1use crate::ObjectID;
5use crate::base_types::SuiAddress;
6use crate::error::{ExecutionError, ExecutionErrorTrait};
7use move_binary_format::file_format::{CodeOffset, TypeParameterIndex};
8use move_core_types::language_storage::ModuleId;
9use serde::{Deserialize, Serialize};
10use std::error::Error;
11use std::fmt::{self, Display, Formatter};
12use sui_macros::EnumVariantOrder;
13use thiserror::Error;
14
15#[cfg(test)]
16#[path = "unit_tests/execution_status_tests.rs"]
17mod execution_status_tests;
18
19#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize)]
20pub enum ExecutionStatus {
21 Success,
22 Failure(ExecutionFailure),
24}
25
26#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize)]
27pub struct ExecutionFailure {
28 pub error: ExecutionErrorKind,
29 pub command: Option<CommandIndex>,
30}
31
32impl From<ExecutionError> for ExecutionFailure {
33 fn from(value: ExecutionError) -> Self {
34 Self {
35 error: value.kind().clone(),
36 command: value.command(),
37 }
38 }
39}
40
41impl Error for ExecutionFailure {}
42
43impl Display for ExecutionFailure {
44 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
45 write!(f, "Execution Failure: {}", self.error)
46 }
47}
48
49impl ExecutionErrorTrait for ExecutionFailure {
50 fn with_command_index(self, command: CommandIndex) -> Self {
51 Self {
52 command: Some(command),
53 ..self
54 }
55 }
56 fn kind(&self) -> &ExecutionErrorKind {
57 &self.error
58 }
59 fn command(&self) -> Option<CommandIndex> {
60 self.command
61 }
62 fn source_ref(&self) -> Option<&(dyn Error + 'static)> {
63 None
64 }
65}
66
67#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize)]
68pub struct CongestedObjects(pub Vec<ObjectID>);
69
70impl fmt::Display for CongestedObjects {
71 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
72 for obj in &self.0 {
73 write!(f, "{}, ", obj)?;
74 }
75 Ok(())
76 }
77}
78
79pub type ExecutionFailureStatus = ExecutionErrorKind;
80
81#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize, Error, EnumVariantOrder)]
82pub enum ExecutionErrorKind {
83 #[error("Insufficient Gas.")]
87 InsufficientGas,
88 #[error("Invalid Gas Object. Possibly not address-owned or possibly not a SUI coin.")]
89 InvalidGasObject,
90 #[error("INVARIANT VIOLATION.")]
91 InvariantViolation,
92 #[error("Attempted to used feature that is not supported yet")]
93 FeatureNotYetSupported,
94 #[error(
95 "Move object with size {object_size} is larger \
96 than the maximum object size {max_object_size}"
97 )]
98 MoveObjectTooBig {
99 object_size: u64,
100 max_object_size: u64,
101 },
102 #[error(
103 "Move package with size {object_size} is larger than the \
104 maximum object size {max_object_size}"
105 )]
106 MovePackageTooBig {
107 object_size: u64,
108 max_object_size: u64,
109 },
110 #[error("Circular Object Ownership, including object {object}.")]
111 CircularObjectOwnership { object: ObjectID },
112
113 #[error("Insufficient coin balance for operation.")]
117 InsufficientCoinBalance,
118 #[error("The coin balance overflows u64")]
119 CoinBalanceOverflow,
120
121 #[error(
125 "Publish Error, Non-zero Address. \
126 The modules in the package must have their self-addresses set to zero."
127 )]
128 PublishErrorNonZeroAddress,
129
130 #[error(
131 "Sui Move Bytecode Verification Error. \
132 Please run the Sui Move Verifier for more information."
133 )]
134 SuiMoveVerificationError,
135
136 #[error(
141 "Move Primitive Runtime Error. Location: {0}. \
142 Arithmetic error, stack overflow, max value depth, etc."
143 )]
144 MovePrimitiveRuntimeError(MoveLocationOpt),
145 #[error("Move Runtime Abort. Location: {0}, Abort Code: {1}")]
146 MoveAbort(MoveLocation, u64),
147 #[error(
148 "Move Bytecode Verification Error. \
149 Please run the Bytecode Verifier for more information."
150 )]
151 VMVerificationOrDeserializationError,
152 #[error("MOVE VM INVARIANT VIOLATION.")]
153 VMInvariantViolation,
154
155 #[error("Function Not Found.")]
159 FunctionNotFound,
160 #[error(
161 "Arity mismatch for Move function. \
162 The number of arguments does not match the number of parameters"
163 )]
164 ArityMismatch,
165 #[error(
166 "Type arity mismatch for Move function. \
167 Mismatch between the number of actual versus expected type arguments."
168 )]
169 TypeArityMismatch,
170 #[error("Non Entry Function Invoked. Move Call must start with an entry function")]
171 NonEntryFunctionInvoked,
172 #[error("Invalid command argument at {arg_idx}. {kind}")]
173 CommandArgumentError {
174 arg_idx: u16,
175 kind: CommandArgumentError,
176 },
177 #[error("Error for type argument at index {argument_idx}: {kind}")]
178 TypeArgumentError {
179 argument_idx: TypeParameterIndex,
180 kind: TypeArgumentError,
181 },
182 #[error(
183 "Unused result without the drop ability. \
184 Command result {result_idx}, return value {secondary_idx}"
185 )]
186 UnusedValueWithoutDrop { result_idx: u16, secondary_idx: u16 },
187 #[error(
188 "Invalid public Move function signature. \
189 Unsupported return type for return value {idx}"
190 )]
191 InvalidPublicFunctionReturnType { idx: u16 },
192 #[error("Invalid Transfer Object, object does not have public transfer.")]
193 InvalidTransferObject,
194
195 #[error(
200 "Effects of size {current_size} bytes too large. \
201 Limit is {max_size} bytes"
202 )]
203 EffectsTooLarge { current_size: u64, max_size: u64 },
204
205 #[error(
206 "Publish/Upgrade Error, Missing dependency. \
207 A dependency of a published or upgraded package has not been assigned an on-chain \
208 address."
209 )]
210 PublishUpgradeMissingDependency,
211
212 #[error(
213 "Publish/Upgrade Error, Dependency downgrade. \
214 Indirect (transitive) dependency of published or upgraded package has been assigned an \
215 on-chain version that is less than the version required by one of the package's \
216 transitive dependencies."
217 )]
218 PublishUpgradeDependencyDowngrade,
219
220 #[error("Invalid package upgrade. {upgrade_error}")]
221 PackageUpgradeError { upgrade_error: PackageUpgradeError },
222
223 #[error(
225 "Written objects of {current_size} bytes too large. \
226 Limit is {max_size} bytes"
227 )]
228 WrittenObjectsTooLarge { current_size: u64, max_size: u64 },
229
230 #[error("Certificate is on the deny list")]
231 CertificateDenied,
232
233 #[error(
234 "Sui Move Bytecode Verification Timeout. \
235 Please run the Sui Move Verifier for more information."
236 )]
237 SuiMoveVerificationTimedout,
238
239 #[error("The shared object operation is not allowed.")]
240 SharedObjectOperationNotAllowed,
241
242 #[error(
243 "Certificate cannot be executed due to a dependency on a deleted shared object or an object that was transferred out of consensus"
244 )]
245 InputObjectDeleted,
246
247 #[error("Certificate is cancelled due to congestion on shared objects: {congested_objects}")]
248 ExecutionCancelledDueToSharedObjectCongestion { congested_objects: CongestedObjects },
249
250 #[error("Address {address:?} is denied for coin {coin_type}")]
251 AddressDeniedForCoin {
252 address: SuiAddress,
253 coin_type: String,
254 },
255
256 #[error("Coin type is globally paused for use: {coin_type}")]
257 CoinTypeGlobalPause { coin_type: String },
258
259 #[error("Certificate is cancelled because randomness could not be generated this epoch")]
260 ExecutionCancelledDueToRandomnessUnavailable,
261
262 #[error(
263 "Move vector element (passed to MakeMoveVec) with size {value_size} is larger \
264 than the maximum size {max_scaled_size}. Note that this maximum is scaled based on the \
265 type of the vector element."
266 )]
267 MoveVectorElemTooBig {
268 value_size: u64,
269 max_scaled_size: u64,
270 },
271
272 #[error(
273 "Move value (possibly an upgrade ticket or a dev-inspect value) with size {value_size} \
274 is larger than the maximum size {max_scaled_size}. Note that this maximum is scaled based \
275 on the type of the value."
276 )]
277 MoveRawValueTooBig {
278 value_size: u64,
279 max_scaled_size: u64,
280 },
281
282 #[error("A valid linkage was unable to be determined for the transaction")]
283 InvalidLinkage,
284
285 #[error("Insufficient funds for funds accumulator withdrawal")]
286 InsufficientFundsForWithdraw,
287
288 #[error("Non-exclusive write input object {id} has been modified")]
289 NonExclusiveWriteInputObjectModified { id: ObjectID },
290 }
293
294#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize, Hash)]
295pub struct MoveLocation {
296 pub module: ModuleId,
297 pub function: u16,
298 pub instruction: CodeOffset,
299 pub function_name: Option<String>,
300}
301
302#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize, Hash)]
303pub struct MoveLocationOpt(pub Option<MoveLocation>);
304
305#[derive(Eq, PartialEq, Copy, Clone, Debug, Serialize, Deserialize, Hash, Error)]
306pub enum CommandArgumentError {
307 #[error("The type of the value does not match the expected type")]
308 TypeMismatch,
309 #[error("The argument cannot be deserialized into a value of the specified type")]
310 InvalidBCSBytes,
311 #[error("The argument cannot be instantiated from raw bytes")]
312 InvalidUsageOfPureArg,
313 #[error(
314 "Invalid argument to private entry function. \
315 These functions cannot take arguments from other Move functions"
316 )]
317 InvalidArgumentToPrivateEntryFunction,
318 #[error("Out of bounds access to input or result vector {idx}")]
319 IndexOutOfBounds { idx: u16 },
320 #[error(
321 "Out of bounds secondary access to result vector \
322 {result_idx} at secondary index {secondary_idx}"
323 )]
324 SecondaryIndexOutOfBounds { result_idx: u16, secondary_idx: u16 },
325 #[error(
326 "Invalid usage of result {result_idx}, \
327 expected a single result but found either no return values or multiple."
328 )]
329 InvalidResultArity { result_idx: u16 },
330 #[error(
331 "Invalid taking of the Gas coin. \
332 It can only be used by-value with TransferObjects"
333 )]
334 InvalidGasCoinUsage,
335 #[error(
336 "Invalid usage of value. \
337 Mutably borrowed values require unique usage. \
338 Immutably borrowed values cannot be taken or borrowed mutably. \
339 Taken values cannot be used again."
340 )]
341 InvalidValueUsage,
342 #[error("Immutable objects cannot be passed by-value.")]
343 InvalidObjectByValue,
344 #[error("Immutable objects cannot be passed by mutable reference, &mut.")]
345 InvalidObjectByMutRef,
346 #[error(
347 "Shared object operations such a wrapping, freezing, or converting to owned are not \
348 allowed."
349 )]
350 SharedObjectOperationNotAllowed,
351 #[error(
352 "Invalid argument arity. Expected a single argument but found a result that expanded to \
353 multiple arguments."
354 )]
355 InvalidArgumentArity,
356 #[error(
357 "Object passed to TransferObject does not have public transfer, i.e. the `store` \
358 ability"
359 )]
360 InvalidTransferObject,
361 #[error(
362 "First argument to MakeMoveVec is not an object. If no type is specified for MakeMoveVec, all arguments must be the same object type."
363 )]
364 InvalidMakeMoveVecNonObjectArgument,
365 #[error("Specified argument location does not have a value and cannot be used")]
366 ArgumentWithoutValue,
367 #[error(
368 "Cannot move a borrowed value. The value's type does resulted in this argument usage \
369 being inferred as a move. This is likely due to the type not having the `copy` ability; \
370 although in rare cases, it could also be this is the last usage of a value without the \
371 `drop` ability."
372 )]
373 CannotMoveBorrowedValue,
374 #[error(
375 "Cannot write to an argument location that is still borrowed, and where that borrow \
376 is an extension of that reference. This is likely due to this argument being used in a \
377 Move call that returns a reference, and that reference is used in a later command."
378 )]
379 CannotWriteToExtendedReference,
380 #[error(
381 "The argument specified cannot be used as a reference argument in the Move call. Either \
382 the argument is a mutable reference and it conflicts with another argument to the call, \
383 or the argument is mutable and another reference extends it and will be used in a later \
384 command."
385 )]
386 InvalidReferenceArgument,
387}
388
389#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize, Hash, Error)]
390pub enum PackageUpgradeError {
391 #[error("Unable to fetch package at {package_id}")]
392 UnableToFetchPackage { package_id: ObjectID },
393 #[error("Object {object_id} is not a package")]
394 NotAPackage { object_id: ObjectID },
395 #[error("New package is incompatible with previous version")]
396 IncompatibleUpgrade,
397 #[error("Digest in upgrade ticket and computed digest disagree")]
398 DigestDoesNotMatch { digest: Vec<u8> },
399 #[error("Upgrade policy {policy} is not a valid upgrade policy")]
400 UnknownUpgradePolicy { policy: u8 },
401 #[error("Package ID {package_id} does not match package ID in upgrade ticket {ticket_id}")]
402 PackageIDDoesNotMatch {
403 package_id: ObjectID,
404 ticket_id: ObjectID,
405 },
406}
407
408#[derive(Eq, PartialEq, Clone, Copy, Debug, Serialize, Deserialize, Hash, Error)]
409pub enum TypeArgumentError {
410 #[error("A type was not found in the module specified.")]
411 TypeNotFound,
412 #[error("A type provided did not match the specified constraints.")]
413 ConstraintNotSatisfied,
414}
415
416impl ExecutionErrorKind {
417 pub fn command_argument_error(kind: CommandArgumentError, arg_idx: u16) -> Self {
418 Self::CommandArgumentError { arg_idx, kind }
419 }
420}
421
422impl Display for MoveLocationOpt {
423 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
424 match &self.0 {
425 None => write!(f, "UNKNOWN"),
426 Some(l) => write!(f, "{l}"),
427 }
428 }
429}
430
431impl Display for MoveLocation {
432 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
433 let Self {
434 module,
435 function,
436 instruction,
437 function_name,
438 } = self;
439 if let Some(fname) = function_name {
440 write!(
441 f,
442 "{module}::{fname} (function index {function}) at offset {instruction}"
443 )
444 } else {
445 write!(
446 f,
447 "{module} in function definition {function} at offset {instruction}"
448 )
449 }
450 }
451}
452
453impl ExecutionStatus {
454 pub fn new_failure(
455 error: ExecutionErrorKind,
456 command: Option<CommandIndex>,
457 ) -> ExecutionStatus {
458 ExecutionStatus::Failure(ExecutionFailure { error, command })
459 }
460
461 pub fn is_ok(&self) -> bool {
462 matches!(self, ExecutionStatus::Success)
463 }
464
465 pub fn is_err(&self) -> bool {
466 matches!(self, ExecutionStatus::Failure(_))
467 }
468
469 pub fn unwrap(&self) {
470 match self {
471 ExecutionStatus::Success => {}
472 ExecutionStatus::Failure(_) => {
473 panic!("Unable to unwrap() on {:?}", self);
474 }
475 }
476 }
477
478 pub fn unwrap_err(self) -> (ExecutionErrorKind, Option<CommandIndex>) {
479 match self {
480 ExecutionStatus::Success => {
481 panic!("Unable to unwrap() on {:?}", self);
482 }
483 ExecutionStatus::Failure(ExecutionFailure { error, command }) => (error, command),
484 }
485 }
486
487 pub fn get_congested_objects(&self) -> Option<&CongestedObjects> {
488 if let ExecutionStatus::Failure(ExecutionFailure {
489 error:
490 ExecutionErrorKind::ExecutionCancelledDueToSharedObjectCongestion { congested_objects },
491 ..
492 }) = self
493 {
494 Some(congested_objects)
495 } else {
496 None
497 }
498 }
499
500 pub fn is_cancelled(&self) -> bool {
501 matches!(
502 self,
503 ExecutionStatus::Failure(ExecutionFailure {
504 error: ExecutionErrorKind::ExecutionCancelledDueToSharedObjectCongestion { .. },
505 ..
506 })
507 )
508 }
509}
510
511pub type CommandIndex = usize;