status.rs 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. use serde::{Deserialize, Serialize};
  2. use strum_macros::Display;
  3. /// Transaction status
  4. #[derive(Clone, Eq, PartialEq, Debug, Display, Serialize, Deserialize)]
  5. #[serde(rename_all = "snake_case")]
  6. pub enum Status {
  7. /// Pending status
  8. ///
  9. /// A transaction has been created. At this status the transaction can be
  10. /// Cancelled.
  11. /// From Processing it can be moved to Settled or Failed.
  12. Pending,
  13. /// Processing
  14. ///
  15. /// The transaction leaves the Pending status and it cannot longer be
  16. /// Cancelled by an external event.
  17. Processing,
  18. /// Cancelled.
  19. ///
  20. /// The transaction has been Cancelled, the funds that were burned are
  21. /// released and can be used again.
  22. Cancelled,
  23. /// Settled
  24. ///
  25. /// The transaction is settled, the inputs used to create the transaction
  26. /// are forever burned.
  27. Settled,
  28. /// Failed
  29. ///
  30. /// The transaction has failed, the inputs used to create the transaction
  31. /// are released and can be used again.
  32. Failed,
  33. }
  34. impl Default for Status {
  35. fn default() -> Self {
  36. Self::Pending
  37. }
  38. }
  39. #[derive(thiserror::Error, Debug)]
  40. pub enum Error {
  41. #[error("Invalid status: {0}")]
  42. InvalidStatus(u32),
  43. }
  44. impl TryFrom<u32> for Status {
  45. type Error = Error;
  46. fn try_from(value: u32) -> Result<Self, Self::Error> {
  47. match value {
  48. 0 => Ok(Self::Pending),
  49. 10 => Ok(Self::Processing),
  50. 20 => Ok(Self::Cancelled),
  51. 30 => Ok(Self::Settled),
  52. 40 => Ok(Self::Failed),
  53. _ => Err(Error::InvalidStatus(value)),
  54. }
  55. }
  56. }
  57. impl From<Status> for u32 {
  58. fn from(value: Status) -> Self {
  59. (&value).into()
  60. }
  61. }
  62. impl From<&Status> for u32 {
  63. fn from(value: &Status) -> Self {
  64. match value {
  65. Status::Pending => 0,
  66. Status::Processing => 10,
  67. Status::Cancelled => 20,
  68. Status::Settled => 30,
  69. Status::Failed => 40,
  70. }
  71. }
  72. }
  73. impl Status {
  74. /// Checks if the current status can transition to the new state.
  75. pub fn can_transition_to(&self, new_status: &Status) -> bool {
  76. if self == new_status {
  77. false
  78. } else {
  79. match self {
  80. Self::Pending => true,
  81. Self::Processing => {
  82. matches!(new_status, Self::Settled | Self::Failed)
  83. }
  84. _ => false,
  85. }
  86. }
  87. }
  88. /// Checks if the current status is a rollback operation.
  89. ///
  90. /// In a rollback operation any previously spent payments are released by the storage layer.
  91. pub fn is_rollback(&self) -> bool {
  92. matches!(self, Self::Cancelled | Self::Failed)
  93. }
  94. /// Checks if the transaction status is finalized
  95. pub fn is_finalized(&self) -> bool {
  96. matches!(self, Self::Cancelled | Self::Settled | Self::Failed)
  97. }
  98. }
  99. #[cfg(test)]
  100. mod test {
  101. use super::*;
  102. #[test]
  103. fn pending() {
  104. let status = Status::Pending;
  105. assert!(!status.can_transition_to(&Status::Pending));
  106. assert!(status.can_transition_to(&Status::Processing));
  107. assert!(status.can_transition_to(&Status::Cancelled));
  108. assert!(status.can_transition_to(&Status::Settled));
  109. assert!(status.can_transition_to(&Status::Failed));
  110. assert!(!status.is_finalized());
  111. assert!(!status.is_rollback());
  112. }
  113. #[test]
  114. fn processing() {
  115. let status = Status::Processing;
  116. assert!(!status.can_transition_to(&Status::Pending));
  117. assert!(!status.can_transition_to(&Status::Processing));
  118. assert!(!status.can_transition_to(&Status::Cancelled));
  119. assert!(status.can_transition_to(&Status::Settled));
  120. assert!(status.can_transition_to(&Status::Failed));
  121. assert!(!status.is_finalized());
  122. assert!(!status.is_rollback());
  123. }
  124. #[test]
  125. fn cancelled() {
  126. let status = Status::Cancelled;
  127. assert!(!status.can_transition_to(&Status::Pending));
  128. assert!(!status.can_transition_to(&Status::Processing));
  129. assert!(!status.can_transition_to(&Status::Cancelled));
  130. assert!(!status.can_transition_to(&Status::Settled));
  131. assert!(!status.can_transition_to(&Status::Failed));
  132. assert!(status.is_finalized());
  133. assert!(status.is_rollback());
  134. }
  135. #[test]
  136. fn settled() {
  137. let status = Status::Settled;
  138. assert!(!status.can_transition_to(&Status::Pending));
  139. assert!(!status.can_transition_to(&Status::Processing));
  140. assert!(!status.can_transition_to(&Status::Cancelled));
  141. assert!(!status.can_transition_to(&Status::Settled));
  142. assert!(!status.can_transition_to(&Status::Failed));
  143. assert!(status.is_finalized());
  144. assert!(!status.is_rollback());
  145. }
  146. #[test]
  147. fn failed() {
  148. let status = Status::Failed;
  149. assert!(!status.can_transition_to(&Status::Pending));
  150. assert!(!status.can_transition_to(&Status::Processing));
  151. assert!(!status.can_transition_to(&Status::Cancelled));
  152. assert!(!status.can_transition_to(&Status::Settled));
  153. assert!(!status.can_transition_to(&Status::Failed));
  154. assert!(status.is_finalized());
  155. assert!(status.is_rollback());
  156. }
  157. }