wallet-core: introduce easier syntax for transactions

This commit is contained in:
Florian Dold 2022-09-13 13:25:41 +02:00
parent 13e7a67477
commit 48540f6264
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
22 changed files with 428 additions and 667 deletions

View File

@ -46,9 +46,13 @@ function upgradeFromStoreMap(
): void { ): void {
if (oldVersion === 0) { if (oldVersion === 0) {
for (const n in storeMap) { for (const n in storeMap) {
const swi: StoreWithIndexes<StoreDescriptor<unknown>, any> = storeMap[n]; const swi: StoreWithIndexes<
any,
StoreDescriptor<unknown>,
any
> = storeMap[n];
const storeDesc: StoreDescriptor<unknown> = swi.store; const storeDesc: StoreDescriptor<unknown> = swi.store;
const s = db.createObjectStore(storeDesc.name, { const s = db.createObjectStore(swi.storeName, {
autoIncrement: storeDesc.autoIncrement, autoIncrement: storeDesc.autoIncrement,
keyPath: storeDesc.keyPath, keyPath: storeDesc.keyPath,
}); });
@ -117,9 +121,7 @@ export async function openTalerDatabase(
const metaDb = new DbAccess(metaDbHandle, walletMetadataStore); const metaDb = new DbAccess(metaDbHandle, walletMetadataStore);
let currentMainVersion: string | undefined; let currentMainVersion: string | undefined;
await metaDb await metaDb
.mktx((x) => ({ .mktx((stores) => [stores.metaConfig])
metaConfig: x.metaConfig,
}))
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const dbVersionRecord = await tx.metaConfig.get(CURRENT_DB_CONFIG_KEY); const dbVersionRecord = await tx.metaConfig.get(CURRENT_DB_CONFIG_KEY);
if (!dbVersionRecord) { if (!dbVersionRecord) {
@ -141,9 +143,7 @@ export async function openTalerDatabase(
// We consider this a pre-release // We consider this a pre-release
// development version, no migration is done. // development version, no migration is done.
await metaDb await metaDb
.mktx((x) => ({ .mktx((stores) => [stores.metaConfig])
metaConfig: x.metaConfig,
}))
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
await tx.metaConfig.put({ await tx.metaConfig.put({
key: CURRENT_DB_CONFIG_KEY, key: CURRENT_DB_CONFIG_KEY,

View File

@ -1079,7 +1079,7 @@ export interface PurchaseRecord {
/** /**
* Pending refunds for the purchase. A refund is pending * Pending refunds for the purchase. A refund is pending
* when the merchant reports a transient error from the exchange. * when the merchant reports a transient error from the exchange.
* *
* FIXME: Put this into a separate object store? * FIXME: Put this into a separate object store?
*/ */
refunds: { [refundKey: string]: WalletRefundItem }; refunds: { [refundKey: string]: WalletRefundItem };
@ -1733,7 +1733,8 @@ export interface OperationAttemptLongpollResult {
export const WalletStoresV1 = { export const WalletStoresV1 = {
coins: describeStore( coins: describeStore(
describeContents<CoinRecord>("coins", { "coins",
describeContents<CoinRecord>({
keyPath: "coinPub", keyPath: "coinPub",
}), }),
{ {
@ -1743,17 +1744,20 @@ export const WalletStoresV1 = {
}, },
), ),
reserves: describeStore( reserves: describeStore(
describeContents<ReserveRecord>("reserves", { "reserves",
describeContents<ReserveRecord>({
keyPath: "reservePub", keyPath: "reservePub",
}), }),
{}, {},
), ),
config: describeStore( config: describeStore(
describeContents<ConfigRecord>("config", { keyPath: "key" }), "config",
describeContents<ConfigRecord>({ keyPath: "key" }),
{}, {},
), ),
auditorTrust: describeStore( auditorTrust: describeStore(
describeContents<AuditorTrustRecord>("auditorTrust", { "auditorTrust",
describeContents<AuditorTrustRecord>({
keyPath: ["currency", "auditorBaseUrl"], keyPath: ["currency", "auditorBaseUrl"],
}), }),
{ {
@ -1764,7 +1768,8 @@ export const WalletStoresV1 = {
}, },
), ),
exchangeTrust: describeStore( exchangeTrust: describeStore(
describeContents<ExchangeTrustRecord>("exchangeTrust", { "exchangeTrust",
describeContents<ExchangeTrustRecord>({
keyPath: ["currency", "exchangeBaseUrl"], keyPath: ["currency", "exchangeBaseUrl"],
}), }),
{ {
@ -1775,7 +1780,8 @@ export const WalletStoresV1 = {
}, },
), ),
denominations: describeStore( denominations: describeStore(
describeContents<DenominationRecord>("denominations", { "denominations",
describeContents<DenominationRecord>({
keyPath: ["exchangeBaseUrl", "denomPubHash"], keyPath: ["exchangeBaseUrl", "denomPubHash"],
}), }),
{ {
@ -1783,19 +1789,22 @@ export const WalletStoresV1 = {
}, },
), ),
exchanges: describeStore( exchanges: describeStore(
describeContents<ExchangeRecord>("exchanges", { "exchanges",
describeContents<ExchangeRecord>({
keyPath: "baseUrl", keyPath: "baseUrl",
}), }),
{}, {},
), ),
exchangeDetails: describeStore( exchangeDetails: describeStore(
describeContents<ExchangeDetailsRecord>("exchangeDetails", { "exchangeDetails",
describeContents<ExchangeDetailsRecord>({
keyPath: ["exchangeBaseUrl", "currency", "masterPublicKey"], keyPath: ["exchangeBaseUrl", "currency", "masterPublicKey"],
}), }),
{}, {},
), ),
proposals: describeStore( proposals: describeStore(
describeContents<ProposalRecord>("proposals", { keyPath: "proposalId" }), "proposals",
describeContents<ProposalRecord>({ keyPath: "proposalId" }),
{ {
byUrlAndOrderId: describeIndex("byUrlAndOrderId", [ byUrlAndOrderId: describeIndex("byUrlAndOrderId", [
"merchantBaseUrl", "merchantBaseUrl",
@ -1804,7 +1813,8 @@ export const WalletStoresV1 = {
}, },
), ),
refreshGroups: describeStore( refreshGroups: describeStore(
describeContents<RefreshGroupRecord>("refreshGroups", { "refreshGroups",
describeContents<RefreshGroupRecord>({
keyPath: "refreshGroupId", keyPath: "refreshGroupId",
}), }),
{ {
@ -1812,13 +1822,15 @@ export const WalletStoresV1 = {
}, },
), ),
recoupGroups: describeStore( recoupGroups: describeStore(
describeContents<RecoupGroupRecord>("recoupGroups", { "recoupGroups",
describeContents<RecoupGroupRecord>({
keyPath: "recoupGroupId", keyPath: "recoupGroupId",
}), }),
{}, {},
), ),
purchases: describeStore( purchases: describeStore(
describeContents<PurchaseRecord>("purchases", { keyPath: "proposalId" }), "purchases",
describeContents<PurchaseRecord>({ keyPath: "proposalId" }),
{ {
byFulfillmentUrl: describeIndex( byFulfillmentUrl: describeIndex(
"byFulfillmentUrl", "byFulfillmentUrl",
@ -1831,7 +1843,8 @@ export const WalletStoresV1 = {
}, },
), ),
tips: describeStore( tips: describeStore(
describeContents<TipRecord>("tips", { keyPath: "walletTipId" }), "tips",
describeContents<TipRecord>({ keyPath: "walletTipId" }),
{ {
byMerchantTipIdAndBaseUrl: describeIndex("byMerchantTipIdAndBaseUrl", [ byMerchantTipIdAndBaseUrl: describeIndex("byMerchantTipIdAndBaseUrl", [
"merchantTipId", "merchantTipId",
@ -1840,7 +1853,8 @@ export const WalletStoresV1 = {
}, },
), ),
withdrawalGroups: describeStore( withdrawalGroups: describeStore(
describeContents<WithdrawalGroupRecord>("withdrawalGroups", { "withdrawalGroups",
describeContents<WithdrawalGroupRecord>({
keyPath: "withdrawalGroupId", keyPath: "withdrawalGroupId",
}), }),
{ {
@ -1853,7 +1867,8 @@ export const WalletStoresV1 = {
}, },
), ),
planchets: describeStore( planchets: describeStore(
describeContents<PlanchetRecord>("planchets", { keyPath: "coinPub" }), "planchets",
describeContents<PlanchetRecord>({ keyPath: "coinPub" }),
{ {
byGroupAndIndex: describeIndex("byGroupAndIndex", [ byGroupAndIndex: describeIndex("byGroupAndIndex", [
"withdrawalGroupId", "withdrawalGroupId",
@ -1864,13 +1879,15 @@ export const WalletStoresV1 = {
}, },
), ),
bankWithdrawUris: describeStore( bankWithdrawUris: describeStore(
describeContents<BankWithdrawUriRecord>("bankWithdrawUris", { "bankWithdrawUris",
describeContents<BankWithdrawUriRecord>({
keyPath: "talerWithdrawUri", keyPath: "talerWithdrawUri",
}), }),
{}, {},
), ),
backupProviders: describeStore( backupProviders: describeStore(
describeContents<BackupProviderRecord>("backupProviders", { "backupProviders",
describeContents<BackupProviderRecord>({
keyPath: "baseUrl", keyPath: "baseUrl",
}), }),
{ {
@ -1884,7 +1901,8 @@ export const WalletStoresV1 = {
}, },
), ),
depositGroups: describeStore( depositGroups: describeStore(
describeContents<DepositGroupRecord>("depositGroups", { "depositGroups",
describeContents<DepositGroupRecord>({
keyPath: "depositGroupId", keyPath: "depositGroupId",
}), }),
{ {
@ -1892,29 +1910,34 @@ export const WalletStoresV1 = {
}, },
), ),
tombstones: describeStore( tombstones: describeStore(
describeContents<TombstoneRecord>("tombstones", { keyPath: "id" }), "tombstones",
describeContents<TombstoneRecord>({ keyPath: "id" }),
{}, {},
), ),
operationRetries: describeStore( operationRetries: describeStore(
describeContents<OperationRetryRecord>("operationRetries", { "operationRetries",
describeContents<OperationRetryRecord>({
keyPath: "id", keyPath: "id",
}), }),
{}, {},
), ),
ghostDepositGroups: describeStore( ghostDepositGroups: describeStore(
describeContents<GhostDepositGroupRecord>("ghostDepositGroups", { "ghostDepositGroups",
describeContents<GhostDepositGroupRecord>({
keyPath: "contractTermsHash", keyPath: "contractTermsHash",
}), }),
{}, {},
), ),
balancesPerCurrency: describeStore( balancesPerCurrency: describeStore(
describeContents<BalancePerCurrencyRecord>("balancesPerCurrency", { "balancesPerCurrency",
describeContents<BalancePerCurrencyRecord>({
keyPath: "currency", keyPath: "currency",
}), }),
{}, {},
), ),
peerPushPaymentIncoming: describeStore( peerPushPaymentIncoming: describeStore(
describeContents<PeerPushPaymentIncomingRecord>("peerPushPaymentIncoming", { "peerPushPaymentIncoming",
describeContents<PeerPushPaymentIncomingRecord>({
keyPath: "peerPushPaymentIncomingId", keyPath: "peerPushPaymentIncomingId",
}), }),
{ {
@ -1925,7 +1948,8 @@ export const WalletStoresV1 = {
}, },
), ),
peerPullPaymentIncoming: describeStore( peerPullPaymentIncoming: describeStore(
describeContents<PeerPullPaymentIncomingRecord>("peerPullPaymentIncoming", { "peerPullPaymentIncoming",
describeContents<PeerPullPaymentIncomingRecord>({
keyPath: "peerPullPaymentIncomingId", keyPath: "peerPullPaymentIncomingId",
}), }),
{ {
@ -1936,21 +1960,17 @@ export const WalletStoresV1 = {
}, },
), ),
peerPullPaymentInitiations: describeStore( peerPullPaymentInitiations: describeStore(
describeContents<PeerPullPaymentInitiationRecord>( "peerPullPaymentInitiations",
"peerPullPaymentInitiations", describeContents<PeerPullPaymentInitiationRecord>({
{ keyPath: "pursePub",
keyPath: "pursePub", }),
},
),
{}, {},
), ),
peerPushPaymentInitiations: describeStore( peerPushPaymentInitiations: describeStore(
describeContents<PeerPushPaymentInitiationRecord>( "peerPushPaymentInitiations",
"peerPushPaymentInitiations", describeContents<PeerPushPaymentInitiationRecord>({
{ keyPath: "pursePub",
keyPath: "pursePub", }),
},
),
{}, {},
), ),
}; };
@ -1962,7 +1982,8 @@ export interface MetaConfigRecord {
export const walletMetadataStore = { export const walletMetadataStore = {
metaConfig: describeStore( metaConfig: describeStore(
describeContents<MetaConfigRecord>("metaConfig", { keyPath: "key" }), "metaConfig",
describeContents<MetaConfigRecord>({ keyPath: "key" }),
{}, {},
), ),
}; };

View File

@ -76,20 +76,20 @@ export async function exportBackup(
): Promise<WalletBackupContentV1> { ): Promise<WalletBackupContentV1> {
await provideBackupState(ws); await provideBackupState(ws);
return ws.db return ws.db
.mktx((x) => ({ .mktx((x) => [
config: x.config, x.config,
exchanges: x.exchanges, x.exchanges,
exchangeDetails: x.exchangeDetails, x.exchangeDetails,
coins: x.coins, x.coins,
denominations: x.denominations, x.denominations,
purchases: x.purchases, x.purchases,
proposals: x.proposals, x.proposals,
refreshGroups: x.refreshGroups, x.refreshGroups,
backupProviders: x.backupProviders, x.backupProviders,
tips: x.tips, x.tips,
recoupGroups: x.recoupGroups, x.recoupGroups,
withdrawalGroups: x.withdrawalGroups, x.withdrawalGroups,
})) ])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const bs = await getWalletBackupState(ws, tx); const bs = await getWalletBackupState(ws, tx);

View File

@ -224,22 +224,22 @@ export async function importBackup(
logger.info(`importing backup ${j2s(backupBlobArg)}`); logger.info(`importing backup ${j2s(backupBlobArg)}`);
return ws.db return ws.db
.mktx((x) => ({ .mktx((x) => [
config: x.config, x.config,
exchanges: x.exchanges, x.exchangeDetails,
exchangeDetails: x.exchangeDetails, x.exchanges,
coins: x.coins, x.coins,
denominations: x.denominations, x.denominations,
purchases: x.purchases, x.purchases,
proposals: x.proposals, x.proposals,
refreshGroups: x.refreshGroups, x.refreshGroups,
backupProviders: x.backupProviders, x.backupProviders,
tips: x.tips, x.tips,
recoupGroups: x.recoupGroups, x.recoupGroups,
withdrawalGroups: x.withdrawalGroups, x.withdrawalGroups,
tombstones: x.tombstones, x.tombstones,
depositGroups: x.depositGroups, x.depositGroups,
})) ])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
// FIXME: validate schema! // FIXME: validate schema!
const backupBlob = backupBlobArg as WalletBackupContentV1; const backupBlob = backupBlobArg as WalletBackupContentV1;

View File

@ -264,7 +264,7 @@ async function runBackupCycleForProvider(
args: BackupForProviderArgs, args: BackupForProviderArgs,
): Promise<OperationAttemptResult> { ): Promise<OperationAttemptResult> {
const provider = await ws.db const provider = await ws.db
.mktx((x) => ({ backupProviders: x.backupProviders })) .mktx((x) => [x.backupProviders])
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
return tx.backupProviders.get(args.backupProviderBaseUrl); return tx.backupProviders.get(args.backupProviderBaseUrl);
}); });
@ -322,9 +322,9 @@ async function runBackupCycleForProvider(
if (resp.status === HttpStatusCode.NotModified) { if (resp.status === HttpStatusCode.NotModified) {
await ws.db await ws.db
.mktx((x) => ({ backupProvider: x.backupProviders })) .mktx((x) => [x.backupProviders])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const prov = await tx.backupProvider.get(provider.baseUrl); const prov = await tx.backupProviders.get(provider.baseUrl);
if (!prov) { if (!prov) {
return; return;
} }
@ -333,7 +333,7 @@ async function runBackupCycleForProvider(
tag: BackupProviderStateTag.Ready, tag: BackupProviderStateTag.Ready,
nextBackupTimestamp: getNextBackupTimestamp(), nextBackupTimestamp: getNextBackupTimestamp(),
}; };
await tx.backupProvider.put(prov); await tx.backupProviders.put(prov);
}); });
return { return {
type: OperationAttemptResultType.Finished, type: OperationAttemptResultType.Finished,
@ -367,10 +367,7 @@ async function runBackupCycleForProvider(
// FIXME: check if the provider is overcharging us! // FIXME: check if the provider is overcharging us!
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [x.backupProviders, x.operationRetries])
backupProviders: x.backupProviders,
operationRetries: x.operationRetries,
}))
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const provRec = await tx.backupProviders.get(provider.baseUrl); const provRec = await tx.backupProviders.get(provider.baseUrl);
checkDbInvariant(!!provRec); checkDbInvariant(!!provRec);
@ -407,7 +404,7 @@ async function runBackupCycleForProvider(
if (resp.status === HttpStatusCode.NoContent) { if (resp.status === HttpStatusCode.NoContent) {
await ws.db await ws.db
.mktx((x) => ({ backupProviders: x.backupProviders })) .mktx((x) => [x.backupProviders])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const prov = await tx.backupProviders.get(provider.baseUrl); const prov = await tx.backupProviders.get(provider.baseUrl);
if (!prov) { if (!prov) {
@ -435,12 +432,9 @@ async function runBackupCycleForProvider(
const cryptoData = await computeBackupCryptoData(ws.cryptoApi, blob); const cryptoData = await computeBackupCryptoData(ws.cryptoApi, blob);
await importBackup(ws, blob, cryptoData); await importBackup(ws, blob, cryptoData);
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [x.backupProviders, x.operationRetries])
backupProvider: x.backupProviders,
operationRetries: x.operationRetries,
}))
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const prov = await tx.backupProvider.get(provider.baseUrl); const prov = await tx.backupProviders.get(provider.baseUrl);
if (!prov) { if (!prov) {
logger.warn("backup provider not found anymore"); logger.warn("backup provider not found anymore");
return; return;
@ -453,7 +447,7 @@ async function runBackupCycleForProvider(
prov.state = { prov.state = {
tag: BackupProviderStateTag.Retrying, tag: BackupProviderStateTag.Retrying,
}; };
await tx.backupProvider.put(prov); await tx.backupProviders.put(prov);
}); });
logger.info("processed existing backup"); logger.info("processed existing backup");
// Now upload our own, merged backup. // Now upload our own, merged backup.
@ -480,7 +474,7 @@ export async function processBackupForProvider(
backupProviderBaseUrl: string, backupProviderBaseUrl: string,
): Promise<OperationAttemptResult> { ): Promise<OperationAttemptResult> {
const provider = await ws.db const provider = await ws.db
.mktx((x) => ({ backupProviders: x.backupProviders })) .mktx((x) => [x.backupProviders])
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
return await tx.backupProviders.get(backupProviderBaseUrl); return await tx.backupProviders.get(backupProviderBaseUrl);
}); });
@ -509,7 +503,7 @@ export async function removeBackupProvider(
req: RemoveBackupProviderRequest, req: RemoveBackupProviderRequest,
): Promise<void> { ): Promise<void> {
await ws.db await ws.db
.mktx(({ backupProviders }) => ({ backupProviders })) .mktx((x) => [x.backupProviders])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
await tx.backupProviders.delete(req.provider); await tx.backupProviders.delete(req.provider);
}); });
@ -539,7 +533,7 @@ export async function runBackupCycle(
req: RunBackupCycleRequest, req: RunBackupCycleRequest,
): Promise<void> { ): Promise<void> {
const providers = await ws.db const providers = await ws.db
.mktx((x) => ({ backupProviders: x.backupProviders })) .mktx((x) => [x.backupProviders])
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
if (req.providers) { if (req.providers) {
const rs = await Promise.all( const rs = await Promise.all(
@ -605,7 +599,7 @@ export async function addBackupProvider(
await provideBackupState(ws); await provideBackupState(ws);
const canonUrl = canonicalizeBaseUrl(req.backupProviderBaseUrl); const canonUrl = canonicalizeBaseUrl(req.backupProviderBaseUrl);
await ws.db await ws.db
.mktx((x) => ({ backupProviders: x.backupProviders })) .mktx((x) => [x.backupProviders])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const oldProv = await tx.backupProviders.get(canonUrl); const oldProv = await tx.backupProviders.get(canonUrl);
if (oldProv) { if (oldProv) {
@ -628,7 +622,7 @@ export async function addBackupProvider(
codecForSyncTermsOfServiceResponse(), codecForSyncTermsOfServiceResponse(),
); );
await ws.db await ws.db
.mktx((x) => ({ backupProviders: x.backupProviders })) .mktx((x) => [x.backupProviders])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
let state: BackupProviderState; let state: BackupProviderState;
if (req.activate) { if (req.activate) {
@ -807,10 +801,7 @@ export async function getBackupInfo(
): Promise<BackupInfo> { ): Promise<BackupInfo> {
const backupConfig = await provideBackupState(ws); const backupConfig = await provideBackupState(ws);
const providerRecords = await ws.db const providerRecords = await ws.db
.mktx((x) => ({ .mktx((x) => [x.backupProviders, x.operationRetries])
backupProviders: x.backupProviders,
operationRetries: x.operationRetries,
}))
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
return await tx.backupProviders.iter().mapAsync(async (bp) => { return await tx.backupProviders.iter().mapAsync(async (bp) => {
const opId = RetryTags.forBackup(bp); const opId = RetryTags.forBackup(bp);
@ -853,7 +844,7 @@ export async function getBackupRecovery(
): Promise<BackupRecovery> { ): Promise<BackupRecovery> {
const bs = await provideBackupState(ws); const bs = await provideBackupState(ws);
const providers = await ws.db const providers = await ws.db
.mktx((x) => ({ backupProviders: x.backupProviders })) .mktx((x) => [x.backupProviders])
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
return await tx.backupProviders.iter().toArray(); return await tx.backupProviders.iter().toArray();
}); });
@ -874,7 +865,7 @@ async function backupRecoveryTheirs(
br: BackupRecovery, br: BackupRecovery,
) { ) {
await ws.db await ws.db
.mktx((x) => ({ config: x.config, backupProviders: x.backupProviders })) .mktx((x) => [x.config, x.backupProviders])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
let backupStateEntry: ConfigRecord | undefined = await tx.config.get( let backupStateEntry: ConfigRecord | undefined = await tx.config.get(
WALLET_BACKUP_STATE_KEY, WALLET_BACKUP_STATE_KEY,
@ -924,7 +915,7 @@ export async function loadBackupRecovery(
): Promise<void> { ): Promise<void> {
const bs = await provideBackupState(ws); const bs = await provideBackupState(ws);
const providers = await ws.db const providers = await ws.db
.mktx((x) => ({ backupProviders: x.backupProviders })) .mktx((x) => [x.backupProviders])
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
return await tx.backupProviders.iter().toArray(); return await tx.backupProviders.iter().toArray();
}); });
@ -954,7 +945,7 @@ export async function exportBackupEncrypted(
await provideBackupState(ws); await provideBackupState(ws);
const blob = await exportBackup(ws); const blob = await exportBackup(ws);
const bs = await ws.db const bs = await ws.db
.mktx((x) => ({ config: x.config })) .mktx((x) => [x.config])
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
return await getWalletBackupState(ws, tx); return await getWalletBackupState(ws, tx);
}); });

View File

@ -29,9 +29,7 @@ export async function provideBackupState(
ws: InternalWalletState, ws: InternalWalletState,
): Promise<WalletBackupConfState> { ): Promise<WalletBackupConfState> {
const bs: ConfigRecord | undefined = await ws.db const bs: ConfigRecord | undefined = await ws.db
.mktx((x) => ({ .mktx((stores) => [stores.config])
config: x.config,
}))
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
return await tx.config.get(WALLET_BACKUP_STATE_KEY); return await tx.config.get(WALLET_BACKUP_STATE_KEY);
}); });
@ -47,9 +45,7 @@ export async function provideBackupState(
// and be based on hostname // and be based on hostname
const deviceId = `wallet-core-${encodeCrock(d)}`; const deviceId = `wallet-core-${encodeCrock(d)}`;
return await ws.db return await ws.db
.mktx((x) => ({ .mktx((x) => [x.config])
config: x.config,
}))
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
let backupStateEntry: ConfigRecord | undefined = await tx.config.get( let backupStateEntry: ConfigRecord | undefined = await tx.config.get(
WALLET_BACKUP_STATE_KEY, WALLET_BACKUP_STATE_KEY,
@ -87,9 +83,7 @@ export async function setWalletDeviceId(
): Promise<void> { ): Promise<void> {
await provideBackupState(ws); await provideBackupState(ws);
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [x.config])
config: x.config,
}))
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
let backupStateEntry: ConfigRecord | undefined = await tx.config.get( let backupStateEntry: ConfigRecord | undefined = await tx.config.get(
WALLET_BACKUP_STATE_KEY, WALLET_BACKUP_STATE_KEY,

View File

@ -139,12 +139,7 @@ export async function getBalances(
logger.trace("starting to compute balance"); logger.trace("starting to compute balance");
const wbal = await ws.db const wbal = await ws.db
.mktx((x) => ({ .mktx((x) => [x.coins, x.refreshGroups, x.purchases, x.withdrawalGroups])
coins: x.coins,
refreshGroups: x.refreshGroups,
purchases: x.purchases,
withdrawalGroups: x.withdrawalGroups,
}))
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
return getBalancesInsideTransaction(ws, tx); return getBalancesInsideTransaction(ws, tx);
}); });

View File

@ -83,9 +83,7 @@ export async function processDepositGroup(
} = {}, } = {},
): Promise<OperationAttemptResult> { ): Promise<OperationAttemptResult> {
const depositGroup = await ws.db const depositGroup = await ws.db
.mktx((x) => ({ .mktx((x) => [x.depositGroups])
depositGroups: x.depositGroups,
}))
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
return tx.depositGroups.get(depositGroupId); return tx.depositGroups.get(depositGroupId);
}); });
@ -141,7 +139,7 @@ export async function processDepositGroup(
}); });
await readSuccessResponseJsonOrThrow(httpResp, codecForDepositSuccess()); await readSuccessResponseJsonOrThrow(httpResp, codecForDepositSuccess());
await ws.db await ws.db
.mktx((x) => ({ depositGroups: x.depositGroups })) .mktx((x) => [x.depositGroups])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const dg = await tx.depositGroups.get(depositGroupId); const dg = await tx.depositGroups.get(depositGroupId);
if (!dg) { if (!dg) {
@ -153,9 +151,7 @@ export async function processDepositGroup(
} }
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [x.depositGroups])
depositGroups: x.depositGroups,
}))
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const dg = await tx.depositGroups.get(depositGroupId); const dg = await tx.depositGroups.get(depositGroupId);
if (!dg) { if (!dg) {
@ -185,9 +181,7 @@ export async function trackDepositGroup(
body: any; body: any;
}[] = []; }[] = [];
const depositGroup = await ws.db const depositGroup = await ws.db
.mktx((x) => ({ .mktx((x) => [x.depositGroups])
depositGroups: x.depositGroups,
}))
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
return tx.depositGroups.get(req.depositGroupId); return tx.depositGroups.get(req.depositGroupId);
}); });
@ -247,10 +241,7 @@ export async function getFeeForDeposit(
const exchangeInfos: { url: string; master_pub: string }[] = []; const exchangeInfos: { url: string; master_pub: string }[] = [];
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [x.exchanges, x.exchangeDetails])
exchanges: x.exchanges,
exchangeDetails: x.exchangeDetails,
}))
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
const allExchanges = await tx.exchanges.iter().toArray(); const allExchanges = await tx.exchanges.iter().toArray();
for (const e of allExchanges) { for (const e of allExchanges) {
@ -315,10 +306,7 @@ export async function prepareDepositGroup(
const exchangeInfos: { url: string; master_pub: string }[] = []; const exchangeInfos: { url: string; master_pub: string }[] = [];
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [x.exchanges, x.exchangeDetails])
exchanges: x.exchanges,
exchangeDetails: x.exchangeDetails,
}))
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
const allExchanges = await tx.exchanges.iter().toArray(); const allExchanges = await tx.exchanges.iter().toArray();
for (const e of allExchanges) { for (const e of allExchanges) {
@ -417,10 +405,7 @@ export async function createDepositGroup(
const exchangeInfos: { url: string; master_pub: string }[] = []; const exchangeInfos: { url: string; master_pub: string }[] = [];
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [x.exchanges, x.exchangeDetails])
exchanges: x.exchanges,
exchangeDetails: x.exchangeDetails,
}))
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
const allExchanges = await tx.exchanges.iter().toArray(); const allExchanges = await tx.exchanges.iter().toArray();
for (const e of allExchanges) { for (const e of allExchanges) {
@ -532,12 +517,13 @@ export async function createDepositGroup(
}; };
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [
depositGroups: x.depositGroups, x.depositGroups,
coins: x.coins, x.coins,
refreshGroups: x.refreshGroups, x.recoupGroups,
denominations: x.denominations, x.denominations,
})) x.refreshGroups,
])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
await applyCoinSpend( await applyCoinSpend(
ws, ws,
@ -565,12 +551,7 @@ export async function getEffectiveDepositAmount(
const exchangeSet: Set<string> = new Set(); const exchangeSet: Set<string> = new Set();
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [x.coins, x.denominations, x.exchanges, x.exchangeDetails])
coins: x.coins,
denominations: x.denominations,
exchanges: x.exchanges,
exchangeDetails: x.exchangeDetails,
}))
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
for (let i = 0; i < pcs.coinPubs.length; i++) { for (let i = 0; i < pcs.coinPubs.length; i++) {
const coin = await tx.coins.get(pcs.coinPubs[i]); const coin = await tx.coins.get(pcs.coinPubs[i]);
@ -637,12 +618,7 @@ export async function getTotalFeesForDepositAmount(
const exchangeSet: Set<string> = new Set(); const exchangeSet: Set<string> = new Set();
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [x.coins, x.denominations, x.exchanges, x.exchangeDetails])
coins: x.coins,
denominations: x.denominations,
exchanges: x.exchanges,
exchangeDetails: x.exchangeDetails,
}))
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
for (let i = 0; i < pcs.coinPubs.length; i++) { for (let i = 0; i < pcs.coinPubs.length; i++) {
const coin = await tx.coins.get(pcs.coinPubs[i]); const coin = await tx.coins.get(pcs.coinPubs[i]);

View File

@ -161,10 +161,7 @@ export async function getExchangeDetails(
} }
getExchangeDetails.makeContext = (db: DbAccess<typeof WalletStoresV1>) => getExchangeDetails.makeContext = (db: DbAccess<typeof WalletStoresV1>) =>
db.mktx((x) => ({ db.mktx((x) => [x.exchanges, x.exchangeDetails]);
exchanges: x.exchanges,
exchangeDetails: x.exchangeDetails,
}));
export async function updateExchangeTermsOfService( export async function updateExchangeTermsOfService(
ws: InternalWalletState, ws: InternalWalletState,
@ -172,10 +169,7 @@ export async function updateExchangeTermsOfService(
tos: ExchangeTosDownloadResult, tos: ExchangeTosDownloadResult,
): Promise<void> { ): Promise<void> {
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [x.exchanges, x.exchangeDetails])
exchanges: x.exchanges,
exchangeDetails: x.exchangeDetails,
}))
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const d = await getExchangeDetails(tx, exchangeBaseUrl); const d = await getExchangeDetails(tx, exchangeBaseUrl);
if (d) { if (d) {
@ -193,10 +187,7 @@ export async function acceptExchangeTermsOfService(
etag: string | undefined, etag: string | undefined,
): Promise<void> { ): Promise<void> {
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [x.exchanges, x.exchangeDetails])
exchanges: x.exchanges,
exchangeDetails: x.exchangeDetails,
}))
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const d = await getExchangeDetails(tx, exchangeBaseUrl); const d = await getExchangeDetails(tx, exchangeBaseUrl);
if (d) { if (d) {
@ -326,10 +317,7 @@ async function provideExchangeRecord(
exchangeDetails: ExchangeDetailsRecord | undefined; exchangeDetails: ExchangeDetailsRecord | undefined;
}> { }> {
return await ws.db return await ws.db
.mktx((x) => ({ .mktx((x) => [x.exchanges, x.exchangeDetails])
exchanges: x.exchanges,
exchangeDetails: x.exchangeDetails,
}))
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
let exchange = await tx.exchanges.get(baseUrl); let exchange = await tx.exchanges.get(baseUrl);
if (!exchange) { if (!exchange) {
@ -569,14 +557,14 @@ export async function updateExchangeFromUrlHandler(
logger.trace("updating exchange info in database"); logger.trace("updating exchange info in database");
const updated = await ws.db const updated = await ws.db
.mktx((x) => ({ .mktx((x) => [
exchanges: x.exchanges, x.exchanges,
exchangeDetails: x.exchangeDetails, x.exchangeDetails,
denominations: x.denominations, x.denominations,
coins: x.coins, x.coins,
refreshGroups: x.refreshGroups, x.refreshGroups,
recoupGroups: x.recoupGroups, x.recoupGroups,
})) ])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const r = await tx.exchanges.get(baseUrl); const r = await tx.exchanges.get(baseUrl);
if (!r) { if (!r) {
@ -770,12 +758,12 @@ export async function getExchangeTrust(
let isAudited = false; let isAudited = false;
return await ws.db return await ws.db
.mktx((x) => ({ .mktx((x) => [
exchanges: x.exchanges, x.exchanges,
exchangeDetails: x.exchangeDetails, x.exchangeDetails,
exchangesTrustStore: x.exchangeTrust, x.exchangeTrust,
auditorTrust: x.auditorTrust, x.auditorTrust,
})) ])
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
const exchangeDetails = await getExchangeDetails( const exchangeDetails = await getExchangeDetails(
tx, tx,
@ -786,7 +774,7 @@ export async function getExchangeTrust(
throw Error(`exchange ${exchangeInfo.baseUrl} details not available`); throw Error(`exchange ${exchangeInfo.baseUrl} details not available`);
} }
const exchangeTrustRecord = const exchangeTrustRecord =
await tx.exchangesTrustStore.indexes.byExchangeMasterPub.get( await tx.exchangeTrust.indexes.byExchangeMasterPub.get(
exchangeDetails.masterPublicKey, exchangeDetails.masterPublicKey,
); );
if ( if (

View File

@ -120,7 +120,7 @@ export async function getTotalPaymentCost(
pcs: PayCoinSelection, pcs: PayCoinSelection,
): Promise<AmountJson> { ): Promise<AmountJson> {
return ws.db return ws.db
.mktx((x) => ({ coins: x.coins, denominations: x.denominations })) .mktx((x) => [x.coins, x.denominations])
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
const costs: AmountJson[] = []; const costs: AmountJson[] = [];
for (let i = 0; i < pcs.coinPubs.length; i++) { for (let i = 0; i < pcs.coinPubs.length; i++) {
@ -222,12 +222,7 @@ export async function getCandidatePayCoins(
const wireFeesPerExchange: Record<string, AmountJson> = {}; const wireFeesPerExchange: Record<string, AmountJson> = {};
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [x.exchanges, x.exchangeDetails, x.denominations, x.coins])
exchanges: x.exchanges,
exchangeDetails: x.exchangeDetails,
denominations: x.denominations,
coins: x.coins,
}))
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
const exchanges = await tx.exchanges.iter().toArray(); const exchanges = await tx.exchanges.iter().toArray();
for (const exchange of exchanges) { for (const exchange of exchanges) {
@ -459,13 +454,13 @@ async function recordConfirmPay(
}; };
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [
proposals: x.proposals, x.proposals,
purchases: x.purchases, x.purchases,
coins: x.coins, x.coins,
refreshGroups: x.refreshGroups, x.refreshGroups,
denominations: x.denominations, x.denominations,
})) ])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const p = await tx.proposals.get(proposal.proposalId); const p = await tx.proposals.get(proposal.proposalId);
if (p) { if (p) {
@ -489,7 +484,7 @@ async function failProposalPermanently(
err: TalerErrorDetail, err: TalerErrorDetail,
): Promise<void> { ): Promise<void> {
await ws.db await ws.db
.mktx((x) => ({ proposals: x.proposals })) .mktx((x) => [x.proposals])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const p = await tx.proposals.get(proposalId); const p = await tx.proposals.get(proposalId);
if (!p) { if (!p) {
@ -567,13 +562,10 @@ export async function processDownloadProposal(
proposalId: string, proposalId: string,
options: {} = {}, options: {} = {},
): Promise<OperationAttemptResult> { ): Promise<OperationAttemptResult> {
const res = ws.db.mktx2((x) => [x.auditorTrust, x.coins])
const proposal = await ws.db const proposal = await ws.db
.mktx((x) => ({ proposals: x.proposals })) .mktx((x) => [x.proposals])
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
return tx.proposals.get(proposalId); return await tx.proposals.get(proposalId);
}); });
if (!proposal) { if (!proposal) {
@ -608,7 +600,7 @@ export async function processDownloadProposal(
const opId = RetryTags.forProposalClaim(proposal); const opId = RetryTags.forProposalClaim(proposal);
const retryRecord = await ws.db const retryRecord = await ws.db
.mktx((x) => ({ operationRetries: x.operationRetries })) .mktx((x) => [x.operationRetries])
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
return tx.operationRetries.get(opId); return tx.operationRetries.get(opId);
}); });
@ -748,7 +740,7 @@ export async function processDownloadProposal(
logger.trace(`extracted contract data: ${j2s(contractData)}`); logger.trace(`extracted contract data: ${j2s(contractData)}`);
await ws.db await ws.db
.mktx((x) => ({ proposals: x.proposals, purchases: x.purchases })) .mktx((x) => [x.purchases, x.proposals])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const p = await tx.proposals.get(proposalId); const p = await tx.proposals.get(proposalId);
if (!p) { if (!p) {
@ -807,7 +799,7 @@ async function startDownloadProposal(
noncePriv: string | undefined, noncePriv: string | undefined,
): Promise<string> { ): Promise<string> {
const oldProposal = await ws.db const oldProposal = await ws.db
.mktx((x) => ({ proposals: x.proposals })) .mktx((x) => [x.proposals])
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
return tx.proposals.indexes.byUrlAndOrderId.get([ return tx.proposals.indexes.byUrlAndOrderId.get([
merchantBaseUrl, merchantBaseUrl,
@ -855,7 +847,7 @@ async function startDownloadProposal(
}; };
await ws.db await ws.db
.mktx((x) => ({ proposals: x.proposals })) .mktx((x) => [x.proposals])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const existingRecord = await tx.proposals.indexes.byUrlAndOrderId.get([ const existingRecord = await tx.proposals.indexes.byUrlAndOrderId.get([
merchantBaseUrl, merchantBaseUrl,
@ -880,7 +872,7 @@ async function storeFirstPaySuccess(
): Promise<void> { ): Promise<void> {
const now = AbsoluteTime.toTimestamp(AbsoluteTime.now()); const now = AbsoluteTime.toTimestamp(AbsoluteTime.now());
await ws.db await ws.db
.mktx((x) => ({ purchases: x.purchases })) .mktx((x) => [x.purchases])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const purchase = await tx.purchases.get(proposalId); const purchase = await tx.purchases.get(proposalId);
@ -916,7 +908,7 @@ async function storePayReplaySuccess(
sessionId: string | undefined, sessionId: string | undefined,
): Promise<void> { ): Promise<void> {
await ws.db await ws.db
.mktx((x) => ({ purchases: x.purchases })) .mktx((x) => [x.purchases])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const purchase = await tx.purchases.get(proposalId); const purchase = await tx.purchases.get(proposalId);
@ -950,9 +942,9 @@ async function handleInsufficientFunds(
logger.trace("handling insufficient funds, trying to re-select coins"); logger.trace("handling insufficient funds, trying to re-select coins");
const proposal = await ws.db const proposal = await ws.db
.mktx((x) => ({ purchaes: x.purchases })) .mktx((x) => [x.purchases])
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
return tx.purchaes.get(proposalId); return tx.purchases.get(proposalId);
}); });
if (!proposal) { if (!proposal) {
return; return;
@ -990,7 +982,7 @@ async function handleInsufficientFunds(
const prevPayCoins: PreviousPayCoins = []; const prevPayCoins: PreviousPayCoins = [];
await ws.db await ws.db
.mktx((x) => ({ coins: x.coins, denominations: x.denominations })) .mktx((x) => [x.coins, x.denominations])
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
for (let i = 0; i < proposal.payCoinSelection.coinPubs.length; i++) { for (let i = 0; i < proposal.payCoinSelection.coinPubs.length; i++) {
const coinPub = proposal.payCoinSelection.coinPubs[i]; const coinPub = proposal.payCoinSelection.coinPubs[i];
@ -1036,12 +1028,7 @@ async function handleInsufficientFunds(
logger.trace("re-selected coins"); logger.trace("re-selected coins");
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [x.purchases, x.coins, x.denominations, x.refreshGroups])
purchases: x.purchases,
coins: x.coins,
denominations: x.denominations,
refreshGroups: x.refreshGroups,
}))
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const p = await tx.purchases.get(proposalId); const p = await tx.purchases.get(proposalId);
if (!p) { if (!p) {
@ -1060,7 +1047,7 @@ async function unblockBackup(
proposalId: string, proposalId: string,
): Promise<void> { ): Promise<void> {
await ws.db await ws.db
.mktx((x) => ({ backupProviders: x.backupProviders })) .mktx((x) => [x.backupProviders])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
await tx.backupProviders.indexes.byPaymentProposalId await tx.backupProviders.indexes.byPaymentProposalId
.iter(proposalId) .iter(proposalId)
@ -1081,7 +1068,7 @@ export async function checkPaymentByProposalId(
sessionId?: string, sessionId?: string,
): Promise<PreparePayResult> { ): Promise<PreparePayResult> {
let proposal = await ws.db let proposal = await ws.db
.mktx((x) => ({ proposals: x.proposals })) .mktx((x) => [x.proposals])
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
return tx.proposals.get(proposalId); return tx.proposals.get(proposalId);
}); });
@ -1095,7 +1082,7 @@ export async function checkPaymentByProposalId(
} }
logger.trace("using existing purchase for same product"); logger.trace("using existing purchase for same product");
proposal = await ws.db proposal = await ws.db
.mktx((x) => ({ proposals: x.proposals })) .mktx((x) => [x.proposals])
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
return tx.proposals.get(existingProposalId); return tx.proposals.get(existingProposalId);
}); });
@ -1118,7 +1105,7 @@ export async function checkPaymentByProposalId(
// First check if we already paid for it. // First check if we already paid for it.
const purchase = await ws.db const purchase = await ws.db
.mktx((x) => ({ purchases: x.purchases })) .mktx((x) => [x.purchases])
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
return tx.purchases.get(proposalId); return tx.purchases.get(proposalId);
}); });
@ -1176,7 +1163,7 @@ export async function checkPaymentByProposalId(
"automatically re-submitting payment with different session ID", "automatically re-submitting payment with different session ID",
); );
await ws.db await ws.db
.mktx((x) => ({ purchases: x.purchases })) .mktx((x) => [x.purchases])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const p = await tx.purchases.get(proposalId); const p = await tx.purchases.get(proposalId);
if (!p) { if (!p) {
@ -1230,7 +1217,7 @@ export async function getContractTermsDetails(
proposalId: string, proposalId: string,
): Promise<WalletContractData> { ): Promise<WalletContractData> {
const proposal = await ws.db const proposal = await ws.db
.mktx((x) => ({ proposals: x.proposals })) .mktx((x) => [x.proposals])
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
return tx.proposals.get(proposalId); return tx.proposals.get(proposalId);
}); });
@ -1296,7 +1283,7 @@ export async function generateDepositPermissions(
denom: DenominationRecord; denom: DenominationRecord;
}> = []; }> = [];
await ws.db await ws.db
.mktx((x) => ({ coins: x.coins, denominations: x.denominations })) .mktx((x) => [x.coins, x.denominations])
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
for (let i = 0; i < payCoinSel.coinPubs.length; i++) { for (let i = 0; i < payCoinSel.coinPubs.length; i++) {
const coin = await tx.coins.get(payCoinSel.coinPubs[i]); const coin = await tx.coins.get(payCoinSel.coinPubs[i]);
@ -1359,7 +1346,7 @@ export async function runPayForConfirmPay(
switch (res.type) { switch (res.type) {
case OperationAttemptResultType.Finished: { case OperationAttemptResultType.Finished: {
const purchase = await ws.db const purchase = await ws.db
.mktx((x) => ({ purchases: x.purchases })) .mktx((x) => [x.purchases])
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
return tx.purchases.get(proposalId); return tx.purchases.get(proposalId);
}); });
@ -1399,7 +1386,7 @@ export async function confirmPay(
`executing confirmPay with proposalId ${proposalId} and sessionIdOverride ${sessionIdOverride}`, `executing confirmPay with proposalId ${proposalId} and sessionIdOverride ${sessionIdOverride}`,
); );
const proposal = await ws.db const proposal = await ws.db
.mktx((x) => ({ proposals: x.proposals })) .mktx((x) => [x.proposals])
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
return tx.proposals.get(proposalId); return tx.proposals.get(proposalId);
}); });
@ -1414,7 +1401,7 @@ export async function confirmPay(
} }
const existingPurchase = await ws.db const existingPurchase = await ws.db
.mktx((x) => ({ purchases: x.purchases })) .mktx((x) => [x.purchases])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const purchase = await tx.purchases.get(proposalId); const purchase = await tx.purchases.get(proposalId);
if ( if (
@ -1508,7 +1495,7 @@ export async function processPurchasePay(
} = {}, } = {},
): Promise<OperationAttemptResult> { ): Promise<OperationAttemptResult> {
const purchase = await ws.db const purchase = await ws.db
.mktx((x) => ({ purchases: x.purchases })) .mktx((x) => [x.purchases])
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
return tx.purchases.get(proposalId); return tx.purchases.get(proposalId);
}); });
@ -1568,20 +1555,12 @@ export async function processPurchasePay(
); );
logger.trace(`got resp ${JSON.stringify(resp)}`); logger.trace(`got resp ${JSON.stringify(resp)}`);
const payOpId = RetryTags.forPay(purchase);
const payRetryRecord = await ws.db
.mktx((x) => ({ operationRetries: x.operationRetries }))
.runReadOnly(async (tx) => {
return await tx.operationRetries.get(payOpId);
});
if (resp.status === HttpStatusCode.BadRequest) { if (resp.status === HttpStatusCode.BadRequest) {
const errDetails = await readUnexpectedResponseDetails(resp); const errDetails = await readUnexpectedResponseDetails(resp);
logger.warn("unexpected 400 response for /pay"); logger.warn("unexpected 400 response for /pay");
logger.warn(j2s(errDetails)); logger.warn(j2s(errDetails));
await ws.db await ws.db
.mktx((x) => ({ purchases: x.purchases })) .mktx((x) => [x.purchases])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const purch = await tx.purchases.get(proposalId); const purch = await tx.purchases.get(proposalId);
if (!purch) { if (!purch) {
@ -1683,7 +1662,7 @@ export async function refuseProposal(
proposalId: string, proposalId: string,
): Promise<void> { ): Promise<void> {
const success = await ws.db const success = await ws.db
.mktx((x) => ({ proposals: x.proposals })) .mktx((x) => [x.proposals])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const proposal = await tx.proposals.get(proposalId); const proposal = await tx.proposals.get(proposalId);
if (!proposal) { if (!proposal) {

View File

@ -242,13 +242,14 @@ export async function initiatePeerToPeerPush(
}); });
const coinSelRes: PeerCoinSelection | undefined = await ws.db const coinSelRes: PeerCoinSelection | undefined = await ws.db
.mktx((x) => ({ .mktx((x) => [
exchanges: x.exchanges, x.exchanges,
coins: x.coins, x.coins,
denominations: x.denominations, x.denominations,
refreshGroups: x.refreshGroups, x.refreshGroups,
peerPushPaymentInitiations: x.peerPushPaymentInitiations, x.peerPullPaymentInitiations,
})) x.peerPushPaymentInitiations,
])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const sel = await selectPeerCoins(ws, tx, instructedAmount); const sel = await selectPeerCoins(ws, tx, instructedAmount);
if (!sel) { if (!sel) {
@ -401,9 +402,7 @@ export async function checkPeerPushPayment(
const peerPushPaymentIncomingId = encodeCrock(getRandomBytes(32)); const peerPushPaymentIncomingId = encodeCrock(getRandomBytes(32));
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [x.peerPushPaymentIncoming])
peerPushPaymentIncoming: x.peerPushPaymentIncoming,
}))
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
await tx.peerPushPaymentIncoming.add({ await tx.peerPushPaymentIncoming.add({
peerPushPaymentIncomingId, peerPushPaymentIncomingId,
@ -456,10 +455,7 @@ async function getMergeReserveInfo(
const newReservePair = await ws.cryptoApi.createEddsaKeypair({}); const newReservePair = await ws.cryptoApi.createEddsaKeypair({});
const mergeReserveInfo: MergeReserveInfo = await ws.db const mergeReserveInfo: MergeReserveInfo = await ws.db
.mktx((x) => ({ .mktx((x) => [x.exchanges, x.withdrawalGroups])
exchanges: x.exchanges,
withdrawalGroups: x.withdrawalGroups,
}))
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const ex = await tx.exchanges.get(req.exchangeBaseUrl); const ex = await tx.exchanges.get(req.exchangeBaseUrl);
checkDbInvariant(!!ex); checkDbInvariant(!!ex);
@ -482,7 +478,7 @@ export async function acceptPeerPushPayment(
req: AcceptPeerPushPaymentRequest, req: AcceptPeerPushPaymentRequest,
): Promise<void> { ): Promise<void> {
const peerInc = await ws.db const peerInc = await ws.db
.mktx((x) => ({ peerPushPaymentIncoming: x.peerPushPaymentIncoming })) .mktx((x) => [x.peerPushPaymentIncoming])
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
return tx.peerPushPaymentIncoming.get(req.peerPushPaymentIncomingId); return tx.peerPushPaymentIncoming.get(req.peerPushPaymentIncomingId);
}); });
@ -564,7 +560,7 @@ export async function acceptPeerPullPayment(
req: AcceptPeerPullPaymentRequest, req: AcceptPeerPullPaymentRequest,
): Promise<void> { ): Promise<void> {
const peerPullInc = await ws.db const peerPullInc = await ws.db
.mktx((x) => ({ peerPullPaymentIncoming: x.peerPullPaymentIncoming })) .mktx((x) => [x.peerPullPaymentIncoming])
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
return tx.peerPullPaymentIncoming.get(req.peerPullPaymentIncomingId); return tx.peerPullPaymentIncoming.get(req.peerPullPaymentIncomingId);
}); });
@ -579,13 +575,13 @@ export async function acceptPeerPullPayment(
peerPullInc.contractTerms.amount, peerPullInc.contractTerms.amount,
); );
const coinSelRes: PeerCoinSelection | undefined = await ws.db const coinSelRes: PeerCoinSelection | undefined = await ws.db
.mktx((x) => ({ .mktx((x) => [
exchanges: x.exchanges, x.exchanges,
coins: x.coins, x.coins,
denominations: x.denominations, x.denominations,
refreshGroups: x.refreshGroups, x.refreshGroups,
peerPullPaymentIncoming: x.peerPullPaymentIncoming, x.peerPullPaymentIncoming,
})) ])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const sel = await selectPeerCoins(ws, tx, instructedAmount); const sel = await selectPeerCoins(ws, tx, instructedAmount);
if (!sel) { if (!sel) {
@ -689,9 +685,7 @@ export async function checkPeerPullPayment(
const peerPullPaymentIncomingId = encodeCrock(getRandomBytes(32)); const peerPullPaymentIncomingId = encodeCrock(getRandomBytes(32));
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [x.peerPullPaymentIncoming])
peerPullPaymentIncoming: x.peerPullPaymentIncoming,
}))
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
await tx.peerPullPaymentIncoming.add({ await tx.peerPullPaymentIncoming.add({
peerPullPaymentIncomingId, peerPullPaymentIncomingId,
@ -775,11 +769,9 @@ export async function initiatePeerRequestForPay(
}); });
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [x.peerPullPaymentInitiations])
peerPullPaymentInitiation: x.peerPullPaymentInitiations,
}))
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
await tx.peerPullPaymentInitiation.put({ await tx.peerPullPaymentInitiations.put({
amount: req.amount, amount: req.amount,
contractTerms, contractTerms,
exchangeBaseUrl: req.exchangeBaseUrl, exchangeBaseUrl: req.exchangeBaseUrl,

View File

@ -357,21 +357,21 @@ export async function getPendingOperations(
): Promise<PendingOperationsResponse> { ): Promise<PendingOperationsResponse> {
const now = AbsoluteTime.now(); const now = AbsoluteTime.now();
return await ws.db return await ws.db
.mktx((x) => ({ .mktx((x) => [
backupProviders: x.backupProviders, x.backupProviders,
exchanges: x.exchanges, x.exchanges,
exchangeDetails: x.exchangeDetails, x.exchangeDetails,
refreshGroups: x.refreshGroups, x.refreshGroups,
coins: x.coins, x.coins,
withdrawalGroups: x.withdrawalGroups, x.withdrawalGroups,
proposals: x.proposals, x.proposals,
tips: x.tips, x.tips,
purchases: x.purchases, x.purchases,
planchets: x.planchets, x.planchets,
depositGroups: x.depositGroups, x.depositGroups,
recoupGroups: x.recoupGroups, x.recoupGroups,
operationRetries: x.operationRetries, x.operationRetries,
})) ])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const resp: PendingOperationsResponse = { const resp: PendingOperationsResponse = {
pendingOperations: [], pendingOperations: [],

View File

@ -96,12 +96,12 @@ async function recoupTipCoin(
// Thus we just put the coin to sleep. // Thus we just put the coin to sleep.
// FIXME: somehow report this to the user // FIXME: somehow report this to the user
await ws.db await ws.db
.mktx((x) => ({ .mktx((stores) => [
recoupGroups: x.recoupGroups, stores.recoupGroups,
denominations: WalletStoresV1.denominations, stores.denominations,
refreshGroups: WalletStoresV1.refreshGroups, stores.refreshGroups,
coins: WalletStoresV1.coins, stores.coins,
})) ])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const recoupGroup = await tx.recoupGroups.get(recoupGroupId); const recoupGroup = await tx.recoupGroups.get(recoupGroupId);
if (!recoupGroup) { if (!recoupGroup) {
@ -123,9 +123,7 @@ async function recoupWithdrawCoin(
): Promise<void> { ): Promise<void> {
const reservePub = cs.reservePub; const reservePub = cs.reservePub;
const denomInfo = await ws.db const denomInfo = await ws.db
.mktx((x) => ({ .mktx((x) => [x.denominations])
denominations: x.denominations,
}))
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
const denomInfo = await ws.getDenomInfo( const denomInfo = await ws.getDenomInfo(
ws, ws,
@ -169,12 +167,7 @@ async function recoupWithdrawCoin(
// FIXME: verify that our expectations about the amount match // FIXME: verify that our expectations about the amount match
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [x.coins, x.denominations, x.recoupGroups, x.refreshGroups])
coins: x.coins,
denominations: x.denominations,
recoupGroups: x.recoupGroups,
refreshGroups: x.refreshGroups,
}))
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const recoupGroup = await tx.recoupGroups.get(recoupGroupId); const recoupGroup = await tx.recoupGroups.get(recoupGroupId);
if (!recoupGroup) { if (!recoupGroup) {
@ -207,10 +200,7 @@ async function recoupRefreshCoin(
cs: RefreshCoinSource, cs: RefreshCoinSource,
): Promise<void> { ): Promise<void> {
const d = await ws.db const d = await ws.db
.mktx((x) => ({ .mktx((x) => [x.coins, x.denominations])
coins: x.coins,
denominations: x.denominations,
}))
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
const denomInfo = await ws.getDenomInfo( const denomInfo = await ws.getDenomInfo(
ws, ws,
@ -257,12 +247,7 @@ async function recoupRefreshCoin(
} }
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [x.coins, x.denominations, x.recoupGroups, x.refreshGroups])
coins: x.coins,
denominations: x.denominations,
recoupGroups: x.recoupGroups,
refreshGroups: x.refreshGroups,
}))
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const recoupGroup = await tx.recoupGroups.get(recoupGroupId); const recoupGroup = await tx.recoupGroups.get(recoupGroupId);
if (!recoupGroup) { if (!recoupGroup) {
@ -319,9 +304,7 @@ export async function processRecoupGroupHandler(
): Promise<OperationAttemptResult> { ): Promise<OperationAttemptResult> {
const forceNow = options.forceNow ?? false; const forceNow = options.forceNow ?? false;
let recoupGroup = await ws.db let recoupGroup = await ws.db
.mktx((x) => ({ .mktx((x) => [x.recoupGroups])
recoupGroups: x.recoupGroups,
}))
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
return tx.recoupGroups.get(recoupGroupId); return tx.recoupGroups.get(recoupGroupId);
}); });
@ -343,9 +326,7 @@ export async function processRecoupGroupHandler(
await Promise.all(ps); await Promise.all(ps);
recoupGroup = await ws.db recoupGroup = await ws.db
.mktx((x) => ({ .mktx((x) => [x.recoupGroups])
recoupGroups: x.recoupGroups,
}))
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
return tx.recoupGroups.get(recoupGroupId); return tx.recoupGroups.get(recoupGroupId);
}); });
@ -366,10 +347,7 @@ export async function processRecoupGroupHandler(
for (let i = 0; i < recoupGroup.coinPubs.length; i++) { for (let i = 0; i < recoupGroup.coinPubs.length; i++) {
const coinPub = recoupGroup.coinPubs[i]; const coinPub = recoupGroup.coinPubs[i];
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [x.coins, x.reserves])
coins: x.coins,
reserves: x.reserves,
}))
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
const coin = await tx.coins.get(coinPub); const coin = await tx.coins.get(coinPub);
if (!coin) { if (!coin) {
@ -414,12 +392,7 @@ export async function processRecoupGroupHandler(
} }
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [x.recoupGroups, x.denominations, x.refreshGroups, x.coins])
recoupGroups: x.recoupGroups,
denominations: WalletStoresV1.denominations,
refreshGroups: WalletStoresV1.refreshGroups,
coins: WalletStoresV1.coins,
}))
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const rg2 = await tx.recoupGroups.get(recoupGroupId); const rg2 = await tx.recoupGroups.get(recoupGroupId);
if (!rg2) { if (!rg2) {
@ -497,10 +470,7 @@ async function processRecoup(
coinIdx: number, coinIdx: number,
): Promise<void> { ): Promise<void> {
const coin = await ws.db const coin = await ws.db
.mktx((x) => ({ .mktx((x) => [x.recoupGroups, x.coins])
recoupGroups: x.recoupGroups,
coins: x.coins,
}))
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
const recoupGroup = await tx.recoupGroups.get(recoupGroupId); const recoupGroup = await tx.recoupGroups.get(recoupGroupId);
if (!recoupGroup) { if (!recoupGroup) {

View File

@ -155,10 +155,7 @@ async function refreshCreateSession(
); );
const d = await ws.db const d = await ws.db
.mktx((x) => ({ .mktx((x) => [x.refreshGroups, x.coins])
refreshGroups: x.refreshGroups,
coins: x.coins,
}))
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const refreshGroup = await tx.refreshGroups.get(refreshGroupId); const refreshGroup = await tx.refreshGroups.get(refreshGroupId);
if (!refreshGroup) { if (!refreshGroup) {
@ -197,9 +194,7 @@ async function refreshCreateSession(
// to update and filter withdrawable denoms. // to update and filter withdrawable denoms.
const { availableAmount, availableDenoms } = await ws.db const { availableAmount, availableDenoms } = await ws.db
.mktx((x) => ({ .mktx((x) => [x.denominations])
denominations: x.denominations,
}))
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
const oldDenom = await ws.getDenomInfo( const oldDenom = await ws.getDenomInfo(
ws, ws,
@ -237,10 +232,7 @@ async function refreshCreateSession(
)} too small`, )} too small`,
); );
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [x.coins, x.refreshGroups])
coins: x.coins,
refreshGroups: x.refreshGroups,
}))
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const rg = await tx.refreshGroups.get(refreshGroupId); const rg = await tx.refreshGroups.get(refreshGroupId);
if (!rg) { if (!rg) {
@ -259,10 +251,7 @@ async function refreshCreateSession(
// Store refresh session for this coin in the database. // Store refresh session for this coin in the database.
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [x.refreshGroups, x.coins])
refreshGroups: x.refreshGroups,
coins: x.coins,
}))
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const rg = await tx.refreshGroups.get(refreshGroupId); const rg = await tx.refreshGroups.get(refreshGroupId);
if (!rg) { if (!rg) {
@ -300,11 +289,7 @@ async function refreshMelt(
coinIndex: number, coinIndex: number,
): Promise<void> { ): Promise<void> {
const d = await ws.db const d = await ws.db
.mktx((x) => ({ .mktx((x) => [x.refreshGroups, x.coins, x.denominations])
refreshGroups: x.refreshGroups,
coins: x.coins,
denominations: x.denominations,
}))
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const refreshGroup = await tx.refreshGroups.get(refreshGroupId); const refreshGroup = await tx.refreshGroups.get(refreshGroupId);
if (!refreshGroup) { if (!refreshGroup) {
@ -414,9 +399,7 @@ async function refreshMelt(
if (resp.status === HttpStatusCode.NotFound) { if (resp.status === HttpStatusCode.NotFound) {
const errDetails = await readUnexpectedResponseDetails(resp); const errDetails = await readUnexpectedResponseDetails(resp);
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [x.refreshGroups])
refreshGroups: x.refreshGroups,
}))
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const rg = await tx.refreshGroups.get(refreshGroupId); const rg = await tx.refreshGroups.get(refreshGroupId);
if (!rg) { if (!rg) {
@ -446,9 +429,7 @@ async function refreshMelt(
refreshSession.norevealIndex = norevealIndex; refreshSession.norevealIndex = norevealIndex;
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [x.refreshGroups])
refreshGroups: x.refreshGroups,
}))
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const rg = await tx.refreshGroups.get(refreshGroupId); const rg = await tx.refreshGroups.get(refreshGroupId);
if (!rg) { if (!rg) {
@ -538,11 +519,7 @@ async function refreshReveal(
): Promise<void> { ): Promise<void> {
logger.info("doing refresh reveal"); logger.info("doing refresh reveal");
const d = await ws.db const d = await ws.db
.mktx((x) => ({ .mktx((x) => [x.refreshGroups, x.coins, x.denominations])
refreshGroups: x.refreshGroups,
coins: x.coins,
denominations: x.denominations,
}))
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
const refreshGroup = await tx.refreshGroups.get(refreshGroupId); const refreshGroup = await tx.refreshGroups.get(refreshGroupId);
if (!refreshGroup) { if (!refreshGroup) {
@ -703,10 +680,7 @@ async function refreshReveal(
} }
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [x.coins, x.refreshGroups])
coins: x.coins,
refreshGroups: x.refreshGroups,
}))
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const rg = await tx.refreshGroups.get(refreshGroupId); const rg = await tx.refreshGroups.get(refreshGroupId);
if (!rg) { if (!rg) {
@ -740,12 +714,8 @@ export async function processRefreshGroup(
logger.info(`processing refresh group ${refreshGroupId}`); logger.info(`processing refresh group ${refreshGroupId}`);
const refreshGroup = await ws.db const refreshGroup = await ws.db
.mktx((x) => ({ .mktx((x) => [x.refreshGroups])
refreshGroups: x.refreshGroups, .runReadOnly(async (tx) => tx.refreshGroups.get(refreshGroupId));
}))
.runReadOnly(async (tx) => {
return tx.refreshGroups.get(refreshGroupId);
});
if (!refreshGroup) { if (!refreshGroup) {
return { return {
type: OperationAttemptResultType.Finished, type: OperationAttemptResultType.Finished,
@ -801,7 +771,7 @@ async function processRefreshSession(
`processing refresh session for coin ${coinIndex} of group ${refreshGroupId}`, `processing refresh session for coin ${coinIndex} of group ${refreshGroupId}`,
); );
let refreshGroup = await ws.db let refreshGroup = await ws.db
.mktx((x) => ({ refreshGroups: x.refreshGroups })) .mktx((x) => [x.refreshGroups])
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
return tx.refreshGroups.get(refreshGroupId); return tx.refreshGroups.get(refreshGroupId);
}); });
@ -814,7 +784,7 @@ async function processRefreshSession(
if (!refreshGroup.refreshSessionPerCoin[coinIndex]) { if (!refreshGroup.refreshSessionPerCoin[coinIndex]) {
await refreshCreateSession(ws, refreshGroupId, coinIndex); await refreshCreateSession(ws, refreshGroupId, coinIndex);
refreshGroup = await ws.db refreshGroup = await ws.db
.mktx((x) => ({ refreshGroups: x.refreshGroups })) .mktx((x) => [x.refreshGroups])
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
return tx.refreshGroups.get(refreshGroupId); return tx.refreshGroups.get(refreshGroupId);
}); });
@ -981,12 +951,7 @@ export async function autoRefresh(
durationFromSpec({ days: 1 }), durationFromSpec({ days: 1 }),
); );
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [x.coins, x.denominations, x.refreshGroups, x.exchanges])
coins: x.coins,
denominations: x.denominations,
refreshGroups: x.refreshGroups,
exchanges: x.exchanges,
}))
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const exchange = await tx.exchanges.get(exchangeBaseUrl); const exchange = await tx.exchanges.get(exchangeBaseUrl);
if (!exchange) { if (!exchange) {

View File

@ -78,9 +78,7 @@ export async function prepareRefund(
} }
const purchase = await ws.db const purchase = await ws.db
.mktx((x) => ({ .mktx((x) => [x.purchases])
purchases: x.purchases,
}))
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
return tx.purchases.indexes.byMerchantUrlAndOrderId.get([ return tx.purchases.indexes.byMerchantUrlAndOrderId.get([
parseResult.merchantBaseUrl, parseResult.merchantBaseUrl,
@ -335,12 +333,7 @@ async function acceptRefunds(
const now = TalerProtocolTimestamp.now(); const now = TalerProtocolTimestamp.now();
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [x.purchases, x.coins, x.denominations, x.refreshGroups])
purchases: x.purchases,
coins: x.coins,
denominations: x.denominations,
refreshGroups: x.refreshGroups,
}))
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const p = await tx.purchases.get(proposalId); const p = await tx.purchases.get(proposalId);
if (!p) { if (!p) {
@ -517,9 +510,7 @@ export async function applyRefund(
} }
const purchase = await ws.db const purchase = await ws.db
.mktx((x) => ({ .mktx((x) => [x.purchases])
purchases: x.purchases,
}))
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
return tx.purchases.indexes.byMerchantUrlAndOrderId.get([ return tx.purchases.indexes.byMerchantUrlAndOrderId.get([
parseResult.merchantBaseUrl, parseResult.merchantBaseUrl,
@ -544,9 +535,7 @@ export async function applyRefundFromPurchaseId(
logger.info("processing purchase for refund"); logger.info("processing purchase for refund");
const success = await ws.db const success = await ws.db
.mktx((x) => ({ .mktx((x) => [x.purchases])
purchases: x.purchases,
}))
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const p = await tx.purchases.get(proposalId); const p = await tx.purchases.get(proposalId);
if (!p) { if (!p) {
@ -569,9 +558,7 @@ export async function applyRefundFromPurchaseId(
} }
const purchase = await ws.db const purchase = await ws.db
.mktx((x) => ({ .mktx((x) => [x.purchases])
purchases: x.purchases,
}))
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
return tx.purchases.get(proposalId); return tx.purchases.get(proposalId);
}); });
@ -642,7 +629,7 @@ async function queryAndSaveAwaitingRefund(
Amounts.cmp(refundAwaiting, purchase.refundAwaiting) !== 0 Amounts.cmp(refundAwaiting, purchase.refundAwaiting) !== 0
) { ) {
await ws.db await ws.db
.mktx((x) => ({ purchases: x.purchases })) .mktx((x) => [x.purchases])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const p = await tx.purchases.get(purchase.proposalId); const p = await tx.purchases.get(purchase.proposalId);
if (!p) { if (!p) {
@ -667,9 +654,7 @@ export async function processPurchaseQueryRefund(
): Promise<OperationAttemptResult> { ): Promise<OperationAttemptResult> {
const waitForAutoRefund = options.waitForAutoRefund ?? false; const waitForAutoRefund = options.waitForAutoRefund ?? false;
const purchase = await ws.db const purchase = await ws.db
.mktx((x) => ({ .mktx((x) => [x.purchases])
purchases: x.purchases,
}))
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
return tx.purchases.get(proposalId); return tx.purchases.get(proposalId);
}); });
@ -729,9 +714,7 @@ export async function processPurchaseQueryRefund(
const abortingCoins: AbortingCoin[] = []; const abortingCoins: AbortingCoin[] = [];
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [x.coins])
coins: x.coins,
}))
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
for (let i = 0; i < purchase.payCoinSelection.coinPubs.length; i++) { for (let i = 0; i < purchase.payCoinSelection.coinPubs.length; i++) {
const coinPub = purchase.payCoinSelection.coinPubs[i]; const coinPub = purchase.payCoinSelection.coinPubs[i];
@ -796,9 +779,7 @@ export async function abortFailedPayWithRefund(
proposalId: string, proposalId: string,
): Promise<void> { ): Promise<void> {
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [x.purchases])
purchases: x.purchases,
}))
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const purchase = await tx.purchases.get(proposalId); const purchase = await tx.purchases.get(proposalId);
if (!purchase) { if (!purchase) {

View File

@ -467,7 +467,7 @@ export async function testPay(
throw Error("payment not done"); throw Error("payment not done");
} }
const purchase = await ws.db const purchase = await ws.db
.mktx((x) => ({ purchases: x.purchases })) .mktx((x) => [x.purchases])
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
return tx.purchases.get(result.proposalId); return tx.purchases.get(result.proposalId);
}); });

View File

@ -71,9 +71,7 @@ export async function prepareTip(
} }
let tipRecord = await ws.db let tipRecord = await ws.db
.mktx((x) => ({ .mktx((x) => [x.tips])
tips: x.tips,
}))
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
return tx.tips.indexes.byMerchantTipIdAndBaseUrl.get([ return tx.tips.indexes.byMerchantTipIdAndBaseUrl.get([
res.merchantTipId, res.merchantTipId,
@ -100,13 +98,13 @@ export async function prepareTip(
await updateExchangeFromUrl(ws, tipPickupStatus.exchange_url); await updateExchangeFromUrl(ws, tipPickupStatus.exchange_url);
//FIXME: is this needed? withdrawDetails is not used //FIXME: is this needed? withdrawDetails is not used
// * if the intention is to update the exchange information in the database // * if the intention is to update the exchange information in the database
// maybe we can use another name. `get` seems like a pure-function // maybe we can use another name. `get` seems like a pure-function
const withdrawDetails = await getExchangeWithdrawalInfo( const withdrawDetails = await getExchangeWithdrawalInfo(
ws, ws,
tipPickupStatus.exchange_url, tipPickupStatus.exchange_url,
amount, amount,
undefined undefined,
); );
const walletTipId = encodeCrock(getRandomBytes(32)); const walletTipId = encodeCrock(getRandomBytes(32));
@ -136,9 +134,7 @@ export async function prepareTip(
denomSelUid, denomSelUid,
}; };
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [x.tips])
tips: x.tips,
}))
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
await tx.tips.put(newTipRecord); await tx.tips.put(newTipRecord);
}); });
@ -166,9 +162,7 @@ export async function processTip(
} = {}, } = {},
): Promise<OperationAttemptResult> { ): Promise<OperationAttemptResult> {
const tipRecord = await ws.db const tipRecord = await ws.db
.mktx((x) => ({ .mktx((x) => [x.tips])
tips: x.tips,
}))
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
return tx.tips.get(walletTipId); return tx.tips.get(walletTipId);
}); });
@ -196,9 +190,7 @@ export async function processTip(
for (const dh of denomsForWithdraw.selectedDenoms) { for (const dh of denomsForWithdraw.selectedDenoms) {
const denom = await ws.db const denom = await ws.db
.mktx((x) => ({ .mktx((x) => [x.denominations])
denominations: x.denominations,
}))
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
return tx.denominations.get([ return tx.denominations.get([
tipRecord.exchangeBaseUrl, tipRecord.exchangeBaseUrl,
@ -324,11 +316,7 @@ export async function processTip(
} }
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [x.coins, x.tips, x.withdrawalGroups])
coins: x.coins,
tips: x.tips,
withdrawalGroups: x.withdrawalGroups,
}))
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const tr = await tx.tips.get(walletTipId); const tr = await tx.tips.get(walletTipId);
if (!tr) { if (!tr) {
@ -355,9 +343,7 @@ export async function acceptTip(
tipId: string, tipId: string,
): Promise<void> { ): Promise<void> {
const found = await ws.db const found = await ws.db
.mktx((x) => ({ .mktx((x) => [x.tips])
tips: x.tips,
}))
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const tipRecord = await tx.tips.get(tipId); const tipRecord = await tx.tips.get(tipId);
if (!tipRecord) { if (!tipRecord) {

View File

@ -126,24 +126,24 @@ export async function getTransactions(
const transactions: Transaction[] = []; const transactions: Transaction[] = [];
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [
coins: x.coins, x.coins,
denominations: x.denominations, x.denominations,
exchanges: x.exchanges, x.depositGroups,
exchangeDetails: x.exchangeDetails, x.exchangeDetails,
proposals: x.proposals, x.exchanges,
purchases: x.purchases, x.operationRetries,
refreshGroups: x.refreshGroups, x.peerPullPaymentIncoming,
tips: x.tips, x.peerPushPaymentInitiations,
withdrawalGroups: x.withdrawalGroups, x.planchets,
planchets: x.planchets, x.proposals,
recoupGroups: x.recoupGroups, x.purchases,
depositGroups: x.depositGroups, x.recoupGroups,
tombstones: x.tombstones, x.recoupGroups,
peerPushPaymentInitiations: x.peerPushPaymentInitiations, x.tips,
peerPullPaymentIncoming: x.peerPullPaymentIncoming, x.tombstones,
operationRetries: x.operationRetries, x.withdrawalGroups,
})) ])
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
tx.peerPushPaymentInitiations.iter().forEachAsync(async (pi) => { tx.peerPushPaymentInitiations.iter().forEachAsync(async (pi) => {
const amount = Amounts.parseOrThrow(pi.amount); const amount = Amounts.parseOrThrow(pi.amount);
@ -609,10 +609,7 @@ export async function deleteTransaction(
) { ) {
const withdrawalGroupId = rest[0]; const withdrawalGroupId = rest[0];
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [x.withdrawalGroups, x.tombstones])
withdrawalGroups: x.withdrawalGroups,
tombstones: x.tombstones,
}))
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const withdrawalGroupRecord = await tx.withdrawalGroups.get( const withdrawalGroupRecord = await tx.withdrawalGroups.get(
withdrawalGroupId, withdrawalGroupId,
@ -628,11 +625,7 @@ export async function deleteTransaction(
} else if (type === TransactionType.Payment) { } else if (type === TransactionType.Payment) {
const proposalId = rest[0]; const proposalId = rest[0];
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [x.proposals, x.purchases, x.tombstones])
proposals: x.proposals,
purchases: x.purchases,
tombstones: x.tombstones,
}))
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
let found = false; let found = false;
const proposal = await tx.proposals.get(proposalId); const proposal = await tx.proposals.get(proposalId);
@ -654,10 +647,7 @@ export async function deleteTransaction(
} else if (type === TransactionType.Refresh) { } else if (type === TransactionType.Refresh) {
const refreshGroupId = rest[0]; const refreshGroupId = rest[0];
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [x.refreshGroups, x.tombstones])
refreshGroups: x.refreshGroups,
tombstones: x.tombstones,
}))
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const rg = await tx.refreshGroups.get(refreshGroupId); const rg = await tx.refreshGroups.get(refreshGroupId);
if (rg) { if (rg) {
@ -670,10 +660,7 @@ export async function deleteTransaction(
} else if (type === TransactionType.Tip) { } else if (type === TransactionType.Tip) {
const tipId = rest[0]; const tipId = rest[0];
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [x.tips, x.tombstones])
tips: x.tips,
tombstones: x.tombstones,
}))
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const tipRecord = await tx.tips.get(tipId); const tipRecord = await tx.tips.get(tipId);
if (tipRecord) { if (tipRecord) {
@ -686,10 +673,7 @@ export async function deleteTransaction(
} else if (type === TransactionType.Deposit) { } else if (type === TransactionType.Deposit) {
const depositGroupId = rest[0]; const depositGroupId = rest[0];
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [x.depositGroups, x.tombstones])
depositGroups: x.depositGroups,
tombstones: x.tombstones,
}))
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const tipRecord = await tx.depositGroups.get(depositGroupId); const tipRecord = await tx.depositGroups.get(depositGroupId);
if (tipRecord) { if (tipRecord) {
@ -704,11 +688,7 @@ export async function deleteTransaction(
const executionTimeStr = rest[1]; const executionTimeStr = rest[1];
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [x.proposals, x.purchases, x.tombstones])
proposals: x.proposals,
purchases: x.purchases,
tombstones: x.tombstones,
}))
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const purchase = await tx.purchases.get(proposalId); const purchase = await tx.purchases.get(proposalId);
if (purchase) { if (purchase) {
@ -726,10 +706,7 @@ export async function deleteTransaction(
} else if (type === TransactionType.PeerPullDebit) { } else if (type === TransactionType.PeerPullDebit) {
const peerPullPaymentIncomingId = rest[0]; const peerPullPaymentIncomingId = rest[0];
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [x.peerPullPaymentIncoming, x.tombstones])
peerPullPaymentIncoming: x.peerPullPaymentIncoming,
tombstones: x.tombstones,
}))
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const debit = await tx.peerPullPaymentIncoming.get( const debit = await tx.peerPullPaymentIncoming.get(
peerPullPaymentIncomingId, peerPullPaymentIncomingId,
@ -747,10 +724,7 @@ export async function deleteTransaction(
} else if (type === TransactionType.PeerPushDebit) { } else if (type === TransactionType.PeerPushDebit) {
const pursePub = rest[0]; const pursePub = rest[0];
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [x.peerPushPaymentInitiations, x.tombstones])
peerPushPaymentInitiations: x.peerPushPaymentInitiations,
tombstones: x.tombstones,
}))
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const debit = await tx.peerPushPaymentInitiations.get(pursePub); const debit = await tx.peerPushPaymentInitiations.get(pursePub);
if (debit) { if (debit) {

View File

@ -195,9 +195,9 @@ export interface ExchangeWithdrawDetails {
/** /**
* If the exchange supports age-restricted coins it will return * If the exchange supports age-restricted coins it will return
* the array of ages. * the array of ages.
* *
*/ */
ageRestrictionOptions?: number[], ageRestrictionOptions?: number[];
} }
/** /**
@ -248,7 +248,7 @@ export function selectWithdrawalDenominations(
for (const d of denoms) { for (const d of denoms) {
let count = 0; let count = 0;
const cost = Amounts.add(d.value, d.feeWithdraw).amount; const cost = Amounts.add(d.value, d.feeWithdraw).amount;
for (; ;) { for (;;) {
if (Amounts.cmp(remaining, cost) < 0) { if (Amounts.cmp(remaining, cost) < 0) {
break; break;
} }
@ -412,7 +412,7 @@ export async function getCandidateWithdrawalDenoms(
exchangeBaseUrl: string, exchangeBaseUrl: string,
): Promise<DenominationRecord[]> { ): Promise<DenominationRecord[]> {
return await ws.db return await ws.db
.mktx((x) => ({ denominations: x.denominations })) .mktx((x) => [x.denominations])
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
const allDenoms = await tx.denominations.indexes.byExchangeBaseUrl.getAll( const allDenoms = await tx.denominations.indexes.byExchangeBaseUrl.getAll(
exchangeBaseUrl, exchangeBaseUrl,
@ -434,9 +434,7 @@ async function processPlanchetGenerate(
coinIdx: number, coinIdx: number,
): Promise<void> { ): Promise<void> {
let planchet = await ws.db let planchet = await ws.db
.mktx((x) => ({ .mktx((x) => [x.planchets])
planchets: x.planchets,
}))
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
return tx.planchets.indexes.byGroupAndIndex.get([ return tx.planchets.indexes.byGroupAndIndex.get([
withdrawalGroup.withdrawalGroupId, withdrawalGroup.withdrawalGroupId,
@ -462,9 +460,7 @@ async function processPlanchetGenerate(
const denomPubHash = maybeDenomPubHash; const denomPubHash = maybeDenomPubHash;
const denom = await ws.db const denom = await ws.db
.mktx((x) => ({ .mktx((x) => [x.denominations])
denominations: x.denominations,
}))
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
return ws.getDenomInfo( return ws.getDenomInfo(
ws, ws,
@ -500,7 +496,7 @@ async function processPlanchetGenerate(
lastError: undefined, lastError: undefined,
}; };
await ws.db await ws.db
.mktx((x) => ({ planchets: x.planchets })) .mktx((x) => [x.planchets])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const p = await tx.planchets.indexes.byGroupAndIndex.get([ const p = await tx.planchets.indexes.byGroupAndIndex.get([
withdrawalGroup.withdrawalGroupId, withdrawalGroup.withdrawalGroupId,
@ -529,12 +525,12 @@ async function processPlanchetExchangeRequest(
`processing planchet exchange request ${withdrawalGroup.withdrawalGroupId}/${coinIdx}`, `processing planchet exchange request ${withdrawalGroup.withdrawalGroupId}/${coinIdx}`,
); );
const d = await ws.db const d = await ws.db
.mktx((x) => ({ .mktx((x) => [
withdrawalGroups: x.withdrawalGroups, x.withdrawalGroups,
planchets: x.planchets, x.planchets,
exchanges: x.exchanges, x.exchanges,
denominations: x.denominations, x.denominations,
})) ])
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
let planchet = await tx.planchets.indexes.byGroupAndIndex.get([ let planchet = await tx.planchets.indexes.byGroupAndIndex.get([
withdrawalGroup.withdrawalGroupId, withdrawalGroup.withdrawalGroupId,
@ -599,7 +595,7 @@ async function processPlanchetExchangeRequest(
logger.trace("withdrawal request failed", e); logger.trace("withdrawal request failed", e);
logger.trace(e); logger.trace(e);
await ws.db await ws.db
.mktx((x) => ({ planchets: x.planchets })) .mktx((x) => [x.planchets])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
let planchet = await tx.planchets.indexes.byGroupAndIndex.get([ let planchet = await tx.planchets.indexes.byGroupAndIndex.get([
withdrawalGroup.withdrawalGroupId, withdrawalGroup.withdrawalGroupId,
@ -631,12 +627,12 @@ async function processPlanchetExchangeBatchRequest(
.map((x) => x.count) .map((x) => x.count)
.reduce((a, b) => a + b); .reduce((a, b) => a + b);
const d = await ws.db const d = await ws.db
.mktx((x) => ({ .mktx((x) => [
withdrawalGroups: x.withdrawalGroups, x.withdrawalGroups,
planchets: x.planchets, x.planchets,
exchanges: x.exchanges, x.exchanges,
denominations: x.denominations, x.denominations,
})) ])
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
const reqBody: { planchets: ExchangeWithdrawRequest[] } = { const reqBody: { planchets: ExchangeWithdrawRequest[] } = {
planchets: [], planchets: [],
@ -705,11 +701,7 @@ async function processPlanchetVerifyAndStoreCoin(
resp: WithdrawResponse, resp: WithdrawResponse,
): Promise<void> { ): Promise<void> {
const d = await ws.db const d = await ws.db
.mktx((x) => ({ .mktx((x) => [x.withdrawalGroups, x.planchets, x.denominations])
withdrawalGroups: x.withdrawalGroups,
planchets: x.planchets,
denominations: x.denominations,
}))
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
let planchet = await tx.planchets.indexes.byGroupAndIndex.get([ let planchet = await tx.planchets.indexes.byGroupAndIndex.get([
withdrawalGroup.withdrawalGroupId, withdrawalGroup.withdrawalGroupId,
@ -768,7 +760,7 @@ async function processPlanchetVerifyAndStoreCoin(
if (!isValid) { if (!isValid) {
await ws.db await ws.db
.mktx((x) => ({ planchets: x.planchets })) .mktx((x) => [x.planchets])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
let planchet = await tx.planchets.indexes.byGroupAndIndex.get([ let planchet = await tx.planchets.indexes.byGroupAndIndex.get([
withdrawalGroup.withdrawalGroupId, withdrawalGroup.withdrawalGroupId,
@ -823,11 +815,7 @@ async function processPlanchetVerifyAndStoreCoin(
// withdrawal succeeded. If so, mark the withdrawal // withdrawal succeeded. If so, mark the withdrawal
// group as finished. // group as finished.
const firstSuccess = await ws.db const firstSuccess = await ws.db
.mktx((x) => ({ .mktx((x) => [x.coins, x.withdrawalGroups, x.planchets])
coins: x.coins,
withdrawalGroups: x.withdrawalGroups,
planchets: x.planchets,
}))
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const p = await tx.planchets.get(planchetCoinPub); const p = await tx.planchets.get(planchetCoinPub);
if (!p || p.withdrawalDone) { if (!p || p.withdrawalDone) {
@ -858,10 +846,7 @@ export async function updateWithdrawalDenoms(
`updating denominations used for withdrawal for ${exchangeBaseUrl}`, `updating denominations used for withdrawal for ${exchangeBaseUrl}`,
); );
const exchangeDetails = await ws.db const exchangeDetails = await ws.db
.mktx((x) => ({ .mktx((x) => [x.exchanges, x.exchangeDetails])
exchanges: x.exchanges,
exchangeDetails: x.exchangeDetails,
}))
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
return ws.exchangeOps.getExchangeDetails(tx, exchangeBaseUrl); return ws.exchangeOps.getExchangeDetails(tx, exchangeBaseUrl);
}); });
@ -890,7 +875,8 @@ export async function updateWithdrawalDenoms(
denom.verificationStatus === DenominationVerificationStatus.Unverified denom.verificationStatus === DenominationVerificationStatus.Unverified
) { ) {
logger.trace( logger.trace(
`Validating denomination (${current + 1}/${denominations.length `Validating denomination (${current + 1}/${
denominations.length
}) signature of ${denom.denomPubHash}`, }) signature of ${denom.denomPubHash}`,
); );
let valid = false; let valid = false;
@ -919,7 +905,7 @@ export async function updateWithdrawalDenoms(
if (updatedDenominations.length > 0) { if (updatedDenominations.length > 0) {
logger.trace("writing denomination batch to db"); logger.trace("writing denomination batch to db");
await ws.db await ws.db
.mktx((x) => ({ denominations: x.denominations })) .mktx((x) => [x.denominations])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
for (let i = 0; i < updatedDenominations.length; i++) { for (let i = 0; i < updatedDenominations.length; i++) {
const denom = updatedDenominations[i]; const denom = updatedDenominations[i];
@ -973,7 +959,7 @@ async function queryReserve(
if ( if (
resp.status === 404 && resp.status === 404 &&
result.talerErrorResponse.code === result.talerErrorResponse.code ===
TalerErrorCode.EXCHANGE_RESERVES_STATUS_UNKNOWN TalerErrorCode.EXCHANGE_RESERVES_STATUS_UNKNOWN
) { ) {
ws.notify({ ws.notify({
type: NotificationType.ReserveNotYetFound, type: NotificationType.ReserveNotYetFound,
@ -988,9 +974,7 @@ async function queryReserve(
logger.trace(`got reserve status ${j2s(result.response)}`); logger.trace(`got reserve status ${j2s(result.response)}`);
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [x.withdrawalGroups])
withdrawalGroups: x.withdrawalGroups,
}))
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const wg = await tx.withdrawalGroups.get(withdrawalGroupId); const wg = await tx.withdrawalGroups.get(withdrawalGroupId);
if (!wg) { if (!wg) {
@ -1011,7 +995,7 @@ export async function processWithdrawalGroup(
): Promise<OperationAttemptResult> { ): Promise<OperationAttemptResult> {
logger.trace("processing withdrawal group", withdrawalGroupId); logger.trace("processing withdrawal group", withdrawalGroupId);
const withdrawalGroup = await ws.db const withdrawalGroup = await ws.db
.mktx((x) => ({ withdrawalGroups: x.withdrawalGroups })) .mktx((x) => [x.withdrawalGroups])
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
return tx.withdrawalGroups.get(withdrawalGroupId); return tx.withdrawalGroups.get(withdrawalGroupId);
}); });
@ -1080,7 +1064,7 @@ export async function processWithdrawalGroup(
if (withdrawalGroup.denomsSel.selectedDenoms.length === 0) { if (withdrawalGroup.denomsSel.selectedDenoms.length === 0) {
await ws.db await ws.db
.mktx((x) => ({ withdrawalGroups: x.withdrawalGroups })) .mktx((x) => [x.withdrawalGroups])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const wg = await tx.withdrawalGroups.get(withdrawalGroupId); const wg = await tx.withdrawalGroups.get(withdrawalGroupId);
if (!wg) { if (!wg) {
@ -1148,11 +1132,7 @@ export async function processWithdrawalGroup(
let errorsPerCoin: Record<number, TalerErrorDetail> = {}; let errorsPerCoin: Record<number, TalerErrorDetail> = {};
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [x.coins, x.withdrawalGroups, x.planchets])
coins: x.coins,
withdrawalGroups: x.withdrawalGroups,
planchets: x.planchets,
}))
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const wg = await tx.withdrawalGroups.get(withdrawalGroupId); const wg = await tx.withdrawalGroups.get(withdrawalGroupId);
if (!wg) { if (!wg) {
@ -1202,7 +1182,9 @@ export async function processWithdrawalGroup(
}; };
} }
const AGE_MASK_GROUPS = "8:10:12:14:16:18".split(":").map(n => parseInt(n, 10)) const AGE_MASK_GROUPS = "8:10:12:14:16:18"
.split(":")
.map((n) => parseInt(n, 10));
export async function getExchangeWithdrawalInfo( export async function getExchangeWithdrawalInfo(
ws: InternalWalletState, ws: InternalWalletState,
@ -1237,14 +1219,14 @@ export async function getExchangeWithdrawalInfo(
exchange, exchange,
); );
let hasDenomWithAgeRestriction = false let hasDenomWithAgeRestriction = false;
let earliestDepositExpiration: TalerProtocolTimestamp | undefined; let earliestDepositExpiration: TalerProtocolTimestamp | undefined;
for (let i = 0; i < selectedDenoms.selectedDenoms.length; i++) { for (let i = 0; i < selectedDenoms.selectedDenoms.length; i++) {
const ds = selectedDenoms.selectedDenoms[i]; const ds = selectedDenoms.selectedDenoms[i];
// FIXME: Do in one transaction! // FIXME: Do in one transaction!
const denom = await ws.db const denom = await ws.db
.mktx((x) => ({ denominations: x.denominations })) .mktx((x) => [x.denominations])
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
return ws.getDenomInfo(ws, tx, exchangeBaseUrl, ds.denomPubHash); return ws.getDenomInfo(ws, tx, exchangeBaseUrl, ds.denomPubHash);
}); });
@ -1262,13 +1244,14 @@ export async function getExchangeWithdrawalInfo(
) { ) {
earliestDepositExpiration = expireDeposit; earliestDepositExpiration = expireDeposit;
} }
hasDenomWithAgeRestriction = hasDenomWithAgeRestriction || denom.denomPub.age_mask > 0 hasDenomWithAgeRestriction =
hasDenomWithAgeRestriction || denom.denomPub.age_mask > 0;
} }
checkLogicInvariant(!!earliestDepositExpiration); checkLogicInvariant(!!earliestDepositExpiration);
const possibleDenoms = await ws.db const possibleDenoms = await ws.db
.mktx((x) => ({ denominations: x.denominations })) .mktx((x) => [x.denominations])
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
const ds = await tx.denominations.indexes.byExchangeBaseUrl.getAll( const ds = await tx.denominations.indexes.byExchangeBaseUrl.getAll(
exchangeBaseUrl, exchangeBaseUrl,
@ -1290,7 +1273,7 @@ export async function getExchangeWithdrawalInfo(
) { ) {
logger.warn( logger.warn(
`wallet's support for exchange protocol version ${WALLET_EXCHANGE_PROTOCOL_VERSION} might be outdated ` + `wallet's support for exchange protocol version ${WALLET_EXCHANGE_PROTOCOL_VERSION} might be outdated ` +
`(exchange has ${exchangeDetails.protocolVersion}), checking for updates`, `(exchange has ${exchangeDetails.protocolVersion}), checking for updates`,
); );
} }
} }
@ -1325,7 +1308,9 @@ export async function getExchangeWithdrawalInfo(
withdrawalAmountRaw: Amounts.stringify(instructedAmount), withdrawalAmountRaw: Amounts.stringify(instructedAmount),
// TODO: remove hardcoding, this should be calculated from the denominations info // TODO: remove hardcoding, this should be calculated from the denominations info
// force enabled for testing // force enabled for testing
ageRestrictionOptions: hasDenomWithAgeRestriction ? AGE_MASK_GROUPS : undefined ageRestrictionOptions: hasDenomWithAgeRestriction
? AGE_MASK_GROUPS
: undefined,
}; };
return ret; return ret;
} }
@ -1369,11 +1354,7 @@ export async function getWithdrawalDetailsForUri(
const exchanges: ExchangeListItem[] = []; const exchanges: ExchangeListItem[] = [];
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [x.exchanges, x.exchangeDetails, x.denominations])
exchanges: x.exchanges,
exchangeDetails: x.exchangeDetails,
denominations: x.denominations,
}))
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
const exchangeRecords = await tx.exchanges.iter().toArray(); const exchangeRecords = await tx.exchanges.iter().toArray();
for (const r of exchangeRecords) { for (const r of exchangeRecords) {
@ -1409,11 +1390,7 @@ export async function getFundingPaytoUrisTx(
withdrawalGroupId: string, withdrawalGroupId: string,
): Promise<string[]> { ): Promise<string[]> {
return await ws.db return await ws.db
.mktx((x) => ({ .mktx((x) => [x.exchanges, x.exchangeDetails, x.withdrawalGroups])
exchanges: x.exchanges,
exchangeDetails: x.exchangeDetails,
withdrawalGroups: x.withdrawalGroups,
}))
.runReadWrite((tx) => getFundingPaytoUris(tx, withdrawalGroupId)); .runReadWrite((tx) => getFundingPaytoUris(tx, withdrawalGroupId));
} }
@ -1461,9 +1438,7 @@ async function getWithdrawalGroupRecordTx(
}, },
): Promise<WithdrawalGroupRecord | undefined> { ): Promise<WithdrawalGroupRecord | undefined> {
return await db return await db
.mktx((x) => ({ .mktx((x) => [x.withdrawalGroups])
withdrawalGroups: x.withdrawalGroups,
}))
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
return tx.withdrawalGroups.get(req.withdrawalGroupId); return tx.withdrawalGroups.get(req.withdrawalGroupId);
}); });
@ -1490,9 +1465,7 @@ async function registerReserveWithBank(
withdrawalGroupId: string, withdrawalGroupId: string,
): Promise<void> { ): Promise<void> {
const withdrawalGroup = await ws.db const withdrawalGroup = await ws.db
.mktx((x) => ({ .mktx((x) => [x.withdrawalGroups])
withdrawalGroups: x.withdrawalGroups,
}))
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
return await tx.withdrawalGroups.get(withdrawalGroupId); return await tx.withdrawalGroups.get(withdrawalGroupId);
}); });
@ -1526,9 +1499,7 @@ async function registerReserveWithBank(
codecForBankWithdrawalOperationPostResponse(), codecForBankWithdrawalOperationPostResponse(),
); );
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [x.withdrawalGroups])
withdrawalGroups: x.withdrawalGroups,
}))
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const r = await tx.withdrawalGroups.get(withdrawalGroupId); const r = await tx.withdrawalGroups.get(withdrawalGroupId);
if (!r) { if (!r) {
@ -1606,9 +1577,7 @@ async function processReserveBankStatus(
if (status.aborted) { if (status.aborted) {
logger.info("bank aborted the withdrawal"); logger.info("bank aborted the withdrawal");
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [x.withdrawalGroups])
withdrawalGroups: x.withdrawalGroups,
}))
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const r = await tx.withdrawalGroups.get(withdrawalGroupId); const r = await tx.withdrawalGroups.get(withdrawalGroupId);
if (!r) { if (!r) {
@ -1648,9 +1617,7 @@ async function processReserveBankStatus(
} }
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [x.withdrawalGroups])
withdrawalGroups: x.withdrawalGroups,
}))
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const r = await tx.withdrawalGroups.get(withdrawalGroupId); const r = await tx.withdrawalGroups.get(withdrawalGroupId);
if (!r) { if (!r) {
@ -1753,13 +1720,13 @@ export async function internalCreateWithdrawalGroup(
); );
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [
withdrawalGroups: x.withdrawalGroups, x.withdrawalGroups,
reserves: x.reserves, x.reserves,
exchanges: x.exchanges, x.exchanges,
exchangeDetails: x.exchangeDetails, x.exchangeDetails,
exchangeTrust: x.exchangeTrust, x.exchangeTrust,
})) ])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
await tx.withdrawalGroups.add(withdrawalGroup); await tx.withdrawalGroups.add(withdrawalGroup);
await tx.reserves.put({ await tx.reserves.put({
@ -1790,7 +1757,7 @@ export async function acceptWithdrawalFromUri(
}, },
): Promise<AcceptWithdrawalResponse> { ): Promise<AcceptWithdrawalResponse> {
const existingWithdrawalGroup = await ws.db const existingWithdrawalGroup = await ws.db
.mktx((x) => ({ withdrawalGroups: x.withdrawalGroups })) .mktx((x) => [x.withdrawalGroups])
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
return await tx.withdrawalGroups.indexes.byTalerWithdrawUri.get( return await tx.withdrawalGroups.indexes.byTalerWithdrawUri.get(
req.talerWithdrawUri, req.talerWithdrawUri,
@ -1899,12 +1866,12 @@ export async function createManualWithdrawal(
const withdrawalGroupId = withdrawalGroup.withdrawalGroupId; const withdrawalGroupId = withdrawalGroup.withdrawalGroupId;
const exchangePaytoUris = await ws.db const exchangePaytoUris = await ws.db
.mktx((x) => ({ .mktx((x) => [
withdrawalGroups: x.withdrawalGroups, x.withdrawalGroups,
exchanges: x.exchanges, x.exchanges,
exchangeDetails: x.exchangeDetails, x.exchangeDetails,
exchangeTrust: x.exchangeTrust, x.exchangeTrust,
})) ])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
return await getFundingPaytoUris(tx, withdrawalGroup.withdrawalGroupId); return await getFundingPaytoUris(tx, withdrawalGroup.withdrawalGroupId);
}); });

View File

@ -36,6 +36,7 @@ import {
} from "@gnu-taler/idb-bridge"; } from "@gnu-taler/idb-bridge";
import { Logger } from "@gnu-taler/taler-util"; import { Logger } from "@gnu-taler/taler-util";
import { performanceNow } from "./timer.js"; import { performanceNow } from "./timer.js";
import { access } from "fs";
const logger = new Logger("query.ts"); const logger = new Logger("query.ts");
@ -280,7 +281,6 @@ export interface IndexDescriptor {
export interface StoreDescriptor<RecordType> { export interface StoreDescriptor<RecordType> {
_dummy: undefined & RecordType; _dummy: undefined & RecordType;
name: string;
keyPath?: IDBKeyPath | IDBKeyPath[]; keyPath?: IDBKeyPath | IDBKeyPath[];
autoIncrement?: boolean; autoIncrement?: boolean;
} }
@ -291,10 +291,9 @@ export interface StoreOptions {
} }
export function describeContents<RecordType = never>( export function describeContents<RecordType = never>(
name: string,
options: StoreOptions, options: StoreOptions,
): StoreDescriptor<RecordType> { ): StoreDescriptor<RecordType> {
return { name, keyPath: options.keyPath, _dummy: undefined as any }; return { keyPath: options.keyPath, _dummy: undefined as any };
} }
export function describeIndex( export function describeIndex(
@ -345,9 +344,11 @@ export interface StoreReadWriteAccessor<RecordType, IndexMap> {
} }
export interface StoreWithIndexes< export interface StoreWithIndexes<
StoreName extends string,
SD extends StoreDescriptor<unknown>, SD extends StoreDescriptor<unknown>,
IndexMap, IndexMap,
> { > {
storeName: StoreName;
store: SD; store: SD;
indexMap: IndexMap; indexMap: IndexMap;
@ -362,11 +363,17 @@ export type GetRecordType<T> = T extends StoreDescriptor<infer X> ? X : unknown;
const storeWithIndexesSymbol = Symbol("StoreWithIndexesMark"); const storeWithIndexesSymbol = Symbol("StoreWithIndexesMark");
export function describeStore<SD extends StoreDescriptor<unknown>, IndexMap>( export function describeStore<
StoreName extends string,
SD extends StoreDescriptor<unknown>,
IndexMap,
>(
name: StoreName,
s: SD, s: SD,
m: IndexMap, m: IndexMap,
): StoreWithIndexes<SD, IndexMap> { ): StoreWithIndexes<StoreName, SD, IndexMap> {
return { return {
storeName: name,
store: s, store: s,
indexMap: m, indexMap: m,
mark: storeWithIndexesSymbol, mark: storeWithIndexesSymbol,
@ -375,6 +382,7 @@ export function describeStore<SD extends StoreDescriptor<unknown>, IndexMap>(
export type GetReadOnlyAccess<BoundStores> = { export type GetReadOnlyAccess<BoundStores> = {
[P in keyof BoundStores]: BoundStores[P] extends StoreWithIndexes< [P in keyof BoundStores]: BoundStores[P] extends StoreWithIndexes<
infer SN,
infer SD, infer SD,
infer IM infer IM
> >
@ -384,6 +392,7 @@ export type GetReadOnlyAccess<BoundStores> = {
export type GetReadWriteAccess<BoundStores> = { export type GetReadWriteAccess<BoundStores> = {
[P in keyof BoundStores]: BoundStores[P] extends StoreWithIndexes< [P in keyof BoundStores]: BoundStores[P] extends StoreWithIndexes<
infer SN,
infer SD, infer SD,
infer IM infer IM
> >
@ -404,8 +413,12 @@ export interface TransactionContext<BoundStores> {
runReadOnly<T>(f: ReadOnlyTransactionFunction<BoundStores, T>): Promise<T>; runReadOnly<T>(f: ReadOnlyTransactionFunction<BoundStores, T>): Promise<T>;
} }
type CheckDescriptor<T> = T extends StoreWithIndexes<infer SD, infer IM> type CheckDescriptor<T> = T extends StoreWithIndexes<
? StoreWithIndexes<SD, IM> infer SN,
infer SD,
infer IM
>
? StoreWithIndexes<SN, SD, IM>
: unknown; : unknown;
type GetPickerType<F, SM> = F extends (x: SM) => infer Out type GetPickerType<F, SM> = F extends (x: SM) => infer Out
@ -477,13 +490,13 @@ function runTx<Arg, Res>(
function makeReadContext( function makeReadContext(
tx: IDBTransaction, tx: IDBTransaction,
storePick: { [n: string]: StoreWithIndexes<any, any> }, storePick: { [n: string]: StoreWithIndexes<any, any, any> },
): any { ): any {
const ctx: { [s: string]: StoreReadOnlyAccessor<any, any> } = {}; const ctx: { [s: string]: StoreReadOnlyAccessor<any, any> } = {};
for (const storeAlias in storePick) { for (const storeAlias in storePick) {
const indexes: { [s: string]: IndexReadOnlyAccessor<any> } = {}; const indexes: { [s: string]: IndexReadOnlyAccessor<any> } = {};
const swi = storePick[storeAlias]; const swi = storePick[storeAlias];
const storeName = swi.store.name; const storeName = swi.storeName;
for (const indexAlias in storePick[storeAlias].indexMap) { for (const indexAlias in storePick[storeAlias].indexMap) {
const indexDescriptor: IndexDescriptor = const indexDescriptor: IndexDescriptor =
storePick[storeAlias].indexMap[indexAlias]; storePick[storeAlias].indexMap[indexAlias];
@ -526,13 +539,13 @@ function makeReadContext(
function makeWriteContext( function makeWriteContext(
tx: IDBTransaction, tx: IDBTransaction,
storePick: { [n: string]: StoreWithIndexes<any, any> }, storePick: { [n: string]: StoreWithIndexes<any, any, any> },
): any { ): any {
const ctx: { [s: string]: StoreReadWriteAccessor<any, any> } = {}; const ctx: { [s: string]: StoreReadWriteAccessor<any, any> } = {};
for (const storeAlias in storePick) { for (const storeAlias in storePick) {
const indexes: { [s: string]: IndexReadWriteAccessor<any> } = {}; const indexes: { [s: string]: IndexReadWriteAccessor<any> } = {};
const swi = storePick[storeAlias]; const swi = storePick[storeAlias];
const storeName = swi.store.name; const storeName = swi.storeName;
for (const indexAlias in storePick[storeAlias].indexMap) { for (const indexAlias in storePick[storeAlias].indexMap) {
const indexDescriptor: IndexDescriptor = const indexDescriptor: IndexDescriptor =
storePick[storeAlias].indexMap[indexAlias]; storePick[storeAlias].indexMap[indexAlias];
@ -585,25 +598,11 @@ function makeWriteContext(
return ctx; return ctx;
} }
const storeList = [ type StoreNamesOf<X> = X extends { [x: number]: infer F }
{ name: "foo" as const, value: 1 as const }, ? F extends { storeName: infer I }
{ name: "bar" as const, value: 2 as const }, ? I
]; : never
// => { foo: { value: 1}, bar: {value: 2} } : never;
type StoreList = typeof storeList;
type StoreNames = StoreList[number] extends { name: infer I } ? I : never;
type H = StoreList[number] & { name: "foo"};
type Cleanup<V> = V extends { name: infer N, value: infer X} ? {name: N, value: X} : never;
type G = {
[X in StoreNames]: {
X: StoreList[number] & { name: X };
};
};
/** /**
* Type-safe access to a database with a particular store map. * Type-safe access to a database with a particular store map.
@ -617,36 +616,41 @@ export class DbAccess<StoreMap> {
return this.db; return this.db;
} }
mktx2< /**
* Run a transaction with selected object stores.
*
* The {@link namePicker} must be a function that selects a list of object
* stores from all available object stores.
*/
mktx<
StoreNames extends keyof StoreMap, StoreNames extends keyof StoreMap,
Stores extends StoreMap[StoreNames], Stores extends StoreMap[StoreNames],
StoreList extends Stores[], StoreList extends Stores[],
>(namePicker: (x: StoreMap) => StoreList): StoreList { BoundStores extends {
return namePicker(this.stores); [X in StoreNamesOf<StoreList>]: StoreList[number] & { storeName: X };
} },
>(namePicker: (x: StoreMap) => StoreList): TransactionContext<BoundStores> {
mktx< const storePick = namePicker(this.stores) as any;
PickerType extends (x: StoreMap) => unknown,
BoundStores extends GetPickerType<PickerType, StoreMap>,
>(f: PickerType): TransactionContext<BoundStores> {
const storePick = f(this.stores) as any;
if (typeof storePick !== "object" || storePick === null) { if (typeof storePick !== "object" || storePick === null) {
throw Error(); throw Error();
} }
const storeNames: string[] = []; const storeNames: string[] = [];
for (const storeAlias of Object.keys(storePick)) { const accessibleStores: { [x: string]: StoreWithIndexes<any, any, any> } =
const swi = (storePick as any)[storeAlias] as StoreWithIndexes<any, any>; {};
for (const swiPicked of storePick) {
const swi = swiPicked as StoreWithIndexes<any, any, any>;
if (swi.mark !== storeWithIndexesSymbol) { if (swi.mark !== storeWithIndexesSymbol) {
throw Error("invalid store descriptor returned from selector function"); throw Error("invalid store descriptor returned from selector function");
} }
storeNames.push(swi.store.name); storeNames.push(swi.storeName);
accessibleStores[swi.storeName] = swi;
} }
const runReadOnly = <T>( const runReadOnly = <T>(
txf: ReadOnlyTransactionFunction<BoundStores, T>, txf: ReadOnlyTransactionFunction<BoundStores, T>,
): Promise<T> => { ): Promise<T> => {
const tx = this.db.transaction(storeNames, "readonly"); const tx = this.db.transaction(storeNames, "readonly");
const readContext = makeReadContext(tx, storePick); const readContext = makeReadContext(tx, accessibleStores);
return runTx(tx, readContext, txf); return runTx(tx, readContext, txf);
}; };
@ -654,7 +658,7 @@ export class DbAccess<StoreMap> {
txf: ReadWriteTransactionFunction<BoundStores, T>, txf: ReadWriteTransactionFunction<BoundStores, T>,
): Promise<T> => { ): Promise<T> => {
const tx = this.db.transaction(storeNames, "readwrite"); const tx = this.db.transaction(storeNames, "readwrite");
const writeContext = makeWriteContext(tx, storePick); const writeContext = makeWriteContext(tx, accessibleStores);
return runTx(tx, writeContext, txf); return runTx(tx, writeContext, txf);
}; };

View File

@ -201,8 +201,9 @@ export async function scheduleRetry(
errorDetail?: TalerErrorDetail, errorDetail?: TalerErrorDetail,
): Promise<void> { ): Promise<void> {
return await ws.db return await ws.db
.mktx((x) => ({ operationRetries: x.operationRetries })) .mktx((x) => [x.operationRetries])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
tx.operationRetries
scheduleRetryInTx(ws, tx, opId, errorDetail); scheduleRetryInTx(ws, tx, opId, errorDetail);
}); });
} }

