diff options
Diffstat (limited to 'packages/taler-wallet-core/src/operations/exchanges.ts')
-rw-r--r-- | packages/taler-wallet-core/src/operations/exchanges.ts | 211 |
1 files changed, 102 insertions, 109 deletions
diff --git a/packages/taler-wallet-core/src/operations/exchanges.ts b/packages/taler-wallet-core/src/operations/exchanges.ts index 460b47e73..678e48fb9 100644 --- a/packages/taler-wallet-core/src/operations/exchanges.ts +++ b/packages/taler-wallet-core/src/operations/exchanges.ts @@ -99,8 +99,8 @@ import { ExchangeEntryDbRecordStatus, ExchangeEntryDbUpdateStatus, PendingTaskType, - WalletDbReadOnlyTransactionArr, - WalletDbReadWriteTransactionArr, + WalletDbReadOnlyTransaction, + WalletDbReadWriteTransaction, createRefreshGroup, createTimeline, isWithdrawableDenom, @@ -115,11 +115,7 @@ import { } from "../index.js"; import { InternalWalletState } from "../internal-wallet-state.js"; import { checkDbInvariant } from "../util/invariants.js"; -import { - DbReadOnlyTransactionArr, - GetReadOnlyAccess, - GetReadWriteAccess, -} from "../util/query.js"; +import { DbReadOnlyTransaction } from "../util/query.js"; import { WALLET_EXCHANGE_PROTOCOL_VERSION } from "../versions.js"; import { TaskIdentifiers, @@ -197,10 +193,7 @@ async function downloadExchangeWithTermsOfService( * Get exchange details from the database. */ async function getExchangeRecordsInternal( - tx: GetReadOnlyAccess<{ - exchanges: typeof WalletStoresV1.exchanges; - exchangeDetails: typeof WalletStoresV1.exchangeDetails; - }>, + tx: WalletDbReadOnlyTransaction<["exchanges", "exchangeDetails"]>, exchangeBaseUrl: string, ): Promise<ExchangeDetailsRecord | undefined> { const r = await tx.exchanges.get(exchangeBaseUrl); @@ -220,7 +213,7 @@ async function getExchangeRecordsInternal( } export async function getExchangeScopeInfo( - tx: WalletDbReadOnlyTransactionArr< + tx: WalletDbReadOnlyTransaction< [ "exchanges", "exchangeDetails", @@ -243,7 +236,7 @@ export async function getExchangeScopeInfo( } async function internalGetExchangeScopeInfo( - tx: WalletDbReadOnlyTransactionArr< + tx: WalletDbReadOnlyTransaction< ["globalCurrencyExchanges", "globalCurrencyAuditors"] >, exchangeDetails: ExchangeDetailsRecord, @@ -284,7 +277,7 @@ async function internalGetExchangeScopeInfo( } async function makeExchangeListItem( - tx: WalletDbReadOnlyTransactionArr< + tx: WalletDbReadOnlyTransaction< ["globalCurrencyExchanges", "globalCurrencyAuditors"] >, r: ExchangeEntryRecord, @@ -328,10 +321,7 @@ export interface ExchangeWireDetails { } export async function getExchangeWireDetailsInTx( - tx: GetReadOnlyAccess<{ - exchanges: typeof WalletStoresV1.exchanges; - exchangeDetails: typeof WalletStoresV1.exchangeDetails; - }>, + tx: WalletDbReadOnlyTransaction<["exchanges", "exchangeDetails"]>, exchangeBaseUrl: string, ): Promise<ExchangeWireDetails | undefined> { const det = await getExchangeRecordsInternal(tx, exchangeBaseUrl); @@ -389,9 +379,9 @@ export async function acceptExchangeTermsOfService( ws: InternalWalletState, exchangeBaseUrl: string, ): Promise<void> { - const notif = await ws.db - .mktx((x) => [x.exchanges, x.exchangeDetails]) - .runReadWrite(async (tx) => { + const notif = await ws.db.runReadWriteTx( + ["exchangeDetails", "exchanges"], + async (tx) => { const exch = await tx.exchanges.get(exchangeBaseUrl); if (exch && exch.tosCurrentEtag) { const oldExchangeState = getExchangeState(exch); @@ -409,7 +399,8 @@ export async function acceptExchangeTermsOfService( } satisfies WalletNotification; } return undefined; - }); + }, + ); if (notif) { ws.notify(notif); } @@ -537,7 +528,7 @@ async function validateGlobalFees( * if the DB transaction succeeds. */ export async function addPresetExchangeEntry( - tx: WalletDbReadWriteTransactionArr<["exchanges"]>, + tx: WalletDbReadWriteTransaction<["exchanges"]>, exchangeBaseUrl: string, currencyHint?: string, ): Promise<{ notification?: WalletNotification }> { @@ -577,10 +568,7 @@ export async function addPresetExchangeEntry( async function provideExchangeRecordInTx( ws: InternalWalletState, - tx: GetReadWriteAccess<{ - exchanges: typeof WalletStoresV1.exchanges; - exchangeDetails: typeof WalletStoresV1.exchangeDetails; - }>, + tx: WalletDbReadWriteTransaction<["exchanges", "exchangeDetails"]>, baseUrl: string, ): Promise<{ exchange: ExchangeEntryRecord; @@ -854,55 +842,58 @@ async function startUpdateExchangeEntry( }`, ); - const { notification } = await ws.db - .mktx((x) => [x.exchanges, x.exchangeDetails]) - .runReadWrite(async (tx) => { + const { notification } = await ws.db.runReadWriteTx( + ["exchanges", "exchangeDetails"], + async (tx) => { return provideExchangeRecordInTx(ws, tx, exchangeBaseUrl); - }); + }, + ); if (notification) { ws.notify(notification); } - const { oldExchangeState, newExchangeState, taskId } = await ws.db - .mktx((x) => [x.exchanges, x.operationRetries]) - .runReadWrite(async (tx) => { - const r = await tx.exchanges.get(canonBaseUrl); - if (!r) { - throw Error("exchange not found"); - } - const oldExchangeState = getExchangeState(r); - switch (r.updateStatus) { - case ExchangeEntryDbUpdateStatus.UnavailableUpdate: - break; - case ExchangeEntryDbUpdateStatus.Suspended: - break; - case ExchangeEntryDbUpdateStatus.ReadyUpdate: - break; - case ExchangeEntryDbUpdateStatus.Ready: { - const nextUpdateTimestamp = AbsoluteTime.fromPreciseTimestamp( - timestampPreciseFromDb(r.nextUpdateStamp), - ); - // Only update if entry is outdated or update is forced. - if ( - options.forceUpdate || - AbsoluteTime.isExpired(nextUpdateTimestamp) - ) { - r.updateStatus = ExchangeEntryDbUpdateStatus.ReadyUpdate; + const { oldExchangeState, newExchangeState, taskId } = + await ws.db.runReadWriteTx( + ["exchanges", "operationRetries"], + async (tx) => { + const r = await tx.exchanges.get(canonBaseUrl); + if (!r) { + throw Error("exchange not found"); + } + const oldExchangeState = getExchangeState(r); + switch (r.updateStatus) { + case ExchangeEntryDbUpdateStatus.UnavailableUpdate: + break; + case ExchangeEntryDbUpdateStatus.Suspended: + break; + case ExchangeEntryDbUpdateStatus.ReadyUpdate: + break; + case ExchangeEntryDbUpdateStatus.Ready: { + const nextUpdateTimestamp = AbsoluteTime.fromPreciseTimestamp( + timestampPreciseFromDb(r.nextUpdateStamp), + ); + // Only update if entry is outdated or update is forced. + if ( + options.forceUpdate || + AbsoluteTime.isExpired(nextUpdateTimestamp) + ) { + r.updateStatus = ExchangeEntryDbUpdateStatus.ReadyUpdate; + } + break; } - break; + case ExchangeEntryDbUpdateStatus.Initial: + r.updateStatus = ExchangeEntryDbUpdateStatus.InitialUpdate; + break; } - case ExchangeEntryDbUpdateStatus.Initial: - r.updateStatus = ExchangeEntryDbUpdateStatus.InitialUpdate; - break; - } - await tx.exchanges.put(r); - const newExchangeState = getExchangeState(r); - // Reset retries for updating the exchange entry. - const taskId = TaskIdentifiers.forExchangeUpdate(r); - await tx.operationRetries.delete(taskId); - return { oldExchangeState, newExchangeState, taskId }; - }); + await tx.exchanges.put(r); + const newExchangeState = getExchangeState(r); + // Reset retries for updating the exchange entry. + const taskId = TaskIdentifiers.forExchangeUpdate(r); + await tx.operationRetries.delete(taskId); + return { oldExchangeState, newExchangeState, taskId }; + }, + ); ws.notify({ type: NotificationType.ExchangeStateTransition, exchangeBaseUrl: canonBaseUrl, @@ -1284,17 +1275,17 @@ export async function updateExchangeFromUrlHandler( } } - const updated = await ws.db - .mktx((x) => [ - x.exchanges, - x.exchangeDetails, - x.exchangeSignKeys, - x.denominations, - x.coins, - x.refreshGroups, - x.recoupGroups, - ]) - .runReadWrite(async (tx) => { + const updated = await ws.db.runReadWriteTx( + [ + "exchanges", + "exchangeDetails", + "exchangeSignKeys", + "denominations", + "coins", + "refreshGroups", + "recoupGroups", + ], + async (tx) => { const r = await tx.exchanges.get(exchangeBaseUrl); if (!r) { logger.warn(`exchange ${exchangeBaseUrl} no longer present`); @@ -1454,7 +1445,8 @@ export async function updateExchangeFromUrlHandler( oldExchangeState, newExchangeState, }; - }); + }, + ); if (recoupGroupId) { const recoupTaskId = constructTaskIdentifier({ @@ -1481,15 +1473,15 @@ export async function updateExchangeFromUrlHandler( if (refreshCheckNecessary) { // Do auto-refresh. - await ws.db - .mktx((x) => [ - x.coins, - x.denominations, - x.coinAvailability, - x.refreshGroups, - x.exchanges, - ]) - .runReadWrite(async (tx) => { + await ws.db.runReadWriteTx( + [ + "coins", + "denominations", + "coinAvailability", + "refreshGroups", + "exchanges", + ], + async (tx) => { const exchange = await tx.exchanges.get(exchangeBaseUrl); if (!exchange || !exchange.detailsPointer) { return; @@ -1547,7 +1539,8 @@ export async function updateExchangeFromUrlHandler( AbsoluteTime.toPreciseTimestamp(minCheckThreshold), ); await tx.exchanges.put(exchange); - }); + }, + ); } ws.notify({ @@ -1599,11 +1592,12 @@ export async function getExchangePaytoUri( ): Promise<string> { // We do the update here, since the exchange might not even exist // yet in our database. - const details = await ws.db - .mktx((x) => [x.exchangeDetails, x.exchanges]) - .runReadOnly(async (tx) => { + const details = await ws.db.runReadOnlyTx( + ["exchanges", "exchangeDetails"], + async (tx) => { return getExchangeRecordsInternal(tx, exchangeBaseUrl); - }); + }, + ); const accounts = details?.wireInfo.accounts ?? []; for (const account of accounts) { const res = parsePaytoUri(account.payto_uri); @@ -1641,15 +1635,13 @@ export async function getExchangeTos( acceptLanguage, ); - await ws.db - .mktx((x) => [x.exchanges, x.exchangeDetails]) - .runReadWrite(async (tx) => { - const updateExchangeEntry = await tx.exchanges.get(exchangeBaseUrl); - if (updateExchangeEntry) { - updateExchangeEntry.tosCurrentEtag = tosDownload.tosEtag; - await tx.exchanges.put(updateExchangeEntry); - } - }); + await ws.db.runReadWriteTx(["exchanges"], async (tx) => { + const updateExchangeEntry = await tx.exchanges.get(exchangeBaseUrl); + if (updateExchangeEntry) { + updateExchangeEntry.tosCurrentEtag = tosDownload.tosEtag; + await tx.exchanges.put(updateExchangeEntry); + } + }); return { acceptedEtag: exch.tosAcceptedEtag, @@ -1738,7 +1730,7 @@ export async function listExchanges( */ export async function markExchangeUsed( ws: InternalWalletState, - tx: GetReadWriteAccess<{ exchanges: typeof WalletStoresV1.exchanges }>, + tx: WalletDbReadWriteTransaction<["exchanges"]>, exchangeBaseUrl: string, ): Promise<{ notif: WalletNotification | undefined }> { exchangeBaseUrl = canonicalizeBaseUrl(exchangeBaseUrl); @@ -1780,9 +1772,9 @@ export async function getExchangeDetailedInfo( ws: InternalWalletState, exchangeBaseurl: string, ): Promise<ExchangeDetailedResponse> { - const exchange = await ws.db - .mktx((x) => [x.exchanges, x.exchangeDetails, x.denominations]) - .runReadOnly(async (tx) => { + const exchange = await ws.db.runReadOnlyTx( + ["exchanges", "exchangeDetails", "denominations"], + async (tx) => { const ex = await tx.exchanges.get(exchangeBaseurl); const dp = ex?.detailsPointer; if (!dp) { @@ -1815,7 +1807,8 @@ export async function getExchangeDetailedInfo( }, denominations, }; - }); + }, + ); if (!exchange) { throw Error(`exchange with base url "${exchangeBaseurl}" not found`); @@ -1930,7 +1923,7 @@ export async function getExchangeDetailedInfo( async function internalGetExchangeResources( ws: InternalWalletState, - tx: DbReadOnlyTransactionArr< + tx: DbReadOnlyTransaction< typeof WalletStoresV1, ["exchanges", "coins", "withdrawalGroups"] >, |