diff options
Diffstat (limited to 'packages/taler-wallet-core/src/operations/pay-peer-pull-credit.ts')
-rw-r--r-- | packages/taler-wallet-core/src/operations/pay-peer-pull-credit.ts | 523 |
1 files changed, 271 insertions, 252 deletions
diff --git a/packages/taler-wallet-core/src/operations/pay-peer-pull-credit.ts b/packages/taler-wallet-core/src/operations/pay-peer-pull-credit.ts index a90eceed7..e655eba4b 100644 --- a/packages/taler-wallet-core/src/operations/pay-peer-pull-credit.ts +++ b/packages/taler-wallet-core/src/operations/pay-peer-pull-credit.ts @@ -69,6 +69,8 @@ import { LongpollResult, TaskRunResult, TaskRunResultType, + TombstoneTag, + TransactionContext, constructTaskIdentifier, runLongpollAsync, } from "./common.js"; @@ -88,6 +90,275 @@ import { const logger = new Logger("pay-peer-pull-credit.ts"); +export class PeerPullCreditTransactionContext implements TransactionContext { + private transactionId: string; + private retryTag: string; + + constructor( + public ws: InternalWalletState, + public pursePub: string, + ) { + this.retryTag = constructTaskIdentifier({ + tag: PendingTaskType.PeerPullCredit, + pursePub, + }); + this.transactionId = constructTransactionIdentifier({ + tag: TransactionType.PeerPullCredit, + pursePub, + }); + } + + async deleteTransaction(): Promise<void> { + const { ws, pursePub } = this; + await ws.db + .mktx((x) => [x.withdrawalGroups, x.peerPullCredit, x.tombstones]) + .runReadWrite(async (tx) => { + const pullIni = await tx.peerPullCredit.get(pursePub); + if (!pullIni) { + return; + } + if (pullIni.withdrawalGroupId) { + const withdrawalGroupId = pullIni.withdrawalGroupId; + const withdrawalGroupRecord = + await tx.withdrawalGroups.get(withdrawalGroupId); + if (withdrawalGroupRecord) { + await tx.withdrawalGroups.delete(withdrawalGroupId); + await tx.tombstones.put({ + id: TombstoneTag.DeleteWithdrawalGroup + ":" + withdrawalGroupId, + }); + } + } + await tx.peerPullCredit.delete(pursePub); + await tx.tombstones.put({ + id: TombstoneTag.DeletePeerPullCredit + ":" + pursePub, + }); + }); + + return; + } + + async suspendTransaction(): Promise<void> { + const { ws, pursePub, retryTag, transactionId } = this; + stopLongpolling(ws, retryTag); + const transitionInfo = await ws.db + .mktx((x) => [x.peerPullCredit]) + .runReadWrite(async (tx) => { + const pullCreditRec = await tx.peerPullCredit.get(pursePub); + if (!pullCreditRec) { + logger.warn(`peer pull credit ${pursePub} not found`); + return; + } + let newStatus: PeerPullPaymentCreditStatus | undefined = undefined; + switch (pullCreditRec.status) { + case PeerPullPaymentCreditStatus.PendingCreatePurse: + newStatus = PeerPullPaymentCreditStatus.SuspendedCreatePurse; + break; + case PeerPullPaymentCreditStatus.PendingMergeKycRequired: + newStatus = PeerPullPaymentCreditStatus.SuspendedMergeKycRequired; + break; + case PeerPullPaymentCreditStatus.PendingWithdrawing: + newStatus = PeerPullPaymentCreditStatus.SuspendedWithdrawing; + break; + case PeerPullPaymentCreditStatus.PendingReady: + newStatus = PeerPullPaymentCreditStatus.SuspendedReady; + break; + case PeerPullPaymentCreditStatus.AbortingDeletePurse: + newStatus = + PeerPullPaymentCreditStatus.SuspendedAbortingDeletePurse; + break; + case PeerPullPaymentCreditStatus.Done: + case PeerPullPaymentCreditStatus.SuspendedCreatePurse: + case PeerPullPaymentCreditStatus.SuspendedMergeKycRequired: + case PeerPullPaymentCreditStatus.SuspendedReady: + case PeerPullPaymentCreditStatus.SuspendedWithdrawing: + case PeerPullPaymentCreditStatus.Aborted: + case PeerPullPaymentCreditStatus.Failed: + case PeerPullPaymentCreditStatus.Expired: + case PeerPullPaymentCreditStatus.SuspendedAbortingDeletePurse: + break; + default: + assertUnreachable(pullCreditRec.status); + } + if (newStatus != null) { + const oldTxState = + computePeerPullCreditTransactionState(pullCreditRec); + pullCreditRec.status = newStatus; + const newTxState = + computePeerPullCreditTransactionState(pullCreditRec); + await tx.peerPullCredit.put(pullCreditRec); + return { + oldTxState, + newTxState, + }; + } + return undefined; + }); + notifyTransition(ws, transactionId, transitionInfo); + } + + async failTransaction(): Promise<void> { + const { ws, pursePub, retryTag, transactionId } = this; + stopLongpolling(ws, retryTag); + const transitionInfo = await ws.db + .mktx((x) => [x.peerPullCredit]) + .runReadWrite(async (tx) => { + const pullCreditRec = await tx.peerPullCredit.get(pursePub); + if (!pullCreditRec) { + logger.warn(`peer pull credit ${pursePub} not found`); + return; + } + let newStatus: PeerPullPaymentCreditStatus | undefined = undefined; + switch (pullCreditRec.status) { + case PeerPullPaymentCreditStatus.PendingCreatePurse: + case PeerPullPaymentCreditStatus.PendingMergeKycRequired: + case PeerPullPaymentCreditStatus.PendingWithdrawing: + case PeerPullPaymentCreditStatus.PendingReady: + case PeerPullPaymentCreditStatus.Done: + case PeerPullPaymentCreditStatus.SuspendedCreatePurse: + case PeerPullPaymentCreditStatus.SuspendedMergeKycRequired: + case PeerPullPaymentCreditStatus.SuspendedReady: + case PeerPullPaymentCreditStatus.SuspendedWithdrawing: + case PeerPullPaymentCreditStatus.Aborted: + case PeerPullPaymentCreditStatus.Failed: + case PeerPullPaymentCreditStatus.Expired: + break; + case PeerPullPaymentCreditStatus.AbortingDeletePurse: + case PeerPullPaymentCreditStatus.SuspendedAbortingDeletePurse: + newStatus = PeerPullPaymentCreditStatus.Failed; + break; + default: + assertUnreachable(pullCreditRec.status); + } + if (newStatus != null) { + const oldTxState = + computePeerPullCreditTransactionState(pullCreditRec); + pullCreditRec.status = newStatus; + const newTxState = + computePeerPullCreditTransactionState(pullCreditRec); + await tx.peerPullCredit.put(pullCreditRec); + return { + oldTxState, + newTxState, + }; + } + return undefined; + }); + notifyTransition(ws, transactionId, transitionInfo); + } + + async resumeTransaction(): Promise<void> { + const { ws, pursePub, retryTag, transactionId } = this; + stopLongpolling(ws, retryTag); + const transitionInfo = await ws.db + .mktx((x) => [x.peerPullCredit]) + .runReadWrite(async (tx) => { + const pullCreditRec = await tx.peerPullCredit.get(pursePub); + if (!pullCreditRec) { + logger.warn(`peer pull credit ${pursePub} not found`); + return; + } + let newStatus: PeerPullPaymentCreditStatus | undefined = undefined; + switch (pullCreditRec.status) { + case PeerPullPaymentCreditStatus.PendingCreatePurse: + case PeerPullPaymentCreditStatus.PendingMergeKycRequired: + case PeerPullPaymentCreditStatus.PendingWithdrawing: + case PeerPullPaymentCreditStatus.PendingReady: + case PeerPullPaymentCreditStatus.AbortingDeletePurse: + case PeerPullPaymentCreditStatus.Done: + case PeerPullPaymentCreditStatus.Failed: + case PeerPullPaymentCreditStatus.Expired: + case PeerPullPaymentCreditStatus.Aborted: + break; + case PeerPullPaymentCreditStatus.SuspendedCreatePurse: + newStatus = PeerPullPaymentCreditStatus.PendingCreatePurse; + break; + case PeerPullPaymentCreditStatus.SuspendedMergeKycRequired: + newStatus = PeerPullPaymentCreditStatus.PendingMergeKycRequired; + break; + case PeerPullPaymentCreditStatus.SuspendedReady: + newStatus = PeerPullPaymentCreditStatus.PendingReady; + break; + case PeerPullPaymentCreditStatus.SuspendedWithdrawing: + newStatus = PeerPullPaymentCreditStatus.PendingWithdrawing; + break; + case PeerPullPaymentCreditStatus.SuspendedAbortingDeletePurse: + newStatus = PeerPullPaymentCreditStatus.AbortingDeletePurse; + break; + default: + assertUnreachable(pullCreditRec.status); + } + if (newStatus != null) { + const oldTxState = + computePeerPullCreditTransactionState(pullCreditRec); + pullCreditRec.status = newStatus; + const newTxState = + computePeerPullCreditTransactionState(pullCreditRec); + await tx.peerPullCredit.put(pullCreditRec); + return { + oldTxState, + newTxState, + }; + } + return undefined; + }); + ws.workAvailable.trigger(); + notifyTransition(ws, transactionId, transitionInfo); + } + + async abortTransaction(): Promise<void> { + const { ws, pursePub, retryTag, transactionId } = this; + stopLongpolling(ws, retryTag); + const transitionInfo = await ws.db + .mktx((x) => [x.peerPullCredit]) + .runReadWrite(async (tx) => { + const pullCreditRec = await tx.peerPullCredit.get(pursePub); + if (!pullCreditRec) { + logger.warn(`peer pull credit ${pursePub} not found`); + return; + } + let newStatus: PeerPullPaymentCreditStatus | undefined = undefined; + switch (pullCreditRec.status) { + case PeerPullPaymentCreditStatus.PendingCreatePurse: + case PeerPullPaymentCreditStatus.PendingMergeKycRequired: + newStatus = PeerPullPaymentCreditStatus.AbortingDeletePurse; + break; + case PeerPullPaymentCreditStatus.PendingWithdrawing: + throw Error("can't abort anymore"); + case PeerPullPaymentCreditStatus.PendingReady: + newStatus = PeerPullPaymentCreditStatus.AbortingDeletePurse; + break; + case PeerPullPaymentCreditStatus.Done: + case PeerPullPaymentCreditStatus.SuspendedCreatePurse: + case PeerPullPaymentCreditStatus.SuspendedMergeKycRequired: + case PeerPullPaymentCreditStatus.SuspendedReady: + case PeerPullPaymentCreditStatus.SuspendedWithdrawing: + case PeerPullPaymentCreditStatus.Aborted: + case PeerPullPaymentCreditStatus.AbortingDeletePurse: + case PeerPullPaymentCreditStatus.Failed: + case PeerPullPaymentCreditStatus.Expired: + case PeerPullPaymentCreditStatus.SuspendedAbortingDeletePurse: + break; + default: + assertUnreachable(pullCreditRec.status); + } + if (newStatus != null) { + const oldTxState = + computePeerPullCreditTransactionState(pullCreditRec); + pullCreditRec.status = newStatus; + const newTxState = + computePeerPullCreditTransactionState(pullCreditRec); + await tx.peerPullCredit.put(pullCreditRec); + return { + oldTxState, + newTxState, + }; + } + return undefined; + }); + notifyTransition(ws, transactionId, transitionInfo); + } +} + async function queryPurseForPeerPullCredit( ws: InternalWalletState, pullIni: PeerPullCreditRecord, @@ -849,258 +1120,6 @@ export async function initiatePeerPullPayment( }; } -export async function suspendPeerPullCreditTransaction( - 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.peerPullCredit]) - .runReadWrite(async (tx) => { - const pullCreditRec = await tx.peerPullCredit.get(pursePub); - if (!pullCreditRec) { - logger.warn(`peer pull credit ${pursePub} not found`); - return; - } - let newStatus: PeerPullPaymentCreditStatus | undefined = undefined; - switch (pullCreditRec.status) { - case PeerPullPaymentCreditStatus.PendingCreatePurse: - newStatus = PeerPullPaymentCreditStatus.SuspendedCreatePurse; - break; - case PeerPullPaymentCreditStatus.PendingMergeKycRequired: - newStatus = PeerPullPaymentCreditStatus.SuspendedMergeKycRequired; - break; - case PeerPullPaymentCreditStatus.PendingWithdrawing: - newStatus = PeerPullPaymentCreditStatus.SuspendedWithdrawing; - break; - case PeerPullPaymentCreditStatus.PendingReady: - newStatus = PeerPullPaymentCreditStatus.SuspendedReady; - break; - case PeerPullPaymentCreditStatus.AbortingDeletePurse: - newStatus = PeerPullPaymentCreditStatus.SuspendedAbortingDeletePurse; - break; - case PeerPullPaymentCreditStatus.Done: - case PeerPullPaymentCreditStatus.SuspendedCreatePurse: - case PeerPullPaymentCreditStatus.SuspendedMergeKycRequired: - case PeerPullPaymentCreditStatus.SuspendedReady: - case PeerPullPaymentCreditStatus.SuspendedWithdrawing: - case PeerPullPaymentCreditStatus.Aborted: - case PeerPullPaymentCreditStatus.Failed: - case PeerPullPaymentCreditStatus.Expired: - case PeerPullPaymentCreditStatus.SuspendedAbortingDeletePurse: - break; - default: - assertUnreachable(pullCreditRec.status); - } - if (newStatus != null) { - const oldTxState = computePeerPullCreditTransactionState(pullCreditRec); - pullCreditRec.status = newStatus; - const newTxState = computePeerPullCreditTransactionState(pullCreditRec); - await tx.peerPullCredit.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.peerPullCredit]) - .runReadWrite(async (tx) => { - const pullCreditRec = await tx.peerPullCredit.get(pursePub); - if (!pullCreditRec) { - logger.warn(`peer pull credit ${pursePub} not found`); - return; - } - let newStatus: PeerPullPaymentCreditStatus | undefined = undefined; - switch (pullCreditRec.status) { - case PeerPullPaymentCreditStatus.PendingCreatePurse: - case PeerPullPaymentCreditStatus.PendingMergeKycRequired: - newStatus = PeerPullPaymentCreditStatus.AbortingDeletePurse; - break; - case PeerPullPaymentCreditStatus.PendingWithdrawing: - throw Error("can't abort anymore"); - case PeerPullPaymentCreditStatus.PendingReady: - newStatus = PeerPullPaymentCreditStatus.AbortingDeletePurse; - break; - case PeerPullPaymentCreditStatus.Done: - case PeerPullPaymentCreditStatus.SuspendedCreatePurse: - case PeerPullPaymentCreditStatus.SuspendedMergeKycRequired: - case PeerPullPaymentCreditStatus.SuspendedReady: - case PeerPullPaymentCreditStatus.SuspendedWithdrawing: - case PeerPullPaymentCreditStatus.Aborted: - case PeerPullPaymentCreditStatus.AbortingDeletePurse: - case PeerPullPaymentCreditStatus.Failed: - case PeerPullPaymentCreditStatus.Expired: - case PeerPullPaymentCreditStatus.SuspendedAbortingDeletePurse: - break; - default: - assertUnreachable(pullCreditRec.status); - } - if (newStatus != null) { - const oldTxState = computePeerPullCreditTransactionState(pullCreditRec); - pullCreditRec.status = newStatus; - const newTxState = computePeerPullCreditTransactionState(pullCreditRec); - await tx.peerPullCredit.put(pullCreditRec); - return { - oldTxState, - newTxState, - }; - } - return undefined; - }); - notifyTransition(ws, transactionId, transitionInfo); -} - -export async function failPeerPullCreditTransaction( - 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.peerPullCredit]) - .runReadWrite(async (tx) => { - const pullCreditRec = await tx.peerPullCredit.get(pursePub); - if (!pullCreditRec) { - logger.warn(`peer pull credit ${pursePub} not found`); - return; - } - let newStatus: PeerPullPaymentCreditStatus | undefined = undefined; - switch (pullCreditRec.status) { - case PeerPullPaymentCreditStatus.PendingCreatePurse: - case PeerPullPaymentCreditStatus.PendingMergeKycRequired: - case PeerPullPaymentCreditStatus.PendingWithdrawing: - case PeerPullPaymentCreditStatus.PendingReady: - case PeerPullPaymentCreditStatus.Done: - case PeerPullPaymentCreditStatus.SuspendedCreatePurse: - case PeerPullPaymentCreditStatus.SuspendedMergeKycRequired: - case PeerPullPaymentCreditStatus.SuspendedReady: - case PeerPullPaymentCreditStatus.SuspendedWithdrawing: - case PeerPullPaymentCreditStatus.Aborted: - case PeerPullPaymentCreditStatus.Failed: - case PeerPullPaymentCreditStatus.Expired: - break; - case PeerPullPaymentCreditStatus.AbortingDeletePurse: - case PeerPullPaymentCreditStatus.SuspendedAbortingDeletePurse: - newStatus = PeerPullPaymentCreditStatus.Failed; - break; - default: - assertUnreachable(pullCreditRec.status); - } - if (newStatus != null) { - const oldTxState = computePeerPullCreditTransactionState(pullCreditRec); - pullCreditRec.status = newStatus; - const newTxState = computePeerPullCreditTransactionState(pullCreditRec); - await tx.peerPullCredit.put(pullCreditRec); - return { - oldTxState, - newTxState, - }; - } - return undefined; - }); - notifyTransition(ws, transactionId, transitionInfo); -} - -export async function resumePeerPullCreditTransaction( - 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.peerPullCredit]) - .runReadWrite(async (tx) => { - const pullCreditRec = await tx.peerPullCredit.get(pursePub); - if (!pullCreditRec) { - logger.warn(`peer pull credit ${pursePub} not found`); - return; - } - let newStatus: PeerPullPaymentCreditStatus | undefined = undefined; - switch (pullCreditRec.status) { - case PeerPullPaymentCreditStatus.PendingCreatePurse: - case PeerPullPaymentCreditStatus.PendingMergeKycRequired: - case PeerPullPaymentCreditStatus.PendingWithdrawing: - case PeerPullPaymentCreditStatus.PendingReady: - case PeerPullPaymentCreditStatus.AbortingDeletePurse: - case PeerPullPaymentCreditStatus.Done: - case PeerPullPaymentCreditStatus.Failed: - case PeerPullPaymentCreditStatus.Expired: - case PeerPullPaymentCreditStatus.Aborted: - break; - case PeerPullPaymentCreditStatus.SuspendedCreatePurse: - newStatus = PeerPullPaymentCreditStatus.PendingCreatePurse; - break; - case PeerPullPaymentCreditStatus.SuspendedMergeKycRequired: - newStatus = PeerPullPaymentCreditStatus.PendingMergeKycRequired; - break; - case PeerPullPaymentCreditStatus.SuspendedReady: - newStatus = PeerPullPaymentCreditStatus.PendingReady; - break; - case PeerPullPaymentCreditStatus.SuspendedWithdrawing: - newStatus = PeerPullPaymentCreditStatus.PendingWithdrawing; - break; - case PeerPullPaymentCreditStatus.SuspendedAbortingDeletePurse: - newStatus = PeerPullPaymentCreditStatus.AbortingDeletePurse; - break; - default: - assertUnreachable(pullCreditRec.status); - } - if (newStatus != null) { - const oldTxState = computePeerPullCreditTransactionState(pullCreditRec); - pullCreditRec.status = newStatus; - const newTxState = computePeerPullCreditTransactionState(pullCreditRec); - await tx.peerPullCredit.put(pullCreditRec); - return { - oldTxState, - newTxState, - }; - } - return undefined; - }); - ws.workAvailable.trigger(); - notifyTransition(ws, transactionId, transitionInfo); -} - export function computePeerPullCreditTransactionState( pullCreditRecord: PeerPullCreditRecord, ): TransactionState { |