aboutsummaryrefslogtreecommitdiff
path: root/packages/taler-wallet-core/src/operations
diff options
context:
space:
mode:
Diffstat (limited to 'packages/taler-wallet-core/src/operations')
-rw-r--r--packages/taler-wallet-core/src/operations/common.ts19
-rw-r--r--packages/taler-wallet-core/src/operations/pay-peer-common.ts6
-rw-r--r--packages/taler-wallet-core/src/operations/pay-peer-pull-debit.ts499
-rw-r--r--packages/taler-wallet-core/src/operations/refresh.ts16
-rw-r--r--packages/taler-wallet-core/src/operations/transactions.ts26
5 files changed, 266 insertions, 300 deletions
diff --git a/packages/taler-wallet-core/src/operations/common.ts b/packages/taler-wallet-core/src/operations/common.ts
index d8fb82be1..1103b7255 100644
--- a/packages/taler-wallet-core/src/operations/common.ts
+++ b/packages/taler-wallet-core/src/operations/common.ts
@@ -1075,3 +1075,22 @@ export namespace TaskIdentifiers {
return `${PendingTaskType.PeerPushCredit}:${ppi.peerPushCreditId}` as TaskId;
}
}
+
+/**
+ * Result of a transaction transition.
+ */
+export enum TransitionResult {
+ Transition = 1,
+ Stay = 2,
+}
+
+/**
+ * Transaction context.
+ *
+ * FIXME: Should eventually be implemented by all transactions.
+ */
+export interface TransactionContext {
+ abortTransaction(): Promise<void>;
+ resumeTransaction(): Promise<void>;
+ failTransaction(): Promise<void>;
+}
diff --git a/packages/taler-wallet-core/src/operations/pay-peer-common.ts b/packages/taler-wallet-core/src/operations/pay-peer-common.ts
index 1a5dc6e89..88eedb530 100644
--- a/packages/taler-wallet-core/src/operations/pay-peer-common.ts
+++ b/packages/taler-wallet-core/src/operations/pay-peer-common.ts
@@ -44,11 +44,7 @@ import { getCandidateWithdrawalDenomsTx } from "./withdraw.js";
const logger = new Logger("operations/peer-to-peer.ts");
/**
- * Get information about the coin selected for signatures
- *
- * @param ws
- * @param csel
- * @returns
+ * Get information about the coin selected for signatures.
*/
export async function queryCoinInfosForSelection(
ws: InternalWalletState,
diff --git a/packages/taler-wallet-core/src/operations/pay-peer-pull-debit.ts b/packages/taler-wallet-core/src/operations/pay-peer-pull-debit.ts
index 72e9e2e4a..9bbe2c875 100644
--- a/packages/taler-wallet-core/src/operations/pay-peer-pull-debit.ts
+++ b/packages/taler-wallet-core/src/operations/pay-peer-pull-debit.ts
@@ -1,6 +1,6 @@
/*
This file is part of GNU Taler
- (C) 2022-2023 Taler Systems S.A.
+ (C) 2022-2024 Taler Systems S.A.
GNU Taler is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
@@ -14,6 +14,15 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
+/**
+ * @fileoverview
+ * Implementation of the peer-pull-debit transaction, i.e.
+ * paying for an invoice the wallet received from another wallet.
+ */
+
+/**
+ * Imports.
+ */
import {
AcceptPeerPullPaymentResponse,
Amounts,
@@ -53,19 +62,25 @@ import {
readTalerErrorResponse,
} from "@gnu-taler/taler-util/http";
import {
+ DbReadWriteTransactionArr,
InternalWalletState,
PeerPullDebitRecordStatus,
PeerPullPaymentIncomingRecord,
PendingTaskType,
RefreshOperationStatus,
+ StoreNames,
+ WalletStoresV1,
createRefreshGroup,
timestampPreciseToDb,
} from "../index.js";
import { assertUnreachable } from "../util/assertUnreachable.js";
+import { PeerCoinRepair, selectPeerCoins } from "../util/coinSelection.js";
import { checkLogicInvariant } from "../util/invariants.js";
import {
TaskRunResult,
TaskRunResultType,
+ TransactionContext,
+ TransitionResult,
constructTaskIdentifier,
spendCoins,
} from "./common.js";
@@ -80,19 +95,181 @@ import {
parseTransactionIdentifier,
stopLongpolling,
} from "./transactions.js";
-import { PeerCoinRepair, selectPeerCoins } from "../util/coinSelection.js";
const logger = new Logger("pay-peer-pull-debit.ts");
+/**
+ * Common context for a peer-pull-debit transaction.
+ */
+export class PeerPullDebitTransactionContext implements TransactionContext {
+ ws: InternalWalletState;
+ transactionId: string;
+ taskId: string;
+ peerPullDebitId: string;
+
+ constructor(ws: InternalWalletState, peerPullDebitId: string) {
+ this.ws = ws;
+ this.transactionId = constructTransactionIdentifier({
+ tag: TransactionType.PeerPullDebit,
+ peerPullDebitId,
+ });
+ this.taskId = constructTaskIdentifier({
+ tag: PendingTaskType.PeerPullDebit,
+ peerPullDebitId,
+ });
+ this.peerPullDebitId = peerPullDebitId;
+ }
+
+ async resumeTransaction(): Promise<void> {
+ const ctx = this;
+ stopLongpolling(ctx.ws, ctx.taskId);
+ await ctx.transition(async (pi) => {
+ switch (pi.status) {
+ case PeerPullDebitRecordStatus.SuspendedDeposit:
+ pi.status = PeerPullDebitRecordStatus.PendingDeposit;
+ return TransitionResult.Transition;
+ case PeerPullDebitRecordStatus.SuspendedAbortingRefresh:
+ pi.status = PeerPullDebitRecordStatus.AbortingRefresh;
+ return TransitionResult.Transition;
+ case PeerPullDebitRecordStatus.Aborted:
+ case PeerPullDebitRecordStatus.AbortingRefresh:
+ case PeerPullDebitRecordStatus.Failed:
+ case PeerPullDebitRecordStatus.DialogProposed:
+ case PeerPullDebitRecordStatus.Done:
+ case PeerPullDebitRecordStatus.PendingDeposit:
+ return TransitionResult.Stay;
+ }
+ });
+ }
+
+ async failTransaction(): Promise<void> {
+ const ctx = this;
+ stopLongpolling(ctx.ws, ctx.taskId);
+ await ctx.transition(async (pi) => {
+ switch (pi.status) {
+ case PeerPullDebitRecordStatus.SuspendedDeposit:
+ case PeerPullDebitRecordStatus.PendingDeposit:
+ case PeerPullDebitRecordStatus.AbortingRefresh:
+ case PeerPullDebitRecordStatus.SuspendedAbortingRefresh:
+ // FIXME: Should we also abort the corresponding refresh session?!
+ pi.status = PeerPullDebitRecordStatus.Failed;
+ return TransitionResult.Transition;
+ default:
+ return TransitionResult.Stay;
+ }
+ });
+ }
+
+ async abortTransaction(): Promise<void> {
+ const ctx = this;
+ await ctx.transitionExtra(
+ {
+ extraStores: [
+ "coinAvailability",
+ "denominations",
+ "refreshGroups",
+ "coins",
+ "coinAvailability",
+ ],
+ },
+ async (pi, tx) => {
+ switch (pi.status) {
+ case PeerPullDebitRecordStatus.SuspendedDeposit:
+ case PeerPullDebitRecordStatus.PendingDeposit:
+ break;
+ default:
+ return TransitionResult.Stay;
+ }
+ const currency = Amounts.currencyOf(pi.totalCostEstimated);
+ const coinPubs: CoinRefreshRequest[] = [];
+
+ if (!pi.coinSel) {
+ throw Error("invalid db state");
+ }
+
+ for (let i = 0; i < pi.coinSel.coinPubs.length; i++) {
+ coinPubs.push({
+ amount: pi.coinSel.contributions[i],
+ coinPub: pi.coinSel.coinPubs[i],
+ });
+ }
+
+ const refresh = await createRefreshGroup(
+ ctx.ws,
+ tx,
+ currency,
+ coinPubs,
+ RefreshReason.AbortPeerPullDebit,
+ );
+
+ pi.status = PeerPullDebitRecordStatus.AbortingRefresh;
+ pi.abortRefreshGroupId = refresh.refreshGroupId;
+ return TransitionResult.Transition;
+ },
+ );
+ }
+
+ async transition(
+ f: (rec: PeerPullPaymentIncomingRecord) => Promise<TransitionResult>,
+ ): Promise<void> {
+ return this.transitionExtra(
+ {
+ extraStores: [],
+ },
+ f,
+ );
+ }
+
+ async transitionExtra<
+ StoreNameArray extends Array<StoreNames<typeof WalletStoresV1>> = [],
+ >(
+ opts: { extraStores: StoreNameArray },
+ f: (
+ rec: PeerPullPaymentIncomingRecord,
+ tx: DbReadWriteTransactionArr<
+ typeof WalletStoresV1,
+ ["peerPullDebit", ...StoreNameArray]
+ >,
+ ) => Promise<TransitionResult>,
+ ): Promise<void> {
+ const ws = this.ws;
+ const extraStores = opts.extraStores ?? [];
+ const transitionInfo = await ws.db.runReadWriteTx(
+ ["peerPullDebit", ...extraStores],
+ async (tx) => {
+ const pi = await tx.peerPullDebit.get(this.peerPullDebitId);
+ if (!pi) {
+ throw Error("peer pull payment not found anymore");
+ }
+ const oldTxState = computePeerPullDebitTransactionState(pi);
+ const res = await f(pi, tx);
+ switch (res) {
+ case TransitionResult.Transition: {
+ await tx.peerPullDebit.put(pi);
+ const newTxState = computePeerPullDebitTransactionState(pi);
+ return {
+ oldTxState,
+ newTxState,
+ };
+ }
+ default:
+ return undefined;
+ }
+ },
+ );
+ notifyTransition(ws, this.transactionId, transitionInfo);
+ }
+}
+
async function handlePurseCreationConflict(
- ws: InternalWalletState,
+ ctx: PeerPullDebitTransactionContext,
peerPullInc: PeerPullPaymentIncomingRecord,
resp: HttpResponse,
): Promise<TaskRunResult> {
- const pursePub = peerPullInc.pursePub;
+ const ws = ctx.ws;
const errResp = await readTalerErrorResponse(resp);
if (errResp.code !== TalerErrorCode.EXCHANGE_GENERIC_INSUFFICIENT_FUNDS) {
- await failPeerPullDebitTransaction(ws, pursePub);
+ await ctx.failTransaction();
return TaskRunResult.finished();
}
@@ -139,29 +316,27 @@ async function handlePurseCreationConflict(
coinSelRes.result.coins,
);
- await ws.db
- .mktx((x) => [x.peerPullDebit])
- .runReadWrite(async (tx) => {
- const myPpi = await tx.peerPullDebit.get(peerPullInc.peerPullDebitId);
- if (!myPpi) {
- return;
- }
- switch (myPpi.status) {
- case PeerPullDebitRecordStatus.PendingDeposit:
- case PeerPullDebitRecordStatus.SuspendedDeposit: {
- const sel = coinSelRes.result;
- myPpi.coinSel = {
- coinPubs: sel.coins.map((x) => x.coinPub),
- contributions: sel.coins.map((x) => x.contribution),
- totalCost: Amounts.stringify(totalAmount),
- };
- break;
- }
- default:
- return;
+ await ws.db.runReadWriteTx(["peerPullDebit"], async (tx) => {
+ const myPpi = await tx.peerPullDebit.get(peerPullInc.peerPullDebitId);
+ if (!myPpi) {
+ return;
+ }
+ switch (myPpi.status) {
+ case PeerPullDebitRecordStatus.PendingDeposit:
+ case PeerPullDebitRecordStatus.SuspendedDeposit: {
+ const sel = coinSelRes.result;
+ myPpi.coinSel = {
+ coinPubs: sel.coins.map((x) => x.coinPub),
+ contributions: sel.coins.map((x) => x.contribution),
+ totalCost: Amounts.stringify(totalAmount),
+ };
+ break;
}
- await tx.peerPullDebit.put(myPpi);
- });
+ default:
+ return;
+ }
+ await tx.peerPullDebit.put(myPpi);
+ });
return TaskRunResult.finished();
}
@@ -169,7 +344,6 @@ async function processPeerPullDebitPendingDeposit(
ws: InternalWalletState,
peerPullInc: PeerPullPaymentIncomingRecord,
): Promise<TaskRunResult> {
- const peerPullDebitId = peerPullInc.peerPullDebitId;
const pursePub = peerPullInc.pursePub;
const coinSel = peerPullInc.coinSel;
@@ -198,15 +372,16 @@ async function processPeerPullDebitPendingDeposit(
logger.trace(`purse deposit payload: ${j2s(depositPayload)}`);
}
- const transactionId = constructTransactionIdentifier({
- tag: TransactionType.PeerPullDebit,
- peerPullDebitId,
- });
-
const httpResp = await ws.http.fetch(purseDepositUrl.href, {
method: "POST",
body: depositPayload,
});
+
+ const ctx = new PeerPullDebitTransactionContext(
+ ws,
+ peerPullInc.peerPullDebitId,
+ );
+
switch (httpResp.status) {
case HttpStatusCode.Ok: {
const resp = await readSuccessResponseJsonOrThrow(
@@ -215,77 +390,21 @@ async function processPeerPullDebitPendingDeposit(
);
logger.trace(`purse deposit response: ${j2s(resp)}`);
- const transitionInfo = await ws.db
- .mktx((x) => [x.peerPullDebit])
- .runReadWrite(async (tx) => {
- const pi = await tx.peerPullDebit.get(peerPullDebitId);
- if (!pi) {
- throw Error("peer pull payment not found anymore");
- }
- if (pi.status !== PeerPullDebitRecordStatus.PendingDeposit) {
- return;
- }
- const oldTxState = computePeerPullDebitTransactionState(pi);
- pi.status = PeerPullDebitRecordStatus.Done;
- const newTxState = computePeerPullDebitTransactionState(pi);
- await tx.peerPullDebit.put(pi);
- return { oldTxState, newTxState };
- });
- notifyTransition(ws, transactionId, transitionInfo);
- break;
+ await ctx.transition(async (r) => {
+ if (r.status !== PeerPullDebitRecordStatus.PendingDeposit) {
+ return TransitionResult.Stay;
+ }
+ r.status = PeerPullDebitRecordStatus.Done;
+ return TransitionResult.Transition;
+ });
+ return TaskRunResult.finished();
}
case HttpStatusCode.Gone: {
- const transitionInfo = await ws.db
- .mktx((x) => [
- x.peerPullDebit,
- x.refreshGroups,
- x.denominations,
- x.coinAvailability,
- x.coins,
- ])
- .runReadWrite(async (tx) => {
- const pi = await tx.peerPullDebit.get(peerPullDebitId);
- if (!pi) {
- throw Error("peer pull payment not found anymore");
- }
- if (pi.status !== PeerPullDebitRecordStatus.PendingDeposit) {
- return;
- }
- const oldTxState = computePeerPullDebitTransactionState(pi);
-
- const currency = Amounts.currencyOf(pi.totalCostEstimated);
- const coinPubs: CoinRefreshRequest[] = [];
-
- if (!pi.coinSel) {
- throw Error("invalid db state");
- }
-
- for (let i = 0; i < pi.coinSel.coinPubs.length; i++) {
- coinPubs.push({
- amount: pi.coinSel.contributions[i],
- coinPub: pi.coinSel.coinPubs[i],
- });
- }
-
- const refresh = await createRefreshGroup(
- ws,
- tx,
- currency,
- coinPubs,
- RefreshReason.AbortPeerPullDebit,
- );
-
- pi.status = PeerPullDebitRecordStatus.AbortingRefresh;
- pi.abortRefreshGroupId = refresh.refreshGroupId;
- const newTxState = computePeerPullDebitTransactionState(pi);
- await tx.peerPullDebit.put(pi);
- return { oldTxState, newTxState };
- });
- notifyTransition(ws, transactionId, transitionInfo);
- break;
+ await ctx.abortTransaction();
+ return TaskRunResult.finished();
}
case HttpStatusCode.Conflict: {
- return handlePurseCreationConflict(ws, peerPullInc, httpResp);
+ return handlePurseCreationConflict(ctx, peerPullInc, httpResp);
}
default: {
const errResp = await readTalerErrorResponse(httpResp);
@@ -295,7 +414,6 @@ async function processPeerPullDebitPendingDeposit(
};
}
}
- return TaskRunResult.finished();
}
async function processPeerPullDebitAbortingRefresh(
@@ -624,6 +742,9 @@ export async function preparePeerPullDebit(
};
}
+/**
+ * FIXME: This belongs in the transaction context!
+ */
export async function suspendPeerPullDebitTransaction(
ws: InternalWalletState,
peerPullDebitId: string,
@@ -683,182 +804,6 @@ export async function suspendPeerPullDebitTransaction(
notifyTransition(ws, transactionId, transitionInfo);
}
-export async function abortPeerPullDebitTransaction(
- ws: InternalWalletState,
- peerPullDebitId: string,
-) {
- const taskId = constructTaskIdentifier({
- tag: PendingTaskType.PeerPullDebit,
- peerPullDebitId,
- });
- const transactionId = constructTransactionIdentifier({
- tag: TransactionType.PeerPullDebit,
- peerPullDebitId,
- });
- stopLongpolling(ws, taskId);
- const transitionInfo = await ws.db
- .mktx((x) => [x.peerPullDebit])
- .runReadWrite(async (tx) => {
- const pullDebitRec = await tx.peerPullDebit.get(peerPullDebitId);
- if (!pullDebitRec) {
- logger.warn(`peer pull debit ${peerPullDebitId} not found`);
- return;
- }
- let newStatus: PeerPullDebitRecordStatus | undefined = undefined;
- switch (pullDebitRec.status) {
- case PeerPullDebitRecordStatus.DialogProposed:
- newStatus = PeerPullDebitRecordStatus.Aborted;
- break;
- case PeerPullDebitRecordStatus.Done:
- 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.peerPullDebit.put(pullDebitRec);
- return {
- oldTxState,
- newTxState,
- };
- }
- return undefined;
- });
- notifyTransition(ws, transactionId, transitionInfo);
-}
-
-export async function failPeerPullDebitTransaction(
- ws: InternalWalletState,
- peerPullDebitId: string,
-) {
- const taskId = constructTaskIdentifier({
- tag: PendingTaskType.PeerPullDebit,
- peerPullDebitId,
- });
- const transactionId = constructTransactionIdentifier({
- tag: TransactionType.PeerPullDebit,
- peerPullDebitId,
- });
- stopLongpolling(ws, taskId);
- const transitionInfo = await ws.db
- .mktx((x) => [x.peerPullDebit])
- .runReadWrite(async (tx) => {
- const pullDebitRec = await tx.peerPullDebit.get(peerPullDebitId);
- if (!pullDebitRec) {
- logger.warn(`peer pull debit ${peerPullDebitId} not found`);
- return;
- }
- let newStatus: PeerPullDebitRecordStatus | undefined = undefined;
- switch (pullDebitRec.status) {
- case PeerPullDebitRecordStatus.DialogProposed:
- newStatus = PeerPullDebitRecordStatus.Aborted;
- break;
- case PeerPullDebitRecordStatus.Done:
- 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);
- }
- if (newStatus != null) {
- const oldTxState = computePeerPullDebitTransactionState(pullDebitRec);
- pullDebitRec.status = newStatus;
- const newTxState = computePeerPullDebitTransactionState(pullDebitRec);
- await tx.peerPullDebit.put(pullDebitRec);
- return {
- oldTxState,
- newTxState,
- };
- }
- return undefined;
- });
- notifyTransition(ws, transactionId, transitionInfo);
-}
-
-export async function resumePeerPullDebitTransaction(
- ws: InternalWalletState,
- peerPullDebitId: string,
-) {
- const taskId = constructTaskIdentifier({
- tag: PendingTaskType.PeerPullDebit,
- peerPullDebitId,
- });
- const transactionId = constructTransactionIdentifier({
- tag: TransactionType.PeerPullDebit,
- peerPullDebitId,
- });
- stopLongpolling(ws, taskId);
- const transitionInfo = await ws.db
- .mktx((x) => [x.peerPullDebit])
- .runReadWrite(async (tx) => {
- const pullDebitRec = await tx.peerPullDebit.get(peerPullDebitId);
- if (!pullDebitRec) {
- logger.warn(`peer pull debit ${peerPullDebitId} not found`);
- return;
- }
- let newStatus: PeerPullDebitRecordStatus | undefined = undefined;
- switch (pullDebitRec.status) {
- case PeerPullDebitRecordStatus.DialogProposed:
- case PeerPullDebitRecordStatus.Done:
- case PeerPullDebitRecordStatus.PendingDeposit:
- break;
- 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);
- }
- if (newStatus != null) {
- const oldTxState = computePeerPullDebitTransactionState(pullDebitRec);
- pullDebitRec.status = newStatus;
- const newTxState = computePeerPullDebitTransactionState(pullDebitRec);
- await tx.peerPullDebit.put(pullDebitRec);
- return {
- oldTxState,
- newTxState,
- };
- }
- return undefined;
- });
- ws.workAvailable.trigger();
- notifyTransition(ws, transactionId, transitionInfo);
-}
-
export function computePeerPullDebitTransactionState(
pullDebitRecord: PeerPullPaymentIncomingRecord,
): TransactionState {
diff --git a/packages/taler-wallet-core/src/operations/refresh.ts b/packages/taler-wallet-core/src/operations/refresh.ts
index 17ac54cfb..a8bcb28d1 100644
--- a/packages/taler-wallet-core/src/operations/refresh.ts
+++ b/packages/taler-wallet-core/src/operations/refresh.ts
@@ -84,6 +84,7 @@ import {
RefreshSessionRecord,
timestampPreciseToDb,
timestampProtocolFromDb,
+ WalletDbReadWriteTransaction,
} from "../index.js";
import {
EXCHANGE_COINS_LOCK,
@@ -92,7 +93,11 @@ import {
import { assertUnreachable } from "../util/assertUnreachable.js";
import { selectWithdrawalDenominations } from "../util/coinSelection.js";
import { checkDbInvariant } from "../util/invariants.js";
-import { GetReadOnlyAccess, GetReadWriteAccess } from "../util/query.js";
+import {
+ DbReadWriteTransaction,
+ GetReadOnlyAccess,
+ GetReadWriteAccess,
+} from "../util/query.js";
import {
constructTaskIdentifier,
makeCoinAvailable,
@@ -1097,12 +1102,9 @@ async function applyRefresh(
*/
export async function createRefreshGroup(
ws: InternalWalletState,
- tx: GetReadWriteAccess<{
- denominations: typeof WalletStoresV1.denominations;
- coins: typeof WalletStoresV1.coins;
- refreshGroups: typeof WalletStoresV1.refreshGroups;
- coinAvailability: typeof WalletStoresV1.coinAvailability;
- }>,
+ tx: WalletDbReadWriteTransaction<
+ "denominations" | "coins" | "refreshGroups" | "coinAvailability"
+ >,
currency: string,
oldCoinPubs: CoinRefreshRequest[],
reason: RefreshReason,
diff --git a/packages/taler-wallet-core/src/operations/transactions.ts b/packages/taler-wallet-core/src/operations/transactions.ts
index 3a219b39b..142eff7c1 100644
--- a/packages/taler-wallet-core/src/operations/transactions.ts
+++ b/packages/taler-wallet-core/src/operations/transactions.ts
@@ -114,11 +114,9 @@ import {
suspendPeerPullCreditTransaction,
} from "./pay-peer-pull-credit.js";
import {
- abortPeerPullDebitTransaction,
computePeerPullDebitTransactionActions,
computePeerPullDebitTransactionState,
- failPeerPullDebitTransaction,
- resumePeerPullDebitTransaction,
+ PeerPullDebitTransactionContext,
suspendPeerPullDebitTransaction,
} from "./pay-peer-pull-debit.js";
import {
@@ -1647,9 +1645,11 @@ export async function failTransaction(
case TransactionType.PeerPullCredit:
await failPeerPullCreditTransaction(ws, tx.pursePub);
return;
- case TransactionType.PeerPullDebit:
- await failPeerPullDebitTransaction(ws, tx.peerPullDebitId);
+ case TransactionType.PeerPullDebit: {
+ const ctx = new PeerPullDebitTransactionContext(ws, tx.peerPullDebitId);
+ await ctx.failTransaction();
return;
+ }
case TransactionType.PeerPushCredit:
await failPeerPushCreditTransaction(ws, tx.peerPushCreditId);
return;
@@ -1692,9 +1692,11 @@ export async function resumeTransaction(
case TransactionType.PeerPushDebit:
await resumePeerPushDebitTransaction(ws, tx.pursePub);
break;
- case TransactionType.PeerPullDebit:
- await resumePeerPullDebitTransaction(ws, tx.peerPullDebitId);
- break;
+ case TransactionType.PeerPullDebit: {
+ const ctx = new PeerPullDebitTransactionContext(ws, tx.peerPullDebitId);
+ await ctx.resumeTransaction();
+ return;
+ }
case TransactionType.PeerPushCredit:
await resumePeerPushCreditTransaction(ws, tx.peerPushCreditId);
break;
@@ -1936,9 +1938,11 @@ export async function abortTransaction(
case TransactionType.PeerPullCredit:
await abortPeerPullCreditTransaction(ws, txId.pursePub);
break;
- case TransactionType.PeerPullDebit:
- await abortPeerPullDebitTransaction(ws, txId.peerPullDebitId);
- break;
+ case TransactionType.PeerPullDebit: {
+ const ctx = new PeerPullDebitTransactionContext(ws, txId.peerPullDebitId);
+ await ctx.abortTransaction();
+ return;
+ }
case TransactionType.PeerPushCredit:
await abortPeerPushCreditTransaction(ws, txId.peerPushCreditId);
break;