View File

@ -328,7 +328,7 @@ export async function storeOperationError(
e: TalerErrorDetail, e: TalerErrorDetail,
): Promise<void> { ): Promise<void> {
await ws.db await ws.db
.mktx((x) => ({ operationRetries: x.operationRetries })) .mktx((x) => [x.operationRetries])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const retryRecord = await tx.operationRetries.get(pendingTaskId); const retryRecord = await tx.operationRetries.get(pendingTaskId);
if (!retryRecord) { if (!retryRecord) {
@ -345,7 +345,7 @@ export async function storeOperationFinished(
pendingTaskId: string, pendingTaskId: string,
): Promise<void> { ): Promise<void> {
await ws.db await ws.db
.mktx((x) => ({ operationRetries: x.operationRetries })) .mktx((x) => [x.operationRetries])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
await tx.operationRetries.delete(pendingTaskId); await tx.operationRetries.delete(pendingTaskId);
}); });
@ -356,7 +356,7 @@ export async function storeOperationPending(
pendingTaskId: string, pendingTaskId: string,
): Promise<void> { ): Promise<void> {
await ws.db await ws.db
.mktx((x) => ({ operationRetries: x.operationRetries })) .mktx((x) => [x.operationRetries])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const retryRecord = await tx.operationRetries.get(pendingTaskId); const retryRecord = await tx.operationRetries.get(pendingTaskId);
if (!retryRecord) { if (!retryRecord) {
@ -542,7 +542,7 @@ async function runTaskLoop(
*/ */
async function fillDefaults(ws: InternalWalletState): Promise<void> { async function fillDefaults(ws: InternalWalletState): Promise<void> {
await ws.db await ws.db
.mktx((x) => ({ config: x.config, auditorTrustStore: x.auditorTrust })) .mktx((x) => [x.config, x.auditorTrust])
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
let applied = false; let applied = false;
await tx.config.iter().forEach((x) => { await tx.config.iter().forEach((x) => {
@ -552,7 +552,7 @@ async function fillDefaults(ws: InternalWalletState): Promise<void> {
}); });
if (!applied) { if (!applied) {
for (const c of builtinAuditors) { for (const c of builtinAuditors) {
await tx.auditorTrustStore.put(c); await tx.auditorTrust.put(c);
} }
} }
// FIXME: make sure exchanges are added transactionally to // FIXME: make sure exchanges are added transactionally to
@ -634,9 +634,7 @@ async function listKnownBankAccounts(
): Promise<KnownBankAccounts> { ): Promise<KnownBankAccounts> {
const accounts: { [account: string]: PaytoUri } = {}; const accounts: { [account: string]: PaytoUri } = {};
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [x.withdrawalGroups])
withdrawalGroups: x.withdrawalGroups,
}))
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
const withdrawalGroups = await tx.withdrawalGroups.iter().toArray(); const withdrawalGroups = await tx.withdrawalGroups.iter().toArray();
for (const r of withdrawalGroups) { for (const r of withdrawalGroups) {
@ -660,11 +658,7 @@ async function getExchanges(
): Promise<ExchangesListResponse> { ): Promise<ExchangesListResponse> {
const exchanges: ExchangeListItem[] = []; const exchanges: ExchangeListItem[] = [];
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [x.exchanges, x.exchangeDetails, x.denominations])
exchanges: x.exchanges,
exchangeDetails: x.exchangeDetails,
denominations: x.denominations,
}))
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
const exchangeRecords = await tx.exchanges.iter().toArray(); const exchangeRecords = await tx.exchanges.iter().toArray();
for (const r of exchangeRecords) { for (const r of exchangeRecords) {
@ -708,11 +702,7 @@ async function getExchangeDetailedInfo(
): Promise<ExchangeFullDetails> { ): Promise<ExchangeFullDetails> {
//TODO: should we use the forceUpdate parameter? //TODO: should we use the forceUpdate parameter?
const exchange = await ws.db const exchange = await ws.db
.mktx((x) => ({ .mktx((x) => [x.exchanges, x.exchangeDetails, x.denominations])
exchanges: x.exchanges,
exchangeDetails: x.exchangeDetails,
denominations: x.denominations,
}))
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
const ex = await tx.exchanges.get(exchangeBaseurl); const ex = await tx.exchanges.get(exchangeBaseurl);
const dp = ex?.detailsPointer; const dp = ex?.detailsPointer;
@ -790,9 +780,7 @@ async function setCoinSuspended(
suspended: boolean, suspended: boolean,
): Promise<void> { ): Promise<void> {
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [x.coins])
coins: x.coins,
}))
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
const c = await tx.coins.get(coinPub); const c = await tx.coins.get(coinPub);
if (!c) { if (!c) {
@ -811,11 +799,7 @@ async function dumpCoins(ws: InternalWalletState): Promise<CoinDumpJson> {
const coinsJson: CoinDumpJson = { coins: [] }; const coinsJson: CoinDumpJson = { coins: [] };
logger.info("dumping coins"); logger.info("dumping coins");
await ws.db await ws.db
.mktx((x) => ({ .mktx((x) => [x.coins, x.denominations, x.withdrawalGroups])
coins: x.coins,
denominations: x.denominations,
withdrawalGroups: x.withdrawalGroups,
}))
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
const coins = await tx.coins.iter().toArray(); const coins = await tx.coins.iter().toArray();
for (const c of coins) { for (const c of coins) {
@ -1065,11 +1049,7 @@ async function dispatchRequestInternal(
const req = codecForForceRefreshRequest().decode(payload); const req = codecForForceRefreshRequest().decode(payload);
const coinPubs = req.coinPubList.map((x) => ({ coinPub: x })); const coinPubs = req.coinPubList.map((x) => ({ coinPub: x }));
const refreshGroupId = await ws.db const refreshGroupId = await ws.db
.mktx((x) => ({ .mktx((x) => [x.refreshGroups, x.denominations, x.coins])
refreshGroups: x.refreshGroups,
denominations: x.denominations,
coins: x.coins,
}))
.runReadWrite(async (tx) => { .runReadWrite(async (tx) => {
return await createRefreshGroup( return await createRefreshGroup(
ws, ws,
@ -1164,10 +1144,7 @@ async function dispatchRequestInternal(
} }
case "listCurrencies": { case "listCurrencies": {
return await ws.db return await ws.db
.mktx((x) => ({ .mktx((x) => [x.auditorTrust, x.exchangeTrust])
auditorTrust: x.auditorTrust,
exchangeTrust: x.exchangeTrust,
}))
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
const trustedAuditors = await tx.auditorTrust.iter().toArray(); const trustedAuditors = await tx.auditorTrust.iter().toArray();
const trustedExchanges = await tx.exchangeTrust.iter().toArray(); const trustedExchanges = await tx.exchangeTrust.iter().toArray();