From 2987f6f8365a15c6761a370bfd0ebf0952ce3f66 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Mon, 8 Jan 2024 18:51:38 +0100 Subject: wallet-core: fix error reporting for exchange entries --- packages/taler-wallet-core/src/db.ts | 16 +------ .../taler-wallet-core/src/operations/balance.ts | 15 ++++-- .../taler-wallet-core/src/operations/exchanges.ts | 34 ++++++++------ .../src/operations/pay-peer-pull-credit.ts | 8 +--- .../taler-wallet-core/src/operations/pending.ts | 54 ++++++++++------------ .../taler-wallet-core/src/operations/withdraw.ts | 7 +-- packages/taler-wallet-core/src/wallet.ts | 6 +-- 7 files changed, 63 insertions(+), 77 deletions(-) (limited to 'packages/taler-wallet-core') diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts index d13e30cc6..76bb2e393 100644 --- a/packages/taler-wallet-core/src/db.ts +++ b/packages/taler-wallet-core/src/db.ts @@ -19,7 +19,6 @@ */ import { Event, - GlobalIDB, IDBDatabase, IDBFactory, IDBObjectStore, @@ -262,7 +261,7 @@ export const OPERATION_STATUS_ACTIVE_FIRST = 0x0100_0000; /** * LAST possible operation status in the active range (inclusive). */ -export const OPERATION_STATUS_ACTIVE_LAST = 0x0113_FFFF; +export const OPERATION_STATUS_ACTIVE_LAST = 0x0113_ffff; /** * Status of a withdrawal. @@ -337,14 +336,6 @@ export enum WithdrawalGroupStatus { AbortedBank = 0x0503_0002, } -/** - * Status range of nonfinal withdrawal groups. - */ -export const withdrawalGroupNonfinalRange = GlobalIDB.KeyRange.bound( - WithdrawalGroupStatus.PendingRegisteringBank, - WithdrawalGroupStatus.PendingAml, -); - /** * Extra info about a withdrawal that is used * with a bank-integrated withdrawal. @@ -1704,11 +1695,6 @@ export enum DepositOperationStatus { Aborted = 0x0503_0000, } -export const depositOperationNonfinalStatusRange = GlobalIDB.KeyRange.bound( - DepositOperationStatus.PendingDeposit, - DepositOperationStatus.PendingKyc, -); - export interface DepositTrackingInfo { // Raw wire transfer identifier of the deposit. wireTransferId: string; diff --git a/packages/taler-wallet-core/src/operations/balance.ts b/packages/taler-wallet-core/src/operations/balance.ts index 1b6ff7844..fdaab0d5f 100644 --- a/packages/taler-wallet-core/src/operations/balance.ts +++ b/packages/taler-wallet-core/src/operations/balance.ts @@ -63,11 +63,12 @@ import { ScopeType, } from "@gnu-taler/taler-util"; import { - depositOperationNonfinalStatusRange, DepositOperationStatus, + OPERATION_STATUS_ACTIVE_FIRST, + OPERATION_STATUS_ACTIVE_LAST, RefreshGroupRecord, + RefreshOperationStatus, WalletStoresV1, - withdrawalGroupNonfinalRange, WithdrawalGroupStatus, } from "../db.js"; import { InternalWalletState } from "../internal-wallet-state.js"; @@ -75,6 +76,7 @@ import { assertUnreachable } from "../util/assertUnreachable.js"; import { checkLogicInvariant } from "../util/invariants.js"; import { GetReadOnlyAccess } from "../util/query.js"; import { getExchangeDetails } from "./exchanges.js"; +import { GlobalIDB } from "@gnu-taler/idb-bridge"; /** * Logger. @@ -142,6 +144,11 @@ export async function getBalancesInsideTransaction( return balanceStore[currency]; }; + const keyRangeActive = GlobalIDB.KeyRange.bound( + OPERATION_STATUS_ACTIVE_FIRST, + OPERATION_STATUS_ACTIVE_LAST, + ); + await tx.coinAvailability.iter().forEach((ca) => { const b = initBalance(ca.currency); const count = ca.visibleCoinCount ?? 0; @@ -159,7 +166,7 @@ export async function getBalancesInsideTransaction( }); await tx.withdrawalGroups.indexes.byStatus - .iter(withdrawalGroupNonfinalRange) + .iter(keyRangeActive) .forEach((wgRecord) => { const b = initBalance( Amounts.currencyOf(wgRecord.denomsSel.totalWithdrawCost), @@ -205,7 +212,7 @@ export async function getBalancesInsideTransaction( // FIXME: Use indexing to filter out final transactions. await tx.depositGroups.indexes.byStatus - .iter(depositOperationNonfinalStatusRange) + .iter(keyRangeActive) .forEach((dgRecord) => { const b = initBalance(Amounts.currencyOf(dgRecord.amount)); switch (dgRecord.operationStatus) { diff --git a/packages/taler-wallet-core/src/operations/exchanges.ts b/packages/taler-wallet-core/src/operations/exchanges.ts index 8f878ecc0..67d598e70 100644 --- a/packages/taler-wallet-core/src/operations/exchanges.ts +++ b/packages/taler-wallet-core/src/operations/exchanges.ts @@ -821,12 +821,13 @@ export async function fetchFreshExchange( ); } - const { exchange, exchangeDetails } = await ws.db - .mktx((x) => [x.exchanges, x.exchangeDetails]) + const { exchange, exchangeDetails, retryInfo } = await ws.db + .mktx((x) => [x.exchanges, x.exchangeDetails, x.operationRetries]) .runReadOnly(async (tx) => { const exchange = await tx.exchanges.get(canonUrl); const exchangeDetails = await getExchangeDetails(tx, canonUrl); - return { exchange, exchangeDetails }; + const retryInfo = await tx.operationRetries.get(operationId); + return { exchange, exchangeDetails, retryInfo }; }); if (!exchange) { @@ -838,7 +839,10 @@ export async function fetchFreshExchange( case ExchangeEntryDbUpdateStatus.ReadyUpdate: break; default: - throw Error("unable to update exchange"); + throw TalerError.fromDetail(TalerErrorCode.WALLET_EXCHANGE_UNAVAILABLE, { + exchangeBaseUrl: canonUrl, + innerError: retryInfo?.lastError, + }); } if (!exchangeDetails) { @@ -1253,24 +1257,24 @@ export async function downloadExchangeInfo( }; } -export async function getExchanges( +/** + * List all exchange entries known to the wallet. + */ +export async function listExchanges( ws: InternalWalletState, ): Promise { const exchanges: ExchangeListItem[] = []; await ws.db - .mktx((x) => [ - x.exchanges, - x.exchangeDetails, - x.denominations, - x.operationRetries, - ]) + .mktx((x) => [x.exchanges, x.exchangeDetails, x.operationRetries]) .runReadOnly(async (tx) => { const exchangeRecords = await tx.exchanges.iter().toArray(); for (const r of exchangeRecords) { + const taskId = constructTaskIdentifier({ + tag: PendingTaskType.ExchangeUpdate, + exchangeBaseUrl: r.baseUrl, + }); const exchangeDetails = await getExchangeDetails(tx, r.baseUrl); - const opRetryRecord = await tx.operationRetries.get( - TaskIdentifiers.forExchangeUpdate(r), - ); + const opRetryRecord = await tx.operationRetries.get(taskId); exchanges.push( makeExchangeListItem(r, exchangeDetails, opRetryRecord?.lastError), ); @@ -1283,7 +1287,7 @@ export async function getExchangeDetailedInfo( ws: InternalWalletState, exchangeBaseurl: string, ): Promise { - //TODO: should we use the forceUpdate parameter? + // TODO: should we use the forceUpdate parameter? const exchange = await ws.db .mktx((x) => [x.exchanges, x.exchangeDetails, x.denominations]) .runReadOnly(async (tx) => { 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 292116bd5..a90eceed7 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 @@ -48,11 +48,7 @@ import { stringifyTalerUri, talerPaytoFromExchangeReserve, } from "@gnu-taler/taler-util"; -import { - readSuccessResponseJsonOrErrorCode, - readSuccessResponseJsonOrThrow, - throwUnexpectedRequestError, -} from "@gnu-taler/taler-util/http"; +import { readSuccessResponseJsonOrThrow } from "@gnu-taler/taler-util/http"; import { KycPendingInfo, KycUserType, @@ -60,10 +56,10 @@ import { PeerPullPaymentCreditStatus, WithdrawalGroupStatus, WithdrawalRecordType, + fetchFreshExchange, timestampOptionalPreciseFromDb, timestampPreciseFromDb, timestampPreciseToDb, - fetchFreshExchange, } from "../index.js"; import { InternalWalletState } from "../internal-wallet-state.js"; import { PendingTaskType } from "../pending-types.js"; diff --git a/packages/taler-wallet-core/src/operations/pending.ts b/packages/taler-wallet-core/src/operations/pending.ts index 560031ad1..8f9506331 100644 --- a/packages/taler-wallet-core/src/operations/pending.ts +++ b/packages/taler-wallet-core/src/operations/pending.ts @@ -24,7 +24,6 @@ import { GlobalIDB } from "@gnu-taler/idb-bridge"; import { AbsoluteTime, - TalerErrorDetail, TalerPreciseTimestamp, TransactionRecordFilter, } from "@gnu-taler/taler-util"; @@ -38,11 +37,8 @@ import { OPERATION_STATUS_ACTIVE_LAST, PeerPullCreditRecord, PeerPullDebitRecordStatus, - PeerPullPaymentCreditStatus, PeerPullPaymentIncomingRecord, - PeerPushCreditStatus, PeerPushDebitRecord, - PeerPushDebitStatus, PeerPushPaymentIncomingRecord, PurchaseRecord, PurchaseStatus, @@ -50,17 +46,13 @@ import { RefreshGroupRecord, RefreshOperationStatus, RefundGroupRecord, - RefundGroupStatus, RewardRecord, - RewardRecordStatus, WalletStoresV1, WithdrawalGroupRecord, - depositOperationNonfinalStatusRange, timestampAbsoluteFromDb, timestampOptionalAbsoluteFromDb, timestampPreciseFromDb, timestampPreciseToDb, - withdrawalGroupNonfinalRange, } from "../db.js"; import { InternalWalletState } from "../internal-wallet-state.js"; import { @@ -224,9 +216,12 @@ export async function iterRecordsForWithdrawal( ): Promise { let withdrawalGroupRecords: WithdrawalGroupRecord[]; if (filter.onlyState === "nonfinal") { - withdrawalGroupRecords = await tx.withdrawalGroups.indexes.byStatus.getAll( - withdrawalGroupNonfinalRange, + const keyRange = GlobalIDB.KeyRange.bound( + OPERATION_STATUS_ACTIVE_FIRST, + OPERATION_STATUS_ACTIVE_LAST, ); + withdrawalGroupRecords = + await tx.withdrawalGroups.indexes.byStatus.getAll(keyRange); } else { withdrawalGroupRecords = await tx.withdrawalGroups.indexes.byStatus.getAll(); @@ -290,9 +285,11 @@ export async function iterRecordsForDeposit( ): Promise { let dgs: DepositGroupRecord[]; if (filter.onlyState === "nonfinal") { - dgs = await tx.depositGroups.indexes.byStatus.getAll( - depositOperationNonfinalStatusRange, + const keyRange = GlobalIDB.KeyRange.bound( + OPERATION_STATUS_ACTIVE_FIRST, + OPERATION_STATUS_ACTIVE_LAST, ); + dgs = await tx.depositGroups.indexes.byStatus.getAll(keyRange); } else { dgs = await tx.depositGroups.indexes.byStatus.getAll(); } @@ -350,11 +347,11 @@ export async function iterRecordsForReward( f: (r: RewardRecord) => Promise, ): Promise { if (filter.onlyState === "nonfinal") { - const range = GlobalIDB.KeyRange.bound( - RewardRecordStatus.PendingPickup, - RewardRecordStatus.PendingPickup, + const keyRange = GlobalIDB.KeyRange.bound( + OPERATION_STATUS_ACTIVE_FIRST, + OPERATION_STATUS_ACTIVE_LAST, ); - await tx.rewards.indexes.byStatus.iter(range).forEachAsync(f); + await tx.rewards.indexes.byStatus.iter(keyRange).forEachAsync(f); } else { await tx.rewards.indexes.byStatus.iter().forEachAsync(f); } @@ -404,7 +401,10 @@ export async function iterRecordsForRefund( f: (r: RefundGroupRecord) => Promise, ): Promise { if (filter.onlyState === "nonfinal") { - const keyRange = GlobalIDB.KeyRange.only(RefundGroupStatus.Pending); + const keyRange = GlobalIDB.KeyRange.bound( + OPERATION_STATUS_ACTIVE_FIRST, + OPERATION_STATUS_ACTIVE_LAST, + ); await tx.refundGroups.indexes.byStatus.iter(keyRange).forEachAsync(f); } else { await tx.refundGroups.iter().forEachAsync(f); @@ -534,8 +534,8 @@ export async function iterRecordsForPeerPullInitiation( ): Promise { if (filter.onlyState === "nonfinal") { const keyRange = GlobalIDB.KeyRange.bound( - PeerPullPaymentCreditStatus.PendingCreatePurse, - PeerPullPaymentCreditStatus.AbortingDeletePurse, + OPERATION_STATUS_ACTIVE_FIRST, + OPERATION_STATUS_ACTIVE_LAST, ); await tx.peerPullCredit.indexes.byStatus.iter(keyRange).forEachAsync(f); } else { @@ -589,8 +589,8 @@ export async function iterRecordsForPeerPullDebit( ): Promise { if (filter.onlyState === "nonfinal") { const keyRange = GlobalIDB.KeyRange.bound( - PeerPullDebitRecordStatus.PendingDeposit, - PeerPullDebitRecordStatus.AbortingRefresh, + OPERATION_STATUS_ACTIVE_FIRST, + OPERATION_STATUS_ACTIVE_LAST, ); await tx.peerPullDebit.indexes.byStatus.iter(keyRange).forEachAsync(f); } else { @@ -641,8 +641,8 @@ export async function iterRecordsForPeerPushInitiation( ): Promise { if (filter.onlyState === "nonfinal") { const keyRange = GlobalIDB.KeyRange.bound( - PeerPushDebitStatus.PendingCreatePurse, - PeerPushDebitStatus.AbortingRefreshExpired, + OPERATION_STATUS_ACTIVE_FIRST, + OPERATION_STATUS_ACTIVE_LAST, ); await tx.peerPushDebit.indexes.byStatus.iter(keyRange).forEachAsync(f); } else { @@ -688,8 +688,8 @@ export async function iterRecordsForPeerPushCredit( ): Promise { if (filter.onlyState === "nonfinal") { const keyRange = GlobalIDB.KeyRange.bound( - PeerPushCreditStatus.PendingMerge, - PeerPushCreditStatus.PendingWithdrawing, + OPERATION_STATUS_ACTIVE_FIRST, + OPERATION_STATUS_ACTIVE_LAST, ); await tx.peerPushCredit.indexes.byStatus.iter(keyRange).forEachAsync(f); } else { @@ -706,10 +706,6 @@ async function gatherPeerPushCreditPending( now: AbsoluteTime, resp: PendingOperationsResponse, ): Promise { - const keyRange = GlobalIDB.KeyRange.bound( - PeerPushCreditStatus.PendingMerge, - PeerPushCreditStatus.PendingWithdrawing, - ); await iterRecordsForPeerPushCredit( tx, { onlyState: "nonfinal" }, diff --git a/packages/taler-wallet-core/src/operations/withdraw.ts b/packages/taler-wallet-core/src/operations/withdraw.ts index 392b3753d..cf4e9a1d5 100644 --- a/packages/taler-wallet-core/src/operations/withdraw.ts +++ b/packages/taler-wallet-core/src/operations/withdraw.ts @@ -62,7 +62,6 @@ import { addPaytoQueryParams, canonicalizeBaseUrl, codecForAny, - codecForBankWithdrawalOperationPostResponse, codecForCashinConversionResponse, codecForConversionBankConfig, codecForExchangeWithdrawBatchResponse, @@ -100,9 +99,7 @@ import { WithdrawalRecordType, } from "../db.js"; import { - ExchangeDetailsRecord, ExchangeEntryDbRecordStatus, - Wallet, isWithdrawableDenom, timestampPreciseToDb, } from "../index.js"; @@ -134,10 +131,10 @@ import { WALLET_EXCHANGE_PROTOCOL_VERSION, } from "../versions.js"; import { + ReadyExchangeSummary, + fetchFreshExchange, getExchangeDetails, getExchangePaytoUri, - fetchFreshExchange, - ReadyExchangeSummary, } from "./exchanges.js"; import { TransitionInfo, diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts index 2d422e59c..154665c47 100644 --- a/packages/taler-wallet-core/src/wallet.ts +++ b/packages/taler-wallet-core/src/wallet.ts @@ -205,7 +205,7 @@ import { getExchangeDetailedInfo, getExchangeDetails, getExchangeTos, - getExchanges, + listExchanges, updateExchangeFromUrlHandler, } from "./operations/exchanges.js"; import { getMerchantInfo } from "./operations/merchants.js"; @@ -963,7 +963,7 @@ async function dispatchRequestInternal( return {}; } case WalletApiOperation.ListExchanges: { - return await getExchanges(ws); + return await listExchanges(ws); } case WalletApiOperation.GetExchangeEntryByUrl: { const req = codecForGetExchangeEntryByUrlRequest().decode(payload); @@ -997,7 +997,7 @@ async function dispatchRequestInternal( case WalletApiOperation.ListExchangesForScopedCurrency: { const req = codecForListExchangesForScopedCurrencyRequest().decode(payload); - const exchangesResp = await getExchanges(ws); + const exchangesResp = await listExchanges(ws); const result: ExchangesShortListResponse = { exchanges: [], }; -- cgit v1.2.3