summaryrefslogtreecommitdiff
path: root/packages/taler-wallet-core
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2022-01-11 21:00:12 +0100
committerFlorian Dold <florian@dold.me>2022-01-11 22:15:56 +0100
commita74cdf05295764258fe9e7f66f73a442a9b46697 (patch)
treed1a662fede130abc1fa33cdbc96c081cc47b23cd /packages/taler-wallet-core
parenta05e891d6e1468fdd99f710301e286857a46aea3 (diff)
downloadwallet-core-a74cdf05295764258fe9e7f66f73a442a9b46697.tar.gz
wallet-core-a74cdf05295764258fe9e7f66f73a442a9b46697.tar.bz2
wallet-core-a74cdf05295764258fe9e7f66f73a442a9b46697.zip
fix DB indexing issues
Diffstat (limited to 'packages/taler-wallet-core')
-rw-r--r--packages/taler-wallet-core/src/db.ts44
-rw-r--r--packages/taler-wallet-core/src/headless/helpers.ts23
-rw-r--r--packages/taler-wallet-core/src/index.node.ts3
-rw-r--r--packages/taler-wallet-core/src/operations/README.md2
-rw-r--r--packages/taler-wallet-core/src/operations/backup/import.ts25
-rw-r--r--packages/taler-wallet-core/src/operations/balance.ts7
-rw-r--r--packages/taler-wallet-core/src/operations/deposits.ts32
-rw-r--r--packages/taler-wallet-core/src/operations/pending.ts167
-rw-r--r--packages/taler-wallet-core/src/operations/refresh.ts3
-rw-r--r--packages/taler-wallet-core/src/operations/reserves.ts9
-rw-r--r--packages/taler-wallet-core/src/operations/withdraw.ts4
11 files changed, 216 insertions, 103 deletions
diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts
index 07e0f4b0a..772061fb9 100644
--- a/packages/taler-wallet-core/src/db.ts
+++ b/packages/taler-wallet-core/src/db.ts
@@ -42,6 +42,7 @@ import {
import { RetryInfo } from "./util/retries.js";
import { PayCoinSelection } from "./util/coinSelection.js";
import { Event, IDBDatabase } from "@gnu-taler/idb-bridge";
+import { PendingTaskInfo } from "./pending-types.js";
/**
* Name of the Taler database. This is effectively the major
@@ -153,6 +154,8 @@ export interface ReserveRecord {
*/
timestampCreated: Timestamp;
+ operationStatus: OperationStatus;
+
/**
* Time when the information about this reserve was posted to the bank.
*
@@ -914,10 +917,19 @@ export enum RefreshCoinStatus {
Frozen = "frozen",
}
+export enum OperationStatus {
+ Finished = "finished",
+ Pending = "pending",
+}
+
export interface RefreshGroupRecord {
+ operationStatus: OperationStatus;
+
/**
* Retry info, even present when the operation isn't active to allow indexing
* on the next retry timestamp.
+ *
+ * FIXME: No, this can be optional, indexing is still possible
*/
retryInfo: RetryInfo;
@@ -1350,6 +1362,8 @@ export interface WithdrawalGroupRecord {
*/
timestampFinish?: Timestamp;
+ operationStatus: OperationStatus;
+
/**
* Amount including fees (i.e. the amount subtracted from the
* reserve to withdraw all coins in this withdrawal session).
@@ -1561,6 +1575,8 @@ export interface DepositGroupRecord {
timestampFinished: Timestamp | undefined;
+ operationStatus: OperationStatus;
+
lastError: TalerErrorDetails | undefined;
/**
@@ -1601,6 +1617,18 @@ export interface TombstoneRecord {
id: string;
}
+export interface BalancePerCurrencyRecord {
+ currency: string;
+
+ availableNow: AmountString;
+
+ availableExpected: AmountString;
+
+ pendingIncoming: AmountString;
+
+ pendingOutgoing: AmountString;
+}
+
export const WalletStoresV1 = {
coins: describeStore(
describeContents<CoinRecord>("coins", {
@@ -1671,7 +1699,9 @@ export const WalletStoresV1 = {
describeContents<RefreshGroupRecord>("refreshGroups", {
keyPath: "refreshGroupId",
}),
- {},
+ {
+ byStatus: describeIndex("byStatus", "operationStatus"),
+ },
),
recoupGroups: describeStore(
describeContents<RecoupGroupRecord>("recoupGroups", {
@@ -1686,6 +1716,7 @@ export const WalletStoresV1 = {
"byInitialWithdrawalGroupId",
"initialWithdrawalGroupId",
),
+ byStatus: describeIndex("byStatus", "operationStatus"),
},
),
purchases: describeStore(
@@ -1716,6 +1747,7 @@ export const WalletStoresV1 = {
}),
{
byReservePub: describeIndex("byReservePub", "reservePub"),
+ byStatus: describeIndex("byStatus", "operationStatus"),
},
),
planchets: describeStore(
@@ -1753,7 +1785,9 @@ export const WalletStoresV1 = {
describeContents<DepositGroupRecord>("depositGroups", {
keyPath: "depositGroupId",
}),
- {},
+ {
+ byStatus: describeIndex("byStatus", "operationStatus"),
+ },
),
tombstones: describeStore(
describeContents<TombstoneRecord>("tombstones", { keyPath: "id" }),
@@ -1765,6 +1799,12 @@ export const WalletStoresV1 = {
}),
{},
),
+ balancesPerCurrency: describeStore(
+ describeContents<BalancePerCurrencyRecord>("balancesPerCurrency", {
+ keyPath: "currency",
+ }),
+ {},
+ ),
};
export interface MetaConfigRecord {
diff --git a/packages/taler-wallet-core/src/headless/helpers.ts b/packages/taler-wallet-core/src/headless/helpers.ts
index 191c48441..d8616f716 100644
--- a/packages/taler-wallet-core/src/headless/helpers.ts
+++ b/packages/taler-wallet-core/src/headless/helpers.ts
@@ -37,6 +37,7 @@ import type { IDBFactory } from "@gnu-taler/idb-bridge";
import { WalletNotification } from "@gnu-taler/taler-util";
import { Wallet } from "../wallet.js";
import * as fs from "fs";
+import { AccessStats } from "@gnu-taler/idb-bridge/src/MemoryBackend";
const logger = new Logger("headless/helpers.ts");
@@ -80,6 +81,21 @@ function makeId(length: number): string {
export async function getDefaultNodeWallet(
args: DefaultNodeWalletArgs = {},
): Promise<Wallet> {
+ const res = await getDefaultNodeWallet2(args);
+ return res.wallet;
+}
+
+/**
+ * Get a wallet instance with default settings for node.
+ *
+ * Extended version that allows getting DB stats.
+ */
+export async function getDefaultNodeWallet2(
+ args: DefaultNodeWalletArgs = {},
+): Promise<{
+ wallet: Wallet;
+ getDbStats: () => AccessStats;
+}> {
BridgeIDBFactory.enableTracing = false;
const myBackend = new MemoryBackend();
myBackend.enableTracing = false;
@@ -121,7 +137,7 @@ export async function getDefaultNodeWallet(
BridgeIDBFactory.enableTracing = false;
const myBridgeIdbFactory = new BridgeIDBFactory(myBackend);
- const myIdbFactory: IDBFactory = (myBridgeIdbFactory as any) as IDBFactory;
+ const myIdbFactory: IDBFactory = myBridgeIdbFactory as any as IDBFactory;
let myHttpLib;
if (args.httpLib) {
@@ -164,5 +180,8 @@ export async function getDefaultNodeWallet(
if (args.notifyHandler) {
w.addNotificationListener(args.notifyHandler);
}
- return w;
+ return {
+ wallet: w,
+ getDbStats: () => myBackend.accessStats,
+ };
}
diff --git a/packages/taler-wallet-core/src/index.node.ts b/packages/taler-wallet-core/src/index.node.ts
index 0860ccc26..7a6ad6a74 100644
--- a/packages/taler-wallet-core/src/index.node.ts
+++ b/packages/taler-wallet-core/src/index.node.ts
@@ -20,6 +20,9 @@ export * from "./index.js";
export { NodeHttpLib } from "./headless/NodeHttpLib.js";
export {
getDefaultNodeWallet,
+ getDefaultNodeWallet2,
DefaultNodeWalletArgs,
} from "./headless/helpers.js";
export * from "./crypto/workers/nodeThreadWorker.js";
+
+export type { AccessStats } from "@gnu-taler/idb-bridge";
diff --git a/packages/taler-wallet-core/src/operations/README.md b/packages/taler-wallet-core/src/operations/README.md
index 32e2fbfc8..ca7140d6a 100644
--- a/packages/taler-wallet-core/src/operations/README.md
+++ b/packages/taler-wallet-core/src/operations/README.md
@@ -4,4 +4,4 @@ This folder contains the implementations for all wallet operations that operate
To avoid cyclic dependencies, these files must **not** reference each other. Instead, other operations should only be accessed via injected dependencies.
-Avoiding cyclic dependencies is important for module bundlers. \ No newline at end of file
+Avoiding cyclic dependencies is important for module bundlers.
diff --git a/packages/taler-wallet-core/src/operations/backup/import.ts b/packages/taler-wallet-core/src/operations/backup/import.ts
index 564d39797..5ca1ebb9d 100644
--- a/packages/taler-wallet-core/src/operations/backup/import.ts
+++ b/packages/taler-wallet-core/src/operations/backup/import.ts
@@ -47,6 +47,7 @@ import {
WireInfo,
WalletStoresV1,
RefreshCoinStatus,
+ OperationStatus,
} from "../../db.js";
import { PayCoinSelection } from "../../util/coinSelection.js";
import { j2s } from "@gnu-taler/taler-util";
@@ -180,8 +181,11 @@ async function getDenomSelStateFromBackup(
const d = await tx.denominations.get([exchangeBaseUrl, s.denom_pub_hash]);
checkBackupInvariant(!!d);
totalCoinValue = Amounts.add(totalCoinValue, d.value).amount;
- totalWithdrawCost = Amounts.add(totalWithdrawCost, d.value, d.feeWithdraw)
- .amount;
+ totalWithdrawCost = Amounts.add(
+ totalWithdrawCost,
+ d.value,
+ d.feeWithdraw,
+ ).amount;
}
return {
selectedDenoms,
@@ -475,6 +479,8 @@ export async function importBackup(
backupExchangeDetails.base_url,
backupReserve.initial_selected_denoms,
),
+ // FIXME!
+ operationStatus: OperationStatus.Pending,
});
}
for (const backupWg of backupReserve.withdrawal_groups) {
@@ -507,6 +513,9 @@ export async function importBackup(
timestampFinish: backupWg.timestamp_finish,
withdrawalGroupId: backupWg.withdrawal_group_id,
denomSelUid: backupWg.selected_denoms_id,
+ operationStatus: backupWg.timestamp_finish
+ ? OperationStatus.Finished
+ : OperationStatus.Pending,
});
}
}
@@ -758,7 +767,8 @@ export async function importBackup(
// FIXME!
payRetryInfo: initRetryInfo(),
download,
- paymentSubmitPending: !backupPurchase.timestamp_first_successful_pay,
+ paymentSubmitPending:
+ !backupPurchase.timestamp_first_successful_pay,
refundQueryRequested: false,
payCoinSelection: await recoverPayCoinSelection(
tx,
@@ -809,10 +819,8 @@ export async function importBackup(
reason = RefreshReason.Scheduled;
break;
}
- const refreshSessionPerCoin: (
- | RefreshSessionRecord
- | undefined
- )[] = [];
+ const refreshSessionPerCoin: (RefreshSessionRecord | undefined)[] =
+ [];
for (const oldCoin of backupRefreshGroup.old_coins) {
const c = await tx.coins.get(oldCoin.coin_pub);
checkBackupInvariant(!!c);
@@ -848,6 +856,9 @@ export async function importBackup(
? RefreshCoinStatus.Finished
: RefreshCoinStatus.Pending,
),
+ operationStatus: backupRefreshGroup.timestamp_finish
+ ? OperationStatus.Finished
+ : OperationStatus.Pending,
inputPerCoin: backupRefreshGroup.old_coins.map((x) =>
Amounts.parseOrThrow(x.input_amount),
),
diff --git a/packages/taler-wallet-core/src/operations/balance.ts b/packages/taler-wallet-core/src/operations/balance.ts
index 298893920..61bae8286 100644
--- a/packages/taler-wallet-core/src/operations/balance.ts
+++ b/packages/taler-wallet-core/src/operations/balance.ts
@@ -47,6 +47,10 @@ export async function getBalancesInsideTransaction(
withdrawalGroups: typeof WalletStoresV1.withdrawalGroups;
}>,
): Promise<BalancesResponse> {
+ return {
+ balances: [],
+ };
+
const balanceStore: Record<string, WalletBalance> = {};
/**
@@ -148,6 +152,9 @@ export async function getBalancesInsideTransaction(
export async function getBalances(
ws: InternalWalletState,
): Promise<BalancesResponse> {
+ return {
+ balances: [],
+ };
logger.trace("starting to compute balance");
const wbal = await ws.db
diff --git a/packages/taler-wallet-core/src/operations/deposits.ts b/packages/taler-wallet-core/src/operations/deposits.ts
index 0a90e0216..afe8e6f30 100644
--- a/packages/taler-wallet-core/src/operations/deposits.ts
+++ b/packages/taler-wallet-core/src/operations/deposits.ts
@@ -50,7 +50,7 @@ import {
getRandomBytes,
stringToBytes,
} from "@gnu-taler/taler-util";
-import { DepositGroupRecord } from "../db.js";
+import { DepositGroupRecord, OperationStatus } from "../db.js";
import { guardOperationException } from "../errors.js";
import { PayCoinSelection, selectPayCoins } from "../util/coinSelection.js";
import { readSuccessResponseJsonOrThrow } from "../util/http.js";
@@ -281,6 +281,7 @@ async function processDepositGroupImpl(
}
if (allDeposited) {
dg.timestampFinished = getTimestampNow();
+ dg.operationStatus = OperationStatus.Finished;
delete dg.lastError;
delete dg.retryInfo;
await tx.depositGroups.put(dg);
@@ -409,11 +410,7 @@ export async function getFeeForDeposit(
refund_deadline: { t_ms: 0 },
};
- const contractData = extractContractData(
- contractTerms,
- "",
- "",
- );
+ const contractData = extractContractData(contractTerms, "", "");
const candidates = await getCandidatePayCoins(ws, contractData);
@@ -436,7 +433,6 @@ export async function getFeeForDeposit(
amount,
payCoinSel,
);
-
}
export async function createDepositGroup(
@@ -570,6 +566,7 @@ export async function createDepositGroup(
salt: wireSalt,
},
retryInfo: initRetryInfo(),
+ operationStatus: OperationStatus.Pending,
lastError: undefined,
};
@@ -708,8 +705,10 @@ export async function getTotalFeeForDepositAmount(
.filter((x) =>
Amounts.isSameCurrency(x.value, pcs.coinContributions[i]),
);
- const amountLeft = Amounts.sub(denom.value, pcs.coinContributions[i])
- .amount;
+ const amountLeft = Amounts.sub(
+ denom.value,
+ pcs.coinContributions[i],
+ ).amount;
const refreshCost = getTotalRefreshCost(allDenoms, denom, amountLeft);
refreshFee.push(refreshCost);
}
@@ -736,8 +735,17 @@ export async function getTotalFeeForDepositAmount(
});
return {
- coin: coinFee.length === 0 ? Amounts.getZero(total.currency) : Amounts.sum(coinFee).amount,
- wire: wireFee.length === 0 ? Amounts.getZero(total.currency) : Amounts.sum(wireFee).amount,
- refresh: refreshFee.length === 0 ? Amounts.getZero(total.currency) : Amounts.sum(refreshFee).amount
+ coin:
+ coinFee.length === 0
+ ? Amounts.getZero(total.currency)
+ : Amounts.sum(coinFee).amount,
+ wire:
+ wireFee.length === 0
+ ? Amounts.getZero(total.currency)
+ : Amounts.sum(wireFee).amount,
+ refresh:
+ refreshFee.length === 0
+ ? Amounts.getZero(total.currency)
+ : Amounts.sum(refreshFee).amount,
};
}
diff --git a/packages/taler-wallet-core/src/operations/pending.ts b/packages/taler-wallet-core/src/operations/pending.ts
index e3d22bfe6..07c29e874 100644
--- a/packages/taler-wallet-core/src/operations/pending.ts
+++ b/packages/taler-wallet-core/src/operations/pending.ts
@@ -28,6 +28,7 @@ import {
WalletStoresV1,
BackupProviderStateTag,
RefreshCoinStatus,
+ OperationStatus,
} from "../db.js";
import {
PendingOperationsResponse,
@@ -37,6 +38,8 @@ import {
import {
getTimestampNow,
isTimestampExpired,
+ j2s,
+ Logger,
Timestamp,
} from "@gnu-taler/taler-util";
import { InternalWalletState } from "../common.js";
@@ -82,33 +85,35 @@ async function gatherReservePending(
now: Timestamp,
resp: PendingOperationsResponse,
): Promise<void> {
- await tx.reserves.iter().forEach((reserve) => {
- const reserveType = reserve.bankInfo
- ? ReserveType.TalerBankWithdraw
- : ReserveType.Manual;
- switch (reserve.reserveStatus) {
- case ReserveRecordStatus.DORMANT:
- // nothing to report as pending
- break;
- case ReserveRecordStatus.WAIT_CONFIRM_BANK:
- case ReserveRecordStatus.QUERYING_STATUS:
- case ReserveRecordStatus.REGISTERING_BANK:
- resp.pendingOperations.push({
- type: PendingTaskType.Reserve,
- givesLifeness: true,
- timestampDue: reserve.retryInfo.nextRetry,
- stage: reserve.reserveStatus,
- timestampCreated: reserve.timestampCreated,
- reserveType,
- reservePub: reserve.reservePub,
- retryInfo: reserve.retryInfo,
- });
- break;
- default:
- // FIXME: report problem!
- break;
- }
- });
+ await tx.reserves.indexes.byStatus
+ .iter(OperationStatus.Pending)
+ .forEach((reserve) => {
+ const reserveType = reserve.bankInfo
+ ? ReserveType.TalerBankWithdraw
+ : ReserveType.Manual;
+ switch (reserve.reserveStatus) {
+ case ReserveRecordStatus.DORMANT:
+ // nothing to report as pending
+ break;
+ case ReserveRecordStatus.WAIT_CONFIRM_BANK:
+ case ReserveRecordStatus.QUERYING_STATUS:
+ case ReserveRecordStatus.REGISTERING_BANK:
+ resp.pendingOperations.push({
+ type: PendingTaskType.Reserve,
+ givesLifeness: true,
+ timestampDue: reserve.retryInfo.nextRetry,
+ stage: reserve.reserveStatus,
+ timestampCreated: reserve.timestampCreated,
+ reserveType,
+ reservePub: reserve.reservePub,
+ retryInfo: reserve.retryInfo,
+ });
+ break;
+ default:
+ // FIXME: report problem!
+ break;
+ }
+ });
}
async function gatherRefreshPending(
@@ -116,24 +121,26 @@ async function gatherRefreshPending(
now: Timestamp,
resp: PendingOperationsResponse,
): Promise<void> {
- await tx.refreshGroups.iter().forEach((r) => {
- if (r.timestampFinished) {
- return;
- }
- if (r.frozen) {
- return;
- }
- resp.pendingOperations.push({
- type: PendingTaskType.Refresh,
- givesLifeness: true,
- timestampDue: r.retryInfo.nextRetry,
- refreshGroupId: r.refreshGroupId,
- finishedPerCoin: r.statusPerCoin.map(
- (x) => x === RefreshCoinStatus.Finished,
- ),
- retryInfo: r.retryInfo,
+ await tx.refreshGroups.indexes.byStatus
+ .iter(OperationStatus.Pending)
+ .forEach((r) => {
+ if (r.timestampFinished) {
+ return;
+ }
+ if (r.frozen) {
+ return;
+ }
+ resp.pendingOperations.push({
+ type: PendingTaskType.Refresh,
+ givesLifeness: true,
+ timestampDue: r.retryInfo.nextRetry,
+ refreshGroupId: r.refreshGroupId,
+ finishedPerCoin: r.statusPerCoin.map(
+ (x) => x === RefreshCoinStatus.Finished,
+ ),
+ retryInfo: r.retryInfo,
+ });
});
- });
}
async function gatherWithdrawalPending(
@@ -144,29 +151,31 @@ async function gatherWithdrawalPending(
now: Timestamp,
resp: PendingOperationsResponse,
): Promise<void> {
- await tx.withdrawalGroups.iter().forEachAsync(async (wsr) => {
- if (wsr.timestampFinish) {
- return;
- }
- let numCoinsWithdrawn = 0;
- let numCoinsTotal = 0;
- await tx.planchets.indexes.byGroup
- .iter(wsr.withdrawalGroupId)
- .forEach((x) => {
- numCoinsTotal++;
- if (x.withdrawalDone) {
- numCoinsWithdrawn++;
- }
+ await tx.withdrawalGroups.indexes.byStatus
+ .iter(OperationStatus.Pending)
+ .forEachAsync(async (wsr) => {
+ if (wsr.timestampFinish) {
+ return;
+ }
+ let numCoinsWithdrawn = 0;
+ let numCoinsTotal = 0;
+ await tx.planchets.indexes.byGroup
+ .iter(wsr.withdrawalGroupId)
+ .forEach((x) => {
+ numCoinsTotal++;
+ if (x.withdrawalDone) {
+ numCoinsWithdrawn++;
+ }
+ });
+ resp.pendingOperations.push({
+ type: PendingTaskType.Withdraw,
+ givesLifeness: true,
+ timestampDue: wsr.retryInfo.nextRetry,
+ withdrawalGroupId: wsr.withdrawalGroupId,
+ lastError: wsr.lastError,
+ retryInfo: wsr.retryInfo,
});
- resp.pendingOperations.push({
- type: PendingTaskType.Withdraw,
- givesLifeness: true,
- timestampDue: wsr.retryInfo.nextRetry,
- withdrawalGroupId: wsr.withdrawalGroupId,
- lastError: wsr.lastError,
- retryInfo: wsr.retryInfo,
});
- });
}
async function gatherProposalPending(
@@ -199,20 +208,22 @@ async function gatherDepositPending(
now: Timestamp,
resp: PendingOperationsResponse,
): Promise<void> {
- await tx.depositGroups.iter().forEach((dg) => {
- if (dg.timestampFinished) {
- return;
- }
- const timestampDue = dg.retryInfo?.nextRetry ?? getTimestampNow();
- resp.pendingOperations.push({
- type: PendingTaskType.Deposit,
- givesLifeness: true,
- timestampDue,
- depositGroupId: dg.depositGroupId,
- lastError: dg.lastError,
- retryInfo: dg.retryInfo,
+ await tx.depositGroups.indexes.byStatus
+ .iter(OperationStatus.Pending)
+ .forEach((dg) => {
+ if (dg.timestampFinished) {
+ return;
+ }
+ const timestampDue = dg.retryInfo?.nextRetry ?? getTimestampNow();
+ resp.pendingOperations.push({
+ type: PendingTaskType.Deposit,
+ givesLifeness: true,
+ timestampDue,
+ depositGroupId: dg.depositGroupId,
+ lastError: dg.lastError,
+ retryInfo: dg.retryInfo,
+ });
});
- });
}
async function gatherTipPending(
diff --git a/packages/taler-wallet-core/src/operations/refresh.ts b/packages/taler-wallet-core/src/operations/refresh.ts
index 00eaa0eac..5b589f1fa 100644
--- a/packages/taler-wallet-core/src/operations/refresh.ts
+++ b/packages/taler-wallet-core/src/operations/refresh.ts
@@ -26,6 +26,7 @@ import {
CoinSourceType,
CoinStatus,
DenominationRecord,
+ OperationStatus,
RefreshCoinStatus,
RefreshGroupRecord,
WalletStoresV1,
@@ -127,6 +128,7 @@ function updateGroupStatus(rg: RefreshGroupRecord): void {
rg.retryInfo = initRetryInfo();
} else {
rg.timestampFinished = getTimestampNow();
+ rg.operationStatus = OperationStatus.Finished;
rg.retryInfo = initRetryInfo();
}
}
@@ -929,6 +931,7 @@ export async function createRefreshGroup(
}
const refreshGroup: RefreshGroupRecord = {
+ operationStatus: OperationStatus.Pending,
timestampFinished: undefined,
statusPerCoin: oldCoinPubs.map(() => RefreshCoinStatus.Pending),
lastError: undefined,
diff --git a/packages/taler-wallet-core/src/operations/reserves.ts b/packages/taler-wallet-core/src/operations/reserves.ts
index 75d517d68..1550d946b 100644
--- a/packages/taler-wallet-core/src/operations/reserves.ts
+++ b/packages/taler-wallet-core/src/operations/reserves.ts
@@ -41,6 +41,7 @@ import {
} from "@gnu-taler/taler-util";
import { InternalWalletState } from "../common.js";
import {
+ OperationStatus,
ReserveBankInfo,
ReserveRecord,
ReserveRecordStatus,
@@ -155,6 +156,7 @@ export async function createReserve(
lastError: undefined,
currency: req.amount.currency,
requestedQuery: false,
+ operationStatus: OperationStatus.Pending,
};
const exchangeInfo = await updateExchangeFromUrl(ws, req.exchange);
@@ -250,6 +252,7 @@ export async function forceQueryReserve(
switch (reserve.reserveStatus) {
case ReserveRecordStatus.DORMANT:
reserve.reserveStatus = ReserveRecordStatus.QUERYING_STATUS;
+ reserve.operationStatus = OperationStatus.Pending;
break;
default:
reserve.requestedQuery = true;
@@ -338,6 +341,7 @@ async function registerReserveWithBank(
}
r.timestampReserveInfoPosted = getTimestampNow();
r.reserveStatus = ReserveRecordStatus.WAIT_CONFIRM_BANK;
+ r.operationStatus = OperationStatus.Pending;
if (!r.bankInfo) {
throw Error("invariant failed");
}
@@ -419,6 +423,7 @@ async function processReserveBankStatusImpl(
const now = getTimestampNow();
r.timestampBankConfirmed = now;
r.reserveStatus = ReserveRecordStatus.BANK_ABORTED;
+ r.operationStatus = OperationStatus.Finished;
r.retryInfo = initRetryInfo();
await tx.reserves.put(r);
});
@@ -455,6 +460,7 @@ async function processReserveBankStatusImpl(
const now = getTimestampNow();
r.timestampBankConfirmed = now;
r.reserveStatus = ReserveRecordStatus.QUERYING_STATUS;
+ r.operationStatus = OperationStatus.Pending;
r.retryInfo = initRetryInfo();
} else {
switch (r.reserveStatus) {
@@ -658,6 +664,7 @@ async function updateReserve(
if (denomSelInfo.selectedDenoms.length === 0) {
newReserve.reserveStatus = ReserveRecordStatus.DORMANT;
+ newReserve.operationStatus = OperationStatus.Finished;
newReserve.lastError = undefined;
newReserve.retryInfo = initRetryInfo();
await tx.reserves.put(newReserve);
@@ -684,11 +691,13 @@ async function updateReserve(
denomsSel: denomSelectionInfoToState(denomSelInfo),
secretSeed: encodeCrock(getRandomBytes(64)),
denomSelUid: encodeCrock(getRandomBytes(32)),
+ operationStatus: OperationStatus.Pending,
};
newReserve.lastError = undefined;
newReserve.retryInfo = initRetryInfo();
newReserve.reserveStatus = ReserveRecordStatus.DORMANT;
+ newReserve.operationStatus = OperationStatus.Finished;
await tx.reserves.put(newReserve);
await tx.withdrawalGroups.put(withdrawalRecord);
diff --git a/packages/taler-wallet-core/src/operations/withdraw.ts b/packages/taler-wallet-core/src/operations/withdraw.ts
index 8b72c40e8..c44435e81 100644
--- a/packages/taler-wallet-core/src/operations/withdraw.ts
+++ b/packages/taler-wallet-core/src/operations/withdraw.ts
@@ -53,6 +53,7 @@ import {
DenomSelectionState,
ExchangeDetailsRecord,
ExchangeRecord,
+ OperationStatus,
PlanchetRecord,
} from "../db.js";
import { walletCoreDebugFlags } from "../util/debugFlags.js";
@@ -968,7 +969,8 @@ async function processWithdrawGroupImpl(
if (wg.timestampFinish === undefined && numFinished === numTotalCoins) {
finishedForFirstTime = true;
wg.timestampFinish = getTimestampNow();
- wg.lastError = undefined;
+ wg.operationStatus = OperationStatus.Finished;
+ delete wg.lastError;
wg.retryInfo = initRetryInfo();
}