wallet-core: use numeric status field to allow range queries

This commit is contained in:
Florian Dold 2022-09-21 20:46:45 +02:00
parent 5d31803c92
commit 7d6bcd42ea
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
10 changed files with 86 additions and 81 deletions

View File

@ -62,6 +62,8 @@ import { Event, IDBDatabase } from "@gnu-taler/idb-bridge";
* will have an index. * will have an index.
* - Amounts are stored as strings, except when they are needed for * - Amounts are stored as strings, except when they are needed for
* indexing. * indexing.
* - Every record that has a corresponding transaction item must have
* an index for a mandatory timestamp field.
* - Optional fields should be avoided, use "T | undefined" instead. * - Optional fields should be avoided, use "T | undefined" instead.
* *
* @author Florian Dold <dold@taler.net> * @author Florian Dold <dold@taler.net>
@ -94,38 +96,45 @@ export const CURRENT_DB_CONFIG_KEY = "currentMainDbName";
*/ */
export const WALLET_DB_MINOR_VERSION = 1; export const WALLET_DB_MINOR_VERSION = 1;
export namespace OperationStatusRange {
export const ACTIVE_START = 10;
export const ACTIVE_END = 29;
export const DORMANT_START = 40;
export const DORMANT_END = 59;
}
/** /**
* Status of a withdrawal. * Status of a withdrawal.
*/ */
export enum ReserveRecordStatus { export enum WithdrawalGroupStatus {
/** /**
* Reserve must be registered with the bank. * Reserve must be registered with the bank.
*/ */
RegisteringBank = "registering-bank", RegisteringBank = OperationStatusRange.ACTIVE_START,
/** /**
* We've registered reserve's information with the bank * We've registered reserve's information with the bank
* and are now waiting for the user to confirm the withdraw * and are now waiting for the user to confirm the withdraw
* with the bank (typically 2nd factor auth). * with the bank (typically 2nd factor auth).
*/ */
WaitConfirmBank = "wait-confirm-bank", WaitConfirmBank = OperationStatusRange.ACTIVE_START + 1,
/** /**
* Querying reserve status with the exchange. * Querying reserve status with the exchange.
*/ */
QueryingStatus = "querying-status", QueryingStatus = OperationStatusRange.ACTIVE_START + 2,
/** /**
* The corresponding withdraw record has been created. * The corresponding withdraw record has been created.
* No further processing is done, unless explicitly requested * No further processing is done, unless explicitly requested
* by the user. * by the user.
*/ */
Dormant = "dormant", Finished = OperationStatusRange.DORMANT_START,
/** /**
* The bank aborted the withdrawal. * The bank aborted the withdrawal.
*/ */
BankAborted = "bank-aborted", BankAborted = OperationStatusRange.DORMANT_START + 1,
} }
/** /**
@ -1354,20 +1363,12 @@ export interface WithdrawalGroupRecord {
*/ */
timestampFinish?: TalerProtocolTimestamp; timestampFinish?: TalerProtocolTimestamp;
/**
* Operation status of the withdrawal group.
* Used for indexing in the database.
*
* FIXME: Redundant with reserveStatus
*/
operationStatus: OperationStatus;
/** /**
* Current status of the reserve. * Current status of the reserve.
* *
* FIXME: Wrong name! * FIXME: Wrong name!
*/ */
reserveStatus: ReserveRecordStatus; status: WithdrawalGroupStatus;
/** /**
* Amount that was sent by the user to fund the reserve. * Amount that was sent by the user to fund the reserve.
@ -1947,7 +1948,7 @@ export const WalletStoresV1 = {
}), }),
{ {
byReservePub: describeIndex("byReservePub", "reservePub"), byReservePub: describeIndex("byReservePub", "reservePub"),
byStatus: describeIndex("byStatus", "operationStatus"), byStatus: describeIndex("byStatus", "status"),
byTalerWithdrawUri: describeIndex( byTalerWithdrawUri: describeIndex(
"byTalerWithdrawUri", "byTalerWithdrawUri",
"wgInfo.bankInfo.talerWithdrawUri", "wgInfo.bankInfo.talerWithdrawUri",

View File

@ -71,6 +71,7 @@ import {
RefreshCoinStatus, RefreshCoinStatus,
RefundState, RefundState,
WALLET_BACKUP_STATE_KEY, WALLET_BACKUP_STATE_KEY,
WithdrawalGroupStatus,
WithdrawalRecordType, WithdrawalRecordType,
} from "../../db.js"; } from "../../db.js";
import { InternalWalletState } from "../../internal-wallet-state.js"; import { InternalWalletState } from "../../internal-wallet-state.js";
@ -167,8 +168,9 @@ export async function exportBackup(
instructed_amount: Amounts.stringify(wg.instructedAmount), instructed_amount: Amounts.stringify(wg.instructedAmount),
reserve_priv: wg.reservePriv, reserve_priv: wg.reservePriv,
restrict_age: wg.restrictAge, restrict_age: wg.restrictAge,
// FIXME: proper status conversion!
operation_status: operation_status:
wg.operationStatus == OperationStatus.Finished wg.status == WithdrawalGroupStatus.Finished
? BackupOperationStatus.Finished ? BackupOperationStatus.Finished
: BackupOperationStatus.Pending, : BackupOperationStatus.Pending,
selected_denoms_uid: wg.denomSelUid, selected_denoms_uid: wg.denomSelUid,

View File

@ -52,7 +52,7 @@ import {
RefreshSessionRecord, RefreshSessionRecord,
RefundState, RefundState,
ReserveBankInfo, ReserveBankInfo,
ReserveRecordStatus, WithdrawalGroupStatus,
WalletContractData, WalletContractData,
WalletRefundItem, WalletRefundItem,
WalletStoresV1, WalletStoresV1,
@ -531,9 +531,6 @@ export async function importBackup(
exchangeBaseUrl: backupWg.exchange_base_url, exchangeBaseUrl: backupWg.exchange_base_url,
instructedAmount: Amounts.parseOrThrow(backupWg.instructed_amount), instructedAmount: Amounts.parseOrThrow(backupWg.instructed_amount),
secretSeed: backupWg.secret_seed, secretSeed: backupWg.secret_seed,
operationStatus: backupWg.timestamp_finish
? OperationStatus.Finished
: OperationStatus.Pending,
denomsSel: await getDenomSelStateFromBackup( denomsSel: await getDenomSelStateFromBackup(
tx, tx,
backupWg.exchange_base_url, backupWg.exchange_base_url,
@ -545,9 +542,9 @@ export async function importBackup(
), ),
reservePriv: backupWg.reserve_priv, reservePriv: backupWg.reserve_priv,
reservePub, reservePub,
reserveStatus: backupWg.timestamp_finish status: backupWg.timestamp_finish
? ReserveRecordStatus.Dormant ? WithdrawalGroupStatus.Finished
: ReserveRecordStatus.QueryingStatus, // FIXME! : WithdrawalGroupStatus.QueryingStatus, // FIXME!
timestampStart: backupWg.timestamp_created, timestampStart: backupWg.timestamp_created,
wgInfo, wgInfo,
restrictAge: backupWg.restrict_age, restrictAge: backupWg.restrict_age,

View File

@ -65,7 +65,7 @@ import {
import { import {
CoinStatus, CoinStatus,
MergeReserveInfo, MergeReserveInfo,
ReserveRecordStatus, WithdrawalGroupStatus,
WalletStoresV1, WalletStoresV1,
WithdrawalRecordType, WithdrawalRecordType,
} from "../db.js"; } from "../db.js";
@ -544,7 +544,7 @@ export async function acceptPeerPushPayment(
contractTerms: peerInc.contractTerms, contractTerms: peerInc.contractTerms,
}, },
exchangeBaseUrl: peerInc.exchangeBaseUrl, exchangeBaseUrl: peerInc.exchangeBaseUrl,
reserveStatus: ReserveRecordStatus.QueryingStatus, reserveStatus: WithdrawalGroupStatus.QueryingStatus,
reserveKeyPair: { reserveKeyPair: {
priv: mergeReserveInfo.reservePriv, priv: mergeReserveInfo.reservePriv,
pub: mergeReserveInfo.reservePub, pub: mergeReserveInfo.reservePub,
@ -828,7 +828,7 @@ export async function initiatePeerRequestForPay(
contractPriv: econtractResp.contractPriv, contractPriv: econtractResp.contractPriv,
}, },
exchangeBaseUrl: req.exchangeBaseUrl, exchangeBaseUrl: req.exchangeBaseUrl,
reserveStatus: ReserveRecordStatus.QueryingStatus, reserveStatus: WithdrawalGroupStatus.QueryingStatus,
reserveKeyPair: { reserveKeyPair: {
priv: mergeReserveInfo.reservePriv, priv: mergeReserveInfo.reservePriv,
pub: mergeReserveInfo.reservePub, pub: mergeReserveInfo.reservePub,

View File

@ -28,6 +28,9 @@ import {
BackupProviderStateTag, BackupProviderStateTag,
RefreshCoinStatus, RefreshCoinStatus,
OperationStatus, OperationStatus,
WithdrawalGroupRecord,
WithdrawalGroupStatus,
OperationStatusRange,
} from "../db.js"; } from "../db.js";
import { import {
PendingOperationsResponse, PendingOperationsResponse,
@ -38,6 +41,7 @@ import { InternalWalletState } from "../internal-wallet-state.js";
import { GetReadOnlyAccess } from "../util/query.js"; import { GetReadOnlyAccess } from "../util/query.js";
import { RetryTags } from "../util/retries.js"; import { RetryTags } from "../util/retries.js";
import { Wallet } from "../wallet.js"; import { Wallet } from "../wallet.js";
import { GlobalIDB } from "@gnu-taler/idb-bridge";
async function gatherExchangePending( async function gatherExchangePending(
tx: GetReadOnlyAccess<{ tx: GetReadOnlyAccess<{
@ -120,7 +124,10 @@ async function gatherWithdrawalPending(
resp: PendingOperationsResponse, resp: PendingOperationsResponse,
): Promise<void> { ): Promise<void> {
const wsrs = await tx.withdrawalGroups.indexes.byStatus.getAll( const wsrs = await tx.withdrawalGroups.indexes.byStatus.getAll(
OperationStatus.Pending, GlobalIDB.KeyRange.bound(
OperationStatusRange.ACTIVE_START,
OperationStatusRange.ACTIVE_END,
),
); );
for (const wsr of wsrs) { for (const wsr of wsrs) {
if (wsr.timestampFinish) { if (wsr.timestampFinish) {

View File

@ -44,7 +44,7 @@ import {
CoinStatus, CoinStatus,
RecoupGroupRecord, RecoupGroupRecord,
RefreshCoinSource, RefreshCoinSource,
ReserveRecordStatus, WithdrawalGroupStatus,
WalletStoresV1, WalletStoresV1,
WithdrawalRecordType, WithdrawalRecordType,
WithdrawCoinSource, WithdrawCoinSource,
@ -382,7 +382,7 @@ export async function processRecoupGroupHandler(
await internalCreateWithdrawalGroup(ws, { await internalCreateWithdrawalGroup(ws, {
amount: Amounts.parseOrThrow(result.balance), amount: Amounts.parseOrThrow(result.balance),
exchangeBaseUrl: recoupGroup.exchangeBaseUrl, exchangeBaseUrl: recoupGroup.exchangeBaseUrl,
reserveStatus: ReserveRecordStatus.QueryingStatus, reserveStatus: WithdrawalGroupStatus.QueryingStatus,
reserveKeyPair: { reserveKeyPair: {
pub: reservePub, pub: reservePub,
priv: reservePrivMap[reservePub], priv: reservePrivMap[reservePub],

View File

@ -31,11 +31,9 @@ import {
TalerProtocolTimestamp, TalerProtocolTimestamp,
Transaction, Transaction,
TransactionByIdRequest, TransactionByIdRequest,
TransactionRefund,
TransactionsRequest, TransactionsRequest,
TransactionsResponse, TransactionsResponse,
TransactionType, TransactionType,
WithdrawalDetails,
WithdrawalType, WithdrawalType,
} from "@gnu-taler/taler-util"; } from "@gnu-taler/taler-util";
import { import {

View File

@ -71,7 +71,7 @@ import {
ExchangeRecord, ExchangeRecord,
OperationStatus, OperationStatus,
PlanchetRecord, PlanchetRecord,
ReserveRecordStatus, WithdrawalGroupStatus,
WalletStoresV1, WalletStoresV1,
WgInfo, WgInfo,
WithdrawalGroupRecord, WithdrawalGroupRecord,
@ -91,7 +91,11 @@ import {
readSuccessResponseJsonOrThrow, readSuccessResponseJsonOrThrow,
throwUnexpectedRequestError, throwUnexpectedRequestError,
} from "../util/http.js"; } from "../util/http.js";
import { checkDbInvariant, checkLogicInvariant } from "../util/invariants.js"; import {
checkDbInvariant,
checkLogicInvariant,
InvariantViolatedError,
} from "../util/invariants.js";
import { DbAccess, GetReadOnlyAccess } from "../util/query.js"; import { DbAccess, GetReadOnlyAccess } from "../util/query.js";
import { import {
OperationAttemptResult, OperationAttemptResult,
@ -962,7 +966,7 @@ async function queryReserve(
withdrawalGroupId, withdrawalGroupId,
}); });
checkDbInvariant(!!withdrawalGroup); checkDbInvariant(!!withdrawalGroup);
if (withdrawalGroup.reserveStatus !== ReserveRecordStatus.QueryingStatus) { if (withdrawalGroup.status !== WithdrawalGroupStatus.QueryingStatus) {
return { ready: true }; return { ready: true };
} }
const reservePub = withdrawalGroup.reservePub; const reservePub = withdrawalGroup.reservePub;
@ -1010,7 +1014,7 @@ async function queryReserve(
logger.warn(`withdrawal group ${withdrawalGroupId} not found`); logger.warn(`withdrawal group ${withdrawalGroupId} not found`);
return; return;
} }
wg.reserveStatus = ReserveRecordStatus.Dormant; wg.status = WithdrawalGroupStatus.Finished;
await tx.withdrawalGroups.put(wg); await tx.withdrawalGroups.put(wg);
}); });
@ -1039,13 +1043,13 @@ export async function processWithdrawalGroup(
throw Error(`withdrawal group ${withdrawalGroupId} not found`); throw Error(`withdrawal group ${withdrawalGroupId} not found`);
} }
switch (withdrawalGroup.reserveStatus) { switch (withdrawalGroup.status) {
case ReserveRecordStatus.RegisteringBank: case WithdrawalGroupStatus.RegisteringBank:
await processReserveBankStatus(ws, withdrawalGroupId); await processReserveBankStatus(ws, withdrawalGroupId);
return await processWithdrawalGroup(ws, withdrawalGroupId, { return await processWithdrawalGroup(ws, withdrawalGroupId, {
forceNow: true, forceNow: true,
}); });
case ReserveRecordStatus.QueryingStatus: { case WithdrawalGroupStatus.QueryingStatus: {
const res = await queryReserve(ws, withdrawalGroupId); const res = await queryReserve(ws, withdrawalGroupId);
if (res.ready) { if (res.ready) {
return await processWithdrawalGroup(ws, withdrawalGroupId, { return await processWithdrawalGroup(ws, withdrawalGroupId, {
@ -1057,7 +1061,7 @@ export async function processWithdrawalGroup(
result: undefined, result: undefined,
}; };
} }
case ReserveRecordStatus.WaitConfirmBank: { case WithdrawalGroupStatus.WaitConfirmBank: {
const res = await processReserveBankStatus(ws, withdrawalGroupId); const res = await processReserveBankStatus(ws, withdrawalGroupId);
switch (res.status) { switch (res.status) {
case BankStatusResultCode.Aborted: case BankStatusResultCode.Aborted:
@ -1075,23 +1079,20 @@ export async function processWithdrawalGroup(
} }
break; break;
} }
case ReserveRecordStatus.BankAborted: { case WithdrawalGroupStatus.BankAborted: {
// FIXME // FIXME
return { return {
type: OperationAttemptResultType.Pending, type: OperationAttemptResultType.Pending,
result: undefined, result: undefined,
}; };
} }
case ReserveRecordStatus.Dormant: case WithdrawalGroupStatus.Finished:
// We can try to withdraw, nothing needs to be done with the reserve. // We can try to withdraw, nothing needs to be done with the reserve.
break; break;
default: default:
logger.warn( throw new InvariantViolatedError(
"unknown reserve record status:", `unknown reserve record status: ${withdrawalGroup.status}`,
withdrawalGroup.reserveStatus,
); );
assertUnreachable(withdrawalGroup.reserveStatus);
break;
} }
await ws.exchangeOps.updateExchangeFromUrl( await ws.exchangeOps.updateExchangeFromUrl(
@ -1108,7 +1109,7 @@ export async function processWithdrawalGroup(
if (!wg) { if (!wg) {
return; return;
} }
wg.operationStatus = OperationStatus.Finished; wg.status = WithdrawalGroupStatus.Finished;
wg.timestampFinish = TalerProtocolTimestamp.now(); wg.timestampFinish = TalerProtocolTimestamp.now();
await tx.withdrawalGroups.put(wg); await tx.withdrawalGroups.put(wg);
}); });
@ -1192,7 +1193,7 @@ export async function processWithdrawalGroup(
if (wg.timestampFinish === undefined && numFinished === numTotalCoins) { if (wg.timestampFinish === undefined && numFinished === numTotalCoins) {
finishedForFirstTime = true; finishedForFirstTime = true;
wg.timestampFinish = TalerProtocolTimestamp.now(); wg.timestampFinish = TalerProtocolTimestamp.now();
wg.operationStatus = OperationStatus.Finished; wg.status = WithdrawalGroupStatus.Finished;
} }
await tx.withdrawalGroups.put(wg); await tx.withdrawalGroups.put(wg);
@ -1508,9 +1509,9 @@ async function registerReserveWithBank(
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
return await tx.withdrawalGroups.get(withdrawalGroupId); return await tx.withdrawalGroups.get(withdrawalGroupId);
}); });
switch (withdrawalGroup?.reserveStatus) { switch (withdrawalGroup?.status) {
case ReserveRecordStatus.WaitConfirmBank: case WithdrawalGroupStatus.WaitConfirmBank:
case ReserveRecordStatus.RegisteringBank: case WithdrawalGroupStatus.RegisteringBank:
break; break;
default: default:
return; return;
@ -1544,9 +1545,9 @@ async function registerReserveWithBank(
if (!r) { if (!r) {
return; return;
} }
switch (r.reserveStatus) { switch (r.status) {
case ReserveRecordStatus.RegisteringBank: case WithdrawalGroupStatus.RegisteringBank:
case ReserveRecordStatus.WaitConfirmBank: case WithdrawalGroupStatus.WaitConfirmBank:
break; break;
default: default:
return; return;
@ -1557,8 +1558,7 @@ async function registerReserveWithBank(
r.wgInfo.bankInfo.timestampReserveInfoPosted = AbsoluteTime.toTimestamp( r.wgInfo.bankInfo.timestampReserveInfoPosted = AbsoluteTime.toTimestamp(
AbsoluteTime.now(), AbsoluteTime.now(),
); );
r.reserveStatus = ReserveRecordStatus.WaitConfirmBank; r.status = WithdrawalGroupStatus.WaitConfirmBank;
r.operationStatus = OperationStatus.Pending;
await tx.withdrawalGroups.put(r); await tx.withdrawalGroups.put(r);
}); });
ws.notify({ type: NotificationType.ReserveRegisteredWithBank }); ws.notify({ type: NotificationType.ReserveRegisteredWithBank });
@ -1575,9 +1575,9 @@ async function processReserveBankStatus(
const withdrawalGroup = await getWithdrawalGroupRecordTx(ws.db, { const withdrawalGroup = await getWithdrawalGroupRecordTx(ws.db, {
withdrawalGroupId, withdrawalGroupId,
}); });
switch (withdrawalGroup?.reserveStatus) { switch (withdrawalGroup?.status) {
case ReserveRecordStatus.WaitConfirmBank: case WithdrawalGroupStatus.WaitConfirmBank:
case ReserveRecordStatus.RegisteringBank: case WithdrawalGroupStatus.RegisteringBank:
break; break;
default: default:
return { return {
@ -1616,9 +1616,9 @@ async function processReserveBankStatus(
if (!r) { if (!r) {
return; return;
} }
switch (r.reserveStatus) { switch (r.status) {
case ReserveRecordStatus.RegisteringBank: case WithdrawalGroupStatus.RegisteringBank:
case ReserveRecordStatus.WaitConfirmBank: case WithdrawalGroupStatus.WaitConfirmBank:
break; break;
default: default:
return; return;
@ -1628,8 +1628,7 @@ async function processReserveBankStatus(
} }
const now = AbsoluteTime.toTimestamp(AbsoluteTime.now()); const now = AbsoluteTime.toTimestamp(AbsoluteTime.now());
r.wgInfo.bankInfo.timestampBankConfirmed = now; r.wgInfo.bankInfo.timestampBankConfirmed = now;
r.reserveStatus = ReserveRecordStatus.BankAborted; r.status = WithdrawalGroupStatus.BankAborted;
r.operationStatus = OperationStatus.Finished;
await tx.withdrawalGroups.put(r); await tx.withdrawalGroups.put(r);
}); });
return { return {
@ -1644,7 +1643,7 @@ async function processReserveBankStatus(
} }
// FIXME: Why do we do this?! // FIXME: Why do we do this?!
if (withdrawalGroup.reserveStatus === ReserveRecordStatus.RegisteringBank) { if (withdrawalGroup.status === WithdrawalGroupStatus.RegisteringBank) {
await registerReserveWithBank(ws, withdrawalGroupId); await registerReserveWithBank(ws, withdrawalGroupId);
return await processReserveBankStatus(ws, withdrawalGroupId); return await processReserveBankStatus(ws, withdrawalGroupId);
} }
@ -1657,9 +1656,9 @@ async function processReserveBankStatus(
return; return;
} }
// Re-check reserve status within transaction // Re-check reserve status within transaction
switch (r.reserveStatus) { switch (r.status) {
case ReserveRecordStatus.RegisteringBank: case WithdrawalGroupStatus.RegisteringBank:
case ReserveRecordStatus.WaitConfirmBank: case WithdrawalGroupStatus.WaitConfirmBank:
break; break;
default: default:
return; return;
@ -1671,8 +1670,7 @@ async function processReserveBankStatus(
logger.info("withdrawal: transfer confirmed by bank."); logger.info("withdrawal: transfer confirmed by bank.");
const now = AbsoluteTime.toTimestamp(AbsoluteTime.now()); const now = AbsoluteTime.toTimestamp(AbsoluteTime.now());
r.wgInfo.bankInfo.timestampBankConfirmed = now; r.wgInfo.bankInfo.timestampBankConfirmed = now;
r.reserveStatus = ReserveRecordStatus.QueryingStatus; r.status = WithdrawalGroupStatus.QueryingStatus;
r.operationStatus = OperationStatus.Pending;
} else { } else {
logger.info("withdrawal: transfer not yet confirmed by bank"); logger.info("withdrawal: transfer not yet confirmed by bank");
r.wgInfo.bankInfo.confirmUrl = status.confirm_transfer_url; r.wgInfo.bankInfo.confirmUrl = status.confirm_transfer_url;
@ -1689,7 +1687,7 @@ async function processReserveBankStatus(
export async function internalCreateWithdrawalGroup( export async function internalCreateWithdrawalGroup(
ws: InternalWalletState, ws: InternalWalletState,
args: { args: {
reserveStatus: ReserveRecordStatus; reserveStatus: WithdrawalGroupStatus;
amount: AmountJson; amount: AmountJson;
exchangeBaseUrl: string; exchangeBaseUrl: string;
forcedDenomSel?: ForcedDenomSel; forcedDenomSel?: ForcedDenomSel;
@ -1728,12 +1726,11 @@ export async function internalCreateWithdrawalGroup(
exchangeBaseUrl: canonExchange, exchangeBaseUrl: canonExchange,
instructedAmount: amount, instructedAmount: amount,
timestampStart: now, timestampStart: now,
operationStatus: OperationStatus.Pending,
rawWithdrawalAmount: initialDenomSel.totalWithdrawCost, rawWithdrawalAmount: initialDenomSel.totalWithdrawCost,
secretSeed, secretSeed,
reservePriv: reserveKeyPair.priv, reservePriv: reserveKeyPair.priv,
reservePub: reserveKeyPair.pub, reservePub: reserveKeyPair.pub,
reserveStatus: args.reserveStatus, status: args.reserveStatus,
withdrawalGroupId, withdrawalGroupId,
restrictAge: args.restrictAge, restrictAge: args.restrictAge,
senderWire: undefined, senderWire: undefined,
@ -1839,7 +1836,7 @@ export async function acceptWithdrawalFromUri(
}, },
restrictAge: req.restrictAge, restrictAge: req.restrictAge,
forcedDenomSel: req.forcedDenomSel, forcedDenomSel: req.forcedDenomSel,
reserveStatus: ReserveRecordStatus.RegisteringBank, reserveStatus: WithdrawalGroupStatus.RegisteringBank,
}); });
const withdrawalGroupId = withdrawalGroup.withdrawalGroupId; const withdrawalGroupId = withdrawalGroup.withdrawalGroupId;
@ -1850,9 +1847,7 @@ export async function acceptWithdrawalFromUri(
const processedWithdrawalGroup = await getWithdrawalGroupRecordTx(ws.db, { const processedWithdrawalGroup = await getWithdrawalGroupRecordTx(ws.db, {
withdrawalGroupId, withdrawalGroupId,
}); });
if ( if (processedWithdrawalGroup?.status === WithdrawalGroupStatus.BankAborted) {
processedWithdrawalGroup?.reserveStatus === ReserveRecordStatus.BankAborted
) {
throw TalerError.fromDetail( throw TalerError.fromDetail(
TalerErrorCode.WALLET_WITHDRAWAL_OPERATION_ABORTED_BY_BANK, TalerErrorCode.WALLET_WITHDRAWAL_OPERATION_ABORTED_BY_BANK,
{}, {},
@ -1898,7 +1893,7 @@ export async function createManualWithdrawal(
exchangeBaseUrl: req.exchangeBaseUrl, exchangeBaseUrl: req.exchangeBaseUrl,
forcedDenomSel: req.forcedDenomSel, forcedDenomSel: req.forcedDenomSel,
restrictAge: req.restrictAge, restrictAge: req.restrictAge,
reserveStatus: ReserveRecordStatus.QueryingStatus, reserveStatus: WithdrawalGroupStatus.QueryingStatus,
}); });
const withdrawalGroupId = withdrawalGroup.withdrawalGroupId; const withdrawalGroupId = withdrawalGroup.withdrawalGroupId;

View File

@ -14,6 +14,13 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/ */
export class InvariantViolatedError extends Error {
constructor(message?: string) {
super(message);
Object.setPrototypeOf(this, InvariantViolatedError.prototype);
}
}
/** /**
* Helpers for invariants. * Helpers for invariants.
*/ */

View File

@ -36,8 +36,6 @@ import {
IDBKeyRange, IDBKeyRange,
} from "@gnu-taler/idb-bridge"; } from "@gnu-taler/idb-bridge";
import { Logger } from "@gnu-taler/taler-util"; import { Logger } from "@gnu-taler/taler-util";
import { performanceNow } from "./timer.js";
import { access } from "fs";
const logger = new Logger("query.ts"); const logger = new Logger("query.ts");