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