gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-wallet-core] branch master updated: finish implementation of abor


From: gnunet
Subject: [taler-wallet-core] branch master updated: finish implementation of abort / cancelAborting on all tx types
Date: Tue, 30 May 2023 12:28:25 +0200

This is an automated email from the git hooks/post-receive script.

dold pushed a commit to branch master
in repository wallet-core.

The following commit(s) were added to refs/heads/master by this push:
     new 000359a5e finish implementation of abort / cancelAborting on all tx 
types
000359a5e is described below

commit 000359a5e746d9b704b05f2f3eb8442e10a31f75
Author: Florian Dold <florian@dold.me>
AuthorDate: Tue May 30 12:28:21 2023 +0200

    finish implementation of abort / cancelAborting on all tx types
---
 packages/taler-util/src/transactions-types.ts      |   1 +
 packages/taler-wallet-core/src/db.ts               |  21 +-
 .../taler-wallet-core/src/operations/deposits.ts   |   2 +-
 .../src/operations/pay-merchant.ts                 |  83 ++++-
 .../taler-wallet-core/src/operations/pay-peer.ts   | 410 +++++++++++++++++++++
 .../taler-wallet-core/src/operations/refresh.ts    |  64 +++-
 packages/taler-wallet-core/src/operations/tip.ts   |  97 ++++-
 .../src/operations/transactions.ts                 |  67 +++-
 8 files changed, 690 insertions(+), 55 deletions(-)

