|
@@ -258,13 +258,13 @@ where
|
|
|
pub async fn store(&self, transaction: Transaction) -> Result<Transaction, Error> {
|
|
|
transaction.validate()?;
|
|
|
|
|
|
- if let Some(previous) = &transaction.revision.previous {
|
|
|
+ let is_updating_status = if let Some(previous) = &transaction.revision.previous {
|
|
|
// Although this operation to check the previous version is being performed outside of
|
|
|
// the writer batch, it is safe to do so because the previous version is
|
|
|
// already stored in the storage layer, and the batch will make sure
|
|
|
// the previous version is the current revision, or else the entire operation will be
|
|
|
// revered
|
|
|
- if let Some(lock_token) = self
|
|
|
+ let previous = self
|
|
|
.config
|
|
|
.storage
|
|
|
.find(Filter {
|
|
@@ -273,64 +273,77 @@ where
|
|
|
})
|
|
|
.await?
|
|
|
.pop()
|
|
|
- .ok_or(Error::TxNotFound)?
|
|
|
- .revision
|
|
|
- .locked
|
|
|
- {
|
|
|
+ .ok_or(Error::TxNotFound)?;
|
|
|
+
|
|
|
+ if let Some(lock_token) = previous.revision.locked.as_ref() {
|
|
|
self.config
|
|
|
.token_manager
|
|
|
- .verify(lock_token, &transaction.revision.update_token)?
|
|
|
+ .verify(lock_token.to_owned(), &transaction.revision.update_token)?
|
|
|
}
|
|
|
- }
|
|
|
+
|
|
|
+ if previous.revision.status != transaction.revision.status {
|
|
|
+ self.config
|
|
|
+ .status
|
|
|
+ .is_valid_transition(&previous.revision.status, &transaction.revision.status)?;
|
|
|
+ true
|
|
|
+ } else {
|
|
|
+ false
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ true
|
|
|
+ };
|
|
|
|
|
|
let mut batch = self.config.storage.begin().await?;
|
|
|
if transaction.revision.previous.is_none() {
|
|
|
Self::store_base_transaction(&transaction, &mut batch).await?;
|
|
|
}
|
|
|
|
|
|
- let (created_updated, spent_updated) = match self
|
|
|
- .config
|
|
|
- .status
|
|
|
- .internal_type(&transaction.revision.status)
|
|
|
- {
|
|
|
- InternalStatus::Reverted => {
|
|
|
- batch
|
|
|
- .update_transaction_payments(
|
|
|
- &transaction.id,
|
|
|
- ReceivedPaymentStatus::Failed,
|
|
|
- ReceivedPaymentStatus::Spendable,
|
|
|
- )
|
|
|
- .await?
|
|
|
+ if is_updating_status {
|
|
|
+ let (created_updated, spent_updated) = match self
|
|
|
+ .config
|
|
|
+ .status
|
|
|
+ .internal_type(&transaction.revision.status)
|
|
|
+ {
|
|
|
+ InternalStatus::Reverted => {
|
|
|
+ batch
|
|
|
+ .update_transaction_payments(
|
|
|
+ &transaction.id,
|
|
|
+ ReceivedPaymentStatus::Failed,
|
|
|
+ ReceivedPaymentStatus::Spendable,
|
|
|
+ )
|
|
|
+ .await?
|
|
|
+ }
|
|
|
+ InternalStatus::Spendable => {
|
|
|
+ batch
|
|
|
+ .update_transaction_payments(
|
|
|
+ &transaction.id,
|
|
|
+ ReceivedPaymentStatus::Spendable,
|
|
|
+ ReceivedPaymentStatus::Spent,
|
|
|
+ )
|
|
|
+ .await?
|
|
|
+ }
|
|
|
+ _ => (transaction.creates.len(), transaction.spends.len()),
|
|
|
+ };
|
|
|
+
|
|
|
+ if transaction.creates.len() != created_updated
|
|
|
+ || transaction.spends.len() != spent_updated
|
|
|
+ {
|
|
|
+ return Err(Error::Transaction(TxError::NoUpdate));
|
|
|
}
|
|
|
- InternalStatus::Spendable => {
|
|
|
+
|
|
|
+ if self
|
|
|
+ .config
|
|
|
+ .status
|
|
|
+ .is_spendable(&transaction.revision.status)
|
|
|
+ {
|
|
|
batch
|
|
|
.update_transaction_payments(
|
|
|
&transaction.id,
|
|
|
ReceivedPaymentStatus::Spendable,
|
|
|
ReceivedPaymentStatus::Spent,
|
|
|
)
|
|
|
- .await?
|
|
|
+ .await?;
|
|
|
}
|
|
|
- _ => (transaction.creates.len(), transaction.spends.len()),
|
|
|
- };
|
|
|
-
|
|
|
- if transaction.creates.len() != created_updated || transaction.spends.len() != spent_updated
|
|
|
- {
|
|
|
- return Err(Error::Transaction(TxError::NoUpdate));
|
|
|
- }
|
|
|
-
|
|
|
- if self
|
|
|
- .config
|
|
|
- .status
|
|
|
- .is_spendable(&transaction.revision.status)
|
|
|
- {
|
|
|
- batch
|
|
|
- .update_transaction_payments(
|
|
|
- &transaction.id,
|
|
|
- ReceivedPaymentStatus::Spendable,
|
|
|
- ReceivedPaymentStatus::Spent,
|
|
|
- )
|
|
|
- .await?;
|
|
|
}
|
|
|
|
|
|
batch
|