summaryrefslogtreecommitdiff
path: root/packages
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2024-04-23 03:09:40 +0200
committerFlorian Dold <florian@dold.me>2024-04-23 03:09:40 +0200
commit1edc144b3595ae1ab6b8af7a43d26b811b2c2623 (patch)
treedb552f6b4a351eb1d0dae902f4d504031852bda7 /packages
parent4b69853c347071acb73efcde9d4969cf06d0dfcc (diff)
downloadwallet-core-1edc144b3595ae1ab6b8af7a43d26b811b2c2623.tar.gz
wallet-core-1edc144b3595ae1ab6b8af7a43d26b811b2c2623.tar.bz2
wallet-core-1edc144b3595ae1ab6b8af7a43d26b811b2c2623.zip
wallet-core: pass options object to all transactions
Diffstat (limited to 'packages')
-rw-r--r--packages/taler-wallet-core/src/attention.ts70
-rw-r--r--packages/taler-wallet-core/src/backup/index.ts361
-rw-r--r--packages/taler-wallet-core/src/balance.ts83
-rw-r--r--packages/taler-wallet-core/src/coinSelection.ts38
-rw-r--r--packages/taler-wallet-core/src/db.ts17
-rw-r--r--packages/taler-wallet-core/src/deposits.ts258
-rw-r--r--packages/taler-wallet-core/src/dev-experiments.ts74
-rw-r--r--packages/taler-wallet-core/src/exchanges.ts141
-rw-r--r--packages/taler-wallet-core/src/instructedAmountConversion.ts9
-rw-r--r--packages/taler-wallet-core/src/observable-wrappers.ts12
-rw-r--r--packages/taler-wallet-core/src/pay-merchant.ts508
-rw-r--r--packages/taler-wallet-core/src/pay-peer-common.ts112
-rw-r--r--packages/taler-wallet-core/src/pay-peer-pull-credit.ts138
-rw-r--r--packages/taler-wallet-core/src/pay-peer-pull-debit.ts73
-rw-r--r--packages/taler-wallet-core/src/pay-peer-push-credit.ts42
-rw-r--r--packages/taler-wallet-core/src/pay-peer-push-debit.ts118
-rw-r--r--packages/taler-wallet-core/src/query.ts20
-rw-r--r--packages/taler-wallet-core/src/recoup.ts81
-rw-r--r--packages/taler-wallet-core/src/refresh.ts128
-rw-r--r--packages/taler-wallet-core/src/shepherd.ts44
-rw-r--r--packages/taler-wallet-core/src/testing.ts9
-rw-r--r--packages/taler-wallet-core/src/transactions.ts132
-rw-r--r--packages/taler-wallet-core/src/wallet.ts431
-rw-r--r--packages/taler-wallet-core/src/withdraw.ts197
24 files changed, 1721 insertions, 1375 deletions
diff --git a/packages/taler-wallet-core/src/attention.ts b/packages/taler-wallet-core/src/attention.ts
index 60d2117f1..7a52ceaa3 100644
--- a/packages/taler-wallet-core/src/attention.ts
+++ b/packages/taler-wallet-core/src/attention.ts
@@ -29,7 +29,7 @@ import {
UserAttentionsResponse,
} from "@gnu-taler/taler-util";
import { timestampPreciseFromDb, timestampPreciseToDb } from "./db.js";
-import { InternalWalletState, WalletExecutionContext } from "./wallet.js";
+import { WalletExecutionContext } from "./wallet.js";
const logger = new Logger("operations/attention.ts");
@@ -37,20 +37,23 @@ export async function getUserAttentionsUnreadCount(
wex: WalletExecutionContext,
req: UserAttentionsRequest,
): Promise<UserAttentionsCountResponse> {
- const total = await wex.db.runReadOnlyTx(["userAttention"], async (tx) => {
- let count = 0;
- await tx.userAttention.iter().forEach((x) => {
- if (
- req.priority !== undefined &&
- UserAttentionPriority[x.info.type] !== req.priority
- )
- return;
- if (x.read !== undefined) return;
- count++;
- });
+ const total = await wex.db.runReadOnlyTx(
+ { storeNames: ["userAttention"] },
+ async (tx) => {
+ let count = 0;
+ await tx.userAttention.iter().forEach((x) => {
+ if (
+ req.priority !== undefined &&
+ UserAttentionPriority[x.info.type] !== req.priority
+ )
+ return;
+ if (x.read !== undefined) return;
+ count++;
+ });
- return count;
- });
+ return count;
+ },
+ );
return { total };
}
@@ -59,30 +62,33 @@ export async function getUserAttentions(
wex: WalletExecutionContext,
req: UserAttentionsRequest,
): Promise<UserAttentionsResponse> {
- return await wex.db.runReadOnlyTx(["userAttention"], async (tx) => {
- const pending: UserAttentionUnreadList = [];
- await tx.userAttention.iter().forEach((x) => {
- if (
- req.priority !== undefined &&
- UserAttentionPriority[x.info.type] !== req.priority
- )
- return;
- pending.push({
- info: x.info,
- when: timestampPreciseFromDb(x.created),
- read: x.read !== undefined,
+ return await wex.db.runReadOnlyTx(
+ { storeNames: ["userAttention"] },
+ async (tx) => {
+ const pending: UserAttentionUnreadList = [];
+ await tx.userAttention.iter().forEach((x) => {
+ if (
+ req.priority !== undefined &&
+ UserAttentionPriority[x.info.type] !== req.priority
+ )
+ return;
+ pending.push({
+ info: x.info,
+ when: timestampPreciseFromDb(x.created),
+ read: x.read !== undefined,
+ });
});
- });
- return { pending };
- });
+ return { pending };
+ },
+ );
}
export async function markAttentionRequestAsRead(
wex: WalletExecutionContext,
req: UserAttentionByIdRequest,
): Promise<void> {
- await wex.db.runReadWriteTx(["userAttention"], async (tx) => {
+ await wex.db.runReadWriteTx({ storeNames: ["userAttention"] }, async (tx) => {
const ua = await tx.userAttention.get([req.entityId, req.type]);
if (!ua) throw Error("attention request not found");
tx.userAttention.put({
@@ -104,7 +110,7 @@ export async function addAttentionRequest(
info: AttentionInfo,
entityId: string,
): Promise<void> {
- await wex.db.runReadWriteTx(["userAttention"], async (tx) => {
+ await wex.db.runReadWriteTx({ storeNames: ["userAttention"] }, async (tx) => {
await tx.userAttention.put({
info,
entityId,
@@ -125,7 +131,7 @@ export async function removeAttentionRequest(
wex: WalletExecutionContext,
req: UserAttentionByIdRequest,
): Promise<void> {
- await wex.db.runReadWriteTx(["userAttention"], async (tx) => {
+ await wex.db.runReadWriteTx({ storeNames: ["userAttention"] }, async (tx) => {
const ua = await tx.userAttention.get([req.entityId, req.type]);
if (!ua) throw Error("attention request not found");
await tx.userAttention.delete([req.entityId, req.type]);
diff --git a/packages/taler-wallet-core/src/backup/index.ts b/packages/taler-wallet-core/src/backup/index.ts
index 5dccf1998..16b5488e7 100644
--- a/packages/taler-wallet-core/src/backup/index.ts
+++ b/packages/taler-wallet-core/src/backup/index.ts
@@ -183,7 +183,7 @@ async function runBackupCycleForProvider(
args: BackupForProviderArgs,
): Promise<TaskRunResult> {
const provider = await wex.db.runReadOnlyTx(
- ["backupProviders"],
+ { storeNames: ["backupProviders"] },
async (tx) => {
return tx.backupProviders.get(args.backupProviderBaseUrl);
},
@@ -244,20 +244,23 @@ async function runBackupCycleForProvider(
logger.trace(`sync response status: ${resp.status}`);
if (resp.status === HttpStatusCode.NotModified) {
- await wex.db.runReadWriteTx(["backupProviders"], async (tx) => {
- const prov = await tx.backupProviders.get(provider.baseUrl);
- if (!prov) {
- return;
- }
- prov.lastBackupCycleTimestamp = timestampPreciseToDb(
- TalerPreciseTimestamp.now(),
- );
- prov.state = {
- tag: BackupProviderStateTag.Ready,
- nextBackupTimestamp: timestampPreciseToDb(getNextBackupTimestamp()),
- };
- await tx.backupProviders.put(prov);
- });
+ await wex.db.runReadWriteTx(
+ { storeNames: ["backupProviders"] },
+ async (tx) => {
+ const prov = await tx.backupProviders.get(provider.baseUrl);
+ if (!prov) {
+ return;
+ }
+ prov.lastBackupCycleTimestamp = timestampPreciseToDb(
+ TalerPreciseTimestamp.now(),
+ );
+ prov.state = {
+ tag: BackupProviderStateTag.Ready,
+ nextBackupTimestamp: timestampPreciseToDb(getNextBackupTimestamp()),
+ };
+ await tx.backupProviders.put(prov);
+ },
+ );
removeAttentionRequest(wex, {
entityId: provider.baseUrl,
@@ -290,41 +293,47 @@ async function runBackupCycleForProvider(
if (res === undefined) {
//claimed
- await wex.db.runReadWriteTx(["backupProviders"], async (tx) => {
+ await wex.db.runReadWriteTx(
+ { storeNames: ["backupProviders"] },
+ async (tx) => {
+ const prov = await tx.backupProviders.get(provider.baseUrl);
+ if (!prov) {
+ logger.warn("backup provider not found anymore");
+ return;
+ }
+ prov.shouldRetryFreshProposal = true;
+ prov.state = {
+ tag: BackupProviderStateTag.Retrying,
+ };
+ await tx.backupProviders.put(prov);
+ },
+ );
+
+ throw Error("not implemented");
+ // return {
+ // type: TaskRunResultType.Pending,
+ // };
+ }
+ const result = res;
+
+ await wex.db.runReadWriteTx(
+ { storeNames: ["backupProviders"] },
+ async (tx) => {
const prov = await tx.backupProviders.get(provider.baseUrl);
if (!prov) {
logger.warn("backup provider not found anymore");
return;
}
- prov.shouldRetryFreshProposal = true;
+ // const opId = TaskIdentifiers.forBackup(prov);
+ // await scheduleRetryInTx(ws, tx, opId);
+ prov.currentPaymentProposalId = result.proposalId;
+ prov.shouldRetryFreshProposal = false;
prov.state = {
tag: BackupProviderStateTag.Retrying,
};
await tx.backupProviders.put(prov);
- });
-
- throw Error("not implemented");
- // return {
- // type: TaskRunResultType.Pending,
- // };
- }
- const result = res;
-
- await wex.db.runReadWriteTx(["backupProviders"], async (tx) => {
- const prov = await tx.backupProviders.get(provider.baseUrl);
- if (!prov) {
- logger.warn("backup provider not found anymore");
- return;
- }
- // const opId = TaskIdentifiers.forBackup(prov);
- // await scheduleRetryInTx(ws, tx, opId);
- prov.currentPaymentProposalId = result.proposalId;
- prov.shouldRetryFreshProposal = false;
- prov.state = {
- tag: BackupProviderStateTag.Retrying,
- };
- await tx.backupProviders.put(prov);
- });
+ },
+ );
addAttentionRequest(
wex,
@@ -343,21 +352,24 @@ async function runBackupCycleForProvider(
}
if (resp.status === HttpStatusCode.NoContent) {
- await wex.db.runReadWriteTx(["backupProviders"], async (tx) => {
- const prov = await tx.backupProviders.get(provider.baseUrl);
- if (!prov) {
- return;
- }
- prov.lastBackupHash = encodeCrock(currentBackupHash);
- prov.lastBackupCycleTimestamp = timestampPreciseToDb(
- TalerPreciseTimestamp.now(),
- );
- prov.state = {
- tag: BackupProviderStateTag.Ready,
- nextBackupTimestamp: timestampPreciseToDb(getNextBackupTimestamp()),
- };
- await tx.backupProviders.put(prov);
- });
+ await wex.db.runReadWriteTx(
+ { storeNames: ["backupProviders"] },
+ async (tx) => {
+ const prov = await tx.backupProviders.get(provider.baseUrl);
+ if (!prov) {
+ return;
+ }
+ prov.lastBackupHash = encodeCrock(currentBackupHash);
+ prov.lastBackupCycleTimestamp = timestampPreciseToDb(
+ TalerPreciseTimestamp.now(),
+ );
+ prov.state = {
+ tag: BackupProviderStateTag.Ready,
+ nextBackupTimestamp: timestampPreciseToDb(getNextBackupTimestamp()),
+ };
+ await tx.backupProviders.put(prov);
+ },
+ );
removeAttentionRequest(wex, {
entityId: provider.baseUrl,
@@ -376,22 +388,25 @@ async function runBackupCycleForProvider(
// const blob = await decryptBackup(backupConfig, backupEnc);
// FIXME: Re-implement backup import with merging
// await importBackup(ws, blob, cryptoData);
- await wex.db.runReadWriteTx(["backupProviders"], async (tx) => {
- const prov = await tx.backupProviders.get(provider.baseUrl);
- if (!prov) {
- logger.warn("backup provider not found anymore");
- return;
- }
- prov.lastBackupHash = encodeCrock(hash(backupEnc));
- // FIXME: Allocate error code for this situation?
- // FIXME: Add operation retry record!
- const opId = TaskIdentifiers.forBackup(prov);
- //await scheduleRetryInTx(ws, tx, opId);
- prov.state = {
- tag: BackupProviderStateTag.Retrying,
- };
- await tx.backupProviders.put(prov);
- });
+ await wex.db.runReadWriteTx(
+ { storeNames: ["backupProviders"] },
+ async (tx) => {
+ const prov = await tx.backupProviders.get(provider.baseUrl);
+ if (!prov) {
+ logger.warn("backup provider not found anymore");
+ return;
+ }
+ prov.lastBackupHash = encodeCrock(hash(backupEnc));
+ // FIXME: Allocate error code for this situation?
+ // FIXME: Add operation retry record!
+ const opId = TaskIdentifiers.forBackup(prov);
+ //await scheduleRetryInTx(ws, tx, opId);
+ prov.state = {
+ tag: BackupProviderStateTag.Retrying,
+ };
+ await tx.backupProviders.put(prov);
+ },
+ );
logger.info("processed existing backup");
// Now upload our own, merged backup.
return await runBackupCycleForProvider(wex, args);
@@ -414,7 +429,7 @@ export async function processBackupForProvider(
backupProviderBaseUrl: string,
): Promise<TaskRunResult> {
const provider = await wex.db.runReadOnlyTx(
- ["backupProviders"],
+ { storeNames: ["backupProviders"] },
async (tx) => {
return await tx.backupProviders.get(backupProviderBaseUrl);
},
@@ -444,9 +459,12 @@ export async function removeBackupProvider(
wex: WalletExecutionContext,
req: RemoveBackupProviderRequest,
): Promise<void> {
- await wex.db.runReadWriteTx(["backupProviders"], async (tx) => {
- await tx.backupProviders.delete(req.provider);
- });
+ await wex.db.runReadWriteTx(
+ { storeNames: ["backupProviders"] },
+ async (tx) => {
+ await tx.backupProviders.delete(req.provider);
+ },
+ );
}
export interface RunBackupCycleRequest {
@@ -473,7 +491,7 @@ export async function runBackupCycle(
req: RunBackupCycleRequest,
): Promise<void> {
const providers = await wex.db.runReadOnlyTx(
- ["backupProviders"],
+ { storeNames: ["backupProviders"] },
async (tx) => {
if (req.providers) {
const rs = await Promise.all(
@@ -553,56 +571,64 @@ export async function addBackupProvider(
logger.info(`adding backup provider ${j2s(req)}`);
await provideBackupState(wex);
const canonUrl = canonicalizeBaseUrl(req.backupProviderBaseUrl);
- await wex.db.runReadWriteTx(["backupProviders"], async (tx) => {
- const oldProv = await tx.backupProviders.get(canonUrl);
- if (oldProv) {
- logger.info("old backup provider found");
+ await wex.db.runReadWriteTx(
+ { storeNames: ["backupProviders"] },
+ async (tx) => {
+ const oldProv = await tx.backupProviders.get(canonUrl);
+ if (oldProv) {
+ logger.info("old backup provider found");
+ if (req.activate) {
+ oldProv.state = {
+ tag: BackupProviderStateTag.Ready,
+ nextBackupTimestamp: timestampPreciseToDb(
+ TalerPreciseTimestamp.now(),
+ ),
+ };
+ logger.info("setting existing backup provider to active");
+ await tx.backupProviders.put(oldProv);
+ }
+ return;
+ }
+ },
+ );
+ const termsUrl = new URL("config", canonUrl);
+ const resp = await wex.http.fetch(termsUrl.href);
+ const terms = await readSuccessResponseJsonOrThrow(
+ resp,
+ codecForSyncTermsOfServiceResponse(),
+ );
+ await wex.db.runReadWriteTx(
+ { storeNames: ["backupProviders"] },
+ async (tx) => {
+ let state: BackupProviderState;
+ //FIXME: what is the difference provisional and ready?
if (req.activate) {
- oldProv.state = {
+ state = {
tag: BackupProviderStateTag.Ready,
nextBackupTimestamp: timestampPreciseToDb(
TalerPreciseTimestamp.now(),
),
};
- logger.info("setting existing backup provider to active");
- await tx.backupProviders.put(oldProv);
+ } else {
+ state = {
+ tag: BackupProviderStateTag.Provisional,
+ };
}
- return;
- }
- });
- const termsUrl = new URL("config", canonUrl);
- const resp = await wex.http.fetch(termsUrl.href);
- const terms = await readSuccessResponseJsonOrThrow(
- resp,
- codecForSyncTermsOfServiceResponse(),
+ await tx.backupProviders.put({
+ state,
+ name: req.name,
+ terms: {
+ annualFee: terms.annual_fee,
+ storageLimitInMegabytes: terms.storage_limit_in_megabytes,
+ supportedProtocolVersion: terms.version,
+ },
+ shouldRetryFreshProposal: false,
+ paymentProposalIds: [],
+ baseUrl: canonUrl,
+ uids: [encodeCrock(getRandomBytes(32))],
+ });
+ },
);
- await wex.db.runReadWriteTx(["backupProviders"], async (tx) => {
- let state: BackupProviderState;
- //FIXME: what is the difference provisional and ready?
- if (req.activate) {
- state = {
- tag: BackupProviderStateTag.Ready,
- nextBackupTimestamp: timestampPreciseToDb(TalerPreciseTimestamp.now()),
- };
- } else {
- state = {
- tag: BackupProviderStateTag.Provisional,
- };
- }
- await tx.backupProviders.put({
- state,
- name: req.name,
- terms: {
- annualFee: terms.annual_fee,
- storageLimitInMegabytes: terms.storage_limit_in_megabytes,
- supportedProtocolVersion: terms.version,
- },
- shouldRetryFreshProposal: false,
- paymentProposalIds: [],
- baseUrl: canonUrl,
- uids: [encodeCrock(getRandomBytes(32))],
- });
- });
return await runFirstBackupCycleForProvider(wex, {
backupProviderBaseUrl: canonUrl,
@@ -706,7 +732,7 @@ export async function getBackupInfo(
): Promise<BackupInfo> {
const backupConfig = await provideBackupState(wex);
const providerRecords = await wex.db.runReadOnlyTx(
- ["backupProviders", "operationRetries"],
+ { storeNames: ["backupProviders", "operationRetries"] },
async (tx) => {
return await tx.backupProviders.iter().mapAsync(async (bp) => {
const opId = TaskIdentifiers.forBackup(bp);
@@ -752,7 +778,7 @@ export async function getBackupRecovery(
): Promise<BackupRecovery> {
const bs = await provideBackupState(wex);
const providers = await wex.db.runReadOnlyTx(
- ["backupProviders"],
+ { storeNames: ["backupProviders"] },
async (tx) => {
return await tx.backupProviders.iter().toArray();
},
@@ -774,48 +800,51 @@ async function backupRecoveryTheirs(
wex: WalletExecutionContext,
br: BackupRecovery,
) {
- await wex.db.runReadWriteTx(["backupProviders", "config"], async (tx) => {
- let backupStateEntry: ConfigRecord | undefined = await tx.config.get(
- ConfigRecordKey.WalletBackupState,
- );
- checkDbInvariant(!!backupStateEntry);
- checkDbInvariant(
- backupStateEntry.key === ConfigRecordKey.WalletBackupState,
- );
- backupStateEntry.value.lastBackupNonce = undefined;
- backupStateEntry.value.lastBackupTimestamp = undefined;
- backupStateEntry.value.lastBackupCheckTimestamp = undefined;
- backupStateEntry.value.lastBackupPlainHash = undefined;
- backupStateEntry.value.walletRootPriv = br.walletRootPriv;
- backupStateEntry.value.walletRootPub = encodeCrock(
- eddsaGetPublic(decodeCrock(br.walletRootPriv)),
- );
- await tx.config.put(backupStateEntry);
- for (const prov of br.providers) {
- const existingProv = await tx.backupProviders.get(prov.url);
- if (!existingProv) {
- await tx.backupProviders.put({
- baseUrl: prov.url,
- name: prov.name,
- paymentProposalIds: [],
- shouldRetryFreshProposal: false,
- state: {
- tag: BackupProviderStateTag.Ready,
- nextBackupTimestamp: timestampPreciseToDb(
- TalerPreciseTimestamp.now(),
- ),
- },
- uids: [encodeCrock(getRandomBytes(32))],
- });
+ await wex.db.runReadWriteTx(
+ { storeNames: ["backupProviders", "config"] },
+ async (tx) => {
+ let backupStateEntry: ConfigRecord | undefined = await tx.config.get(
+ ConfigRecordKey.WalletBackupState,
+ );
+ checkDbInvariant(!!backupStateEntry);
+ checkDbInvariant(
+ backupStateEntry.key === ConfigRecordKey.WalletBackupState,
+ );
+ backupStateEntry.value.lastBackupNonce = undefined;
+ backupStateEntry.value.lastBackupTimestamp = undefined;
+ backupStateEntry.value.lastBackupCheckTimestamp = undefined;
+ backupStateEntry.value.lastBackupPlainHash = undefined;
+ backupStateEntry.value.walletRootPriv = br.walletRootPriv;
+ backupStateEntry.value.walletRootPub = encodeCrock(
+ eddsaGetPublic(decodeCrock(br.walletRootPriv)),
+ );
+ await tx.config.put(backupStateEntry);
+ for (const prov of br.providers) {
+ const existingProv = await tx.backupProviders.get(prov.url);
+ if (!existingProv) {
+ await tx.backupProviders.put({
+ baseUrl: prov.url,
+ name: prov.name,
+ paymentProposalIds: [],
+ shouldRetryFreshProposal: false,
+ state: {
+ tag: BackupProviderStateTag.Ready,
+ nextBackupTimestamp: timestampPreciseToDb(
+ TalerPreciseTimestamp.now(),
+ ),
+ },
+ uids: [encodeCrock(getRandomBytes(32))],
+ });
+ }
}
- }
- const providers = await tx.backupProviders.iter().toArray();
- for (const prov of providers) {
- prov.lastBackupCycleTimestamp = undefined;
- prov.lastBackupHash = undefined;
- await tx.backupProviders.put(prov);
- }
- });
+ const providers = await tx.backupProviders.iter().toArray();
+ for (const prov of providers) {
+ prov.lastBackupCycleTimestamp = undefined;
+ prov.lastBackupHash = undefined;
+ await tx.backupProviders.put(prov);
+ }
+ },
+ );
}
async function backupRecoveryOurs(
@@ -831,7 +860,7 @@ export async function loadBackupRecovery(
): Promise<void> {
const bs = await provideBackupState(wex);
const providers = await wex.db.runReadOnlyTx(
- ["backupProviders"],
+ { storeNames: ["backupProviders"] },
async (tx) => {
return await tx.backupProviders.iter().toArray();
},
@@ -879,7 +908,7 @@ export async function provideBackupState(
wex: WalletExecutionContext,
): Promise<WalletBackupConfState> {
const bs: ConfigRecord | undefined = await wex.db.runReadOnlyTx(
- ["config"],
+ { storeNames: ["config"] },
async (tx) => {
return await tx.config.get(ConfigRecordKey.WalletBackupState);
},
@@ -895,7 +924,7 @@ export async function provideBackupState(
// FIXME: device ID should be configured when wallet is initialized
// and be based on hostname
const deviceId = `wallet-core-${encodeCrock(d)}`;
- return await wex.db.runReadWriteTx(["config"], async (tx) => {
+ return await wex.db.runReadWriteTx({ storeNames: ["config"] }, async (tx) => {
let backupStateEntry: ConfigRecord | undefined = await tx.config.get(
ConfigRecordKey.WalletBackupState,
);
@@ -933,7 +962,7 @@ export async function setWalletDeviceId(
deviceId: string,
): Promise<void> {
await provideBackupState(wex);
- await wex.db.runReadWriteTx(["config"], async (tx) => {
+ await wex.db.runReadWriteTx({ storeNames: ["config"] }, async (tx) => {
let backupStateEntry: ConfigRecord | undefined = await tx.config.get(
ConfigRecordKey.WalletBackupState,
);
diff --git a/packages/taler-wallet-core/src/balance.ts b/packages/taler-wallet-core/src/balance.ts
index ca7642163..1fef9876e 100644
--- a/packages/taler-wallet-core/src/balance.ts
+++ b/packages/taler-wallet-core/src/balance.ts
@@ -472,19 +472,21 @@ export async function getBalances(
logger.trace("starting to compute balance");
const wbal = await wex.db.runReadWriteTx(
- [
- "coinAvailability",
- "coins",
- "depositGroups",
- "exchangeDetails",
- "exchanges",
- "globalCurrencyAuditors",
- "globalCurrencyExchanges",
- "purchases",
- "refreshGroups",
- "withdrawalGroups",
- "peerPushDebit",
- ],
+ {
+ storeNames: [
+ "coinAvailability",
+ "coins",
+ "depositGroups",
+ "exchangeDetails",
+ "exchanges",
+ "globalCurrencyAuditors",
+ "globalCurrencyExchanges",
+ "purchases",
+ "refreshGroups",
+ "withdrawalGroups",
+ "peerPushDebit",
+ ],
+ },
async (tx) => {
return getBalancesInsideTransaction(wex, tx);
},
@@ -557,13 +559,15 @@ export async function getPaymentBalanceDetails(
req: PaymentRestrictionsForBalance,
): Promise<PaymentBalanceDetails> {
return await wex.db.runReadOnlyTx(
- [
- "coinAvailability",
- "refreshGroups",
- "exchanges",
- "exchangeDetails",
- "denominations",
- ],
+ {
+ storeNames: [
+ "coinAvailability",
+ "refreshGroups",
+ "exchanges",
+ "exchangeDetails",
+ "denominations",
+ ],
+ },
async (tx) => {
return getPaymentBalanceDetailsInTx(wex, tx, req);
},
@@ -729,25 +733,28 @@ export async function getBalanceDetail(
): Promise<PaymentBalanceDetails> {
const exchanges: { exchangeBaseUrl: string; exchangePub: string }[] = [];
const wires = new Array<string>();
- await wex.db.runReadOnlyTx(["exchanges", "exchangeDetails"], async (tx) => {
- const allExchanges = await tx.exchanges.iter().toArray();
- for (const e of allExchanges) {
- const details = await getExchangeWireDetailsInTx(tx, e.baseUrl);
- if (!details || req.currency !== details.currency) {
- continue;
- }
- details.wireInfo.accounts.forEach((a) => {
- const payto = parsePaytoUri(a.payto_uri);
- if (payto && !wires.includes(payto.targetType)) {
- wires.push(payto.targetType);
+ await wex.db.runReadOnlyTx(
+ { storeNames: ["exchanges", "exchangeDetails"] },
+ async (tx) => {
+ const allExchanges = await tx.exchanges.iter().toArray();
+ for (const e of allExchanges) {
+ const details = await getExchangeWireDetailsInTx(tx, e.baseUrl);
+ if (!details || req.currency !== details.currency) {
+ continue;
}
- });
- exchanges.push({
- exchangePub: details.masterPublicKey,
- exchangeBaseUrl: e.baseUrl,
- });
- }
- });
+ details.wireInfo.accounts.forEach((a) => {
+ const payto = parsePaytoUri(a.payto_uri);
+ if (payto && !wires.includes(payto.targetType)) {
+ wires.push(payto.targetType);
+ }
+ });
+ exchanges.push({
+ exchangePub: details.masterPublicKey,
+ exchangeBaseUrl: e.baseUrl,
+ });
+ }
+ },
+ );
return await getPaymentBalanceDetails(wex, {
currency: req.currency,
diff --git a/packages/taler-wallet-core/src/coinSelection.ts b/packages/taler-wallet-core/src/coinSelection.ts
index 6a7d79d83..a60e41ecd 100644
--- a/packages/taler-wallet-core/src/coinSelection.ts
+++ b/packages/taler-wallet-core/src/coinSelection.ts
@@ -268,14 +268,16 @@ export async function selectPayCoins(
}
return await wex.db.runReadOnlyTx(
- [
- "coinAvailability",
- "denominations",
- "refreshGroups",
- "exchanges",
- "exchangeDetails",
- "coins",
- ],
+ {
+ storeNames: [
+ "coinAvailability",
+ "denominations",
+ "refreshGroups",
+ "exchanges",
+ "exchangeDetails",
+ "coins",
+ ],
+ },
async (tx) => {
const materialAvSel = await internalSelectPayCoins(wex, tx, req, false);
@@ -1140,15 +1142,17 @@ export async function selectPeerCoins(
}
return await wex.db.runReadWriteTx(
- [
- "exchanges",
- "contractTerms",
- "coins",
- "coinAvailability",
- "denominations",
- "refreshGroups",
- "exchangeDetails",
- ],
+ {
+ storeNames: [
+ "exchanges",
+ "contractTerms",
+ "coins",
+ "coinAvailability",
+ "denominations",
+ "refreshGroups",
+ "exchangeDetails",
+ ],
+ },
async (tx): Promise<SelectPeerCoinsResult> => {
const exchanges = await tx.exchanges.iter().toArray();
const currency = Amounts.currencyOf(instructedAmount);
diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts
index 5da8518ea..085e909cf 100644
--- a/packages/taler-wallet-core/src/db.ts
+++ b/packages/taler-wallet-core/src/db.ts
@@ -3305,7 +3305,7 @@ export async function openTalerDatabase(
CancellationToken.CONTINUE,
);
let currentMainVersion: string | undefined;
- await metaDb.runReadWriteTx(["metaConfig"], async (tx) => {
+ await metaDb.runReadWriteTx({ storeNames: ["metaConfig"] }, async (tx) => {
const dbVersionRecord = await tx.metaConfig.get(CURRENT_DB_CONFIG_KEY);
if (!dbVersionRecord) {
currentMainVersion = TALER_WALLET_MAIN_DB_NAME;
@@ -3330,12 +3330,15 @@ export async function openTalerDatabase(
case "taler-wallet-main-v9":
// We consider this a pre-release
// development version, no migration is done.
- await metaDb.runReadWriteTx(["metaConfig"], async (tx) => {
- await tx.metaConfig.put({
- key: CURRENT_DB_CONFIG_KEY,
- value: TALER_WALLET_MAIN_DB_NAME,
- });
- });
+ await metaDb.runReadWriteTx(
+ { storeNames: ["metaConfig"] },
+ async (tx) => {
+ await tx.metaConfig.put({
+ key: CURRENT_DB_CONFIG_KEY,
+ value: TALER_WALLET_MAIN_DB_NAME,
+ });
+ },
+ );
break;
default:
throw Error(
diff --git a/packages/taler-wallet-core/src/deposits.ts b/packages/taler-wallet-core/src/deposits.ts
index 50f26ea9c..dbba55247 100644
--- a/packages/taler-wallet-core/src/deposits.ts
+++ b/packages/taler-wallet-core/src/deposits.ts
@@ -139,22 +139,25 @@ export class DepositTransactionContext implements TransactionContext {
const ws = this.wex;
// FIXME: We should check first if we are in a final state
// where deletion is allowed.
- await ws.db.runReadWriteTx(["depositGroups", "tombstones"], async (tx) => {
- const tipRecord = await tx.depositGroups.get(depositGroupId);
- if (tipRecord) {
- await tx.depositGroups.delete(depositGroupId);
- await tx.tombstones.put({
- id: TombstoneTag.DeleteDepositGroup + ":" + depositGroupId,
- });
- }
- });
+ await ws.db.runReadWriteTx(
+ { storeNames: ["depositGroups", "tombstones"] },
+ async (tx) => {
+ const tipRecord = await tx.depositGroups.get(depositGroupId);
+ if (tipRecord) {
+ await tx.depositGroups.delete(depositGroupId);
+ await tx.tombstones.put({
+ id: TombstoneTag.DeleteDepositGroup + ":" + depositGroupId,
+ });
+ }
+ },
+ );
return;
}
async suspendTransaction(): Promise<void> {
const { wex, depositGroupId, transactionId, taskId: retryTag } = this;
const transitionInfo = await wex.db.runReadWriteTx(
- ["depositGroups"],
+ { storeNames: ["depositGroups"] },
async (tx) => {
const dg = await tx.depositGroups.get(depositGroupId);
if (!dg) {
@@ -197,7 +200,7 @@ export class DepositTransactionContext implements TransactionContext {
async abortTransaction(): Promise<void> {
const { wex, depositGroupId, transactionId, taskId: retryTag } = this;
const transitionInfo = await wex.db.runReadWriteTx(
- ["depositGroups"],
+ { storeNames: ["depositGroups"] },
async (tx) => {
const dg = await tx.depositGroups.get(depositGroupId);
if (!dg) {
@@ -235,7 +238,7 @@ export class DepositTransactionContext implements TransactionContext {
async resumeTransaction(): Promise<void> {
const { wex, depositGroupId, transactionId, taskId: retryTag } = this;
const transitionInfo = await wex.db.runReadWriteTx(
- ["depositGroups"],
+ { storeNames: ["depositGroups"] },
async (tx) => {
const dg = await tx.depositGroups.get(depositGroupId);
if (!dg) {
@@ -278,7 +281,7 @@ export class DepositTransactionContext implements TransactionContext {
async failTransaction(): Promise<void> {
const { wex, depositGroupId, transactionId, taskId } = this;
const transitionInfo = await wex.db.runReadWriteTx(
- ["depositGroups"],
+ { storeNames: ["depositGroups"] },
async (tx) => {
const dg = await tx.depositGroups.get(depositGroupId);
if (!dg) {
@@ -435,7 +438,7 @@ async function refundDepositGroup(
default: {
const coinPub = payCoinSelection.coinPubs[i];
const coinExchange = await wex.db.runReadOnlyTx(
- ["coins"],
+ { storeNames: ["coins"] },
async (tx) => {
const coinRecord = await tx.coins.get(coinPub);
checkDbInvariant(!!coinRecord);
@@ -497,14 +500,16 @@ async function refundDepositGroup(
const currency = Amounts.currencyOf(depositGroup.totalPayCost);
const res = await wex.db.runReadWriteTx(
- [
- "depositGroups",
- "refreshGroups",
- "refreshSessions",
- "coins",
- "denominations",
- "coinAvailability",
- ],
+ {
+ storeNames: [
+ "depositGroups",
+ "refreshGroups",
+ "refreshSessions",
+ "coins",
+ "denominations",
+ "coinAvailability",
+ ],
+ },
async (tx) => {
const newDg = await tx.depositGroups.get(depositGroup.depositGroupId);
if (!newDg) {
@@ -571,7 +576,7 @@ async function waitForRefreshOnDepositGroup(
depositGroupId: depositGroup.depositGroupId,
});
const transitionInfo = await wex.db.runReadWriteTx(
- ["depositGroups", "refreshGroups"],
+ { storeNames: ["depositGroups", "refreshGroups"] },
async (tx) => {
const refreshGroup = await tx.refreshGroups.get(abortRefreshGroupId);
let newOpState: DepositOperationStatus | undefined;
@@ -660,7 +665,7 @@ async function processDepositGroupPendingKyc(
kycStatusRes.status === HttpStatusCode.NoContent
) {
const transitionInfo = await wex.db.runReadWriteTx(
- ["depositGroups"],
+ { storeNames: ["depositGroups"] },
async (tx) => {
const newDg = await tx.depositGroups.get(depositGroupId);
if (!newDg) {
@@ -719,7 +724,7 @@ async function transitionToKycRequired(
const kycStatus = await kycStatusReq.json();
logger.info(`kyc status: ${j2s(kycStatus)}`);
const transitionInfo = await wex.db.runReadWriteTx(
- ["depositGroups"],
+ { storeNames: ["depositGroups"] },
async (tx) => {
const dg = await tx.depositGroups.get(depositGroupId);
if (!dg) {
@@ -768,7 +773,7 @@ async function processDepositGroupPendingTrack(
const coinPub = payCoinSelection.coinPubs[i];
// FIXME: Make the URL part of the coin selection?
const exchangeBaseUrl = await wex.db.runReadWriteTx(
- ["coins"],
+ { storeNames: ["coins"] },
async (tx) => {
const coinRecord = await tx.coins.get(coinPub);
checkDbInvariant(!!coinRecord);
@@ -844,41 +849,44 @@ async function processDepositGroupPendingTrack(
}
if (updatedTxStatus !== undefined) {
- await wex.db.runReadWriteTx(["depositGroups"], async (tx) => {
- const dg = await tx.depositGroups.get(depositGroupId);
- if (!dg) {
- return;
- }
- if (!dg.statusPerCoin) {
- return;
- }
- if (updatedTxStatus !== undefined) {
- dg.statusPerCoin[i] = updatedTxStatus;
- }
- if (newWiredCoin) {
- /**
- * FIXME: if there is a new wire information from the exchange
- * it should add up to the previous tracking states.
- *
- * This may loose information by overriding prev state.
- *
- * And: add checks to integration tests
- */
- if (!dg.trackingState) {
- dg.trackingState = {};
+ await wex.db.runReadWriteTx(
+ { storeNames: ["depositGroups"] },
+ async (tx) => {
+ const dg = await tx.depositGroups.get(depositGroupId);
+ if (!dg) {
+ return;
}
-
- dg.trackingState[newWiredCoin.id] = newWiredCoin.value;
- }
- await tx.depositGroups.put(dg);
- });
+ if (!dg.statusPerCoin) {
+ return;
+ }
+ if (updatedTxStatus !== undefined) {
+ dg.statusPerCoin[i] = updatedTxStatus;
+ }
+ if (newWiredCoin) {
+ /**
+ * FIXME: if there is a new wire information from the exchange
+ * it should add up to the previous tracking states.
+ *
+ * This may loose information by overriding prev state.
+ *
+ * And: add checks to integration tests
+ */
+ if (!dg.trackingState) {
+ dg.trackingState = {};
+ }
+
+ dg.trackingState[newWiredCoin.id] = newWiredCoin.value;
+ }
+ await tx.depositGroups.put(dg);
+ },
+ );
}
}
let allWired = true;
const transitionInfo = await wex.db.runReadWriteTx(
- ["depositGroups"],
+ { storeNames: ["depositGroups"] },
async (tx) => {
const dg = await tx.depositGroups.get(depositGroupId);
if (!dg) {
@@ -929,7 +937,7 @@ async function processDepositGroupPendingDeposit(
logger.info("processing deposit group in pending(deposit)");
const depositGroupId = depositGroup.depositGroupId;
const contractTermsRec = await wex.db.runReadOnlyTx(
- ["contractTerms"],
+ { storeNames: ["contractTerms"] },
async (tx) => {
return tx.contractTerms.get(depositGroup.contractTermsHash);
},
@@ -987,14 +995,16 @@ async function processDepositGroupPendingDeposit(
}
const transitionDone = await wex.db.runReadWriteTx(
- [
- "depositGroups",
- "coins",
- "coinAvailability",
- "refreshGroups",
- "refreshSessions",
- "denominations",
- ],
+ {
+ storeNames: [
+ "depositGroups",
+ "coins",
+ "coinAvailability",
+ "refreshGroups",
+ "refreshSessions",
+ "denominations",
+ ],
+ },
async (tx) => {
const dg = await tx.depositGroups.get(depositGroupId);
if (!dg) {
@@ -1094,27 +1104,30 @@ async function processDepositGroupPendingDeposit(
codecForBatchDepositSuccess(),
);
- await wex.db.runReadWriteTx(["depositGroups"], async (tx) => {
- const dg = await tx.depositGroups.get(depositGroupId);
- if (!dg) {
- return;
- }
- if (!dg.statusPerCoin) {
- return;
- }
- for (const batchIndex of batchIndexes) {
- const coinStatus = dg.statusPerCoin[batchIndex];
- switch (coinStatus) {
- case DepositElementStatus.DepositPending:
- dg.statusPerCoin[batchIndex] = DepositElementStatus.Tracking;
- await tx.depositGroups.put(dg);
+ await wex.db.runReadWriteTx(
+ { storeNames: ["depositGroups"] },
+ async (tx) => {
+ const dg = await tx.depositGroups.get(depositGroupId);
+ if (!dg) {
+ return;
}
- }
- });
+ if (!dg.statusPerCoin) {
+ return;
+ }
+ for (const batchIndex of batchIndexes) {
+ const coinStatus = dg.statusPerCoin[batchIndex];
+ switch (coinStatus) {
+ case DepositElementStatus.DepositPending:
+ dg.statusPerCoin[batchIndex] = DepositElementStatus.Tracking;
+ await tx.depositGroups.put(dg);
+ }
+ }
+ },
+ );
}
const transitionInfo = await wex.db.runReadWriteTx(
- ["depositGroups"],
+ { storeNames: ["depositGroups"] },
async (tx) => {
const dg = await tx.depositGroups.get(depositGroupId);
if (!dg) {
@@ -1140,7 +1153,7 @@ export async function processDepositGroup(
depositGroupId: string,
): Promise<TaskRunResult> {
const depositGroup = await wex.db.runReadOnlyTx(
- ["depositGroups"],
+ { storeNames: ["depositGroups"] },
async (tx) => {
return tx.depositGroups.get(depositGroupId);
},
@@ -1174,7 +1187,7 @@ async function getExchangeWireFee(
time: TalerProtocolTimestamp,
): Promise<WireFee> {
const exchangeDetails = await wex.db.runReadOnlyTx(
- ["exchangeDetails", "exchanges"],
+ { storeNames: ["exchangeDetails", "exchanges"] },
async (tx) => {
const ex = await tx.exchanges.get(baseUrl);
if (!ex || !ex.detailsPointer) return undefined;
@@ -1281,19 +1294,22 @@ export async function checkDepositGroup(
const exchangeInfos: ExchangeHandle[] = [];
- await wex.db.runReadOnlyTx(["exchangeDetails", "exchanges"], async (tx) => {
- const allExchanges = await tx.exchanges.iter().toArray();
- for (const e of allExchanges) {
- const details = await getExchangeWireDetailsInTx(tx, e.baseUrl);
- if (!details || amount.currency !== details.currency) {
- continue;
+ await wex.db.runReadOnlyTx(
+ { storeNames: ["exchangeDetails", "exchanges"] },
+ async (tx) => {
+ const allExchanges = await tx.exchanges.iter().toArray();
+ for (const e of allExchanges) {
+ const details = await getExchangeWireDetailsInTx(tx, e.baseUrl);
+ if (!details || amount.currency !== details.currency) {
+ continue;
+ }
+ exchangeInfos.push({
+ master_pub: details.masterPublicKey,
+ url: e.baseUrl,
+ });
}
- exchangeInfos.push({
- master_pub: details.masterPublicKey,
- url: e.baseUrl,
- });
- }
- });
+ },
+ );
const now = AbsoluteTime.now();
const nowRounded = AbsoluteTime.toProtocolTimestamp(now);
@@ -1404,19 +1420,22 @@ export async function createDepositGroup(
const exchangeInfos: { url: string; master_pub: string }[] = [];
- await wex.db.runReadOnlyTx(["exchanges", "exchangeDetails"], async (tx) => {
- const allExchanges = await tx.exchanges.iter().toArray();
- for (const e of allExchanges) {
- const details = await getExchangeWireDetailsInTx(tx, e.baseUrl);
- if (!details || amount.currency !== details.currency) {
- continue;
+ await wex.db.runReadOnlyTx(
+ { storeNames: ["exchanges", "exchangeDetails"] },
+ async (tx) => {
+ const allExchanges = await tx.exchanges.iter().toArray();
+ for (const e of allExchanges) {
+ const details = await getExchangeWireDetailsInTx(tx, e.baseUrl);
+ if (!details || amount.currency !== details.currency) {
+ continue;
+ }
+ exchangeInfos.push({
+ master_pub: details.masterPublicKey,
+ url: e.baseUrl,
+ });
}
- exchangeInfos.push({
- master_pub: details.masterPublicKey,
- url: e.baseUrl,
- });
- }
- });
+ },
+ );
const now = AbsoluteTime.now();
const wireDeadline = AbsoluteTime.toProtocolTimestamp(
@@ -1569,16 +1588,18 @@ export async function createDepositGroup(
const transactionId = ctx.transactionId;
const newTxState = await wex.db.runReadWriteTx(
- [
- "depositGroups",
- "coins",
- "recoupGroups",
- "denominations",
- "refreshGroups",
- "refreshSessions",
- "coinAvailability",
- "contractTerms",
- ],
+ {
+ storeNames: [
+ "depositGroups",
+ "coins",
+ "recoupGroups",
+ "denominations",
+ "refreshGroups",
+ "refreshSessions",
+ "coinAvailability",
+ "contractTerms",
+ ],
+ },
async (tx) => {
if (depositGroup.payCoinSelection) {
await spendCoins(wex, tx, {
@@ -1635,7 +1656,7 @@ export async function getCounterpartyEffectiveDepositAmount(
const exchangeSet: Set<string> = new Set();
await wex.db.runReadOnlyTx(
- ["coins", "denominations", "exchangeDetails", "exchanges"],
+ { storeNames: ["coins", "denominations", "exchangeDetails", "exchanges"] },
async (tx) => {
for (let i = 0; i < pcs.length; i++) {
const denom = await getDenomInfo(
@@ -1694,10 +1715,9 @@ async function getTotalFeesForDepositAmount(
const coinFee: AmountJson[] = [];
const refreshFee: AmountJson[] = [];
const exchangeSet: Set<string> = new Set();
- const currency = Amounts.currencyOf(total);
await wex.db.runReadOnlyTx(
- ["coins", "denominations", "exchanges", "exchangeDetails"],
+ { storeNames: ["coins", "denominations", "exchanges", "exchangeDetails"] },
async (tx) => {
for (let i = 0; i < pcs.length; i++) {
const denom = await getDenomInfo(
diff --git a/packages/taler-wallet-core/src/dev-experiments.ts b/packages/taler-wallet-core/src/dev-experiments.ts
index db2ff5d06..5cb9400be 100644
--- a/packages/taler-wallet-core/src/dev-experiments.ts
+++ b/packages/taler-wallet-core/src/dev-experiments.ts
@@ -79,23 +79,26 @@ export async function applyDevExperiment(
}
case "insert-pending-refresh": {
const refreshGroupId = encodeCrock(getRandomBytes(32));
- await wex.db.runReadWriteTx(["refreshGroups"], async (tx) => {
- const newRg: RefreshGroupRecord = {
- currency: "TESTKUDOS",
- expectedOutputPerCoin: [],
- inputPerCoin: [],
- oldCoinPubs: [],
- operationStatus: RefreshOperationStatus.Pending,
- reason: RefreshReason.Manual,
- refreshGroupId,
- statusPerCoin: [],
- timestampCreated: timestampPreciseToDb(TalerPreciseTimestamp.now()),
- timestampFinished: undefined,
- originatingTransactionId: undefined,
- infoPerExchange: {},
- };
- await tx.refreshGroups.put(newRg);
- });
+ await wex.db.runReadWriteTx(
+ { storeNames: ["refreshGroups"] },
+ async (tx) => {
+ const newRg: RefreshGroupRecord = {
+ currency: "TESTKUDOS",
+ expectedOutputPerCoin: [],
+ inputPerCoin: [],
+ oldCoinPubs: [],
+ operationStatus: RefreshOperationStatus.Pending,
+ reason: RefreshReason.Manual,
+ refreshGroupId,
+ statusPerCoin: [],
+ timestampCreated: timestampPreciseToDb(TalerPreciseTimestamp.now()),
+ timestampFinished: undefined,
+ originatingTransactionId: undefined,
+ infoPerExchange: {},
+ };
+ await tx.refreshGroups.put(newRg);
+ },
+ );
wex.taskScheduler.startShepherdTask(
constructTaskIdentifier({
tag: PendingTaskType.Refresh,
@@ -105,23 +108,26 @@ export async function applyDevExperiment(
return;
}
case "insert-denom-loss": {
- await wex.db.runReadWriteTx(["denomLossEvents"], async (tx) => {
- const eventId = encodeCrock(getRandomBytes(32));
- const newRg: DenomLossEventRecord = {
- amount: "TESTKUDOS:42",
- currency: "TESTKUDOS",
- exchangeBaseUrl: "https://exchange.test.taler.net/",
- denomLossEventId: eventId,
- denomPubHashes: [
- encodeCrock(getRandomBytes(64)),
- encodeCrock(getRandomBytes(64)),
- ],
- eventType: DenomLossEventType.DenomExpired,
- status: DenomLossStatus.Done,
- timestampCreated: timestampPreciseToDb(TalerPreciseTimestamp.now()),
- };
- await tx.denomLossEvents.put(newRg);
- });
+ await wex.db.runReadWriteTx(
+ { storeNames: ["denomLossEvents"] },
+ async (tx) => {
+ const eventId = encodeCrock(getRandomBytes(32));
+ const newRg: DenomLossEventRecord = {
+ amount: "TESTKUDOS:42",
+ currency: "TESTKUDOS",
+ exchangeBaseUrl: "https://exchange.test.taler.net/",
+ denomLossEventId: eventId,
+ denomPubHashes: [
+ encodeCrock(getRandomBytes(64)),
+ encodeCrock(getRandomBytes(64)),
+ ],
+ eventType: DenomLossEventType.DenomExpired,
+ status: DenomLossStatus.Done,
+ timestampCreated: timestampPreciseToDb(TalerPreciseTimestamp.now()),
+ };
+ await tx.denomLossEvents.put(newRg);
+ },
+ );
return;
}
}
diff --git a/packages/taler-wallet-core/src/exchanges.ts b/packages/taler-wallet-core/src/exchanges.ts
index 5f0c744e2..d5ca7abbf 100644
--- a/packages/taler-wallet-core/src/exchanges.ts
+++ b/packages/taler-wallet-core/src/exchanges.ts
@@ -312,8 +312,8 @@ async function makeExchangeListItem(
): Promise<ExchangeListItem> {
const lastUpdateErrorInfo: OperationErrorInfo | undefined = lastError
? {
- error: lastError,
- }
+ error: lastError,
+ }
: undefined;
let scopeInfo: ScopeInfo | undefined = undefined;
@@ -377,13 +377,15 @@ export async function lookupExchangeByUri(
req: GetExchangeEntryByUrlRequest,
): Promise<ExchangeListItem> {
return await wex.db.runReadOnlyTx(
- [
- "exchanges",
- "exchangeDetails",
- "operationRetries",
- "globalCurrencyAuditors",
- "globalCurrencyExchanges",
- ],
+ {
+ storeNames: [
+ "exchanges",
+ "exchangeDetails",
+ "operationRetries",
+ "globalCurrencyAuditors",
+ "globalCurrencyExchanges",
+ ],
+ },
async (tx) => {
const exchangeRec = await tx.exchanges.get(req.exchangeBaseUrl);
if (!exchangeRec) {
@@ -414,7 +416,7 @@ export async function acceptExchangeTermsOfService(
exchangeBaseUrl: string,
): Promise<void> {
const notif = await wex.db.runReadWriteTx(
- ["exchangeDetails", "exchanges"],
+ { storeNames: ["exchangeDetails", "exchanges"] },
async (tx) => {
const exch = await tx.exchanges.get(exchangeBaseUrl);
if (exch && exch.tosCurrentEtag) {
@@ -449,7 +451,7 @@ export async function forgetExchangeTermsOfService(
exchangeBaseUrl: string,
): Promise<void> {
const notif = await wex.db.runReadWriteTx(
- ["exchangeDetails", "exchanges"],
+ { storeNames: ["exchangeDetails", "exchanges"] },
async (tx) => {
const exch = await tx.exchanges.get(exchangeBaseUrl);
if (exch) {
@@ -915,12 +917,13 @@ async function startUpdateExchangeEntry(
const canonBaseUrl = canonicalizeBaseUrl(exchangeBaseUrl);
logger.info(
- `starting update of exchange entry ${canonBaseUrl}, forced=${options.forceUpdate ?? false
+ `starting update of exchange entry ${canonBaseUrl}, forced=${
+ options.forceUpdate ?? false
}`,
);
const { notification } = await wex.db.runReadWriteTx(
- ["exchanges", "exchangeDetails"],
+ { storeNames: ["exchanges", "exchangeDetails"] },
async (tx) => {
wex.ws.exchangeCache.clear();
return provideExchangeRecordInTx(wex.ws, tx, exchangeBaseUrl);
@@ -935,7 +938,7 @@ async function startUpdateExchangeEntry(
const { oldExchangeState, newExchangeState, taskId } =
await wex.db.runReadWriteTx(
- ["exchanges", "operationRetries"],
+ { storeNames: ["exchanges", "operationRetries"] },
async (tx) => {
const r = await tx.exchanges.get(canonBaseUrl);
if (!r) {
@@ -1029,13 +1032,15 @@ async function internalWaitReadyExchange(
logger.info(`waiting for ready exchange ${canonUrl}`);
const { exchange, exchangeDetails, retryInfo, scopeInfo } =
await wex.db.runReadOnlyTx(
- [
- "exchanges",
- "exchangeDetails",
- "operationRetries",
- "globalCurrencyAuditors",
- "globalCurrencyExchanges",
- ],
+ {
+ storeNames: [
+ "exchanges",
+ "exchangeDetails",
+ "operationRetries",
+ "globalCurrencyAuditors",
+ "globalCurrencyExchanges",
+ ],
+ },
async (tx) => {
const exchange = await tx.exchanges.get(canonUrl);
const exchangeDetails = await getExchangeRecordsInternal(
@@ -1290,7 +1295,7 @@ export async function updateExchangeFromUrlHandler(
exchangeBaseUrl = canonicalizeBaseUrl(exchangeBaseUrl);
const oldExchangeRec = await wex.db.runReadOnlyTx(
- ["exchanges"],
+ { storeNames: ["exchanges"] },
async (tx) => {
return tx.exchanges.get(exchangeBaseUrl);
},
@@ -1450,17 +1455,19 @@ export async function updateExchangeFromUrlHandler(
let peerPaymentsDisabled = checkPeerPaymentsDisabled(keysInfo);
const updated = await wex.db.runReadWriteTx(
- [
- "exchanges",
- "exchangeDetails",
- "exchangeSignKeys",
- "denominations",
- "coins",
- "refreshGroups",
- "recoupGroups",
- "coinAvailability",
- "denomLossEvents",
- ],
+ {
+ storeNames: [
+ "exchanges",
+ "exchangeDetails",
+ "exchangeSignKeys",
+ "denominations",
+ "coins",
+ "refreshGroups",
+ "recoupGroups",
+ "coinAvailability",
+ "denomLossEvents",
+ ],
+ },
async (tx) => {
const r = await tx.exchanges.get(exchangeBaseUrl);
if (!r) {
@@ -1666,14 +1673,16 @@ export async function updateExchangeFromUrlHandler(
if (refreshCheckNecessary) {
// Do auto-refresh.
await wex.db.runReadWriteTx(
- [
- "coins",
- "denominations",
- "coinAvailability",
- "refreshGroups",
- "refreshSessions",
- "exchanges",
- ],
+ {
+ storeNames: [
+ "coins",
+ "denominations",
+ "coinAvailability",
+ "refreshGroups",
+ "refreshSessions",
+ "exchanges",
+ ],
+ },
async (tx) => {
const exchange = await tx.exchanges.get(exchangeBaseUrl);
if (!exchange || !exchange.detailsPointer) {
@@ -1969,7 +1978,7 @@ export class DenomLossTransactionContext implements TransactionContext {
}
async deleteTransaction(): Promise<void> {
const transitionInfo = await this.wex.db.runReadWriteTx(
- ["denomLossEvents"],
+ { storeNames: ["denomLossEvents"] },
async (tx) => {
const rec = await tx.denomLossEvents.get(this.denomLossEventId);
if (rec) {
@@ -2080,7 +2089,7 @@ export async function getExchangePaytoUri(
// We do the update here, since the exchange might not even exist
// yet in our database.
const details = await wex.db.runReadOnlyTx(
- ["exchanges", "exchangeDetails"],
+ { storeNames: ["exchanges", "exchangeDetails"] },
async (tx) => {
return getExchangeRecordsInternal(tx, exchangeBaseUrl);
},
@@ -2122,7 +2131,7 @@ export async function getExchangeTos(
acceptLanguage,
);
- await wex.db.runReadWriteTx(["exchanges"], async (tx) => {
+ await wex.db.runReadWriteTx({ storeNames: ["exchanges"] }, async (tx) => {
const updateExchangeEntry = await tx.exchanges.get(exchangeBaseUrl);
if (updateExchangeEntry) {
updateExchangeEntry.tosCurrentEtag = tosDownload.tosEtag;
@@ -2179,13 +2188,15 @@ export async function listExchanges(
): Promise<ExchangesListResponse> {
const exchanges: ExchangeListItem[] = [];
await wex.db.runReadOnlyTx(
- [
- "exchanges",
- "operationRetries",
- "exchangeDetails",
- "globalCurrencyAuditors",
- "globalCurrencyExchanges",
- ],
+ {
+ storeNames: [
+ "exchanges",
+ "operationRetries",
+ "exchangeDetails",
+ "globalCurrencyAuditors",
+ "globalCurrencyExchanges",
+ ],
+ },
async (tx) => {
const exchangeRecords = await tx.exchanges.iter().toArray();
for (const r of exchangeRecords) {
@@ -2262,7 +2273,7 @@ export async function getExchangeDetailedInfo(
exchangeBaseurl: string,
): Promise<ExchangeDetailedResponse> {
const exchange = await wex.db.runReadOnlyTx(
- ["exchanges", "exchangeDetails", "denominations"],
+ { storeNames: ["exchanges", "exchangeDetails", "denominations"] },
async (tx) => {
const ex = await tx.exchanges.get(exchangeBaseurl);
const dp = ex?.detailsPointer;
@@ -2520,17 +2531,19 @@ export async function deleteExchange(
let inUse: boolean = false;
const exchangeBaseUrl = canonicalizeBaseUrl(req.exchangeBaseUrl);
await wex.db.runReadWriteTx(
- [
- "exchanges",
- "exchangeDetails",
- "transactions",
- "coinAvailability",
- "coins",
- "denominations",
- "exchangeSignKeys",
- "withdrawalGroups",
- "planchets",
- ],
+ {
+ storeNames: [
+ "exchanges",
+ "exchangeDetails",
+ "transactions",
+ "coinAvailability",
+ "coins",
+ "denominations",
+ "exchangeSignKeys",
+ "withdrawalGroups",
+ "planchets",
+ ],
+ },
async (tx) => {
const exchangeRec = await tx.exchanges.get(exchangeBaseUrl);
if (!exchangeRec) {
@@ -2562,7 +2575,7 @@ export async function getExchangeResources(
): Promise<GetExchangeResourcesResponse> {
// Withdrawals include internal withdrawals from peer transactions
const res = await wex.db.runReadOnlyTx(
- ["exchanges", "withdrawalGroups", "coins"],
+ { storeNames: ["exchanges", "withdrawalGroups", "coins"] },
async (tx) => {
const exchangeRecord = await tx.exchanges.get(exchangeBaseUrl);
if (!exchangeRecord) {
diff --git a/packages/taler-wallet-core/src/instructedAmountConversion.ts b/packages/taler-wallet-core/src/instructedAmountConversion.ts
index 63ccb8b56..1f7d95959 100644
--- a/packages/taler-wallet-core/src/instructedAmountConversion.ts
+++ b/packages/taler-wallet-core/src/instructedAmountConversion.ts
@@ -150,7 +150,14 @@ async function getAvailableDenoms(
const operationType = getOperationType(TransactionType.Deposit);
return await wex.db.runReadOnlyTx(
- ["exchanges", "exchangeDetails", "denominations", "coinAvailability"],
+ {
+ storeNames: [
+ "exchanges",
+ "exchangeDetails",
+ "denominations",
+ "coinAvailability",
+ ],
+ },
async (tx) => {
const list: CoinInfo[] = [];
const exchanges: Record<string, ExchangeInfo> = {};
diff --git a/packages/taler-wallet-core/src/observable-wrappers.ts b/packages/taler-wallet-core/src/observable-wrappers.ts
index 7cd65f38e..626899d9e 100644
--- a/packages/taler-wallet-core/src/observable-wrappers.ts
+++ b/packages/taler-wallet-core/src/observable-wrappers.ts
@@ -195,7 +195,9 @@ export class ObservableDbAccess<StoreMap> implements DbAccess<StoreMap> {
}
async runReadWriteTx<T, StoreNameArray extends StoreNames<StoreMap>[]>(
- storeNames: StoreNameArray,
+ opts: {
+ storeNames: StoreNameArray;
+ },
txf: (tx: DbReadWriteTransaction<StoreMap, StoreNameArray>) => Promise<T>,
): Promise<T> {
const location = getCallerInfo();
@@ -205,7 +207,7 @@ export class ObservableDbAccess<StoreMap> implements DbAccess<StoreMap> {
location,
});
try {
- const ret = await this.impl.runReadWriteTx(storeNames, txf);
+ const ret = await this.impl.runReadWriteTx(opts, txf);
this.oc.observe({
type: ObservabilityEventType.DbQueryFinishSuccess,
name: "<unknown>",
@@ -223,7 +225,9 @@ export class ObservableDbAccess<StoreMap> implements DbAccess<StoreMap> {
}
async runReadOnlyTx<T, StoreNameArray extends StoreNames<StoreMap>[]>(
- storeNames: StoreNameArray,
+ opts: {
+ storeNames: StoreNameArray;
+ },
txf: (tx: DbReadOnlyTransaction<StoreMap, StoreNameArray>) => Promise<T>,
): Promise<T> {
const location = getCallerInfo();
@@ -233,7 +237,7 @@ export class ObservableDbAccess<StoreMap> implements DbAccess<StoreMap> {
name: "<unknown>",
location,
});
- const ret = await this.impl.runReadOnlyTx(storeNames, txf);
+ const ret = await this.impl.runReadOnlyTx(opts, txf);
this.oc.observe({
type: ObservabilityEventType.DbQueryFinishSuccess,
name: "<unknown>",
diff --git a/packages/taler-wallet-core/src/pay-merchant.ts b/packages/taler-wallet-core/src/pay-merchant.ts
index f9d20d415..49ebc282e 100644
--- a/packages/taler-wallet-core/src/pay-merchant.ts
+++ b/packages/taler-wallet-core/src/pay-merchant.ts
@@ -200,7 +200,7 @@ export class PayMerchantTransactionContext implements TransactionContext {
const ws = this.wex;
const extraStores = opts.extraStores ?? [];
const transitionInfo = await ws.db.runReadWriteTx(
- ["purchases", ...extraStores],
+ { storeNames: ["purchases", ...extraStores] },
async (tx) => {
const purchaseRec = await tx.purchases.get(this.proposalId);
if (!purchaseRec) {
@@ -227,26 +227,29 @@ export class PayMerchantTransactionContext implements TransactionContext {
async deleteTransaction(): Promise<void> {
const { wex: ws, proposalId } = this;
- await ws.db.runReadWriteTx(["purchases", "tombstones"], async (tx) => {
- let found = false;
- const purchase = await tx.purchases.get(proposalId);
- if (purchase) {
- found = true;
- await tx.purchases.delete(proposalId);
- }
- if (found) {
- await tx.tombstones.put({
- id: TombstoneTag.DeletePayment + ":" + proposalId,
- });
- }
- });
+ await ws.db.runReadWriteTx(
+ { storeNames: ["purchases", "tombstones"] },
+ async (tx) => {
+ let found = false;
+ const purchase = await tx.purchases.get(proposalId);
+ if (purchase) {
+ found = true;
+ await tx.purchases.delete(proposalId);
+ }
+ if (found) {
+ await tx.tombstones.put({
+ id: TombstoneTag.DeletePayment + ":" + proposalId,
+ });
+ }
+ },
+ );
}
async suspendTransaction(): Promise<void> {
const { wex, proposalId, transactionId } = this;
wex.taskScheduler.stopShepherdTask(this.taskId);
const transitionInfo = await wex.db.runReadWriteTx(
- ["purchases"],
+ { storeNames: ["purchases"] },
async (tx) => {
const purchase = await tx.purchases.get(proposalId);
if (!purchase) {
@@ -268,15 +271,17 @@ export class PayMerchantTransactionContext implements TransactionContext {
async abortTransaction(): Promise<void> {
const { wex, proposalId, transactionId } = this;
const transitionInfo = await wex.db.runReadWriteTx(
- [
- "purchases",
- "refreshGroups",
- "refreshSessions",
- "denominations",
- "coinAvailability",
- "coins",
- "operationRetries",
- ],
+ {
+ storeNames: [
+ "purchases",
+ "refreshGroups",
+ "refreshSessions",
+ "denominations",
+ "coinAvailability",
+ "coins",
+ "operationRetries",
+ ],
+ },
async (tx) => {
const purchase = await tx.purchases.get(proposalId);
if (!purchase) {
@@ -344,7 +349,7 @@ export class PayMerchantTransactionContext implements TransactionContext {
async resumeTransaction(): Promise<void> {
const { wex, proposalId, transactionId, taskId: retryTag } = this;
const transitionInfo = await wex.db.runReadWriteTx(
- ["purchases"],
+ { storeNames: ["purchases"] },
async (tx) => {
const purchase = await tx.purchases.get(proposalId);
if (!purchase) {
@@ -367,14 +372,16 @@ export class PayMerchantTransactionContext implements TransactionContext {
async failTransaction(): Promise<void> {
const { wex, proposalId, transactionId } = this;
const transitionInfo = await wex.db.runReadWriteTx(
- [
- "purchases",
- "refreshGroups",
- "denominations",
- "coinAvailability",
- "coins",
- "operationRetries",
- ],
+ {
+ storeNames: [
+ "purchases",
+ "refreshGroups",
+ "denominations",
+ "coinAvailability",
+ "coins",
+ "operationRetries",
+ ],
+ },
async (tx) => {
const purchase = await tx.purchases.get(proposalId);
if (!purchase) {
@@ -415,15 +422,18 @@ export class RefundTransactionContext implements TransactionContext {
async deleteTransaction(): Promise<void> {
const { wex, refundGroupId, transactionId } = this;
- await wex.db.runReadWriteTx(["refundGroups", "tombstones"], async (tx) => {
- const refundRecord = await tx.refundGroups.get(refundGroupId);
- if (!refundRecord) {
- return;
- }
- await tx.refundGroups.delete(refundGroupId);
- await tx.tombstones.put({ id: transactionId });
- // FIXME: Also tombstone the refund items, so that they won't reappear.
- });
+ await wex.db.runReadWriteTx(
+ { storeNames: ["refundGroups", "tombstones"] },
+ async (tx) => {
+ const refundRecord = await tx.refundGroups.get(refundGroupId);
+ if (!refundRecord) {
+ return;
+ }
+ await tx.refundGroups.delete(refundGroupId);
+ await tx.tombstones.put({ id: transactionId });
+ // FIXME: Also tombstone the refund items, so that they won't reappear.
+ },
+ );
}
suspendTransaction(): Promise<void> {
@@ -455,31 +465,34 @@ export async function getTotalPaymentCost(
currency: string,
pcs: SelectedProspectiveCoin[],
): Promise<AmountJson> {
- return wex.db.runReadOnlyTx(["coins", "denominations"], async (tx) => {
- const costs: AmountJson[] = [];
- for (let i = 0; i < pcs.length; i++) {
- const denom = await tx.denominations.get([
- pcs[i].exchangeBaseUrl,
- pcs[i].denomPubHash,
- ]);
- if (!denom) {
- throw Error(
- "can't calculate payment cost, denomination for coin not found",
+ return wex.db.runReadOnlyTx(
+ { storeNames: ["coins", "denominations"] },
+ async (tx) => {
+ const costs: AmountJson[] = [];
+ for (let i = 0; i < pcs.length; i++) {
+ const denom = await tx.denominations.get([
+ pcs[i].exchangeBaseUrl,
+ pcs[i].denomPubHash,
+ ]);
+ if (!denom) {
+ throw Error(
+ "can't calculate payment cost, denomination for coin not found",
+ );
+ }
+ const amountLeft = Amounts.sub(denom.value, pcs[i].contribution).amount;
+ const refreshCost = await getTotalRefreshCost(
+ wex,
+ tx,
+ DenominationRecord.toDenomInfo(denom),
+ amountLeft,
);
+ costs.push(Amounts.parseOrThrow(pcs[i].contribution));
+ costs.push(refreshCost);
}
- const amountLeft = Amounts.sub(denom.value, pcs[i].contribution).amount;
- const refreshCost = await getTotalRefreshCost(
- wex,
- tx,
- DenominationRecord.toDenomInfo(denom),
- amountLeft,
- );
- costs.push(Amounts.parseOrThrow(pcs[i].contribution));
- costs.push(refreshCost);
- }
- const zero = Amounts.zeroOfCurrency(currency);
- return Amounts.sum([zero, ...costs]).amount;
- });
+ const zero = Amounts.zeroOfCurrency(currency);
+ return Amounts.sum([zero, ...costs]).amount;
+ },
+ );
}
async function failProposalPermanently(
@@ -492,7 +505,7 @@ async function failProposalPermanently(
proposalId,
});
const transitionInfo = await wex.db.runReadWriteTx(
- ["purchases"],
+ { storeNames: ["purchases"] },
async (tx) => {
const p = await tx.purchases.get(proposalId);
if (!p) {
@@ -554,7 +567,10 @@ export async function expectProposalDownload(
if (parentTx) {
return getFromTransaction(parentTx);
}
- return await wex.db.runReadOnlyTx(["contractTerms"], getFromTransaction);
+ return await wex.db.runReadOnlyTx(
+ { storeNames: ["contractTerms"] },
+ getFromTransaction,
+ );
}
export function extractContractData(
@@ -593,9 +609,12 @@ async function processDownloadProposal(
wex: WalletExecutionContext,
proposalId: string,
): Promise<TaskRunResult> {
- const proposal = await wex.db.runReadOnlyTx(["purchases"], async (tx) => {
- return await tx.purchases.get(proposalId);
- });
+ const proposal = await wex.db.runReadOnlyTx(
+ { storeNames: ["purchases"] },
+ async (tx) => {
+ return await tx.purchases.get(proposalId);
+ },
+ );
if (!proposal) {
return TaskRunResult.finished();
@@ -766,7 +785,7 @@ async function processDownloadProposal(
logger.trace(`extracted contract data: ${j2s(contractData)}`);
const transitionInfo = await wex.db.runReadWriteTx(
- ["purchases", "contractTerms"],
+ { storeNames: ["purchases", "contractTerms"] },
async (tx) => {
const p = await tx.purchases.get(proposalId);
if (!p) {
@@ -839,12 +858,15 @@ async function createOrReusePurchase(
claimToken: string | undefined,
noncePriv: string | undefined,
): Promise<string> {
- const oldProposals = await wex.db.runReadOnlyTx(["purchases"], async (tx) => {
- return tx.purchases.indexes.byUrlAndOrderId.getAll([
- merchantBaseUrl,
- orderId,
- ]);
- });
+ const oldProposals = await wex.db.runReadOnlyTx(
+ { storeNames: ["purchases"] },
+ async (tx) => {
+ return tx.purchases.indexes.byUrlAndOrderId.getAll([
+ merchantBaseUrl,
+ orderId,
+ ]);
+ },
+ );
const oldProposal = oldProposals.find((p) => {
return (
@@ -878,7 +900,7 @@ async function createOrReusePurchase(
// if this transaction was shared and the order is paid then it
// means that another wallet already paid the proposal
const transitionInfo = await wex.db.runReadWriteTx(
- ["purchases"],
+ { storeNames: ["purchases"] },
async (tx) => {
const p = await tx.purchases.get(oldProposal.proposalId);
if (!p) {
@@ -944,7 +966,7 @@ async function createOrReusePurchase(
};
const transitionInfo = await wex.db.runReadWriteTx(
- ["purchases"],
+ { storeNames: ["purchases"] },
async (tx) => {
await tx.purchases.put(proposalRecord);
const oldTxState: TransactionState = {
@@ -978,7 +1000,7 @@ async function storeFirstPaySuccess(
});
const now = AbsoluteTime.toPreciseTimestamp(AbsoluteTime.now());
const transitionInfo = await wex.db.runReadWriteTx(
- ["contractTerms", "purchases"],
+ { storeNames: ["contractTerms", "purchases"] },
async (tx) => {
const purchase = await tx.purchases.get(proposalId);
@@ -1042,7 +1064,7 @@ async function storePayReplaySuccess(
proposalId,
});
const transitionInfo = await wex.db.runReadWriteTx(
- ["purchases"],
+ { storeNames: ["purchases"] },
async (tx) => {
const purchase = await tx.purchases.get(proposalId);
@@ -1085,9 +1107,12 @@ async function handleInsufficientFunds(
): Promise<void> {
logger.trace("handling insufficient funds, trying to re-select coins");
- const proposal = await wex.db.runReadOnlyTx(["purchases"], async (tx) => {
- return tx.purchases.get(proposalId);
- });
+ const proposal = await wex.db.runReadOnlyTx(
+ { storeNames: ["purchases"] },
+ async (tx) => {
+ return tx.purchases.get(proposalId);
+ },
+ );
if (!proposal) {
return;
}
@@ -1127,16 +1152,19 @@ async function handleInsufficientFunds(
return;
}
- await wex.db.runReadOnlyTx(["coins", "denominations"], async (tx) => {
- for (let i = 0; i < payCoinSelection.coinPubs.length; i++) {
- const coinPub = payCoinSelection.coinPubs[i];
- const contrib = payCoinSelection.coinContributions[i];
- prevPayCoins.push({
- coinPub,
- contribution: Amounts.parseOrThrow(contrib),
- });
- }
- });
+ await wex.db.runReadOnlyTx(
+ { storeNames: ["coins", "denominations"] },
+ async (tx) => {
+ for (let i = 0; i < payCoinSelection.coinPubs.length; i++) {
+ const coinPub = payCoinSelection.coinPubs[i];
+ const contrib = payCoinSelection.coinContributions[i];
+ prevPayCoins.push({
+ coinPub,
+ contribution: Amounts.parseOrThrow(contrib),
+ });
+ }
+ },
+ );
const res = await selectPayCoins(wex, {
restrictExchanges: {
@@ -1165,14 +1193,16 @@ async function handleInsufficientFunds(
logger.trace("re-selected coins");
await wex.db.runReadWriteTx(
- [
- "purchases",
- "coins",
- "coinAvailability",
- "denominations",
- "refreshGroups",
- "refreshSessions",
- ],
+ {
+ storeNames: [
+ "purchases",
+ "coins",
+ "coinAvailability",
+ "denominations",
+ "refreshGroups",
+ "refreshSessions",
+ ],
+ },
async (tx) => {
const p = await tx.purchases.get(proposalId);
if (!p) {
@@ -1221,9 +1251,12 @@ async function checkPaymentByProposalId(
proposalId: string,
sessionId?: string,
): Promise<PreparePayResult> {
- let proposal = await wex.db.runReadOnlyTx(["purchases"], async (tx) => {
- return tx.purchases.get(proposalId);
- });
+ let proposal = await wex.db.runReadOnlyTx(
+ { storeNames: ["purchases"] },
+ async (tx) => {
+ return tx.purchases.get(proposalId);
+ },
+ );
if (!proposal) {
throw Error(`could not get proposal ${proposalId}`);
}
@@ -1232,7 +1265,7 @@ async function checkPaymentByProposalId(
if (existingProposalId) {
logger.trace("using existing purchase for same product");
const oldProposal = await wex.db.runReadOnlyTx(
- ["purchases"],
+ { storeNames: ["purchases"] },
async (tx) => {
return tx.purchases.get(existingProposalId);
},
@@ -1266,9 +1299,12 @@ async function checkPaymentByProposalId(
});
// First check if we already paid for it.
- const purchase = await wex.db.runReadOnlyTx(["purchases"], async (tx) => {
- return tx.purchases.get(proposalId);
- });
+ const purchase = await wex.db.runReadOnlyTx(
+ { storeNames: ["purchases"] },
+ async (tx) => {
+ return tx.purchases.get(proposalId);
+ },
+ );
if (
!purchase ||
@@ -1344,7 +1380,7 @@ async function checkPaymentByProposalId(
);
logger.trace(`last: ${purchase.lastSessionId}, current: ${sessionId}`);
const transitionInfo = await wex.db.runReadWriteTx(
- ["purchases"],
+ { storeNames: ["purchases"] },
async (tx) => {
const p = await tx.purchases.get(proposalId);
if (!p) {
@@ -1421,9 +1457,12 @@ export async function getContractTermsDetails(
wex: WalletExecutionContext,
proposalId: string,
): Promise<WalletContractData> {
- const proposal = await wex.db.runReadOnlyTx(["purchases"], async (tx) => {
- return tx.purchases.get(proposalId);
- });
+ const proposal = await wex.db.runReadOnlyTx(
+ { storeNames: ["purchases"] },
+ async (tx) => {
+ return tx.purchases.get(proposalId);
+ },
+ );
if (!proposal) {
throw Error(`proposal with id ${proposalId} not found`);
@@ -1513,7 +1552,7 @@ async function internalWaitProposalDownloaded(
): Promise<void> {
while (true) {
const { purchase, retryInfo } = await ctx.wex.db.runReadOnlyTx(
- ["purchases", "operationRetries"],
+ { storeNames: ["purchases", "operationRetries"] },
async (tx) => {
return {
purchase: await tx.purchases.get(ctx.proposalId),
@@ -1610,24 +1649,27 @@ export async function generateDepositPermissions(
coin: CoinRecord;
denom: DenominationRecord;
}> = [];
- await wex.db.runReadOnlyTx(["coins", "denominations"], async (tx) => {
- for (let i = 0; i < payCoinSel.coinContributions.length; i++) {
- const coin = await tx.coins.get(payCoinSel.coinPubs[i]);
- if (!coin) {
- throw Error("can't pay, allocated coin not found anymore");
- }
- const denom = await tx.denominations.get([
- coin.exchangeBaseUrl,
- coin.denomPubHash,
- ]);
- if (!denom) {
- throw Error(
- "can't pay, denomination of allocated coin not found anymore",
- );
+ await wex.db.runReadOnlyTx(
+ { storeNames: ["coins", "denominations"] },
+ async (tx) => {
+ for (let i = 0; i < payCoinSel.coinContributions.length; i++) {
+ const coin = await tx.coins.get(payCoinSel.coinPubs[i]);
+ if (!coin) {
+ throw Error("can't pay, allocated coin not found anymore");
+ }
+ const denom = await tx.denominations.get([
+ coin.exchangeBaseUrl,
+ coin.denomPubHash,
+ ]);
+ if (!denom) {
+ throw Error(
+ "can't pay, denomination of allocated coin not found anymore",
+ );
+ }
+ coinWithDenom.push({ coin, denom });
}
- coinWithDenom.push({ coin, denom });
- }
- });
+ },
+ );
for (let i = 0; i < payCoinSel.coinContributions.length; i++) {
const { coin, denom } = coinWithDenom[i];
@@ -1662,7 +1704,7 @@ async function internalWaitPaymentResult(
): Promise<ConfirmPayResult> {
while (true) {
const txRes = await ctx.wex.db.runReadOnlyTx(
- ["purchases", "operationRetries"],
+ { storeNames: ["purchases", "operationRetries"] },
async (tx) => {
const purchase = await tx.purchases.get(ctx.proposalId);
const retryRecord = await tx.operationRetries.get(ctx.taskId);
@@ -1776,9 +1818,12 @@ export async function confirmPay(
logger.trace(
`executing confirmPay with proposalId ${proposalId} and sessionIdOverride ${sessionIdOverride}`,
);
- const proposal = await wex.db.runReadOnlyTx(["purchases"], async (tx) => {
- return tx.purchases.get(proposalId);
- });
+ const proposal = await wex.db.runReadOnlyTx(
+ { storeNames: ["purchases"] },
+ async (tx) => {
+ return tx.purchases.get(proposalId);
+ },
+ );
if (!proposal) {
throw Error(`proposal with id ${proposalId} not found`);
@@ -1790,7 +1835,7 @@ export async function confirmPay(
}
const existingPurchase = await wex.db.runReadWriteTx(
- ["purchases"],
+ { storeNames: ["purchases"] },
async (tx) => {
const purchase = await tx.purchases.get(proposalId);
if (
@@ -1875,14 +1920,16 @@ export async function confirmPay(
);
const transitionInfo = await wex.db.runReadWriteTx(
- [
- "purchases",
- "coins",
- "refreshGroups",
- "refreshSessions",
- "denominations",
- "coinAvailability",
- ],
+ {
+ storeNames: [
+ "purchases",
+ "coins",
+ "refreshGroups",
+ "refreshSessions",
+ "denominations",
+ "coinAvailability",
+ ],
+ },
async (tx) => {
const p = await tx.purchases.get(proposal.proposalId);
if (!p) {
@@ -1954,9 +2001,12 @@ export async function processPurchase(
wex: WalletExecutionContext,
proposalId: string,
): Promise<TaskRunResult> {
- const purchase = await wex.db.runReadOnlyTx(["purchases"], async (tx) => {
- return tx.purchases.get(proposalId);
- });
+ const purchase = await wex.db.runReadOnlyTx(
+ { storeNames: ["purchases"] },
+ async (tx) => {
+ return tx.purchases.get(proposalId);
+ },
+ );
if (!purchase) {
return {
type: TaskRunResultType.Error,
@@ -2013,9 +2063,12 @@ async function processPurchasePay(
wex: WalletExecutionContext,
proposalId: string,
): Promise<TaskRunResult> {
- const purchase = await wex.db.runReadOnlyTx(["purchases"], async (tx) => {
- return tx.purchases.get(proposalId);
- });
+ const purchase = await wex.db.runReadOnlyTx(
+ { storeNames: ["purchases"] },
+ async (tx) => {
+ return tx.purchases.get(proposalId);
+ },
+ );
if (!purchase) {
return {
type: TaskRunResultType.Error,
@@ -2056,7 +2109,7 @@ async function processPurchasePay(
if (paid) {
const transitionInfo = await wex.db.runReadWriteTx(
- ["purchases"],
+ { storeNames: ["purchases"] },
async (tx) => {
const p = await tx.purchases.get(purchase.proposalId);
if (!p) {
@@ -2128,14 +2181,16 @@ async function processPurchasePay(
);
const transitionDone = await wex.db.runReadWriteTx(
- [
- "purchases",
- "coins",
- "refreshGroups",
- "refreshSessions",
- "denominations",
- "coinAvailability",
- ],
+ {
+ storeNames: [
+ "purchases",
+ "coins",
+ "refreshGroups",
+ "refreshSessions",
+ "denominations",
+ "coinAvailability",
+ ],
+ },
async (tx) => {
const p = await tx.purchases.get(proposalId);
if (!p) {
@@ -2329,7 +2384,7 @@ export async function refuseProposal(
proposalId,
});
const transitionInfo = await wex.db.runReadWriteTx(
- ["purchases"],
+ { storeNames: ["purchases"] },
async (tx) => {
const proposal = await tx.purchases.get(proposalId);
if (!proposal) {
@@ -2603,42 +2658,45 @@ export async function sharePayment(
merchantBaseUrl: string,
orderId: string,
): Promise<SharePaymentResult> {
- const result = await wex.db.runReadWriteTx(["purchases"], async (tx) => {
- const p = await tx.purchases.indexes.byUrlAndOrderId.get([
- merchantBaseUrl,
- orderId,
- ]);
- if (!p) {
- logger.warn("purchase does not exist anymore");
- return undefined;
- }
- if (
- p.purchaseStatus !== PurchaseStatus.DialogProposed &&
- p.purchaseStatus !== PurchaseStatus.DialogShared
- ) {
- // FIXME: purchase can be shared before being paid
- return undefined;
- }
- const oldTxState = computePayMerchantTransactionState(p);
- if (p.purchaseStatus === PurchaseStatus.DialogProposed) {
- p.purchaseStatus = PurchaseStatus.DialogShared;
- p.shared = true;
- await tx.purchases.put(p);
- }
+ const result = await wex.db.runReadWriteTx(
+ { storeNames: ["purchases"] },
+ async (tx) => {
+ const p = await tx.purchases.indexes.byUrlAndOrderId.get([
+ merchantBaseUrl,
+ orderId,
+ ]);
+ if (!p) {
+ logger.warn("purchase does not exist anymore");
+ return undefined;
+ }
+ if (
+ p.purchaseStatus !== PurchaseStatus.DialogProposed &&
+ p.purchaseStatus !== PurchaseStatus.DialogShared
+ ) {
+ // FIXME: purchase can be shared before being paid
+ return undefined;
+ }
+ const oldTxState = computePayMerchantTransactionState(p);
+ if (p.purchaseStatus === PurchaseStatus.DialogProposed) {
+ p.purchaseStatus = PurchaseStatus.DialogShared;
+ p.shared = true;
+ await tx.purchases.put(p);
+ }
- const newTxState = computePayMerchantTransactionState(p);
+ const newTxState = computePayMerchantTransactionState(p);
- return {
- proposalId: p.proposalId,
- nonce: p.noncePriv,
- session: p.lastSessionId ?? p.downloadSessionId,
- token: p.claimToken,
- transitionInfo: {
- oldTxState,
- newTxState,
- },
- };
- });
+ return {
+ proposalId: p.proposalId,
+ nonce: p.noncePriv,
+ session: p.lastSessionId ?? p.downloadSessionId,
+ token: p.claimToken,
+ transitionInfo: {
+ oldTxState,
+ newTxState,
+ },
+ };
+ },
+ );
if (result === undefined) {
throw Error("This purchase can't be shared");
@@ -2713,7 +2771,7 @@ async function processPurchaseDialogShared(
);
if (paid) {
const transitionInfo = await wex.db.runReadWriteTx(
- ["purchases"],
+ { storeNames: ["purchases"] },
async (tx) => {
const p = await tx.purchases.get(purchase.proposalId);
if (!p) {
@@ -2752,15 +2810,16 @@ async function processPurchaseAutoRefund(
const download = await expectProposalDownload(wex, purchase);
- const noAutoRefundOrExpired = !purchase.autoRefundDeadline ||
- AbsoluteTime.isExpired(
- AbsoluteTime.fromProtocolTimestamp(
- timestampProtocolFromDb(purchase.autoRefundDeadline),
- ),
- )
+ const noAutoRefundOrExpired =
+ !purchase.autoRefundDeadline ||
+ AbsoluteTime.isExpired(
+ AbsoluteTime.fromProtocolTimestamp(
+ timestampProtocolFromDb(purchase.autoRefundDeadline),
+ ),
+ );
const totalKnownRefund = await wex.db.runReadOnlyTx(
- ["refundGroups"],
+ { storeNames: ["refundGroups"] },
async (tx) => {
const refunds = await tx.refundGroups.indexes.byProposalId.getAll(
purchase.proposalId,
@@ -2778,12 +2837,13 @@ async function processPurchaseAutoRefund(
},
);
- const refundedIsLessThanPrice = Amounts.cmp(download.contractData.amount, totalKnownRefund) === +1
- const nothingMoreToRefund = !refundedIsLessThanPrice
+ const refundedIsLessThanPrice =
+ Amounts.cmp(download.contractData.amount, totalKnownRefund) === +1;
+ const nothingMoreToRefund = !refundedIsLessThanPrice;
if (noAutoRefundOrExpired || nothingMoreToRefund) {
const transitionInfo = await wex.db.runReadWriteTx(
- ["purchases"],
+ { storeNames: ["purchases"] },
async (tx) => {
const p = await tx.purchases.get(purchase.proposalId);
if (!p) {
@@ -2831,7 +2891,7 @@ async function processPurchaseAutoRefund(
if (orderStatus.refund_pending) {
const transitionInfo = await wex.db.runReadWriteTx(
- ["purchases"],
+ { storeNames: ["purchases"] },
async (tx) => {
const p = await tx.purchases.get(purchase.proposalId);
if (!p) {
@@ -2875,7 +2935,7 @@ async function processPurchaseAbortingRefund(
throw Error("can't abort, no coins selected");
}
- await wex.db.runReadOnlyTx(["coins"], async (tx) => {
+ await wex.db.runReadOnlyTx({ storeNames: ["coins"] }, async (tx) => {
for (let i = 0; i < payCoinSelection.coinPubs.length; i++) {
const coinPub = payCoinSelection.coinPubs[i];
const coin = await tx.coins.get(coinPub);
@@ -2981,7 +3041,7 @@ async function processPurchaseQueryRefund(
if (!orderStatus.refund_pending) {
const transitionInfo = await wex.db.runReadWriteTx(
- ["purchases"],
+ { storeNames: ["purchases"] },
async (tx) => {
const p = await tx.purchases.get(purchase.proposalId);
if (!p) {
@@ -3008,7 +3068,7 @@ async function processPurchaseQueryRefund(
).amount;
const transitionInfo = await wex.db.runReadWriteTx(
- ["purchases"],
+ { storeNames: ["purchases"] },
async (tx) => {
const p = await tx.purchases.get(purchase.proposalId);
if (!p) {
@@ -3076,7 +3136,7 @@ export async function startRefundQueryForUri(
throw Error("expected taler://refund URI");
}
const purchaseRecord = await wex.db.runReadOnlyTx(
- ["purchases"],
+ { storeNames: ["purchases"] },
async (tx) => {
return tx.purchases.indexes.byUrlAndOrderId.get([
parsedUri.merchantBaseUrl,
@@ -3107,7 +3167,7 @@ export async function startQueryRefund(
): Promise<void> {
const ctx = new PayMerchantTransactionContext(wex, proposalId);
const transitionInfo = await wex.db.runReadWriteTx(
- ["purchases"],
+ { storeNames: ["purchases"] },
async (tx) => {
const p = await tx.purchases.get(proposalId);
if (!p) {
@@ -3200,18 +3260,20 @@ async function storeRefunds(
const currency = Amounts.currencyOf(download.contractData.amount);
const result = await wex.db.runReadWriteTx(
- [
- "coins",
- "denominations",
- "purchases",
- "refundItems",
- "refundGroups",
- "denominations",
- "coins",
- "coinAvailability",
- "refreshGroups",
- "refreshSessions",
- ],
+ {
+ storeNames: [
+ "coins",
+ "denominations",
+ "purchases",
+ "refundItems",
+ "refundGroups",
+ "denominations",
+ "coins",
+ "coinAvailability",
+ "refreshGroups",
+ "refreshSessions",
+ ],
+ },
async (tx) => {
const myPurchase = await tx.purchases.get(purchase.proposalId);
if (!myPurchase) {
diff --git a/packages/taler-wallet-core/src/pay-peer-common.ts b/packages/taler-wallet-core/src/pay-peer-common.ts
index 0bb290440..bfd39b657 100644
--- a/packages/taler-wallet-core/src/pay-peer-common.ts
+++ b/packages/taler-wallet-core/src/pay-peer-common.ts
@@ -43,31 +43,34 @@ export async function queryCoinInfosForSelection(
csel: DbPeerPushPaymentCoinSelection,
): Promise<SpendCoinDetails[]> {
let infos: SpendCoinDetails[] = [];
- await wex.db.runReadOnlyTx(["coins", "denominations"], async (tx) => {
- for (let i = 0; i < csel.coinPubs.length; i++) {
- const coin = await tx.coins.get(csel.coinPubs[i]);
- if (!coin) {
- throw Error("coin not found anymore");
- }
- const denom = await getDenomInfo(
- wex,
- tx,
- coin.exchangeBaseUrl,
- coin.denomPubHash,
- );
- if (!denom) {
- throw Error("denom for coin not found anymore");
+ await wex.db.runReadOnlyTx(
+ { storeNames: ["coins", "denominations"] },
+ async (tx) => {
+ for (let i = 0; i < csel.coinPubs.length; i++) {
+ const coin = await tx.coins.get(csel.coinPubs[i]);
+ if (!coin) {
+ throw Error("coin not found anymore");
+ }
+ const denom = await getDenomInfo(
+ wex,
+ tx,
+ coin.exchangeBaseUrl,
+ coin.denomPubHash,
+ );
+ if (!denom) {
+ throw Error("denom for coin not found anymore");
+ }
+ infos.push({
+ coinPriv: coin.coinPriv,
+ coinPub: coin.coinPub,
+ denomPubHash: coin.denomPubHash,
+ denomSig: coin.denomSig,
+ ageCommitmentProof: coin.ageCommitmentProof,
+ contribution: csel.contributions[i],
+ });
}
- infos.push({
- coinPriv: coin.coinPriv,
- coinPub: coin.coinPub,
- denomPubHash: coin.denomPubHash,
- denomSig: coin.denomSig,
- ageCommitmentProof: coin.ageCommitmentProof,
- contribution: csel.contributions[i],
- });
- }
- });
+ },
+ );
return infos;
}
@@ -75,36 +78,39 @@ export async function getTotalPeerPaymentCost(
wex: WalletExecutionContext,
pcs: SelectedProspectiveCoin[],
): Promise<AmountJson> {
- return wex.db.runReadOnlyTx(["coins", "denominations"], async (tx) => {
- const costs: AmountJson[] = [];
- for (let i = 0; i < pcs.length; i++) {
- const denomInfo = await getDenomInfo(
- wex,
- tx,
- pcs[i].exchangeBaseUrl,
- pcs[i].denomPubHash,
- );
- if (!denomInfo) {
- throw Error(
- "can't calculate payment cost, denomination for coin not found",
+ return wex.db.runReadOnlyTx(
+ { storeNames: ["coins", "denominations"] },
+ async (tx) => {
+ const costs: AmountJson[] = [];
+ for (let i = 0; i < pcs.length; i++) {
+ const denomInfo = await getDenomInfo(
+ wex,
+ tx,
+ pcs[i].exchangeBaseUrl,
+ pcs[i].denomPubHash,
+ );
+ if (!denomInfo) {
+ throw Error(
+ "can't calculate payment cost, denomination for coin not found",
+ );
+ }
+ const amountLeft = Amounts.sub(
+ denomInfo.value,
+ pcs[i].contribution,
+ ).amount;
+ const refreshCost = await getTotalRefreshCost(
+ wex,
+ tx,
+ denomInfo,
+ amountLeft,
);
+ costs.push(Amounts.parseOrThrow(pcs[i].contribution));
+ costs.push(refreshCost);
}
- const amountLeft = Amounts.sub(
- denomInfo.value,
- pcs[i].contribution,
- ).amount;
- const refreshCost = await getTotalRefreshCost(
- wex,
- tx,
- denomInfo,
- amountLeft,
- );
- costs.push(Amounts.parseOrThrow(pcs[i].contribution));
- costs.push(refreshCost);
- }
- const zero = Amounts.zeroOfAmount(pcs[0].contribution);
- return Amounts.sum([zero, ...costs]).amount;
- });
+ const zero = Amounts.zeroOfAmount(pcs[0].contribution);
+ return Amounts.sum([zero, ...costs]).amount;
+ },
+ );
}
interface ExchangePurseStatus {
@@ -131,7 +137,7 @@ export async function getMergeReserveInfo(
const newReservePair = await wex.cryptoApi.createEddsaKeypair({});
const mergeReserveRecord: ReserveRecord = await wex.db.runReadWriteTx(
- ["exchanges", "reserves"],
+ { storeNames: ["exchanges", "reserves"] },
async (tx) => {
const ex = await tx.exchanges.get(req.exchangeBaseUrl);
checkDbInvariant(!!ex);
diff --git a/packages/taler-wallet-core/src/pay-peer-pull-credit.ts b/packages/taler-wallet-core/src/pay-peer-pull-credit.ts
index 4155f83e6..840c244d0 100644
--- a/packages/taler-wallet-core/src/pay-peer-pull-credit.ts
+++ b/packages/taler-wallet-core/src/pay-peer-pull-credit.ts
@@ -110,7 +110,7 @@ export class PeerPullCreditTransactionContext implements TransactionContext {
async deleteTransaction(): Promise<void> {
const { wex: ws, pursePub } = this;
await ws.db.runReadWriteTx(
- ["withdrawalGroups", "peerPullCredit", "tombstones"],
+ { storeNames: ["withdrawalGroups", "peerPullCredit", "tombstones"] },
async (tx) => {
const pullIni = await tx.peerPullCredit.get(pursePub);
if (!pullIni) {
@@ -140,7 +140,7 @@ export class PeerPullCreditTransactionContext implements TransactionContext {
async suspendTransaction(): Promise<void> {
const { wex, pursePub, taskId: retryTag, transactionId } = this;
const transitionInfo = await wex.db.runReadWriteTx(
- ["peerPullCredit"],
+ { storeNames: ["peerPullCredit"] },
async (tx) => {
const pullCreditRec = await tx.peerPullCredit.get(pursePub);
if (!pullCreditRec) {
@@ -200,7 +200,7 @@ export class PeerPullCreditTransactionContext implements TransactionContext {
async failTransaction(): Promise<void> {
const { wex, pursePub, taskId: retryTag, transactionId } = this;
const transitionInfo = await wex.db.runReadWriteTx(
- ["peerPullCredit"],
+ { storeNames: ["peerPullCredit"] },
async (tx) => {
const pullCreditRec = await tx.peerPullCredit.get(pursePub);
if (!pullCreditRec) {
@@ -251,7 +251,7 @@ export class PeerPullCreditTransactionContext implements TransactionContext {
async resumeTransaction(): Promise<void> {
const { wex, pursePub, taskId: retryTag, transactionId } = this;
const transitionInfo = await wex.db.runReadWriteTx(
- ["peerPullCredit"],
+ { storeNames: ["peerPullCredit"] },
async (tx) => {
const pullCreditRec = await tx.peerPullCredit.get(pursePub);
if (!pullCreditRec) {
@@ -310,7 +310,7 @@ export class PeerPullCreditTransactionContext implements TransactionContext {
async abortTransaction(): Promise<void> {
const { wex, pursePub, taskId: retryTag, transactionId } = this;
const transitionInfo = await wex.db.runReadWriteTx(
- ["peerPullCredit"],
+ { storeNames: ["peerPullCredit"] },
async (tx) => {
const pullCreditRec = await tx.peerPullCredit.get(pursePub);
if (!pullCreditRec) {
@@ -388,7 +388,7 @@ async function queryPurseForPeerPullCredit(
case HttpStatusCode.Gone: {
// Exchange says that purse doesn't exist anymore => expired!
const transitionInfo = await wex.db.runReadWriteTx(
- ["peerPullCredit"],
+ { storeNames: ["peerPullCredit"] },
async (tx) => {
const finPi = await tx.peerPullCredit.get(pullIni.pursePub);
if (!finPi) {
@@ -426,9 +426,12 @@ async function queryPurseForPeerPullCredit(
return TaskRunResult.backoff();
}
- const reserve = await wex.db.runReadOnlyTx(["reserves"], async (tx) => {
- return await tx.reserves.get(pullIni.mergeReserveRowId);
- });
+ const reserve = await wex.db.runReadOnlyTx(
+ { storeNames: ["reserves"] },
+ async (tx) => {
+ return await tx.reserves.get(pullIni.mergeReserveRowId);
+ },
+ );
if (!reserve) {
throw Error("reserve for peer pull credit not found in wallet DB");
@@ -449,7 +452,7 @@ async function queryPurseForPeerPullCredit(
},
});
const transitionInfo = await wex.db.runReadWriteTx(
- ["peerPullCredit"],
+ { storeNames: ["peerPullCredit"] },
async (tx) => {
const finPi = await tx.peerPullCredit.get(pullIni.pursePub);
if (!finPi) {
@@ -497,7 +500,7 @@ async function longpollKycStatus(
kycStatusRes.status === HttpStatusCode.NoContent
) {
const transitionInfo = await wex.db.runReadWriteTx(
- ["peerPullCredit"],
+ { storeNames: ["peerPullCredit"] },
async (tx) => {
const peerIni = await tx.peerPullCredit.get(pursePub);
if (!peerIni) {
@@ -548,13 +551,15 @@ async function processPeerPullCreditAbortingDeletePurse(
logger.info(`deleted purse with response status ${resp.status}`);
const transitionInfo = await wex.db.runReadWriteTx(
- [
- "peerPullCredit",
- "refreshGroups",
- "denominations",
- "coinAvailability",
- "coins",
- ],
+ {
+ storeNames: [
+ "peerPullCredit",
+ "refreshGroups",
+ "denominations",
+ "coinAvailability",
+ "coins",
+ ],
+ },
async (tx) => {
const ppiRec = await tx.peerPullCredit.get(pursePub);
if (!ppiRec) {
@@ -593,7 +598,7 @@ async function handlePeerPullCreditWithdrawing(
const wgId = pullIni.withdrawalGroupId;
let finished: boolean = false;
const transitionInfo = await wex.db.runReadWriteTx(
- ["peerPullCredit", "withdrawalGroups"],
+ { storeNames: ["peerPullCredit", "withdrawalGroups"] },
async (tx) => {
const ppi = await tx.peerPullCredit.get(pullIni.pursePub);
if (!ppi) {
@@ -640,16 +645,19 @@ async function handlePeerPullCreditCreatePurse(
): Promise<TaskRunResult> {
const purseFee = Amounts.stringify(Amounts.zeroOfAmount(pullIni.amount));
const pursePub = pullIni.pursePub;
- const mergeReserve = await wex.db.runReadOnlyTx(["reserves"], async (tx) => {
- return tx.reserves.get(pullIni.mergeReserveRowId);
- });
+ const mergeReserve = await wex.db.runReadOnlyTx(
+ { storeNames: ["reserves"] },
+ async (tx) => {
+ return tx.reserves.get(pullIni.mergeReserveRowId);
+ },
+ );
if (!mergeReserve) {
throw Error("merge reserve for peer pull payment not found in database");
}
const contractTermsRecord = await wex.db.runReadOnlyTx(
- ["contractTerms"],
+ { storeNames: ["contractTerms"] },
async (tx) => {
return tx.contractTerms.get(pullIni.contractTermsHash);
},
@@ -737,7 +745,7 @@ async function handlePeerPullCreditCreatePurse(
});
const transitionInfo = await wex.db.runReadWriteTx(
- ["peerPullCredit"],
+ { storeNames: ["peerPullCredit"] },
async (tx) => {
const pi2 = await tx.peerPullCredit.get(pursePub);
if (!pi2) {
@@ -758,9 +766,12 @@ export async function processPeerPullCredit(
wex: WalletExecutionContext,
pursePub: string,
): Promise<TaskRunResult> {
- const pullIni = await wex.db.runReadOnlyTx(["peerPullCredit"], async (tx) => {
- return tx.peerPullCredit.get(pursePub);
- });
+ const pullIni = await wex.db.runReadOnlyTx(
+ { storeNames: ["peerPullCredit"] },
+ async (tx) => {
+ return tx.peerPullCredit.get(pursePub);
+ },
+ );
if (!pullIni) {
throw Error("peer pull payment initiation not found in database");
}
@@ -847,7 +858,7 @@ async function processPeerPullCreditKycRequired(
const kycStatus = await kycStatusRes.json();
logger.info(`kyc status: ${j2s(kycStatus)}`);
const { transitionInfo, result } = await wex.db.runReadWriteTx(
- ["peerPullCredit"],
+ { storeNames: ["peerPullCredit"] },
async (tx) => {
const peerInc = await tx.peerPullCredit.get(pursePub);
if (!peerInc) {
@@ -947,42 +958,45 @@ async function getPreferredExchangeForCurrency(
): Promise<string | undefined> {
// Find an exchange with the matching currency.
// Prefer exchanges with the most recent withdrawal.
- const url = await wex.db.runReadOnlyTx(["exchanges"], async (tx) => {
- const exchanges = await tx.exchanges.iter().toArray();
- let candidate = undefined;
- for (const e of exchanges) {
- if (e.detailsPointer?.currency !== currency) {
- continue;
- }
- if (!candidate) {
- candidate = e;
- continue;
- }
- if (candidate.lastWithdrawal && !e.lastWithdrawal) {
- continue;
- }
- const exchangeLastWithdrawal = timestampOptionalPreciseFromDb(
- e.lastWithdrawal,
- );
- const candidateLastWithdrawal = timestampOptionalPreciseFromDb(
- candidate.lastWithdrawal,
- );
- if (exchangeLastWithdrawal && candidateLastWithdrawal) {
- if (
- AbsoluteTime.cmp(
- AbsoluteTime.fromPreciseTimestamp(exchangeLastWithdrawal),
- AbsoluteTime.fromPreciseTimestamp(candidateLastWithdrawal),
- ) > 0
- ) {
+ const url = await wex.db.runReadOnlyTx(
+ { storeNames: ["exchanges"] },
+ async (tx) => {
+ const exchanges = await tx.exchanges.iter().toArray();
+ let candidate = undefined;
+ for (const e of exchanges) {
+ if (e.detailsPointer?.currency !== currency) {
+ continue;
+ }
+ if (!candidate) {
candidate = e;
+ continue;
+ }
+ if (candidate.lastWithdrawal && !e.lastWithdrawal) {
+ continue;
+ }
+ const exchangeLastWithdrawal = timestampOptionalPreciseFromDb(
+ e.lastWithdrawal,
+ );
+ const candidateLastWithdrawal = timestampOptionalPreciseFromDb(
+ candidate.lastWithdrawal,
+ );
+ if (exchangeLastWithdrawal && candidateLastWithdrawal) {
+ if (
+ AbsoluteTime.cmp(
+ AbsoluteTime.fromPreciseTimestamp(exchangeLastWithdrawal),
+ AbsoluteTime.fromPreciseTimestamp(candidateLastWithdrawal),
+ ) > 0
+ ) {
+ candidate = e;
+ }
}
}
- }
- if (candidate) {
- return candidate.baseUrl;
- }
- return undefined;
- });
+ if (candidate) {
+ return candidate.baseUrl;
+ }
+ return undefined;
+ },
+ );
return url;
}
@@ -1039,7 +1053,7 @@ export async function initiatePeerPullPayment(
const mergeTimestamp = TalerPreciseTimestamp.now();
const transitionInfo = await wex.db.runReadWriteTx(
- ["peerPullCredit", "contractTerms"],
+ { storeNames: ["peerPullCredit", "contractTerms"] },
async (tx) => {
const ppi: PeerPullCreditRecord = {
amount: req.partialContractTerms.amount,
diff --git a/packages/taler-wallet-core/src/pay-peer-pull-debit.ts b/packages/taler-wallet-core/src/pay-peer-pull-debit.ts
index 92eb44a87..0355b58ad 100644
--- a/packages/taler-wallet-core/src/pay-peer-pull-debit.ts
+++ b/packages/taler-wallet-core/src/pay-peer-pull-debit.ts
@@ -126,13 +126,16 @@ export class PeerPullDebitTransactionContext implements TransactionContext {
const transactionId = this.transactionId;
const ws = this.wex;
const peerPullDebitId = this.peerPullDebitId;
- await ws.db.runReadWriteTx(["peerPullDebit", "tombstones"], async (tx) => {
- const debit = await tx.peerPullDebit.get(peerPullDebitId);
- if (debit) {
- await tx.peerPullDebit.delete(peerPullDebitId);
- await tx.tombstones.put({ id: transactionId });
- }
- });
+ await ws.db.runReadWriteTx(
+ { storeNames: ["peerPullDebit", "tombstones"] },
+ async (tx) => {
+ const debit = await tx.peerPullDebit.get(peerPullDebitId);
+ if (debit) {
+ await tx.peerPullDebit.delete(peerPullDebitId);
+ await tx.tombstones.put({ id: transactionId });
+ }
+ },
+ );
}
async suspendTransaction(): Promise<void> {
@@ -141,7 +144,7 @@ export class PeerPullDebitTransactionContext implements TransactionContext {
const wex = this.wex;
const peerPullDebitId = this.peerPullDebitId;
const transitionInfo = await wex.db.runReadWriteTx(
- ["peerPullDebit"],
+ { storeNames: ["peerPullDebit"] },
async (tx) => {
const pullDebitRec = await tx.peerPullDebit.get(peerPullDebitId);
if (!pullDebitRec) {
@@ -305,7 +308,7 @@ export class PeerPullDebitTransactionContext implements TransactionContext {
const wex = this.wex;
const extraStores = opts.extraStores ?? [];
const transitionInfo = await wex.db.runReadWriteTx(
- ["peerPullDebit", ...extraStores],
+ { storeNames: ["peerPullDebit", ...extraStores] },
async (tx) => {
const pi = await tx.peerPullDebit.get(this.peerPullDebitId);
if (!pi) {
@@ -398,7 +401,7 @@ async function handlePurseCreationConflict(
coinSelRes.result.coins,
);
- await ws.db.runReadWriteTx(["peerPullDebit"], async (tx) => {
+ await ws.db.runReadWriteTx({ storeNames: ["peerPullDebit"] }, async (tx) => {
const myPpi = await tx.peerPullDebit.get(peerPullInc.peerPullDebitId);
if (!myPpi) {
return;
@@ -470,15 +473,17 @@ async function processPeerPullDebitPendingDeposit(
// FIXME: Missing notification here!
const transitionDone = await wex.db.runReadWriteTx(
- [
- "exchanges",
- "coins",
- "denominations",
- "refreshGroups",
- "refreshSessions",
- "peerPullDebit",
- "coinAvailability",
- ],
+ {
+ storeNames: [
+ "exchanges",
+ "coins",
+ "denominations",
+ "refreshGroups",
+ "refreshSessions",
+ "peerPullDebit",
+ "coinAvailability",
+ ],
+ },
async (tx) => {
const pi = await tx.peerPullDebit.get(peerPullDebitId);
if (!pi) {
@@ -608,7 +613,7 @@ async function processPeerPullDebitAbortingRefresh(
peerPullDebitId,
});
const transitionInfo = await wex.db.runReadWriteTx(
- ["peerPullDebit", "refreshGroups"],
+ { storeNames: ["peerPullDebit", "refreshGroups"] },
async (tx) => {
const refreshGroup = await tx.refreshGroups.get(abortRefreshGroupId);
let newOpState: PeerPullDebitRecordStatus | undefined;
@@ -650,7 +655,7 @@ export async function processPeerPullDebit(
peerPullDebitId: string,
): Promise<TaskRunResult> {
const peerPullInc = await wex.db.runReadOnlyTx(
- ["peerPullDebit"],
+ { storeNames: ["peerPullDebit"] },
async (tx) => {
return tx.peerPullDebit.get(peerPullDebitId);
},
@@ -680,7 +685,7 @@ export async function confirmPeerPullDebit(
peerPullDebitId = parsedTx.peerPullDebitId;
const peerPullInc = await wex.db.runReadOnlyTx(
- ["peerPullDebit"],
+ { storeNames: ["peerPullDebit"] },
async (tx) => {
return tx.peerPullDebit.get(peerPullDebitId);
},
@@ -726,15 +731,17 @@ export async function confirmPeerPullDebit(
// FIXME: Missing notification here!
await wex.db.runReadWriteTx(
- [
- "exchanges",
- "coins",
- "denominations",
- "refreshGroups",
- "refreshSessions",
- "peerPullDebit",
- "coinAvailability",
- ],
+ {
+ storeNames: [
+ "exchanges",
+ "coins",
+ "denominations",
+ "refreshGroups",
+ "refreshSessions",
+ "peerPullDebit",
+ "coinAvailability",
+ ],
+ },
async (tx) => {
const pi = await tx.peerPullDebit.get(peerPullDebitId);
if (!pi) {
@@ -798,7 +805,7 @@ export async function preparePeerPullDebit(
}
const existing = await wex.db.runReadOnlyTx(
- ["peerPullDebit", "contractTerms"],
+ { storeNames: ["peerPullDebit", "contractTerms"] },
async (tx) => {
const peerPullDebitRecord =
await tx.peerPullDebit.indexes.byExchangeAndContractPriv.get([
@@ -911,7 +918,7 @@ export async function preparePeerPullDebit(
const totalAmount = await getTotalPeerPaymentCost(wex, coins);
await wex.db.runReadWriteTx(
- ["peerPullDebit", "contractTerms"],
+ { storeNames: ["peerPullDebit", "contractTerms"] },
async (tx) => {
await tx.contractTerms.put({
h: contractTermsHash,
diff --git a/packages/taler-wallet-core/src/pay-peer-push-credit.ts b/packages/taler-wallet-core/src/pay-peer-push-credit.ts
index 281b3ff61..93f1a63a7 100644
--- a/packages/taler-wallet-core/src/pay-peer-push-credit.ts
+++ b/packages/taler-wallet-core/src/pay-peer-push-credit.ts
@@ -114,7 +114,7 @@ export class PeerPushCreditTransactionContext implements TransactionContext {
async deleteTransaction(): Promise<void> {
const { wex, peerPushCreditId } = this;
await wex.db.runReadWriteTx(
- ["withdrawalGroups", "peerPushCredit", "tombstones"],
+ { storeNames: ["withdrawalGroups", "peerPushCredit", "tombstones"] },
async (tx) => {
const pushInc = await tx.peerPushCredit.get(peerPushCreditId);
if (!pushInc) {
@@ -143,7 +143,7 @@ export class PeerPushCreditTransactionContext implements TransactionContext {
async suspendTransaction(): Promise<void> {
const { wex, peerPushCreditId, taskId: retryTag, transactionId } = this;
const transitionInfo = await wex.db.runReadWriteTx(
- ["peerPushCredit"],
+ { storeNames: ["peerPushCredit"] },
async (tx) => {
const pushCreditRec = await tx.peerPushCredit.get(peerPushCreditId);
if (!pushCreditRec) {
@@ -197,7 +197,7 @@ export class PeerPushCreditTransactionContext implements TransactionContext {
async abortTransaction(): Promise<void> {
const { wex, peerPushCreditId, taskId: retryTag, transactionId } = this;
const transitionInfo = await wex.db.runReadWriteTx(
- ["peerPushCredit"],
+ { storeNames: ["peerPushCredit"] },
async (tx) => {
const pushCreditRec = await tx.peerPushCredit.get(peerPushCreditId);
if (!pushCreditRec) {
@@ -254,7 +254,7 @@ export class PeerPushCreditTransactionContext implements TransactionContext {
async resumeTransaction(): Promise<void> {
const { wex, peerPushCreditId, taskId: retryTag, transactionId } = this;
const transitionInfo = await wex.db.runReadWriteTx(
- ["peerPushCredit"],
+ { storeNames: ["peerPushCredit"] },
async (tx) => {
const pushCreditRec = await tx.peerPushCredit.get(peerPushCreditId);
if (!pushCreditRec) {
@@ -307,7 +307,7 @@ export class PeerPushCreditTransactionContext implements TransactionContext {
async failTransaction(): Promise<void> {
const { wex, peerPushCreditId, taskId: retryTag, transactionId } = this;
const transitionInfo = await wex.db.runReadWriteTx(
- ["peerPushCredit"],
+ { storeNames: ["peerPushCredit"] },
async (tx) => {
const pushCreditRec = await tx.peerPushCredit.get(peerPushCreditId);
if (!pushCreditRec) {
@@ -365,7 +365,7 @@ export async function preparePeerPushCredit(
}
const existing = await wex.db.runReadOnlyTx(
- ["contractTerms", "peerPushCredit"],
+ { storeNames: ["contractTerms", "peerPushCredit"] },
async (tx) => {
const existingPushInc =
await tx.peerPushCredit.indexes.byExchangeAndContractPriv.get([
@@ -460,7 +460,7 @@ export async function preparePeerPushCredit(
);
const transitionInfo = await wex.db.runReadWriteTx(
- ["contractTerms", "peerPushCredit"],
+ { storeNames: ["contractTerms", "peerPushCredit"] },
async (tx) => {
const rec: PeerPushPaymentIncomingRecord = {
peerPushCreditId,
@@ -545,7 +545,7 @@ async function longpollKycStatus(
kycStatusRes.status === HttpStatusCode.NoContent
) {
const transitionInfo = await wex.db.runReadWriteTx(
- ["peerPushCredit"],
+ { storeNames: ["peerPushCredit"] },
async (tx) => {
const peerInc = await tx.peerPushCredit.get(peerPushCreditId);
if (!peerInc) {
@@ -606,7 +606,7 @@ async function processPeerPushCreditKycRequired(
const kycStatus = await kycStatusRes.json();
logger.info(`kyc status: ${j2s(kycStatus)}`);
const { transitionInfo, result } = await wex.db.runReadWriteTx(
- ["peerPushCredit"],
+ { storeNames: ["peerPushCredit"] },
async (tx) => {
const peerInc = await tx.peerPushCredit.get(peerPushCreditId);
if (!peerInc) {
@@ -731,14 +731,16 @@ async function handlePendingMerge(
});
const txRes = await wex.db.runReadWriteTx(
- [
- "contractTerms",
- "peerPushCredit",
- "withdrawalGroups",
- "reserves",
- "exchanges",
- "exchangeDetails",
- ],
+ {
+ storeNames: [
+ "contractTerms",
+ "peerPushCredit",
+ "withdrawalGroups",
+ "reserves",
+ "exchanges",
+ "exchangeDetails",
+ ],
+ },
async (tx) => {
const peerInc = await tx.peerPushCredit.get(peerPushCreditId);
if (!peerInc) {
@@ -798,7 +800,7 @@ async function handlePendingWithdrawing(
const wgId = peerInc.withdrawalGroupId;
let finished: boolean = false;
const transitionInfo = await wex.db.runReadWriteTx(
- ["peerPushCredit", "withdrawalGroups"],
+ { storeNames: ["peerPushCredit", "withdrawalGroups"] },
async (tx) => {
const ppi = await tx.peerPushCredit.get(peerInc.peerPushCreditId);
if (!ppi) {
@@ -846,7 +848,7 @@ export async function processPeerPushCredit(
let peerInc: PeerPushPaymentIncomingRecord | undefined;
let contractTerms: PeerContractTerms | undefined;
await wex.db.runReadWriteTx(
- ["contractTerms", "peerPushCredit"],
+ { storeNames: ["contractTerms", "peerPushCredit"] },
async (tx) => {
peerInc = await tx.peerPushCredit.get(peerPushCreditId);
if (!peerInc) {
@@ -915,7 +917,7 @@ export async function confirmPeerPushCredit(
logger.trace(`confirming peer-push-credit ${peerPushCreditId}`);
await wex.db.runReadWriteTx(
- ["contractTerms", "peerPushCredit"],
+ { storeNames: ["contractTerms", "peerPushCredit"] },
async (tx) => {
peerInc = await tx.peerPushCredit.get(peerPushCreditId);
if (!peerInc) {
diff --git a/packages/taler-wallet-core/src/pay-peer-push-debit.ts b/packages/taler-wallet-core/src/pay-peer-push-debit.ts
index 63a02d7a7..6452407ff 100644
--- a/packages/taler-wallet-core/src/pay-peer-push-debit.ts
+++ b/packages/taler-wallet-core/src/pay-peer-push-debit.ts
@@ -104,19 +104,22 @@ export class PeerPushDebitTransactionContext implements TransactionContext {
async deleteTransaction(): Promise<void> {
const { wex, pursePub, transactionId } = this;
- await wex.db.runReadWriteTx(["peerPushDebit", "tombstones"], async (tx) => {
- const debit = await tx.peerPushDebit.get(pursePub);
- if (debit) {
- await tx.peerPushDebit.delete(pursePub);
- await tx.tombstones.put({ id: transactionId });
- }
- });
+ await wex.db.runReadWriteTx(
+ { storeNames: ["peerPushDebit", "tombstones"] },
+ async (tx) => {
+ const debit = await tx.peerPushDebit.get(pursePub);
+ if (debit) {
+ await tx.peerPushDebit.delete(pursePub);
+ await tx.tombstones.put({ id: transactionId });
+ }
+ },
+ );
}
async suspendTransaction(): Promise<void> {
const { wex, pursePub, transactionId, taskId: retryTag } = this;
const transitionInfo = await wex.db.runReadWriteTx(
- ["peerPushDebit"],
+ { storeNames: ["peerPushDebit"] },
async (tx) => {
const pushDebitRec = await tx.peerPushDebit.get(pursePub);
if (!pushDebitRec) {
@@ -174,7 +177,7 @@ export class PeerPushDebitTransactionContext implements TransactionContext {
async abortTransaction(): Promise<void> {
const { wex, pursePub, transactionId, taskId: retryTag } = this;
const transitionInfo = await wex.db.runReadWriteTx(
- ["peerPushDebit"],
+ { storeNames: ["peerPushDebit"] },
async (tx) => {
const pushDebitRec = await tx.peerPushDebit.get(pursePub);
if (!pushDebitRec) {
@@ -228,7 +231,7 @@ export class PeerPushDebitTransactionContext implements TransactionContext {
async resumeTransaction(): Promise<void> {
const { wex, pursePub, transactionId, taskId: retryTag } = this;
const transitionInfo = await wex.db.runReadWriteTx(
- ["peerPushDebit"],
+ { storeNames: ["peerPushDebit"] },
async (tx) => {
const pushDebitRec = await tx.peerPushDebit.get(pursePub);
if (!pushDebitRec) {
@@ -286,7 +289,7 @@ export class PeerPushDebitTransactionContext implements TransactionContext {
async failTransaction(): Promise<void> {
const { wex, pursePub, transactionId, taskId: retryTag } = this;
const transitionInfo = await wex.db.runReadWriteTx(
- ["peerPushDebit"],
+ { storeNames: ["peerPushDebit"] },
async (tx) => {
const pushDebitRec = await tx.peerPushDebit.get(pursePub);
if (!pushDebitRec) {
@@ -434,7 +437,7 @@ async function handlePurseCreationConflict(
assertUnreachable(coinSelRes);
}
- await wex.db.runReadWriteTx(["peerPushDebit"], async (tx) => {
+ await wex.db.runReadWriteTx({ storeNames: ["peerPushDebit"] }, async (tx) => {
const myPpi = await tx.peerPushDebit.get(peerPushInitiation.pursePub);
if (!myPpi) {
return;
@@ -470,7 +473,7 @@ async function processPeerPushDebitCreateReserve(
logger.trace(`processing ${transactionId} pending(create-reserve)`);
const contractTermsRecord = await wex.db.runReadOnlyTx(
- ["contractTerms"],
+ { storeNames: ["contractTerms"] },
async (tx) => {
return tx.contractTerms.get(hContractTerms);
},
@@ -503,16 +506,18 @@ async function processPeerPushDebitCreateReserve(
assertUnreachable(coinSelRes);
}
const transitionDone = await wex.db.runReadWriteTx(
- [
- "exchanges",
- "contractTerms",
- "coins",
- "coinAvailability",
- "denominations",
- "refreshGroups",
- "refreshSessions",
- "peerPushDebit",
- ],
+ {
+ storeNames: [
+ "exchanges",
+ "contractTerms",
+ "coins",
+ "coinAvailability",
+ "denominations",
+ "refreshGroups",
+ "refreshSessions",
+ "peerPushDebit",
+ ],
+ },
async (tx) => {
const ppi = await tx.peerPushDebit.get(pursePub);
if (!ppi) {
@@ -720,14 +725,16 @@ async function processPeerPushDebitAbortingDeletePurse(
logger.info(`deleted purse with response status ${resp.status}`);
const transitionInfo = await wex.db.runReadWriteTx(
- [
- "peerPushDebit",
- "refreshGroups",
- "refreshSessions",
- "denominations",
- "coinAvailability",
- "coins",
- ],
+ {
+ storeNames: [
+ "peerPushDebit",
+ "refreshGroups",
+ "refreshSessions",
+ "denominations",
+ "coinAvailability",
+ "coins",
+ ],
+ },
async (tx) => {
const ppiRec = await tx.peerPushDebit.get(pursePub);
if (!ppiRec) {
@@ -779,6 +786,7 @@ interface SimpleTransition {
stTo: PeerPushDebitStatus;
}
+// FIXME: This should be a transition on the peer push debit transaction context!
async function transitionPeerPushDebitTransaction(
wex: WalletExecutionContext,
pursePub: string,
@@ -789,7 +797,7 @@ async function transitionPeerPushDebitTransaction(
pursePub,
});
const transitionInfo = await wex.db.runReadWriteTx(
- ["peerPushDebit"],
+ { storeNames: ["peerPushDebit"] },
async (tx) => {
const ppiRec = await tx.peerPushDebit.get(pursePub);
if (!ppiRec) {
@@ -826,7 +834,7 @@ async function processPeerPushDebitAbortingRefreshDeleted(
await waitRefreshFinal(wex, peerPushInitiation.abortRefreshGroupId);
}
const transitionInfo = await wex.db.runReadWriteTx(
- ["refreshGroups", "peerPushDebit"],
+ { storeNames: ["refreshGroups", "peerPushDebit"] },
async (tx) => {
const refreshGroup = await tx.refreshGroups.get(abortRefreshGroupId);
let newOpState: PeerPushDebitStatus | undefined;
@@ -875,7 +883,7 @@ async function processPeerPushDebitAbortingRefreshExpired(
pursePub: peerPushInitiation.pursePub,
});
const transitionInfo = await wex.db.runReadWriteTx(
- ["peerPushDebit", "refreshGroups"],
+ { storeNames: ["peerPushDebit", "refreshGroups"] },
async (tx) => {
const refreshGroup = await tx.refreshGroups.get(abortRefreshGroupId);
let newOpState: PeerPushDebitStatus | undefined;
@@ -958,14 +966,16 @@ async function processPeerPushDebitReady(
} else if (resp.status === HttpStatusCode.Gone) {
logger.info(`purse ${pursePub} is gone, aborting peer-push-debit`);
const transitionInfo = await wex.db.runReadWriteTx(
- [
- "peerPushDebit",
- "refreshGroups",
- "refreshSessions",
- "denominations",
- "coinAvailability",
- "coins",
- ],
+ {
+ storeNames: [
+ "peerPushDebit",
+ "refreshGroups",
+ "refreshSessions",
+ "denominations",
+ "coinAvailability",
+ "coins",
+ ],
+ },
async (tx) => {
const ppiRec = await tx.peerPushDebit.get(pursePub);
if (!ppiRec) {
@@ -1019,7 +1029,7 @@ export async function processPeerPushDebit(
pursePub: string,
): Promise<TaskRunResult> {
const peerPushInitiation = await wex.db.runReadOnlyTx(
- ["peerPushDebit"],
+ { storeNames: ["peerPushDebit"] },
async (tx) => {
return tx.peerPushDebit.get(pursePub);
},
@@ -1118,16 +1128,18 @@ export async function initiatePeerPushDebit(
const contractEncNonce = encodeCrock(getRandomBytes(24));
const transitionInfo = await wex.db.runReadWriteTx(
- [
- "exchanges",
- "contractTerms",
- "coins",
- "coinAvailability",
- "denominations",
- "refreshGroups",
- "refreshSessions",
- "peerPushDebit",
- ],
+ {
+ storeNames: [
+ "exchanges",
+ "contractTerms",
+ "coins",
+ "coinAvailability",
+ "denominations",
+ "refreshGroups",
+ "refreshSessions",
+ "peerPushDebit",
+ ],
+ },
async (tx) => {
const ppi: PeerPushDebitRecord = {
amount: Amounts.stringify(instructedAmount),
diff --git a/packages/taler-wallet-core/src/query.ts b/packages/taler-wallet-core/src/query.ts
index 0a321b835..eb5752fbe 100644
--- a/packages/taler-wallet-core/src/query.ts
+++ b/packages/taler-wallet-core/src/query.ts
@@ -819,12 +819,16 @@ export interface DbAccess<StoreMap> {
): Promise<T>;
runReadWriteTx<T, StoreNameArray extends Array<StoreNames<StoreMap>>>(
- storeNames: StoreNameArray,
+ opts: {
+ storeNames: StoreNameArray;
+ },
txf: (tx: DbReadWriteTransaction<StoreMap, StoreNameArray>) => Promise<T>,
): Promise<T>;
runReadOnlyTx<T, StoreNameArray extends Array<StoreNames<StoreMap>>>(
- storeNames: StoreNameArray,
+ opts: {
+ storeNames: StoreNameArray;
+ },
txf: (tx: DbReadOnlyTransaction<StoreMap, StoreNameArray>) => Promise<T>,
): Promise<T>;
}
@@ -945,13 +949,15 @@ export class DbAccessImpl<StoreMap> implements DbAccess<StoreMap> {
}
async runReadWriteTx<T, StoreNameArray extends Array<StoreNames<StoreMap>>>(
- storeNames: StoreNameArray,
+ opts: {
+ storeNames: StoreNameArray;
+ },
txf: (tx: DbReadWriteTransaction<StoreMap, StoreNameArray>) => Promise<T>,
): Promise<T> {
const accessibleStores: { [x: string]: StoreWithIndexes<any, any, any> } =
{};
const strStoreNames: string[] = [];
- for (const sn of storeNames) {
+ for (const sn of opts.storeNames) {
const swi = (this.stores as any)[sn] as StoreWithIndexes<any, any, any>;
strStoreNames.push(swi.storeName);
accessibleStores[swi.storeName] = swi;
@@ -969,13 +975,15 @@ export class DbAccessImpl<StoreMap> implements DbAccess<StoreMap> {
}
runReadOnlyTx<T, StoreNameArray extends Array<StoreNames<StoreMap>>>(
- storeNames: StoreNameArray,
+ opts: {
+ storeNames: StoreNameArray;
+ },
txf: (tx: DbReadOnlyTransaction<StoreMap, StoreNameArray>) => Promise<T>,
): Promise<T> {
const accessibleStores: { [x: string]: StoreWithIndexes<any, any, any> } =
{};
const strStoreNames: string[] = [];
- for (const sn of storeNames) {
+ for (const sn of opts.storeNames) {
const swi = (this.stores as any)[sn] as StoreWithIndexes<any, any, any>;
strStoreNames.push(swi.storeName);
accessibleStores[swi.storeName] = swi;
diff --git a/packages/taler-wallet-core/src/recoup.ts b/packages/taler-wallet-core/src/recoup.ts
index 758ba106d..6a09f9a0e 100644
--- a/packages/taler-wallet-core/src/recoup.ts
+++ b/packages/taler-wallet-core/src/recoup.ts
@@ -99,7 +99,7 @@ async function recoupRewardCoin(
// Thus we just put the coin to sleep.
// FIXME: somehow report this to the user
await wex.db.runReadWriteTx(
- ["recoupGroups", "denominations", "refreshGroups", "coins"],
+ { storeNames: ["recoupGroups", "denominations", "refreshGroups", "coins"] },
async (tx) => {
const recoupGroup = await tx.recoupGroups.get(recoupGroupId);
if (!recoupGroup) {
@@ -121,7 +121,7 @@ async function recoupRefreshCoin(
cs: RefreshCoinSource,
): Promise<void> {
const d = await wex.db.runReadOnlyTx(
- ["coins", "denominations"],
+ { storeNames: ["coins", "denominations"] },
async (tx) => {
const denomInfo = await getDenomInfo(
wex,
@@ -168,7 +168,7 @@ async function recoupRefreshCoin(
}
await wex.db.runReadWriteTx(
- ["coins", "denominations", "recoupGroups", "refreshGroups"],
+ { storeNames: ["coins", "denominations", "recoupGroups", "refreshGroups"] },
async (tx) => {
const recoupGroup = await tx.recoupGroups.get(recoupGroupId);
if (!recoupGroup) {
@@ -233,7 +233,7 @@ export async function recoupWithdrawCoin(
): Promise<void> {
const reservePub = cs.reservePub;
const denomInfo = await wex.db.runReadOnlyTx(
- ["denominations"],
+ { storeNames: ["denominations"] },
async (tx) => {
const denomInfo = await getDenomInfo(
wex,
@@ -276,7 +276,7 @@ export async function recoupWithdrawCoin(
// FIXME: verify that our expectations about the amount match
await wex.db.runReadWriteTx(
- ["coins", "denominations", "recoupGroups", "refreshGroups"],
+ { storeNames: ["coins", "denominations", "recoupGroups", "refreshGroups"] },
async (tx) => {
const recoupGroup = await tx.recoupGroups.get(recoupGroupId);
if (!recoupGroup) {
@@ -300,9 +300,12 @@ export async function processRecoupGroup(
wex: WalletExecutionContext,
recoupGroupId: string,
): Promise<TaskRunResult> {
- let recoupGroup = await wex.db.runReadOnlyTx(["recoupGroups"], async (tx) => {
- return tx.recoupGroups.get(recoupGroupId);
- });
+ let recoupGroup = await wex.db.runReadOnlyTx(
+ { storeNames: ["recoupGroups"] },
+ async (tx) => {
+ return tx.recoupGroups.get(recoupGroupId);
+ },
+ );
if (!recoupGroup) {
return TaskRunResult.finished();
}
@@ -320,9 +323,12 @@ export async function processRecoupGroup(
});
await Promise.all(ps);
- recoupGroup = await wex.db.runReadOnlyTx(["recoupGroups"], async (tx) => {
- return tx.recoupGroups.get(recoupGroupId);
- });
+ recoupGroup = await wex.db.runReadOnlyTx(
+ { storeNames: ["recoupGroups"] },
+ async (tx) => {
+ return tx.recoupGroups.get(recoupGroupId);
+ },
+ );
if (!recoupGroup) {
return TaskRunResult.finished();
}
@@ -339,22 +345,25 @@ export async function processRecoupGroup(
const reservePrivMap: Record<string, string> = {};
for (let i = 0; i < recoupGroup.coinPubs.length; i++) {
const coinPub = recoupGroup.coinPubs[i];
- await wex.db.runReadOnlyTx(["coins", "reserves"], async (tx) => {
- const coin = await tx.coins.get(coinPub);
- if (!coin) {
- throw Error(`Coin ${coinPub} not found, can't request recoup`);
- }
- if (coin.coinSource.type === CoinSourceType.Withdraw) {
- const reserve = await tx.reserves.indexes.byReservePub.get(
- coin.coinSource.reservePub,
- );
- if (!reserve) {
- return;
+ await wex.db.runReadOnlyTx(
+ { storeNames: ["coins", "reserves"] },
+ async (tx) => {
+ const coin = await tx.coins.get(coinPub);
+ if (!coin) {
+ throw Error(`Coin ${coinPub} not found, can't request recoup`);
}
- reserveSet.add(coin.coinSource.reservePub);
- reservePrivMap[coin.coinSource.reservePub] = reserve.reservePriv;
- }
- });
+ if (coin.coinSource.type === CoinSourceType.Withdraw) {
+ const reserve = await tx.reserves.indexes.byReservePub.get(
+ coin.coinSource.reservePub,
+ );
+ if (!reserve) {
+ return;
+ }
+ reserveSet.add(coin.coinSource.reservePub);
+ reservePrivMap[coin.coinSource.reservePub] = reserve.reservePriv;
+ }
+ },
+ );
}
for (const reservePub of reserveSet) {
@@ -385,14 +394,16 @@ export async function processRecoupGroup(
}
await wex.db.runReadWriteTx(
- [
- "recoupGroups",
- "coinAvailability",
- "denominations",
- "refreshGroups",
- "refreshSessions",
- "coins",
- ],
+ {
+ storeNames: [
+ "recoupGroups",
+ "coinAvailability",
+ "denominations",
+ "refreshGroups",
+ "refreshSessions",
+ "coins",
+ ],
+ },
async (tx) => {
const rg2 = await tx.recoupGroups.get(recoupGroupId);
if (!rg2) {
@@ -502,7 +513,7 @@ async function processRecoupForCoin(
coinIdx: number,
): Promise<void> {
const coin = await wex.db.runReadOnlyTx(
- ["coins", "recoupGroups"],
+ { storeNames: ["coins", "recoupGroups"] },
async (tx) => {
const recoupGroup = await tx.recoupGroups.get(recoupGroupId);
if (!recoupGroup) {
diff --git a/packages/taler-wallet-core/src/refresh.ts b/packages/taler-wallet-core/src/refresh.ts
index 99ac5737b..7800967e6 100644
--- a/packages/taler-wallet-core/src/refresh.ts
+++ b/packages/taler-wallet-core/src/refresh.ts
@@ -186,7 +186,7 @@ export class RefreshTransactionContext implements TransactionContext {
? [...baseStores, ...opts.extraStores]
: baseStores;
const transitionInfo = await this.wex.db.runReadWriteTx(
- stores,
+ { storeNames: stores },
async (tx) => {
const wgRec = await tx.refreshGroups.get(this.refreshGroupId);
let oldTxState: TransactionState;
@@ -565,7 +565,14 @@ async function refreshMelt(
): Promise<void> {
const ctx = new RefreshTransactionContext(wex, refreshGroupId);
const d = await wex.db.runReadWriteTx(
- ["refreshGroups", "refreshSessions", "coins", "denominations"],
+ {
+ storeNames: [
+ "refreshGroups",
+ "refreshSessions",
+ "coins",
+ "denominations",
+ ],
+ },
async (tx) => {
const refreshGroup = await tx.refreshGroups.get(refreshGroupId);
if (!refreshGroup) {
@@ -723,7 +730,7 @@ async function refreshMelt(
refreshSession.norevealIndex = norevealIndex;
await wex.db.runReadWriteTx(
- ["refreshGroups", "refreshSessions"],
+ { storeNames: ["refreshGroups", "refreshSessions"] },
async (tx) => {
const rg = await tx.refreshGroups.get(refreshGroupId);
if (!rg) {
@@ -755,13 +762,15 @@ async function handleRefreshMeltGone(
// FIXME: Validate signature.
await ctx.wex.db.runReadWriteTx(
- [
- "refreshGroups",
- "refreshSessions",
- "coins",
- "denominations",
- "coinAvailability",
- ],
+ {
+ storeNames: [
+ "refreshGroups",
+ "refreshSessions",
+ "coins",
+ "denominations",
+ "coinAvailability",
+ ],
+ },
async (tx) => {
const rg = await tx.refreshGroups.get(ctx.refreshGroupId);
if (!rg) {
@@ -832,13 +841,15 @@ async function handleRefreshMeltConflict(
// FIXME: If response seems wrong, report to auditor (in the future!);
await ctx.wex.db.runReadWriteTx(
- [
- "refreshGroups",
- "refreshSessions",
- "denominations",
- "coins",
- "coinAvailability",
- ],
+ {
+ storeNames: [
+ "refreshGroups",
+ "refreshSessions",
+ "denominations",
+ "coins",
+ "coinAvailability",
+ ],
+ },
async (tx) => {
const rg = await tx.refreshGroups.get(ctx.refreshGroupId);
if (!rg) {
@@ -891,13 +902,15 @@ async function handleRefreshMeltNotFound(
): Promise<void> {
// FIXME: Validate the exchange's error response
await ctx.wex.db.runReadWriteTx(
- [
- "refreshGroups",
- "refreshSessions",
- "coins",
- "denominations",
- "coinAvailability",
- ],
+ {
+ storeNames: [
+ "refreshGroups",
+ "refreshSessions",
+ "coins",
+ "denominations",
+ "coinAvailability",
+ ],
+ },
async (tx) => {
const rg = await tx.refreshGroups.get(ctx.refreshGroupId);
if (!rg) {
@@ -993,7 +1006,14 @@ async function refreshReveal(
);
const ctx = new RefreshTransactionContext(wex, refreshGroupId);
const d = await wex.db.runReadOnlyTx(
- ["refreshGroups", "refreshSessions", "coins", "denominations"],
+ {
+ storeNames: [
+ "refreshGroups",
+ "refreshSessions",
+ "coins",
+ "denominations",
+ ],
+ },
async (tx) => {
const refreshGroup = await tx.refreshGroups.get(refreshGroupId);
if (!refreshGroup) {
@@ -1187,13 +1207,15 @@ async function refreshReveal(
}
await wex.db.runReadWriteTx(
- [
- "coins",
- "denominations",
- "coinAvailability",
- "refreshGroups",
- "refreshSessions",
- ],
+ {
+ storeNames: [
+ "coins",
+ "denominations",
+ "coinAvailability",
+ "refreshGroups",
+ "refreshSessions",
+ ],
+ },
async (tx) => {
const rg = await tx.refreshGroups.get(refreshGroupId);
if (!rg) {
@@ -1247,13 +1269,15 @@ async function handleRefreshRevealError(
errDetails: TalerErrorDetail,
): Promise<void> {
await ctx.wex.db.runReadWriteTx(
- [
- "refreshGroups",
- "refreshSessions",
- "coins",
- "denominations",
- "coinAvailability",
- ],
+ {
+ storeNames: [
+ "refreshGroups",
+ "refreshSessions",
+ "coins",
+ "denominations",
+ "coinAvailability",
+ ],
+ },
async (tx) => {
const rg = await tx.refreshGroups.get(ctx.refreshGroupId);
if (!rg) {
@@ -1288,7 +1312,7 @@ export async function processRefreshGroup(
logger.trace(`processing refresh group ${refreshGroupId}`);
const refreshGroup = await wex.db.runReadOnlyTx(
- ["refreshGroups"],
+ { storeNames: ["refreshGroups"] },
async (tx) => tx.refreshGroups.get(refreshGroupId),
);
if (!refreshGroup) {
@@ -1344,7 +1368,7 @@ export async function processRefreshGroup(
// status of the whole refresh group.
const transitionInfo = await wex.db.runReadWriteTx(
- ["coins", "coinAvailability", "refreshGroups"],
+ { storeNames: ["coins", "coinAvailability", "refreshGroups"] },
async (tx) => {
const rg = await tx.refreshGroups.get(refreshGroupId);
if (!rg) {
@@ -1420,7 +1444,7 @@ async function processRefreshSession(
`processing refresh session for coin ${coinIndex} of group ${refreshGroupId}`,
);
let { refreshGroup, refreshSession } = await wex.db.runReadOnlyTx(
- ["refreshGroups", "refreshSessions"],
+ { storeNames: ["refreshGroups", "refreshSessions"] },
async (tx) => {
const rg = await tx.refreshGroups.get(refreshGroupId);
const rs = await tx.refreshSessions.get([refreshGroupId, coinIndex]);
@@ -1710,7 +1734,7 @@ export function getRefreshesForTransaction(
wex: WalletExecutionContext,
transactionId: string,
): Promise<string[]> {
- return wex.db.runReadOnlyTx(["refreshGroups"], async (tx) => {
+ return wex.db.runReadOnlyTx({ storeNames: ["refreshGroups"] }, async (tx) => {
const groups =
await tx.refreshGroups.indexes.byOriginatingTransactionId.getAll(
transactionId,
@@ -1736,13 +1760,15 @@ export async function forceRefresh(
throw Error("refusing to create empty refresh group");
}
const res = await wex.db.runReadWriteTx(
- [
- "refreshGroups",
- "coinAvailability",
- "refreshSessions",
- "denominations",
- "coins",
- ],
+ {
+ storeNames: [
+ "refreshGroups",
+ "coinAvailability",
+ "refreshSessions",
+ "denominations",
+ "coins",
+ ],
+ },
async (tx) => {
let coinPubs: CoinRefreshRequest[] = [];
for (const c of req.refreshCoinSpecs) {
@@ -1828,7 +1854,7 @@ async function internalWaitRefreshFinal(
// Check if refresh is final
const res = await ctx.wex.db.runReadOnlyTx(
- ["refreshGroups", "operationRetries"],
+ { storeNames: ["refreshGroups", "operationRetries"] },
async (tx) => {
return {
rg: await tx.refreshGroups.get(ctx.refreshGroupId),
diff --git a/packages/taler-wallet-core/src/shepherd.ts b/packages/taler-wallet-core/src/shepherd.ts
index 62133d4b9..5e2d23fd9 100644
--- a/packages/taler-wallet-core/src/shepherd.ts
+++ b/packages/taler-wallet-core/src/shepherd.ts
@@ -474,9 +474,12 @@ async function storeTaskProgress(
ws: InternalWalletState,
pendingTaskId: string,
): Promise<void> {
- await ws.db.runReadWriteTx(["operationRetries"], async (tx) => {
- await tx.operationRetries.delete(pendingTaskId);
- });
+ await ws.db.runReadWriteTx(
+ { storeNames: ["operationRetries"] },
+ async (tx) => {
+ await tx.operationRetries.delete(pendingTaskId);
+ },
+ );
}
async function storePendingTaskPending(
@@ -523,9 +526,12 @@ async function storePendingTaskFinished(
ws: InternalWalletState,
pendingTaskId: string,
): Promise<void> {
- await ws.db.runReadWriteTx(["operationRetries"], async (tx) => {
- await tx.operationRetries.delete(pendingTaskId);
- });
+ await ws.db.runReadWriteTx(
+ { storeNames: ["operationRetries"] },
+ async (tx) => {
+ await tx.operationRetries.delete(pendingTaskId);
+ },
+ );
}
function getWalletExecutionContextForTask(
@@ -947,18 +953,20 @@ export async function getActiveTaskIds(
taskIds: [],
};
await ws.db.runReadWriteTx(
- [
- "exchanges",
- "refreshGroups",
- "withdrawalGroups",
- "purchases",
- "depositGroups",
- "recoupGroups",
- "peerPullCredit",
- "peerPushDebit",
- "peerPullDebit",
- "peerPushCredit",
- ],
+ {
+ storeNames: [
+ "exchanges",
+ "refreshGroups",
+ "withdrawalGroups",
+ "purchases",
+ "depositGroups",
+ "recoupGroups",
+ "peerPullCredit",
+ "peerPushDebit",
+ "peerPullDebit",
+ "peerPushCredit",
+ ],
+ },
async (tx) => {
const active = GlobalIDB.KeyRange.bound(
OPERATION_STATUS_ACTIVE_FIRST,
diff --git a/packages/taler-wallet-core/src/testing.ts b/packages/taler-wallet-core/src/testing.ts
index 2f149cfa8..899c4a8b2 100644
--- a/packages/taler-wallet-core/src/testing.ts
+++ b/packages/taler-wallet-core/src/testing.ts
@@ -858,9 +858,12 @@ export async function testPay(
if (r.type != ConfirmPayResultType.Done) {
throw Error("payment not done");
}
- const purchase = await wex.db.runReadOnlyTx(["purchases"], async (tx) => {
- return tx.purchases.get(result.proposalId);
- });
+ const purchase = await wex.db.runReadOnlyTx(
+ { storeNames: ["purchases"] },
+ async (tx) => {
+ return tx.purchases.get(result.proposalId);
+ },
+ );
checkLogicInvariant(!!purchase);
return {
numCoins: purchase.payInfo?.payCoinSelection?.coinContributions.length ?? 0,
diff --git a/packages/taler-wallet-core/src/transactions.ts b/packages/taler-wallet-core/src/transactions.ts
index 43ef09220..f6216d641 100644
--- a/packages/taler-wallet-core/src/transactions.ts
+++ b/packages/taler-wallet-core/src/transactions.ts
@@ -226,12 +226,14 @@ export async function getTransactionById(
case TransactionType.Withdrawal: {
const withdrawalGroupId = parsedTx.withdrawalGroupId;
return await wex.db.runReadWriteTx(
- [
- "withdrawalGroups",
- "exchangeDetails",
- "exchanges",
- "operationRetries",
- ],
+ {
+ storeNames: [
+ "withdrawalGroups",
+ "exchangeDetails",
+ "exchanges",
+ "operationRetries",
+ ],
+ },
async (tx) => {
const withdrawalGroupRecord =
await tx.withdrawalGroups.get(withdrawalGroupId);
@@ -267,7 +269,7 @@ export async function getTransactionById(
case TransactionType.DenomLoss: {
const rec = await wex.db.runReadOnlyTx(
- ["denomLossEvents"],
+ { storeNames: ["denomLossEvents"] },
async (tx) => {
return tx.denomLossEvents.get(parsedTx.denomLossEventId);
},
@@ -284,13 +286,15 @@ export async function getTransactionById(
case TransactionType.Payment: {
const proposalId = parsedTx.proposalId;
return await wex.db.runReadWriteTx(
- [
- "purchases",
- "tombstones",
- "operationRetries",
- "contractTerms",
- "refundGroups",
- ],
+ {
+ storeNames: [
+ "purchases",
+ "tombstones",
+ "operationRetries",
+ "contractTerms",
+ "refundGroups",
+ ],
+ },
async (tx) => {
const purchase = await tx.purchases.get(proposalId);
if (!purchase) throw Error("not found");
@@ -317,7 +321,7 @@ export async function getTransactionById(
// FIXME: We should return info about the refresh here!;
const refreshGroupId = parsedTx.refreshGroupId;
return await wex.db.runReadOnlyTx(
- ["refreshGroups", "operationRetries"],
+ { storeNames: ["refreshGroups", "operationRetries"] },
async (tx) => {
const refreshGroupRec = await tx.refreshGroups.get(refreshGroupId);
if (!refreshGroupRec) {
@@ -334,7 +338,7 @@ export async function getTransactionById(
case TransactionType.Deposit: {
const depositGroupId = parsedTx.depositGroupId;
return await wex.db.runReadWriteTx(
- ["depositGroups", "operationRetries"],
+ { storeNames: ["depositGroups", "operationRetries"] },
async (tx) => {
const depositRecord = await tx.depositGroups.get(depositGroupId);
if (!depositRecord) throw Error("not found");
@@ -349,7 +353,14 @@ export async function getTransactionById(
case TransactionType.Refund: {
return await wex.db.runReadOnlyTx(
- ["refundGroups", "purchases", "operationRetries", "contractTerms"],
+ {
+ storeNames: [
+ "refundGroups",
+ "purchases",
+ "operationRetries",
+ "contractTerms",
+ ],
+ },
async (tx) => {
const refundRecord = await tx.refundGroups.get(
parsedTx.refundGroupId,
@@ -367,7 +378,7 @@ export async function getTransactionById(
}
case TransactionType.PeerPullDebit: {
return await wex.db.runReadWriteTx(
- ["peerPullDebit", "contractTerms"],
+ { storeNames: ["peerPullDebit", "contractTerms"] },
async (tx) => {
const debit = await tx.peerPullDebit.get(parsedTx.peerPullDebitId);
if (!debit) throw Error("not found");
@@ -386,7 +397,7 @@ export async function getTransactionById(
case TransactionType.PeerPushDebit: {
return await wex.db.runReadWriteTx(
- ["peerPushDebit", "contractTerms"],
+ { storeNames: ["peerPushDebit", "contractTerms"] },
async (tx) => {
const debit = await tx.peerPushDebit.get(parsedTx.pursePub);
if (!debit) throw Error("not found");
@@ -403,12 +414,14 @@ export async function getTransactionById(
case TransactionType.PeerPushCredit: {
const peerPushCreditId = parsedTx.peerPushCreditId;
return await wex.db.runReadWriteTx(
- [
- "peerPushCredit",
- "contractTerms",
- "withdrawalGroups",
- "operationRetries",
- ],
+ {
+ storeNames: [
+ "peerPushCredit",
+ "contractTerms",
+ "withdrawalGroups",
+ "operationRetries",
+ ],
+ },
async (tx) => {
const pushInc = await tx.peerPushCredit.get(peerPushCreditId);
if (!pushInc) throw Error("not found");
@@ -441,12 +454,14 @@ export async function getTransactionById(
case TransactionType.PeerPullCredit: {
const pursePub = parsedTx.pursePub;
return await wex.db.runReadWriteTx(
- [
- "peerPullCredit",
- "contractTerms",
- "withdrawalGroups",
- "operationRetries",
- ],
+ {
+ storeNames: [
+ "peerPullCredit",
+ "contractTerms",
+ "withdrawalGroups",
+ "operationRetries",
+ ],
+ },
async (tx) => {
const pushInc = await tx.peerPullCredit.get(pursePub);
if (!pushInc) throw Error("not found");
@@ -1039,7 +1054,14 @@ export async function getWithdrawalTransactionByUri(
request: WithdrawalTransactionByURIRequest,
): Promise<TransactionWithdrawal | undefined> {
return await wex.db.runReadWriteTx(
- ["withdrawalGroups", "exchangeDetails", "exchanges", "operationRetries"],
+ {
+ storeNames: [
+ "withdrawalGroups",
+ "exchangeDetails",
+ "exchanges",
+ "operationRetries",
+ ],
+ },
async (tx) => {
const withdrawalGroupRecord =
await tx.withdrawalGroups.indexes.byTalerWithdrawUri.get(
@@ -1092,28 +1114,30 @@ export async function getTransactions(
}
await wex.db.runReadOnlyTx(
- [
- "coins",
- "denominations",
- "depositGroups",
- "exchangeDetails",
- "exchanges",
- "operationRetries",
- "peerPullDebit",
- "peerPushDebit",
- "peerPushCredit",
- "peerPullCredit",
- "planchets",
- "purchases",
- "contractTerms",
- "recoupGroups",
- "rewards",
- "tombstones",
- "withdrawalGroups",
- "refreshGroups",
- "refundGroups",
- "denomLossEvents",
- ],
+ {
+ storeNames: [
+ "coins",
+ "denominations",
+ "depositGroups",
+ "exchangeDetails",
+ "exchanges",
+ "operationRetries",
+ "peerPullDebit",
+ "peerPushDebit",
+ "peerPushCredit",
+ "peerPullCredit",
+ "planchets",
+ "purchases",
+ "contractTerms",
+ "recoupGroups",
+ "rewards",
+ "tombstones",
+ "withdrawalGroups",
+ "refreshGroups",
+ "refundGroups",
+ "denomLossEvents",
+ ],
+ },
async (tx) => {
await iterRecordsForPeerPushDebit(tx, filter, async (pi) => {
const amount = Amounts.parseOrThrow(pi.amount);
diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts
index 810c78583..b59f52840 100644
--- a/packages/taler-wallet-core/src/wallet.ts
+++ b/packages/taler-wallet-core/src/wallet.ts
@@ -331,28 +331,31 @@ type CancelFn = () => void;
*/
async function fillDefaults(wex: WalletExecutionContext): Promise<void> {
const notifications: WalletNotification[] = [];
- await wex.db.runReadWriteTx(["config", "exchanges"], async (tx) => {
- const appliedRec = await tx.config.get("currencyDefaultsApplied");
- let alreadyApplied = appliedRec ? !!appliedRec.value : false;
- if (alreadyApplied) {
- logger.trace("defaults already applied");
- return;
- }
- for (const exch of wex.ws.config.builtin.exchanges) {
- const resp = await addPresetExchangeEntry(
- tx,
- exch.exchangeBaseUrl,
- exch.currencyHint,
- );
- if (resp.notification) {
- notifications.push(resp.notification);
+ await wex.db.runReadWriteTx(
+ { storeNames: ["config", "exchanges"] },
+ async (tx) => {
+ const appliedRec = await tx.config.get("currencyDefaultsApplied");
+ let alreadyApplied = appliedRec ? !!appliedRec.value : false;
+ if (alreadyApplied) {
+ logger.trace("defaults already applied");
+ return;
}
- }
- await tx.config.put({
- key: ConfigRecordKey.CurrencyDefaultsApplied,
- value: true,
- });
- });
+ for (const exch of wex.ws.config.builtin.exchanges) {
+ const resp = await addPresetExchangeEntry(
+ tx,
+ exch.exchangeBaseUrl,
+ exch.currencyHint,
+ );
+ if (resp.notification) {
+ notifications.push(resp.notification);
+ }
+ }
+ await tx.config.put({
+ key: ConfigRecordKey.CurrencyDefaultsApplied,
+ value: true,
+ });
+ },
+ );
for (const notif of notifications) {
wex.ws.notify(notif);
}
@@ -387,7 +390,7 @@ async function listKnownBankAccounts(
currency?: string,
): Promise<KnownBankAccounts> {
const accounts: KnownBankAccountsInfo[] = [];
- await wex.db.runReadOnlyTx(["bankAccounts"], async (tx) => {
+ await wex.db.runReadOnlyTx({ storeNames: ["bankAccounts"] }, async (tx) => {
const knownAccounts = await tx.bankAccounts.iter().toArray();
for (const r of knownAccounts) {
if (currency && currency !== r.currency) {
@@ -415,7 +418,7 @@ async function addKnownBankAccounts(
alias: string,
currency: string,
): Promise<void> {
- await wex.db.runReadWriteTx(["bankAccounts"], async (tx) => {
+ await wex.db.runReadWriteTx({ storeNames: ["bankAccounts"] }, async (tx) => {
tx.bankAccounts.put({
uri: payto,
alias: alias,
@@ -432,7 +435,7 @@ async function forgetKnownBankAccounts(
wex: WalletExecutionContext,
payto: string,
): Promise<void> {
- await wex.db.runReadWriteTx(["bankAccounts"], async (tx) => {
+ await wex.db.runReadWriteTx({ storeNames: ["bankAccounts"] }, async (tx) => {
const account = await tx.bankAccounts.get(payto);
if (!account) {
throw Error(`account not found: ${payto}`);
@@ -447,39 +450,42 @@ async function setCoinSuspended(
coinPub: string,
suspended: boolean,
): Promise<void> {
- await wex.db.runReadWriteTx(["coins", "coinAvailability"], async (tx) => {
- const c = await tx.coins.get(coinPub);
- if (!c) {
- logger.warn(`coin ${coinPub} not found, won't suspend`);
- return;
- }
- const coinAvailability = await tx.coinAvailability.get([
- c.exchangeBaseUrl,
- c.denomPubHash,
- c.maxAge,
- ]);
- checkDbInvariant(!!coinAvailability);
- if (suspended) {
- if (c.status !== CoinStatus.Fresh) {
+ await wex.db.runReadWriteTx(
+ { storeNames: ["coins", "coinAvailability"] },
+ async (tx) => {
+ const c = await tx.coins.get(coinPub);
+ if (!c) {
+ logger.warn(`coin ${coinPub} not found, won't suspend`);
return;
}
- if (coinAvailability.freshCoinCount === 0) {
- throw Error(
- `invalid coin count ${coinAvailability.freshCoinCount} in DB`,
- );
- }
- coinAvailability.freshCoinCount--;
- c.status = CoinStatus.FreshSuspended;
- } else {
- if (c.status == CoinStatus.Dormant) {
- return;
+ const coinAvailability = await tx.coinAvailability.get([
+ c.exchangeBaseUrl,
+ c.denomPubHash,
+ c.maxAge,
+ ]);
+ checkDbInvariant(!!coinAvailability);
+ if (suspended) {
+ if (c.status !== CoinStatus.Fresh) {
+ return;
+ }
+ if (coinAvailability.freshCoinCount === 0) {
+ throw Error(
+ `invalid coin count ${coinAvailability.freshCoinCount} in DB`,
+ );
+ }
+ coinAvailability.freshCoinCount--;
+ c.status = CoinStatus.FreshSuspended;
+ } else {
+ if (c.status == CoinStatus.Dormant) {
+ return;
+ }
+ coinAvailability.freshCoinCount++;
+ c.status = CoinStatus.Fresh;
}
- coinAvailability.freshCoinCount++;
- c.status = CoinStatus.Fresh;
- }
- await tx.coins.put(c);
- await tx.coinAvailability.put(coinAvailability);
- });
+ await tx.coins.put(c);
+ await tx.coinAvailability.put(coinAvailability);
+ },
+ );
}
/**
@@ -488,55 +494,58 @@ async function setCoinSuspended(
async function dumpCoins(wex: WalletExecutionContext): Promise<CoinDumpJson> {
const coinsJson: CoinDumpJson = { coins: [] };
logger.info("dumping coins");
- await wex.db.runReadOnlyTx(["coins", "denominations"], async (tx) => {
- const coins = await tx.coins.iter().toArray();
- for (const c of coins) {
- const denom = await tx.denominations.get([
- c.exchangeBaseUrl,
- c.denomPubHash,
- ]);
- if (!denom) {
- logger.warn("no denom found for coin");
- continue;
- }
- const cs = c.coinSource;
- let refreshParentCoinPub: string | undefined;
- if (cs.type == CoinSourceType.Refresh) {
- refreshParentCoinPub = cs.oldCoinPub;
- }
- let withdrawalReservePub: string | undefined;
- if (cs.type == CoinSourceType.Withdraw) {
- withdrawalReservePub = cs.reservePub;
- }
- const denomInfo = await getDenomInfo(
- wex,
- tx,
- c.exchangeBaseUrl,
- c.denomPubHash,
- );
- if (!denomInfo) {
- logger.warn("no denomination found for coin");
- continue;
+ await wex.db.runReadOnlyTx(
+ { storeNames: ["coins", "denominations"] },
+ async (tx) => {
+ const coins = await tx.coins.iter().toArray();
+ for (const c of coins) {
+ const denom = await tx.denominations.get([
+ c.exchangeBaseUrl,
+ c.denomPubHash,
+ ]);
+ if (!denom) {
+ logger.warn("no denom found for coin");
+ continue;
+ }
+ const cs = c.coinSource;
+ let refreshParentCoinPub: string | undefined;
+ if (cs.type == CoinSourceType.Refresh) {
+ refreshParentCoinPub = cs.oldCoinPub;
+ }
+ let withdrawalReservePub: string | undefined;
+ if (cs.type == CoinSourceType.Withdraw) {
+ withdrawalReservePub = cs.reservePub;
+ }
+ const denomInfo = await getDenomInfo(
+ wex,
+ tx,
+ c.exchangeBaseUrl,
+ c.denomPubHash,
+ );
+ if (!denomInfo) {
+ logger.warn("no denomination found for coin");
+ continue;
+ }
+ coinsJson.coins.push({
+ coin_pub: c.coinPub,
+ denom_pub: denomInfo.denomPub,
+ denom_pub_hash: c.denomPubHash,
+ denom_value: denom.value,
+ exchange_base_url: c.exchangeBaseUrl,
+ refresh_parent_coin_pub: refreshParentCoinPub,
+ withdrawal_reserve_pub: withdrawalReservePub,
+ coin_status: c.status,
+ ageCommitmentProof: c.ageCommitmentProof,
+ spend_allocation: c.spendAllocation
+ ? {
+ amount: c.spendAllocation.amount,
+ id: c.spendAllocation.id,
+ }
+ : undefined,
+ });
}
- coinsJson.coins.push({
- coin_pub: c.coinPub,
- denom_pub: denomInfo.denomPub,
- denom_pub_hash: c.denomPubHash,
- denom_value: denom.value,
- exchange_base_url: c.exchangeBaseUrl,
- refresh_parent_coin_pub: refreshParentCoinPub,
- withdrawal_reserve_pub: withdrawalReservePub,
- coin_status: c.status,
- ageCommitmentProof: c.ageCommitmentProof,
- spend_allocation: c.spendAllocation
- ? {
- amount: c.spendAllocation.amount,
- id: c.spendAllocation.id,
- }
- : undefined,
- });
- }
- });
+ },
+ );
return coinsJson;
}
@@ -713,7 +722,7 @@ async function dispatchRequestInternal(
// Write to the DB to make sure that we're failing early in
// case the DB is not writeable.
try {
- await wex.db.runReadWriteTx(["config"], async (tx) => {
+ await wex.db.runReadWriteTx({ storeNames: ["config"] }, async (tx) => {
tx.config.put({
key: ConfigRecordKey.LastInitInfo,
value: timestampProtocolToDb(TalerProtocolTimestamp.now()),
@@ -824,20 +833,24 @@ async function dispatchRequestInternal(
numLost: 0,
numOffered: 0,
};
- await wex.db.runReadOnlyTx(["denominations"], async (tx) => {
- const denoms = await tx.denominations.indexes.byExchangeBaseUrl.getAll(
- req.exchangeBaseUrl,
- );
- for (const d of denoms) {
- denomStats.numKnown++;
- if (d.isOffered) {
- denomStats.numOffered++;
- }
- if (d.isLost) {
- denomStats.numLost++;
+ await wex.db.runReadOnlyTx(
+ { storeNames: ["denominations"] },
+ async (tx) => {
+ const denoms =
+ await tx.denominations.indexes.byExchangeBaseUrl.getAll(
+ req.exchangeBaseUrl,
+ );
+ for (const d of denoms) {
+ denomStats.numKnown++;
+ if (d.isOffered) {
+ denomStats.numOffered++;
+ }
+ if (d.isLost) {
+ denomStats.numLost++;
+ }
}
- }
- });
+ },
+ );
return denomStats;
}
case WalletApiOperation.ListExchanges: {
@@ -1026,7 +1039,7 @@ async function dispatchRequestInternal(
const tasksInfo = await Promise.all(
allTasksId.map(async (id) => {
return await wex.db.runReadOnlyTx(
- ["operationRetries"],
+ { storeNames: ["operationRetries"] },
async (tx) => {
return tx.operationRetries.get(id);
},
@@ -1245,89 +1258,112 @@ async function dispatchRequestInternal(
const resp: ListGlobalCurrencyExchangesResponse = {
exchanges: [],
};
- await wex.db.runReadOnlyTx(["globalCurrencyExchanges"], async (tx) => {
- const gceList = await tx.globalCurrencyExchanges.iter().toArray();
- for (const gce of gceList) {
- resp.exchanges.push({
- currency: gce.currency,
- exchangeBaseUrl: gce.exchangeBaseUrl,
- exchangeMasterPub: gce.exchangeMasterPub,
- });
- }
- });
+ await wex.db.runReadOnlyTx(
+ { storeNames: ["globalCurrencyExchanges"] },
+ async (tx) => {
+ const gceList = await tx.globalCurrencyExchanges.iter().toArray();
+ for (const gce of gceList) {
+ resp.exchanges.push({
+ currency: gce.currency,
+ exchangeBaseUrl: gce.exchangeBaseUrl,
+ exchangeMasterPub: gce.exchangeMasterPub,
+ });
+ }
+ },
+ );
return resp;
}
case WalletApiOperation.ListGlobalCurrencyAuditors: {
const resp: ListGlobalCurrencyAuditorsResponse = {
auditors: [],
};
- await wex.db.runReadOnlyTx(["globalCurrencyAuditors"], async (tx) => {
- const gcaList = await tx.globalCurrencyAuditors.iter().toArray();
- for (const gca of gcaList) {
- resp.auditors.push({
- currency: gca.currency,
- auditorBaseUrl: gca.auditorBaseUrl,
- auditorPub: gca.auditorPub,
- });
- }
- });
+ await wex.db.runReadOnlyTx(
+ { storeNames: ["globalCurrencyAuditors"] },
+ async (tx) => {
+ const gcaList = await tx.globalCurrencyAuditors.iter().toArray();
+ for (const gca of gcaList) {
+ resp.auditors.push({
+ currency: gca.currency,
+ auditorBaseUrl: gca.auditorBaseUrl,
+ auditorPub: gca.auditorPub,
+ });
+ }
+ },
+ );
return resp;
}
case WalletApiOperation.AddGlobalCurrencyExchange: {
const req = codecForAddGlobalCurrencyExchangeRequest().decode(payload);
- await wex.db.runReadWriteTx(["globalCurrencyExchanges"], async (tx) => {
- const key = [req.currency, req.exchangeBaseUrl, req.exchangeMasterPub];
- const existingRec =
- await tx.globalCurrencyExchanges.indexes.byCurrencyAndUrlAndPub.get(
- key,
- );
- if (existingRec) {
- return;
- }
- wex.ws.exchangeCache.clear();
- await tx.globalCurrencyExchanges.add({
- currency: req.currency,
- exchangeBaseUrl: req.exchangeBaseUrl,
- exchangeMasterPub: req.exchangeMasterPub,
- });
- });
+ await wex.db.runReadWriteTx(
+ { storeNames: ["globalCurrencyExchanges"] },
+ async (tx) => {
+ const key = [
+ req.currency,
+ req.exchangeBaseUrl,
+ req.exchangeMasterPub,
+ ];
+ const existingRec =
+ await tx.globalCurrencyExchanges.indexes.byCurrencyAndUrlAndPub.get(
+ key,
+ );
+ if (existingRec) {
+ return;
+ }
+ wex.ws.exchangeCache.clear();
+ await tx.globalCurrencyExchanges.add({
+ currency: req.currency,
+ exchangeBaseUrl: req.exchangeBaseUrl,
+ exchangeMasterPub: req.exchangeMasterPub,
+ });
+ },
+ );
return {};
}
case WalletApiOperation.RemoveGlobalCurrencyExchange: {
const req = codecForRemoveGlobalCurrencyExchangeRequest().decode(payload);
- await wex.db.runReadWriteTx(["globalCurrencyExchanges"], async (tx) => {
- const key = [req.currency, req.exchangeBaseUrl, req.exchangeMasterPub];
- const existingRec =
- await tx.globalCurrencyExchanges.indexes.byCurrencyAndUrlAndPub.get(
- key,
- );
- if (!existingRec) {
- return;
- }
- wex.ws.exchangeCache.clear();
- checkDbInvariant(!!existingRec.id);
- await tx.globalCurrencyExchanges.delete(existingRec.id);
- });
+ await wex.db.runReadWriteTx(
+ { storeNames: ["globalCurrencyExchanges"] },
+ async (tx) => {
+ const key = [
+ req.currency,
+ req.exchangeBaseUrl,
+ req.exchangeMasterPub,
+ ];
+ const existingRec =
+ await tx.globalCurrencyExchanges.indexes.byCurrencyAndUrlAndPub.get(
+ key,
+ );
+ if (!existingRec) {
+ return;
+ }
+ wex.ws.exchangeCache.clear();
+ checkDbInvariant(!!existingRec.id);
+ await tx.globalCurrencyExchanges.delete(existingRec.id);
+ },
+ );
return {};
}
case WalletApiOperation.AddGlobalCurrencyAuditor: {
const req = codecForAddGlobalCurrencyAuditorRequest().decode(payload);
- await wex.db.runReadWriteTx(["globalCurrencyAuditors"], async (tx) => {
- const key = [req.currency, req.auditorBaseUrl, req.auditorPub];
- const existingRec =
- await tx.globalCurrencyAuditors.indexes.byCurrencyAndUrlAndPub.get(
- key,
- );
- if (existingRec) {
- return;
- }
- await tx.globalCurrencyAuditors.add({
- currency: req.currency,
- auditorBaseUrl: req.auditorBaseUrl,
- auditorPub: req.auditorPub,
- });
- wex.ws.exchangeCache.clear();
- });
+ await wex.db.runReadWriteTx(
+ { storeNames: ["globalCurrencyAuditors"] },
+ async (tx) => {
+ const key = [req.currency, req.auditorBaseUrl, req.auditorPub];
+ const existingRec =
+ await tx.globalCurrencyAuditors.indexes.byCurrencyAndUrlAndPub.get(
+ key,
+ );
+ if (existingRec) {
+ return;
+ }
+ await tx.globalCurrencyAuditors.add({
+ currency: req.currency,
+ auditorBaseUrl: req.auditorBaseUrl,
+ auditorPub: req.auditorPub,
+ });
+ wex.ws.exchangeCache.clear();
+ },
+ );
return {};
}
case WalletApiOperation.TestingWaitTasksDone: {
@@ -1336,19 +1372,22 @@ async function dispatchRequestInternal(
}
case WalletApiOperation.RemoveGlobalCurrencyAuditor: {
const req = codecForRemoveGlobalCurrencyAuditorRequest().decode(payload);
- await wex.db.runReadWriteTx(["globalCurrencyAuditors"], async (tx) => {
- const key = [req.currency, req.auditorBaseUrl, req.auditorPub];
- const existingRec =
- await tx.globalCurrencyAuditors.indexes.byCurrencyAndUrlAndPub.get(
- key,
- );
- if (!existingRec) {
- return;
- }
- checkDbInvariant(!!existingRec.id);
- await tx.globalCurrencyAuditors.delete(existingRec.id);
- wex.ws.exchangeCache.clear();
- });
+ await wex.db.runReadWriteTx(
+ { storeNames: ["globalCurrencyAuditors"] },
+ async (tx) => {
+ const key = [req.currency, req.auditorBaseUrl, req.auditorPub];
+ const existingRec =
+ await tx.globalCurrencyAuditors.indexes.byCurrencyAndUrlAndPub.get(
+ key,
+ );
+ if (!existingRec) {
+ return;
+ }
+ checkDbInvariant(!!existingRec.id);
+ await tx.globalCurrencyAuditors.delete(existingRec.id);
+ wex.ws.exchangeCache.clear();
+ },
+ );
return {};
}
case WalletApiOperation.ImportDb: {
@@ -1434,7 +1473,7 @@ async function dispatchRequestInternal(
let loopCount = 0;
while (true) {
logger.info(`looping test write tx, iteration ${loopCount}`);
- await wex.db.runReadWriteTx(["config"], async (tx) => {
+ await wex.db.runReadWriteTx({ storeNames: ["config"] }, async (tx) => {
await tx.config.put({
key: ConfigRecordKey.TestLoopTx,
value: loopCount,
diff --git a/packages/taler-wallet-core/src/withdraw.ts b/packages/taler-wallet-core/src/withdraw.ts
index ecd654edf..4936135bd 100644
--- a/packages/taler-wallet-core/src/withdraw.ts
+++ b/packages/taler-wallet-core/src/withdraw.ts
@@ -325,7 +325,7 @@ export class WithdrawTransactionContext implements TransactionContext {
? [...baseStores, ...opts.extraStores]
: baseStores;
const transitionInfo = await this.wex.db.runReadWriteTx(
- stores,
+ { storeNames: stores },
async (tx) => {
const wgRec = await tx.withdrawalGroups.get(this.withdrawalGroupId);
let oldTxState: TransactionState;
@@ -773,9 +773,12 @@ async function getCandidateWithdrawalDenoms(
exchangeBaseUrl: string,
currency: string,
): Promise<DenominationRecord[]> {
- return await wex.db.runReadOnlyTx(["denominations"], async (tx) => {
- return getCandidateWithdrawalDenomsTx(wex, tx, exchangeBaseUrl, currency);
- });
+ return await wex.db.runReadOnlyTx(
+ { storeNames: ["denominations"] },
+ async (tx) => {
+ return getCandidateWithdrawalDenomsTx(wex, tx, exchangeBaseUrl, currency);
+ },
+ );
}
export async function getCandidateWithdrawalDenomsTx(
@@ -806,12 +809,15 @@ async function processPlanchetGenerate(
withdrawalGroup: WithdrawalGroupRecord,
coinIdx: number,
): Promise<void> {
- let planchet = await wex.db.runReadOnlyTx(["planchets"], async (tx) => {
- return tx.planchets.indexes.byGroupAndIndex.get([
- withdrawalGroup.withdrawalGroupId,
- coinIdx,
- ]);
- });
+ let planchet = await wex.db.runReadOnlyTx(
+ { storeNames: ["planchets"] },
+ async (tx) => {
+ return tx.planchets.indexes.byGroupAndIndex.get([
+ withdrawalGroup.withdrawalGroupId,
+ coinIdx,
+ ]);
+ },
+ );
if (planchet) {
return;
}
@@ -837,9 +843,17 @@ async function processPlanchetGenerate(
}
const denomPubHash = maybeDenomPubHash;
- const denom = await wex.db.runReadOnlyTx(["denominations"], async (tx) => {
- return getDenomInfo(wex, tx, withdrawalGroup.exchangeBaseUrl, denomPubHash);
- });
+ const denom = await wex.db.runReadOnlyTx(
+ { storeNames: ["denominations"] },
+ async (tx) => {
+ return getDenomInfo(
+ wex,
+ tx,
+ withdrawalGroup.exchangeBaseUrl,
+ denomPubHash,
+ );
+ },
+ );
checkDbInvariant(!!denom);
const r = await wex.cryptoApi.createPlanchet({
denomPub: denom.denomPub,
@@ -865,7 +879,7 @@ async function processPlanchetGenerate(
ageCommitmentProof: r.ageCommitmentProof,
lastError: undefined,
};
- await wex.db.runReadWriteTx(["planchets"], async (tx) => {
+ await wex.db.runReadWriteTx({ storeNames: ["planchets"] }, async (tx) => {
const p = await tx.planchets.indexes.byGroupAndIndex.get([
withdrawalGroup.withdrawalGroupId,
coinIdx,
@@ -1008,48 +1022,51 @@ async function processPlanchetExchangeBatchRequest(
// Indices of coins that are included in the batch request
const requestCoinIdxs: number[] = [];
- await wex.db.runReadOnlyTx(["planchets", "denominations"], async (tx) => {
- for (
- let coinIdx = args.coinStartIndex;
- coinIdx < args.coinStartIndex + args.batchSize &&
- coinIdx < wgContext.numPlanchets;
- coinIdx++
- ) {
- let planchet = await tx.planchets.indexes.byGroupAndIndex.get([
- withdrawalGroup.withdrawalGroupId,
- coinIdx,
- ]);
- if (!planchet) {
- continue;
- }
- if (planchet.planchetStatus === PlanchetStatus.WithdrawalDone) {
- logger.warn("processPlanchet: planchet already withdrawn");
- continue;
- }
- if (planchet.planchetStatus === PlanchetStatus.AbortedReplaced) {
- continue;
- }
- const denom = await getDenomInfo(
- wex,
- tx,
- withdrawalGroup.exchangeBaseUrl,
- planchet.denomPubHash,
- );
+ await wex.db.runReadOnlyTx(
+ { storeNames: ["planchets", "denominations"] },
+ async (tx) => {
+ for (
+ let coinIdx = args.coinStartIndex;
+ coinIdx < args.coinStartIndex + args.batchSize &&
+ coinIdx < wgContext.numPlanchets;
+ coinIdx++
+ ) {
+ let planchet = await tx.planchets.indexes.byGroupAndIndex.get([
+ withdrawalGroup.withdrawalGroupId,
+ coinIdx,
+ ]);
+ if (!planchet) {
+ continue;
+ }
+ if (planchet.planchetStatus === PlanchetStatus.WithdrawalDone) {
+ logger.warn("processPlanchet: planchet already withdrawn");
+ continue;
+ }
+ if (planchet.planchetStatus === PlanchetStatus.AbortedReplaced) {
+ continue;
+ }
+ const denom = await getDenomInfo(
+ wex,
+ tx,
+ withdrawalGroup.exchangeBaseUrl,
+ planchet.denomPubHash,
+ );
- if (!denom) {
- logger.error("db inconsistent: denom for planchet not found");
- continue;
- }
+ if (!denom) {
+ logger.error("db inconsistent: denom for planchet not found");
+ continue;
+ }
- const planchetReq: ExchangeWithdrawRequest = {
- denom_pub_hash: planchet.denomPubHash,
- reserve_sig: planchet.withdrawSig,
- coin_ev: planchet.coinEv,
- };
- batchReq.planchets.push(planchetReq);
- requestCoinIdxs.push(coinIdx);
- }
- });
+ const planchetReq: ExchangeWithdrawRequest = {
+ denom_pub_hash: planchet.denomPubHash,
+ reserve_sig: planchet.withdrawSig,
+ coin_ev: planchet.coinEv,
+ };
+ batchReq.planchets.push(planchetReq);
+ requestCoinIdxs.push(coinIdx);
+ }
+ },
+ );
if (batchReq.planchets.length == 0) {
logger.warn("empty withdrawal batch");
@@ -1064,7 +1081,7 @@ async function processPlanchetExchangeBatchRequest(
coinIdx: number,
): Promise<void> {
logger.trace(`withdrawal request failed: ${j2s(errDetail)}`);
- await wex.db.runReadWriteTx(["planchets"], async (tx) => {
+ await wex.db.runReadWriteTx({ storeNames: ["planchets"] }, async (tx) => {
let planchet = await tx.planchets.indexes.byGroupAndIndex.get([
withdrawalGroup.withdrawalGroupId,
coinIdx,
@@ -1136,7 +1153,7 @@ async function processPlanchetVerifyAndStoreCoin(
const withdrawalGroup = wgContext.wgRecord;
logger.trace(`checking and storing planchet idx=${coinIdx}`);
const d = await wex.db.runReadOnlyTx(
- ["planchets", "denominations"],
+ { storeNames: ["planchets", "denominations"] },
async (tx) => {
let planchet = await tx.planchets.indexes.byGroupAndIndex.get([
withdrawalGroup.withdrawalGroupId,
@@ -1200,7 +1217,7 @@ async function processPlanchetVerifyAndStoreCoin(
});
if (!isValid) {
- await wex.db.runReadWriteTx(["planchets"], async (tx) => {
+ await wex.db.runReadWriteTx({ storeNames: ["planchets"] }, async (tx) => {
let planchet = await tx.planchets.indexes.byGroupAndIndex.get([
withdrawalGroup.withdrawalGroupId,
coinIdx,
@@ -1254,7 +1271,7 @@ async function processPlanchetVerifyAndStoreCoin(
wgContext.planchetsFinished.add(planchet.coinPub);
await wex.db.runReadWriteTx(
- ["planchets", "coins", "coinAvailability", "denominations"],
+ { storeNames: ["planchets", "coins", "coinAvailability", "denominations"] },
async (tx) => {
const p = await tx.planchets.get(planchetCoinPub);
if (!p || p.planchetStatus === PlanchetStatus.WithdrawalDone) {
@@ -1280,7 +1297,7 @@ export async function updateWithdrawalDenoms(
`updating denominations used for withdrawal for ${exchangeBaseUrl}`,
);
const exchangeDetails = await wex.db.runReadOnlyTx(
- ["exchanges", "exchangeDetails"],
+ { storeNames: ["exchanges", "exchangeDetails"] },
async (tx) => {
return getExchangeWireDetailsInTx(tx, exchangeBaseUrl);
},
@@ -1343,12 +1360,15 @@ export async function updateWithdrawalDenoms(
}
if (updatedDenominations.length > 0) {
logger.trace("writing denomination batch to db");
- await wex.db.runReadWriteTx(["denominations"], async (tx) => {
- for (let i = 0; i < updatedDenominations.length; i++) {
- const denom = updatedDenominations[i];
- await tx.denominations.put(denom);
- }
- });
+ await wex.db.runReadWriteTx(
+ { storeNames: ["denominations"] },
+ async (tx) => {
+ for (let i = 0; i < updatedDenominations.length; i++) {
+ const denom = updatedDenominations[i];
+ await tx.denominations.put(denom);
+ }
+ },
+ );
wex.ws.denomInfoCache.clear();
logger.trace("done with DB write");
}
@@ -1560,7 +1580,7 @@ async function redenominateWithdrawal(
): Promise<void> {
logger.trace(`redenominating withdrawal group ${withdrawalGroupId}`);
await wex.db.runReadWriteTx(
- ["withdrawalGroups", "planchets", "denominations"],
+ { storeNames: ["withdrawalGroups", "planchets", "denominations"] },
async (tx) => {
const wg = await tx.withdrawalGroups.get(withdrawalGroupId);
if (!wg) {
@@ -1728,7 +1748,7 @@ async function processWithdrawalGroupPendingReady(
wgRecord: withdrawalGroup,
};
- await wex.db.runReadOnlyTx(["planchets"], async (tx) => {
+ await wex.db.runReadOnlyTx({ storeNames: ["planchets"] }, async (tx) => {
const planchets =
await tx.planchets.indexes.byGroup.getAll(withdrawalGroupId);
for (const p of planchets) {
@@ -1772,7 +1792,7 @@ async function processWithdrawalGroupPendingReady(
let redenomRequired = false;
- await wex.db.runReadOnlyTx(["planchets"], async (tx) => {
+ await wex.db.runReadOnlyTx({ storeNames: ["planchets"] }, async (tx) => {
const planchets =
await tx.planchets.indexes.byGroup.getAll(withdrawalGroupId);
for (const p of planchets) {
@@ -1876,7 +1896,7 @@ export async function processWithdrawalGroup(
): Promise<TaskRunResult> {
logger.trace("processing withdrawal group", withdrawalGroupId);
const withdrawalGroup = await wex.db.runReadOnlyTx(
- ["withdrawalGroups"],
+ { storeNames: ["withdrawalGroups"] },
async (tx) => {
return tx.withdrawalGroups.get(withdrawalGroupId);
},
@@ -2192,9 +2212,12 @@ async function getWithdrawalGroupRecordTx(
withdrawalGroupId: string;
},
): Promise<WithdrawalGroupRecord | undefined> {
- return await db.runReadOnlyTx(["withdrawalGroups"], async (tx) => {
- return tx.withdrawalGroups.get(req.withdrawalGroupId);
- });
+ return await db.runReadOnlyTx(
+ { storeNames: ["withdrawalGroups"] },
+ async (tx) => {
+ return tx.withdrawalGroups.get(req.withdrawalGroupId);
+ },
+ );
}
export function getReserveRequestTimeout(r: WithdrawalGroupRecord): Duration {
@@ -2230,7 +2253,7 @@ async function registerReserveWithBank(
withdrawalGroupId: string,
): Promise<void> {
const withdrawalGroup = await wex.db.runReadOnlyTx(
- ["withdrawalGroups"],
+ { storeNames: ["withdrawalGroups"] },
async (tx) => {
return await tx.withdrawalGroups.get(withdrawalGroupId);
},
@@ -2497,7 +2520,7 @@ export async function internalPrepareCreateWithdrawalGroup(
withdrawalGroupId = args.forcedWithdrawalGroupId;
const wgId = withdrawalGroupId;
const existingWg = await wex.db.runReadOnlyTx(
- ["withdrawalGroups"],
+ { storeNames: ["withdrawalGroups"] },
async (tx) => {
return tx.withdrawalGroups.get(wgId);
},
@@ -2684,14 +2707,16 @@ export async function internalCreateWithdrawalGroup(
prep.withdrawalGroup.withdrawalGroupId,
);
const res = await wex.db.runReadWriteTx(
- [
- "withdrawalGroups",
- "reserves",
- "exchanges",
- "exchangeDetails",
- "transactions",
- "operationRetries",
- ],
+ {
+ storeNames: [
+ "withdrawalGroups",
+ "reserves",
+ "exchanges",
+ "exchangeDetails",
+ "transactions",
+ "operationRetries",
+ ],
+ },
async (tx) => {
const res = await internalPerformCreateWithdrawalGroup(wex, tx, prep);
await updateWithdrawalTransaction(ctx, tx);
@@ -2727,7 +2752,7 @@ export async function acceptWithdrawalFromUri(
`accepting withdrawal via ${req.talerWithdrawUri}, canonicalized selected exchange ${selectedExchange}`,
);
const existingWithdrawalGroup = await wex.db.runReadOnlyTx(
- ["withdrawalGroups"],
+ { storeNames: ["withdrawalGroups"] },
async (tx) => {
return await tx.withdrawalGroups.indexes.byTalerWithdrawUri.get(
req.talerWithdrawUri,
@@ -2821,7 +2846,7 @@ async function internalWaitWithdrawalRegistered(
): Promise<void> {
while (true) {
const { withdrawalRec, retryRec } = await wex.db.runReadOnlyTx(
- ["withdrawalGroups", "operationRetries"],
+ { storeNames: ["withdrawalGroups", "operationRetries"] },
async (tx) => {
return {
withdrawalRec: await tx.withdrawalGroups.get(ctx.withdrawalGroupId),
@@ -3069,7 +3094,7 @@ export async function createManualWithdrawal(
);
const exchangePaytoUris = await wex.db.runReadOnlyTx(
- ["withdrawalGroups", "exchanges", "exchangeDetails"],
+ { storeNames: ["withdrawalGroups", "exchanges", "exchangeDetails"] },
async (tx) => {
return await getFundingPaytoUris(tx, withdrawalGroup.withdrawalGroupId);
},
@@ -3136,7 +3161,7 @@ async function internalWaitWithdrawalFinal(
// Check if refresh is final
const res = await ctx.wex.db.runReadOnlyTx(
- ["withdrawalGroups", "operationRetries"],
+ { storeNames: ["withdrawalGroups", "operationRetries"] },
async (tx) => {
return {
wg: await tx.withdrawalGroups.get(ctx.withdrawalGroupId),