diff --git a/packages/taler-util/src/transactions-types.ts 
b/packages/taler-util/src/transactions-types.ts
index 38cbea736..c06bc7369 100644
--- a/packages/taler-util/src/transactions-types.ts
+++ b/packages/taler-util/src/transactions-types.ts
@@ -116,6 +116,7 @@ export enum TransactionMinorState {
   WithdrawCoins = "withdraw-coins",
   ExchangeWaitReserve = "exchange-wait-reserve",
   AbortingBank = "aborting-bank",
+  Aborting = "aborting",
   Refused = "refused",
   Withdraw = "withdraw",
   MerchantOrderProposed = "merchant-order-proposed",
diff --git a/packages/taler-wallet-core/src/db.ts 
b/packages/taler-wallet-core/src/db.ts
index 3edaf8af5..3147cb9b9 100644
--- a/packages/taler-wallet-core/src/db.ts
+++ b/packages/taler-wallet-core/src/db.ts
@@ -879,6 +879,7 @@ export enum TipRecordStatus {
   SuspendidPickup = 21,
 
   Done = 50,
+  Aborted = 51,
 }
 
 export enum RefreshCoinStatus {
@@ -899,9 +900,10 @@ export enum OperationStatus {
 
 export enum RefreshOperationStatus {
   Pending = 10 /* ACTIVE_START */,
+  Suspended = 20 /* DORMANT_START + 2 */,
+
   Finished = 50 /* DORMANT_START */,
-  FinishedWithError = 51 /* DORMANT_START + 1 */,
-  Suspended = 52 /* DORMANT_START + 2 */,
+  Failed = 51 /* DORMANT_START + 1 */,
 }
 
 export enum DepositGroupOperationStatus {
@@ -1155,6 +1157,8 @@ export enum PurchaseStatus {
    * Payment was successful.
    */
   Done = 54,
+
+  FailedAbort = 55,
 }
 
 /**
@@ -1778,6 +1782,7 @@ export enum PeerPushPaymentInitiationStatus {
 
   Done = 50 /* DORMANT_START */,
   Aborted = 51,
+  Failed = 52,
 }
 
 export interface PeerPushPaymentCoinSelection {
@@ -1850,13 +1855,17 @@ export enum PeerPullPaymentInitiationStatus {
   PendingReady = 11 /* ACTIVE_START + 1 */,
   PendingMergeKycRequired = 12 /* ACTIVE_START + 2 */,
   PendingWithdrawing = 13,
+  AbortingDeletePurse = 14,
 
   SuspendedCreatePurse = 30,
   SuspendedReady = 31,
   SuspendedMergeKycRequired = 32,
   SuspendedWithdrawing = 33,
+  SuspendedAbortingDeletePurse = 34,
 
   DonePurseDeposited = 50 /* DORMANT_START */,
+  Failed = 51,
+  Aborted = 52,
 }
 
 export interface PeerPullPaymentInitiationRecord {
@@ -1927,6 +1936,8 @@ export enum PeerPushPaymentIncomingStatus {
   DialogProposed = 30 /* USER_ATTENTION_START */,
 
   Done = 50 /* DORMANT_START */,
+  Aborted = 51,
+  Failed = 52,
 }
 
 /**
@@ -1978,12 +1989,16 @@ export interface PeerPushPaymentIncomingRecord {
 
 export enum PeerPullDebitRecordStatus {
   PendingDeposit = 10 /* ACTIVE_START */,
+  AbortingRefresh = 11,
 
-  SuspendedDeposit = 11,
+  SuspendedDeposit = 20,
+  SuspendedAbortingRefresh = 21,
 
   DialogProposed = 30 /* USER_ATTENTION_START */,
 
   DonePaid = 50 /* DORMANT_START */,
+  Aborted = 51,
+  Failed = 52,
 }
 
 export interface PeerPullPaymentCoinSelection {
diff --git a/packages/taler-wallet-core/src/operations/deposits.ts 
b/packages/taler-wallet-core/src/operations/deposits.ts
index de881ddd2..1ed2a705e 100644
--- a/packages/taler-wallet-core/src/operations/deposits.ts
+++ b/packages/taler-wallet-core/src/operations/deposits.ts
@@ -447,7 +447,7 @@ async function waitForRefreshOnDepositGroup(
           newOpState = DepositOperationStatus.Aborted;
         } else if (
           refreshGroup.operationStatus ===
-          RefreshOperationStatus.FinishedWithError
+          RefreshOperationStatus.Failed
         ) {
           newOpState = DepositOperationStatus.Aborted;
         }
diff --git a/packages/taler-wallet-core/src/operations/pay-merchant.ts 
b/packages/taler-wallet-core/src/operations/pay-merchant.ts
index 30c75f695..8462f2fb9 100644
--- a/packages/taler-wallet-core/src/operations/pay-merchant.ts
+++ b/packages/taler-wallet-core/src/operations/pay-merchant.ts
@@ -1508,6 +1508,7 @@ export async function processPurchase(
     case PurchaseStatus.SuspendedPendingAcceptRefund:
     case PurchaseStatus.SuspendedQueryingAutoRefund:
     case PurchaseStatus.SuspendedQueryingRefund:
+    case PurchaseStatus.FailedAbort:
       return {
         type: OperationAttemptResultType.Finished,
         result: undefined,
@@ -1790,10 +1791,55 @@ export async function abortPayMerchant(
   ws.workAvailable.trigger();
 }
 
+export async function cancelAbortingPaymentTransaction(
+  ws: InternalWalletState,
+  proposalId: string,
+): Promise<void> {
+  const transactionId = constructTransactionIdentifier({
+    tag: TransactionType.Payment,
+    proposalId,
+  });
+  const opId = constructTaskIdentifier({
+    tag: PendingTaskType.Purchase,
+    proposalId,
+  });
+  const transitionInfo = await ws.db
+    .mktx((x) => [
+      x.purchases,
+      x.refreshGroups,
+      x.denominations,
+      x.coinAvailability,
+      x.coins,
+      x.operationRetries,
+    ])
+    .runReadWrite(async (tx) => {
+      const purchase = await tx.purchases.get(proposalId);
+      if (!purchase) {
+        throw Error("purchase not found");
+      }
+      const oldTxState = computePayMerchantTransactionState(purchase);
+      let newState: PurchaseStatus | undefined = undefined;
+      switch (purchase.purchaseStatus) {
+        case PurchaseStatus.AbortingWithRefund:
+          newState = PurchaseStatus.FailedAbort;
+          break;
+      }
+      if (newState) {
+        purchase.purchaseStatus = newState;
+        await tx.purchases.put(purchase);
+      }
+      const newTxState = computePayMerchantTransactionState(purchase);
+      return { oldTxState, newTxState };
+    });
+  notifyTransition(ws, transactionId, transitionInfo);
+  ws.workAvailable.trigger();
+}
 
-const transitionSuspend: { [x in PurchaseStatus]?: {
-  next: PurchaseStatus | undefined,
-} } = {
+const transitionSuspend: {
+  [x in PurchaseStatus]?: {
+    next: PurchaseStatus | undefined;
+  };
+} = {
   [PurchaseStatus.PendingDownloadingProposal]: {
     next: PurchaseStatus.SuspendedDownloadingProposal,
   },
@@ -1808,12 +1854,14 @@ const transitionSuspend: { [x in PurchaseStatus]?: {
   },
   [PurchaseStatus.PendingQueryingAutoRefund]: {
     next: PurchaseStatus.SuspendedQueryingAutoRefund,
-  }
-}
+  },
+};
 
-const transitionResume: { [x in PurchaseStatus]?: {
-  next: PurchaseStatus | undefined,
-} } = {
+const transitionResume: {
+  [x in PurchaseStatus]?: {
+    next: PurchaseStatus | undefined;
+  };
+} = {
   [PurchaseStatus.SuspendedDownloadingProposal]: {
     next: PurchaseStatus.PendingDownloadingProposal,
   },
@@ -1828,9 +1876,8 @@ const transitionResume: { [x in PurchaseStatus]?: {
   },
   [PurchaseStatus.SuspendedQueryingAutoRefund]: {
     next: PurchaseStatus.PendingQueryingAutoRefund,
-  }
-}
-
+  },
+};
 
 export async function suspendPayMerchant(
   ws: InternalWalletState,
@@ -1846,9 +1893,7 @@ export async function suspendPayMerchant(
   });
   stopLongpolling(ws, opId);
   const transitionInfo = await ws.db
-    .mktx((x) => [
-      x.purchases,
-    ])
+    .mktx((x) => [x.purchases])
     .runReadWrite(async (tx) => {
       const purchase = await tx.purchases.get(proposalId);
       if (!purchase) {
@@ -1867,7 +1912,6 @@ export async function suspendPayMerchant(
   ws.workAvailable.trigger();
 }
 
-
 export async function resumePayMerchant(
   ws: InternalWalletState,
   proposalId: string,
@@ -1882,9 +1926,7 @@ export async function resumePayMerchant(
   });
   stopLongpolling(ws, opId);
   const transitionInfo = await ws.db
-    .mktx((x) => [
-      x.purchases,
-    ])
+    .mktx((x) => [x.purchases])
     .runReadWrite(async (tx) => {
       const purchase = await tx.purchases.get(proposalId);
       if (!purchase) {
@@ -2010,6 +2052,11 @@ export function computePayMerchantTransactionState(
         major: TransactionMajorState.Failed,
         minor: TransactionMinorState.ClaimProposal,
       };
+    case PurchaseStatus.FailedAbort:
+      return {
+        major: TransactionMajorState.Failed,
+        minor: TransactionMinorState.AbortingBank,
+      };
   }
 }
 
diff --git a/packages/taler-wallet-core/src/operations/pay-peer.ts 
b/packages/taler-wallet-core/src/operations/pay-peer.ts
index 95878543b..031bdfb92 100644
--- a/packages/taler-wallet-core/src/operations/pay-peer.ts
+++ b/packages/taler-wallet-core/src/operations/pay-peer.ts
@@ -2005,6 +2005,10 @@ export function computePeerPushDebitTransactionState(
       return {
         major: TransactionMajorState.Done,
       };
+    case PeerPushPaymentInitiationStatus.Failed:
+      return {
+        major: TransactionMajorState.Failed,
+      }
   }
 }
 
@@ -2048,6 +2052,8 @@ export async function abortPeerPushDebitTransaction(
         case PeerPushPaymentInitiationStatus.Aborted:
           // Do nothing
           break;
+        case PeerPushPaymentInitiationStatus.Failed:
+          break;
         default:
           assertUnreachable(pushDebitRec.status);
       }
@@ -2104,6 +2110,7 @@ export async function 
cancelAbortingPeerPushDebitTransaction(
         case PeerPushPaymentInitiationStatus.PendingCreatePurse:
         case PeerPushPaymentInitiationStatus.Done:
         case PeerPushPaymentInitiationStatus.Aborted:
+        case PeerPushPaymentInitiationStatus.Failed:
           // Do nothing
           break;
         default:
@@ -2166,6 +2173,7 @@ export async function suspendPeerPushDebitTransaction(
         case PeerPushPaymentInitiationStatus.SuspendedCreatePurse:
         case PeerPushPaymentInitiationStatus.Done:
         case PeerPushPaymentInitiationStatus.Aborted:
+        case PeerPushPaymentInitiationStatus.Failed:
           // Do nothing
           break;
         default:
@@ -2220,6 +2228,138 @@ export async function suspendPeerPullDebitTransaction(
           break;
         case PeerPullDebitRecordStatus.SuspendedDeposit:
           break;
+        case PeerPullDebitRecordStatus.Aborted:
+          break;
+        case PeerPullDebitRecordStatus.AbortingRefresh:
+          newStatus = PeerPullDebitRecordStatus.SuspendedAbortingRefresh;
+          break;
+        case PeerPullDebitRecordStatus.Failed:
+          break;
+        case PeerPullDebitRecordStatus.SuspendedAbortingRefresh:
+          break;
+        default:
+          assertUnreachable(pullDebitRec.status);
+      }
+      if (newStatus != null) {
+        const oldTxState = computePeerPullDebitTransactionState(pullDebitRec);
+        pullDebitRec.status = newStatus;
+        const newTxState = computePeerPullDebitTransactionState(pullDebitRec);
+        await tx.peerPullPaymentIncoming.put(pullDebitRec);
+        return {
+          oldTxState,
+          newTxState,
+        };
+      }
+      return undefined;
+    });
+  notifyTransition(ws, transactionId, transitionInfo);
+}
+
+export async function abortPeerPullDebitTransaction(
+  ws: InternalWalletState,
+  peerPullPaymentIncomingId: string,
+) {
+  const taskId = constructTaskIdentifier({
+    tag: PendingTaskType.PeerPullDebit,
+    peerPullPaymentIncomingId,
+  });
+  const transactionId = constructTransactionIdentifier({
+    tag: TransactionType.PeerPullDebit,
+    peerPullPaymentIncomingId,
+  });
+  stopLongpolling(ws, taskId);
+  const transitionInfo = await ws.db
+    .mktx((x) => [x.peerPullPaymentIncoming])
+    .runReadWrite(async (tx) => {
+      const pullDebitRec = await tx.peerPullPaymentIncoming.get(
+        peerPullPaymentIncomingId,
+      );
+      if (!pullDebitRec) {
+        logger.warn(`peer pull debit ${peerPullPaymentIncomingId} not found`);
+        return;
+      }
+      let newStatus: PeerPullDebitRecordStatus | undefined = undefined;
+      switch (pullDebitRec.status) {
+        case PeerPullDebitRecordStatus.DialogProposed:
+          newStatus = PeerPullDebitRecordStatus.Aborted;
+          break;
+        case PeerPullDebitRecordStatus.DonePaid:
+          break;
+        case PeerPullDebitRecordStatus.PendingDeposit:
+          newStatus = PeerPullDebitRecordStatus.AbortingRefresh;
+          break;
+        case PeerPullDebitRecordStatus.SuspendedDeposit:
+          break;
+        case PeerPullDebitRecordStatus.Aborted:
+          break;
+        case PeerPullDebitRecordStatus.AbortingRefresh:
+          break;
+        case PeerPullDebitRecordStatus.Failed:
+          break;
+        case PeerPullDebitRecordStatus.SuspendedAbortingRefresh:
+          break;
+        default:
+          assertUnreachable(pullDebitRec.status);
+      }
+      if (newStatus != null) {
+        const oldTxState = computePeerPullDebitTransactionState(pullDebitRec);
+        pullDebitRec.status = newStatus;
+        const newTxState = computePeerPullDebitTransactionState(pullDebitRec);
+        await tx.peerPullPaymentIncoming.put(pullDebitRec);
+        return {
+          oldTxState,
+          newTxState,
+        };
+      }
+      return undefined;
+    });
+  notifyTransition(ws, transactionId, transitionInfo);
+}
+
+
+export async function cancelAbortingPeerPullDebitTransaction(
+  ws: InternalWalletState,
+  peerPullPaymentIncomingId: string,
+) {
+  const taskId = constructTaskIdentifier({
+    tag: PendingTaskType.PeerPullDebit,
+    peerPullPaymentIncomingId,
+  });
+  const transactionId = constructTransactionIdentifier({
+    tag: TransactionType.PeerPullDebit,
+    peerPullPaymentIncomingId,
+  });
+  stopLongpolling(ws, taskId);
+  const transitionInfo = await ws.db
+    .mktx((x) => [x.peerPullPaymentIncoming])
+    .runReadWrite(async (tx) => {
+      const pullDebitRec = await tx.peerPullPaymentIncoming.get(
+        peerPullPaymentIncomingId,
+      );
+      if (!pullDebitRec) {
+        logger.warn(`peer pull debit ${peerPullPaymentIncomingId} not found`);
+        return;
+      }
+      let newStatus: PeerPullDebitRecordStatus | undefined = undefined;
+      switch (pullDebitRec.status) {
+        case PeerPullDebitRecordStatus.DialogProposed:
+          newStatus = PeerPullDebitRecordStatus.Aborted;
+          break;
+        case PeerPullDebitRecordStatus.DonePaid:
+          break;
+        case PeerPullDebitRecordStatus.PendingDeposit:
+          break;
+        case PeerPullDebitRecordStatus.SuspendedDeposit:
+          break;
+        case PeerPullDebitRecordStatus.Aborted:
+          break;
+        case PeerPullDebitRecordStatus.Failed:
+          break;
+        case PeerPullDebitRecordStatus.SuspendedAbortingRefresh:
+        case PeerPullDebitRecordStatus.AbortingRefresh:
+          // FIXME: abort underlying refresh!
+          newStatus = PeerPullDebitRecordStatus.Failed;
+          break;
         default:
           assertUnreachable(pullDebitRec.status);
       }
@@ -2270,6 +2410,15 @@ export async function resumePeerPullDebitTransaction(
         case PeerPullDebitRecordStatus.SuspendedDeposit:
           newStatus = PeerPullDebitRecordStatus.PendingDeposit;
           break;
+        case PeerPullDebitRecordStatus.Aborted:
+          break;
+        case PeerPullDebitRecordStatus.AbortingRefresh:
+          break;
+        case PeerPullDebitRecordStatus.Failed:
+          break;
+        case PeerPullDebitRecordStatus.SuspendedAbortingRefresh:
+          newStatus = PeerPullDebitRecordStatus.AbortingRefresh;
+          break;
         default:
           assertUnreachable(pullDebitRec.status);
       }
@@ -2330,6 +2479,10 @@ export async function suspendPeerPushCreditTransaction(
           // FIXME: Suspend internal withdrawal transaction!
           newStatus = PeerPushPaymentIncomingStatus.SuspendedWithdrawing;
           break;
+        case PeerPushPaymentIncomingStatus.Aborted:
+          break;
+        case PeerPushPaymentIncomingStatus.Failed:
+          break;
         default:
           assertUnreachable(pushCreditRec.status);
       }
@@ -2348,6 +2501,81 @@ export async function suspendPeerPushCreditTransaction(
   notifyTransition(ws, transactionId, transitionInfo);
 }
 
+
+export async function abortPeerPushCreditTransaction(
+  ws: InternalWalletState,
+  peerPushPaymentIncomingId: string,
+) {
+  const taskId = constructTaskIdentifier({
+    tag: PendingTaskType.PeerPushCredit,
+    peerPushPaymentIncomingId,
+  });
+  const transactionId = constructTransactionIdentifier({
+    tag: TransactionType.PeerPushCredit,
+    peerPushPaymentIncomingId,
+  });
+  stopLongpolling(ws, taskId);
+  const transitionInfo = await ws.db
+    .mktx((x) => [x.peerPushPaymentIncoming])
+    .runReadWrite(async (tx) => {
+      const pushCreditRec = await tx.peerPushPaymentIncoming.get(
+        peerPushPaymentIncomingId,
+      );
+      if (!pushCreditRec) {
+        logger.warn(`peer push credit ${peerPushPaymentIncomingId} not found`);
+        return;
+      }
+      let newStatus: PeerPushPaymentIncomingStatus | undefined = undefined;
+      switch (pushCreditRec.status) {
+        case PeerPushPaymentIncomingStatus.DialogProposed:
+          newStatus = PeerPushPaymentIncomingStatus.Aborted;
+          break;
+        case PeerPushPaymentIncomingStatus.Done:
+          break;
+        case PeerPushPaymentIncomingStatus.SuspendedMerge:
+        case PeerPushPaymentIncomingStatus.SuspendedMergeKycRequired:
+        case PeerPushPaymentIncomingStatus.SuspendedWithdrawing:
+          newStatus = PeerPushPaymentIncomingStatus.Aborted;
+          break;
+        case PeerPushPaymentIncomingStatus.PendingMergeKycRequired:
+          newStatus = PeerPushPaymentIncomingStatus.Aborted;
+          break;
+        case PeerPushPaymentIncomingStatus.PendingMerge:
+          newStatus = PeerPushPaymentIncomingStatus.Aborted;
+          break;
+        case PeerPushPaymentIncomingStatus.PendingWithdrawing:
+          newStatus = PeerPushPaymentIncomingStatus.Aborted;
+          break;
+        case PeerPushPaymentIncomingStatus.Aborted:
+          break;
+        case PeerPushPaymentIncomingStatus.Failed:
+          break;
+        default:
+          assertUnreachable(pushCreditRec.status);
+      }
+      if (newStatus != null) {
+        const oldTxState = 
computePeerPushCreditTransactionState(pushCreditRec);
+        pushCreditRec.status = newStatus;
+        const newTxState = 
computePeerPushCreditTransactionState(pushCreditRec);
+        await tx.peerPushPaymentIncoming.put(pushCreditRec);
+        return {
+          oldTxState,
+          newTxState,
+        };
+      }
+      return undefined;
+    });
+  notifyTransition(ws, transactionId, transitionInfo);
+}
+
+export async function cancelAbortingPeerPushCreditTransaction(
+  ws: InternalWalletState,
+  peerPushPaymentIncomingId: string,
+) {
+  // We don't have any "aborting" states!
+  throw Error("can't run cancel-aborting on peer-push-credit transaction");
+}
+
 export async function resumePeerPushCreditTransaction(
   ws: InternalWalletState,
   peerPushPaymentIncomingId: string,
@@ -2388,6 +2616,10 @@ export async function resumePeerPushCreditTransaction(
           // FIXME: resume underlying "internal-withdrawal" transaction.
           newStatus = PeerPushPaymentIncomingStatus.PendingWithdrawing;
           break;
+        case PeerPushPaymentIncomingStatus.Aborted:
+          break;
+        case PeerPushPaymentIncomingStatus.Failed:
+          break;
         default:
           assertUnreachable(pushCreditRec.status);
       }
@@ -2442,11 +2674,135 @@ export async function suspendPeerPullCreditTransaction(
         case PeerPullPaymentInitiationStatus.PendingReady:
           newStatus = PeerPullPaymentInitiationStatus.SuspendedReady;
           break;
+        case PeerPullPaymentInitiationStatus.AbortingDeletePurse:
+          newStatus =
+            PeerPullPaymentInitiationStatus.SuspendedAbortingDeletePurse;
+          break;
+        case PeerPullPaymentInitiationStatus.DonePurseDeposited:
+        case PeerPullPaymentInitiationStatus.SuspendedCreatePurse:
+        case PeerPullPaymentInitiationStatus.SuspendedMergeKycRequired:
+        case PeerPullPaymentInitiationStatus.SuspendedReady:
+        case PeerPullPaymentInitiationStatus.SuspendedWithdrawing:
+        case PeerPullPaymentInitiationStatus.Aborted:
+        case PeerPullPaymentInitiationStatus.Failed:
+        case PeerPullPaymentInitiationStatus.SuspendedAbortingDeletePurse:
+          break;
+        default:
+          assertUnreachable(pullCreditRec.status);
+      }
+      if (newStatus != null) {
+        const oldTxState = 
computePeerPullCreditTransactionState(pullCreditRec);
+        pullCreditRec.status = newStatus;
+        const newTxState = 
computePeerPullCreditTransactionState(pullCreditRec);
+        await tx.peerPullPaymentInitiations.put(pullCreditRec);
+        return {
+          oldTxState,
+          newTxState,
+        };
+      }
+      return undefined;
+    });
+  notifyTransition(ws, transactionId, transitionInfo);
+}
+
+export async function abortPeerPullCreditTransaction(
+  ws: InternalWalletState,
+  pursePub: string,
+) {
+  const taskId = constructTaskIdentifier({
+    tag: PendingTaskType.PeerPullCredit,
+    pursePub,
+  });
+  const transactionId = constructTransactionIdentifier({
+    tag: TransactionType.PeerPullCredit,
+    pursePub,
+  });
+  stopLongpolling(ws, taskId);
+  const transitionInfo = await ws.db
+    .mktx((x) => [x.peerPullPaymentInitiations])
+    .runReadWrite(async (tx) => {
+      const pullCreditRec = await tx.peerPullPaymentInitiations.get(pursePub);
+      if (!pullCreditRec) {
+        logger.warn(`peer pull credit ${pursePub} not found`);
+        return;
+      }
+      let newStatus: PeerPullPaymentInitiationStatus | undefined = undefined;
+      switch (pullCreditRec.status) {
+        case PeerPullPaymentInitiationStatus.PendingCreatePurse:
+        case PeerPullPaymentInitiationStatus.PendingMergeKycRequired:
+          newStatus = PeerPullPaymentInitiationStatus.AbortingDeletePurse;
+          break;
+        case PeerPullPaymentInitiationStatus.PendingWithdrawing:
+          throw Error("can't abort anymore");
+        case PeerPullPaymentInitiationStatus.PendingReady:
+          newStatus = PeerPullPaymentInitiationStatus.AbortingDeletePurse;
+          break;
+        case PeerPullPaymentInitiationStatus.DonePurseDeposited:
+        case PeerPullPaymentInitiationStatus.SuspendedCreatePurse:
+        case PeerPullPaymentInitiationStatus.SuspendedMergeKycRequired:
+        case PeerPullPaymentInitiationStatus.SuspendedReady:
+        case PeerPullPaymentInitiationStatus.SuspendedWithdrawing:
+        case PeerPullPaymentInitiationStatus.Aborted:
+        case PeerPullPaymentInitiationStatus.AbortingDeletePurse:
+        case PeerPullPaymentInitiationStatus.Failed:
+        case PeerPullPaymentInitiationStatus.SuspendedAbortingDeletePurse:
+          break;
+        default:
+          assertUnreachable(pullCreditRec.status);
+      }
+      if (newStatus != null) {
+        const oldTxState = 
computePeerPullCreditTransactionState(pullCreditRec);
+        pullCreditRec.status = newStatus;
+        const newTxState = 
computePeerPullCreditTransactionState(pullCreditRec);
+        await tx.peerPullPaymentInitiations.put(pullCreditRec);
+        return {
+          oldTxState,
+          newTxState,
+        };
+      }
+      return undefined;
+    });
+  notifyTransition(ws, transactionId, transitionInfo);
+}
+
+export async function cancelAbortingPeerPullCreditTransaction(
+  ws: InternalWalletState,
+  pursePub: string,
+) {
+  const taskId = constructTaskIdentifier({
+    tag: PendingTaskType.PeerPullCredit,
+    pursePub,
+  });
+  const transactionId = constructTransactionIdentifier({
+    tag: TransactionType.PeerPullCredit,
+    pursePub,
+  });
+  stopLongpolling(ws, taskId);
+  const transitionInfo = await ws.db
+    .mktx((x) => [x.peerPullPaymentInitiations])
+    .runReadWrite(async (tx) => {
+      const pullCreditRec = await tx.peerPullPaymentInitiations.get(pursePub);
+      if (!pullCreditRec) {
+        logger.warn(`peer pull credit ${pursePub} not found`);
+        return;
+      }
+      let newStatus: PeerPullPaymentInitiationStatus | undefined = undefined;
+      switch (pullCreditRec.status) {
+        case PeerPullPaymentInitiationStatus.PendingCreatePurse:
+        case PeerPullPaymentInitiationStatus.PendingMergeKycRequired:
+        case PeerPullPaymentInitiationStatus.PendingWithdrawing:
+        case PeerPullPaymentInitiationStatus.PendingReady:
         case PeerPullPaymentInitiationStatus.DonePurseDeposited:
         case PeerPullPaymentInitiationStatus.SuspendedCreatePurse:
         case PeerPullPaymentInitiationStatus.SuspendedMergeKycRequired:
         case PeerPullPaymentInitiationStatus.SuspendedReady:
         case PeerPullPaymentInitiationStatus.SuspendedWithdrawing:
+        case PeerPullPaymentInitiationStatus.Aborted:
+        case PeerPullPaymentInitiationStatus.Failed:
+          break;
+        case PeerPullPaymentInitiationStatus.AbortingDeletePurse:
+        case PeerPullPaymentInitiationStatus.SuspendedAbortingDeletePurse:
+          newStatus = PeerPullPaymentInitiationStatus.Failed;
           break;
         default:
           assertUnreachable(pullCreditRec.status);
@@ -2493,7 +2849,11 @@ export async function resumePeerPullCreditTransaction(
         case PeerPullPaymentInitiationStatus.PendingMergeKycRequired:
         case PeerPullPaymentInitiationStatus.PendingWithdrawing:
         case PeerPullPaymentInitiationStatus.PendingReady:
+        case PeerPullPaymentInitiationStatus.AbortingDeletePurse:
         case PeerPullPaymentInitiationStatus.DonePurseDeposited:
+        case PeerPullPaymentInitiationStatus.Failed:
+        case PeerPullPaymentInitiationStatus.Aborted:
+          break;
         case PeerPullPaymentInitiationStatus.SuspendedCreatePurse:
           newStatus = PeerPullPaymentInitiationStatus.PendingCreatePurse;
           break;
@@ -2506,6 +2866,9 @@ export async function resumePeerPullCreditTransaction(
         case PeerPullPaymentInitiationStatus.SuspendedWithdrawing:
           newStatus = PeerPullPaymentInitiationStatus.PendingWithdrawing;
           break;
+        case PeerPullPaymentInitiationStatus.SuspendedAbortingDeletePurse:
+          newStatus = PeerPullPaymentInitiationStatus.AbortingDeletePurse;
+          break;
         default:
           assertUnreachable(pullCreditRec.status);
       }
@@ -2566,6 +2929,7 @@ export async function resumePeerPushDebitTransaction(
         case PeerPushPaymentInitiationStatus.PendingReady:
         case PeerPushPaymentInitiationStatus.Done:
         case PeerPushPaymentInitiationStatus.Aborted:
+        case PeerPushPaymentInitiationStatus.Failed:
           // Do nothing
           break;
         default:
@@ -2630,6 +2994,16 @@ export function computePeerPushCreditTransactionState(
         major: TransactionMajorState.Suspended,
         minor: TransactionMinorState.Withdraw,
       };
+    case PeerPushPaymentIncomingStatus.Aborted:
+      return {
+        major: TransactionMajorState.Aborted
+      };
+    case PeerPushPaymentIncomingStatus.Failed:
+      return {
+        major: TransactionMajorState.Failed,
+      }
+    default:
+      assertUnreachable(pushCreditRecord.status);
   }
 }
 
@@ -2681,6 +3055,24 @@ export function computePeerPullCreditTransactionState(
         major: TransactionMajorState.Suspended,
         minor: TransactionMinorState.MergeKycRequired,
       };
+    case PeerPullPaymentInitiationStatus.Aborted:
+      return {
+        major: TransactionMajorState.Aborted,
+      };
+    case PeerPullPaymentInitiationStatus.AbortingDeletePurse:
+      return {
+        major: TransactionMajorState.Aborting,
+        minor: TransactionMinorState.DeletePurse,
+      };
+    case PeerPullPaymentInitiationStatus.Failed:
+      return {
+        major: TransactionMajorState.Failed,
+      };
+    case PeerPullPaymentInitiationStatus.SuspendedAbortingDeletePurse:
+      return {
+        major: TransactionMajorState.Aborting,
+        minor: TransactionMinorState.DeletePurse,
+      };
   }
 }
 
@@ -2707,5 +3099,23 @@ export function computePeerPullDebitTransactionState(
         major: TransactionMajorState.Suspended,
         minor: TransactionMinorState.Deposit,
       };
+    case PeerPullDebitRecordStatus.Aborted:
+      return {
+        major: TransactionMajorState.Aborted,
+      };
+    case PeerPullDebitRecordStatus.AbortingRefresh:
+      return {
+        major: TransactionMajorState.Aborting,
+        minor: TransactionMinorState.Refresh,
+      };
+    case PeerPullDebitRecordStatus.Failed:
+      return {
+        major: TransactionMajorState.Failed,
+      };
+    case PeerPullDebitRecordStatus.SuspendedAbortingRefresh:
+      return {
+        major: TransactionMajorState.SuspendedAborting,
+        minor: TransactionMinorState.Refresh,
+      };
   }
 }
diff --git a/packages/taler-wallet-core/src/operations/refresh.ts 
b/packages/taler-wallet-core/src/operations/refresh.ts
index c46344313..8437d2d0b 100644
--- a/packages/taler-wallet-core/src/operations/refresh.ts
+++ b/packages/taler-wallet-core/src/operations/refresh.ts
@@ -96,7 +96,7 @@ import {
   PendingTaskType,
   WalletConfig,
 } from "../index.js";
-import { constructTransactionIdentifier } from "./transactions.js";
+import { constructTransactionIdentifier, notifyTransition } from 
"./transactions.js";
 
 const logger = new Logger("refresh.ts");
 
@@ -158,7 +158,7 @@ function updateGroupStatus(rg: RefreshGroupRecord): void {
   if (allDone) {
     if (anyFrozen) {
       rg.timestampFinished = TalerPreciseTimestamp.now();
-      rg.operationStatus = RefreshOperationStatus.FinishedWithError;
+      rg.operationStatus = RefreshOperationStatus.Failed;
     } else {
       rg.timestampFinished = TalerPreciseTimestamp.now();
       rg.operationStatus = RefreshOperationStatus.Finished;
@@ -1189,7 +1189,7 @@ export function computeRefreshTransactionState(
       return {
         major: TransactionMajorState.Done,
       };
-    case RefreshOperationStatus.FinishedWithError:
+    case RefreshOperationStatus.Failed:
       return {
         major: TransactionMajorState.Failed,
       };
@@ -1261,7 +1261,7 @@ export async function resumeRefreshGroup(
     tag: TransactionType.Refresh,
     refreshGroupId,
   });
-  let res = await ws.db
+  const transitionInfo = await ws.db
     .mktx((x) => [x.refreshGroups])
     .runReadWrite(async (tx) => {
       const dg = await tx.refreshGroups.get(refreshGroupId);
@@ -1289,19 +1289,57 @@ export async function resumeRefreshGroup(
       return undefined;
     });
   ws.workAvailable.trigger();
-  if (res) {
-    ws.notify({
-      type: NotificationType.TransactionStateTransition,
-      transactionId,
-      oldTxState: res.oldTxState,
-      newTxState: res.newTxState,
-    });
-  }
+  notifyTransition(ws, transactionId, transitionInfo);
+}
+
+export async function cancelAbortingRefreshGroup(
+  ws: InternalWalletState,
+  refreshGroupId: string,
+): Promise<void> {
+  throw Error("action cancel-aborting not allowed on refreshes");
 }
 
 export async function abortRefreshGroup(
   ws: InternalWalletState,
   refreshGroupId: string,
 ): Promise<void> {
-  throw Error("can't abort refresh groups.");
+  const transactionId = constructTransactionIdentifier({
+    tag: TransactionType.Refresh,
+    refreshGroupId,
+  });
+  const transitionInfo = await ws.db
+    .mktx((x) => [x.refreshGroups])
+    .runReadWrite(async (tx) => {
+      const dg = await tx.refreshGroups.get(refreshGroupId);
+      if (!dg) {
+        logger.warn(
+          `can't resume refresh group, refreshGroupId=${refreshGroupId} not 
found`,
+        );
+        return;
+      }
+      const oldState = computeRefreshTransactionState(dg);
+      let newStatus: RefreshOperationStatus | undefined;
+      switch (dg.operationStatus) {
+        case RefreshOperationStatus.Finished:
+          break;;
+        case RefreshOperationStatus.Pending:
+        case RefreshOperationStatus.Suspended:
+          newStatus = RefreshOperationStatus.Failed;
+          break;
+        case RefreshOperationStatus.Failed:
+          break;
+        default:
+          assertUnreachable(dg.operationStatus);
+      }
+      if (newStatus) {
+        dg.operationStatus = newStatus;
+        await tx.refreshGroups.put(dg);
+      }
+      return {
+        oldTxState: oldState,
+        newTxState: computeRefreshTransactionState(dg),
+      };
+    });
+  ws.workAvailable.trigger();
+  notifyTransition(ws, transactionId, transitionInfo);
 }
diff --git a/packages/taler-wallet-core/src/operations/tip.ts 
b/packages/taler-wallet-core/src/operations/tip.ts
index 70b595c2f..0bee2b406 100644
--- a/packages/taler-wallet-core/src/operations/tip.ts
+++ b/packages/taler-wallet-core/src/operations/tip.ts
@@ -87,21 +87,28 @@ const logger = new Logger("operations/tip.ts");
 export function computeTipTransactionStatus(
   tipRecord: TipRecord,
 ): TransactionState {
-  if (tipRecord.pickedUpTimestamp) {
-    return {
-      major: TransactionMajorState.Done,
-    };
-  }
-  if (tipRecord.acceptedTimestamp) {
-    return {
-      major: TransactionMajorState.Pending,
-      minor: TransactionMinorState.Pickup,
-    };
+  switch (tipRecord.status) {
+    case TipRecordStatus.Done:
+      return {
+        major: TransactionMajorState.Done,
+      };
+    case TipRecordStatus.Aborted:
+      return {
+        major: TransactionMajorState.Aborted,
+      };
+    case TipRecordStatus.PendingPickup:
+      return {
+        major: TransactionMajorState.Pending,
+        minor: TransactionMinorState.Pickup,
+      };
+    case TipRecordStatus.SuspendidPickup:
+      return {
+        major: TransactionMajorState.Pending,
+        minor: TransactionMinorState.User,
+      };
+    default:
+      assertUnreachable(tipRecord.status);
   }
-  return {
-    major: TransactionMajorState.Pending,
-    minor: TransactionMinorState.User,
-  };
 }
 
 export async function prepareTip(
@@ -445,6 +452,7 @@ export async function suspendTipTransaction(
       switch (tipRec.status) {
         case TipRecordStatus.Done:
         case TipRecordStatus.SuspendidPickup:
+        case TipRecordStatus.Aborted:
           break;
         case TipRecordStatus.PendingPickup:
           newStatus = TipRecordStatus.SuspendidPickup;
@@ -492,11 +500,72 @@ export async function resumeTipTransaction(
       let newStatus: TipRecordStatus | undefined = undefined;
       switch (tipRec.status) {
         case TipRecordStatus.Done:
+          break;
         case TipRecordStatus.SuspendidPickup:
           newStatus = TipRecordStatus.PendingPickup;
           break;
         case TipRecordStatus.PendingPickup:
           break;
+        case TipRecordStatus.Aborted:
+          break;
+        default:
+          assertUnreachable(tipRec.status);
+      }
+      if (newStatus != null) {
+        const oldTxState = computeTipTransactionStatus(tipRec);
+        tipRec.status = newStatus;
+        const newTxState = computeTipTransactionStatus(tipRec);
+        await tx.tips.put(tipRec);
+        return {
+          oldTxState,
+          newTxState,
+        };
+      }
+      return undefined;
+    });
+  notifyTransition(ws, transactionId, transitionInfo);
+}
+
+export async function cancelAbortingTipTransaction(
+  ws: InternalWalletState,
+  walletTipId: string,
+): Promise<void> {
+  // We don't have an "aborting" state, so this should never happen!
+  throw Error("can't run cance-aborting on tip transaction");
+}
+
+export async function abortTipTransaction(
+  ws: InternalWalletState,
+  walletTipId: string,
+): Promise<void> {
+  const taskId = constructTaskIdentifier({
+    tag: PendingTaskType.TipPickup,
+    walletTipId,
+  });
+  const transactionId = constructTransactionIdentifier({
+    tag: TransactionType.Tip,
+    walletTipId,
+  });
+  stopLongpolling(ws, taskId);
+  const transitionInfo = await ws.db
+    .mktx((x) => [x.tips])
+    .runReadWrite(async (tx) => {
+      const tipRec = await tx.tips.get(walletTipId);
+      if (!tipRec) {
+        logger.warn(`transaction tip ${walletTipId} not found`);
+        return;
+      }
+      let newStatus: TipRecordStatus | undefined = undefined;
+      switch (tipRec.status) {
+        case TipRecordStatus.Done:
+          break;
+        case TipRecordStatus.SuspendidPickup:
+          newStatus = TipRecordStatus.Aborted;
+          break;
+        case TipRecordStatus.PendingPickup:
+          break;
+        case TipRecordStatus.Aborted:
+          break;
         default:
           assertUnreachable(tipRec.status);
       }
diff --git a/packages/taler-wallet-core/src/operations/transactions.ts 
b/packages/taler-wallet-core/src/operations/transactions.ts
index f1cfaed45..d424019ac 100644
--- a/packages/taler-wallet-core/src/operations/transactions.ts
+++ b/packages/taler-wallet-core/src/operations/transactions.ts
@@ -82,6 +82,7 @@ import {
 import { getExchangeDetails } from "./exchanges.js";
 import {
   abortPayMerchant,
+  cancelAbortingPaymentTransaction,
   computePayMerchantTransactionState,
   computeRefundTransactionState,
   expectProposalDownload,
@@ -90,6 +91,14 @@ import {
   suspendPayMerchant,
 } from "./pay-merchant.js";
 import {
+  abortPeerPullCreditTransaction,
+  abortPeerPullDebitTransaction,
+  abortPeerPushCreditTransaction,
+  abortPeerPushDebitTransaction,
+  cancelAbortingPeerPullCreditTransaction,
+  cancelAbortingPeerPullDebitTransaction,
+  cancelAbortingPeerPushCreditTransaction,
+  cancelAbortingPeerPushDebitTransaction,
   computePeerPullCreditTransactionState,
   computePeerPullDebitTransactionState,
   computePeerPushCreditTransactionState,
@@ -104,11 +113,15 @@ import {
   suspendPeerPushDebitTransaction,
 } from "./pay-peer.js";
 import {
+  abortRefreshGroup,
+  cancelAbortingRefreshGroup,
   computeRefreshTransactionState,
   resumeRefreshGroup,
   suspendRefreshGroup,
 } from "./refresh.js";
 import {
+  abortTipTransaction,
+  cancelAbortingTipTransaction,
   computeTipTransactionStatus,
   resumeTipTransaction,
   suspendTipTransaction,
@@ -1492,11 +1505,35 @@ export async function cancelAbortingTransaction(
     case TransactionType.Deposit:
       await cancelAbortingDepositGroup(ws, tx.depositGroupId);
       return;
+    case TransactionType.InternalWithdrawal:
     case TransactionType.Withdrawal:
       await cancelAbortingWithdrawalTransaction(ws, tx.withdrawalGroupId);
       return;
+    case TransactionType.Payment:
+      await cancelAbortingPaymentTransaction(ws, tx.proposalId);
+      return;
+    case TransactionType.Refund:
+      throw Error("can't do cancel-aborting on refund transaction");
+    case TransactionType.Tip:
+      await cancelAbortingTipTransaction(ws, tx.walletTipId);
+      return;
+    case TransactionType.Refresh:
+      await cancelAbortingRefreshGroup(ws, tx.refreshGroupId);
+      return;
+    case TransactionType.PeerPullCredit:
+      await cancelAbortingPeerPullCreditTransaction(ws, tx.pursePub);
+      return;
+    case TransactionType.PeerPullDebit:
+      await cancelAbortingPeerPullDebitTransaction(ws, 
tx.peerPullPaymentIncomingId);
+      return;
+    case TransactionType.PeerPushCredit:
+      await cancelAbortingPeerPushCreditTransaction(ws, 
tx.peerPushPaymentIncomingId);
+      return;
+    case TransactionType.PeerPushDebit:
+      await cancelAbortingPeerPushDebitTransaction(ws, tx.pursePub);
+      return;
     default:
-      logger.warn(`unable to suspend transaction of type '${tx.tag}'`);
+      assertUnreachable(tx);
   }
 }
 
@@ -1774,18 +1811,36 @@ export async function abortTransaction(
       await abortPayMerchant(ws, txId.proposalId);
       break;
     }
-    case TransactionType.Withdrawal: {
+    case TransactionType.Withdrawal:
+    case TransactionType.InternalWithdrawal: {
       await abortWithdrawalTransaction(ws, txId.withdrawalGroupId);
       break;
     }
     case TransactionType.Deposit:
       await abortDepositGroup(ws, txId.depositGroupId);
       break;
+    case TransactionType.Tip:
+      await abortTipTransaction(ws, txId.walletTipId);
+      break;
+    case TransactionType.Refund:
+      throw Error("can't abort refund transactions");
+    case TransactionType.Refresh:
+      await abortRefreshGroup(ws, txId.refreshGroupId);
+      break;
+    case TransactionType.PeerPullCredit:
+      await abortPeerPullCreditTransaction(ws, txId.pursePub);
+      break;
+    case TransactionType.PeerPullDebit:
+      await abortPeerPullDebitTransaction(ws, txId.peerPullPaymentIncomingId);
+      break;
+    case TransactionType.PeerPushCredit:
+      await abortPeerPushCreditTransaction(ws, txId.peerPushPaymentIncomingId);
+      break;
+    case TransactionType.PeerPushDebit:
+      await abortPeerPushDebitTransaction(ws, txId.pursePub);
+      break;
     default: {
-      const unknownTxType: any = txId.tag;
-      throw Error(
-        `can't abort a '${unknownTxType}' transaction: not yet implemented`,
-      );
+      assertUnreachable(txId);
     }
   }
 }

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]