From b2d0ad57ddf251a109d536cdc49fb6505dbdc50c Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Tue, 11 Jul 2023 15:41:48 +0200 Subject: sqlite3 backend for idb-bridge / wallet-core --- packages/taler-wallet-core/src/db.ts | 5 +- packages/taler-wallet-core/src/host-common.ts | 2 +- packages/taler-wallet-core/src/host-impl.node.ts | 69 +++- packages/taler-wallet-core/src/host-impl.qtart.ts | 116 ++++++- packages/taler-wallet-core/src/host.ts | 1 - .../taler-wallet-core/src/operations/pending.ts | 350 ++++++++++++++++----- .../taler-wallet-core/src/operations/testing.ts | 3 + .../src/operations/transactions.ts | 31 +- packages/taler-wallet-core/src/util/query.ts | 4 +- packages/taler-wallet-core/src/wallet.ts | 1 + 10 files changed, 453 insertions(+), 129 deletions(-) (limited to 'packages/taler-wallet-core') diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts index c7d0b0bda..1d0d3a6e5 100644 --- a/packages/taler-wallet-core/src/db.ts +++ b/packages/taler-wallet-core/src/db.ts @@ -119,7 +119,7 @@ export const CURRENT_DB_CONFIG_KEY = "currentMainDbName"; * backwards-compatible way or object stores and indices * are added. */ -export const WALLET_DB_MINOR_VERSION = 9; +export const WALLET_DB_MINOR_VERSION = 10; /** * Ranges for operation status fields. @@ -2675,6 +2675,9 @@ export const WalletStoresV1 = { }), { byProposalId: describeIndex("byProposalId", "proposalId"), + byStatus: describeIndex("byStatus", "status", { + versionAdded: 10, + }), }, ), refundItems: describeStore( diff --git a/packages/taler-wallet-core/src/host-common.ts b/packages/taler-wallet-core/src/host-common.ts index 21e7f1157..c56d7ed1c 100644 --- a/packages/taler-wallet-core/src/host-common.ts +++ b/packages/taler-wallet-core/src/host-common.ts @@ -16,7 +16,7 @@ import { WalletNotification } from "@gnu-taler/taler-util"; import { HttpRequestLibrary } from "@gnu-taler/taler-util/http"; -import { WalletConfig, WalletConfigParameter } from "./index.js"; +import { WalletConfigParameter } from "./index.js"; /** * Helpers to initiate a wallet in a host environment. diff --git a/packages/taler-wallet-core/src/host-impl.node.ts b/packages/taler-wallet-core/src/host-impl.node.ts index 150bba49a..ceda7243f 100644 --- a/packages/taler-wallet-core/src/host-impl.node.ts +++ b/packages/taler-wallet-core/src/host-impl.node.ts @@ -27,6 +27,7 @@ import type { IDBFactory } from "@gnu-taler/idb-bridge"; import { BridgeIDBFactory, MemoryBackend, + createSqliteBackend, shimIndexedDB, } from "@gnu-taler/idb-bridge"; import { AccessStats } from "@gnu-taler/idb-bridge"; @@ -39,24 +40,21 @@ import { createPlatformHttpLib } from "@gnu-taler/taler-util/http"; import { SetTimeoutTimerAPI } from "./util/timer.js"; import { Wallet } from "./wallet.js"; import { DefaultNodeWalletArgs, makeTempfileId } from "./host-common.js"; +import { createNodeSqlite3Impl } from "@gnu-taler/idb-bridge/node-sqlite3-bindings"; const logger = new Logger("host-impl.node.ts"); -/** - * Get a wallet instance with default settings for node. - * - * Extended version that allows getting DB stats. - */ -export async function createNativeWalletHost2( +interface MakeDbResult { + idbFactory: BridgeIDBFactory; + getStats: () => AccessStats; +} + +async function makeFileDb( args: DefaultNodeWalletArgs = {}, -): Promise<{ - wallet: Wallet; - getDbStats: () => AccessStats; -}> { +): Promise { BridgeIDBFactory.enableTracing = false; const myBackend = new MemoryBackend(); myBackend.enableTracing = false; - const storagePath = args.persistentStoragePath; if (storagePath) { try { @@ -96,8 +94,41 @@ export async function createNativeWalletHost2( BridgeIDBFactory.enableTracing = false; const myBridgeIdbFactory = new BridgeIDBFactory(myBackend); - const myIdbFactory: IDBFactory = myBridgeIdbFactory as any as IDBFactory; + return { + idbFactory: myBridgeIdbFactory, + getStats: () => myBackend.accessStats, + }; +} +async function makeSqliteDb( + args: DefaultNodeWalletArgs, +): Promise { + BridgeIDBFactory.enableTracing = false; + const imp = await createNodeSqlite3Impl(); + const myBackend = await createSqliteBackend(imp, { + filename: args.persistentStoragePath ?? ":memory:", + }); + myBackend.enableTracing = false; + const myBridgeIdbFactory = new BridgeIDBFactory(myBackend); + return { + getStats() { + throw Error("not implemented"); + }, + idbFactory: myBridgeIdbFactory, + }; +} + +/** + * Get a wallet instance with default settings for node. + * + * Extended version that allows getting DB stats. + */ +export async function createNativeWalletHost2( + args: DefaultNodeWalletArgs = {}, +): Promise<{ + wallet: Wallet; + getDbStats: () => AccessStats; +}> { let myHttpLib; if (args.httpLib) { myHttpLib = args.httpLib; @@ -115,7 +146,17 @@ export async function createNativeWalletHost2( ); }; - shimIndexedDB(myBridgeIdbFactory); + let dbResp: MakeDbResult; + + if (!args.persistentStoragePath || args.persistentStoragePath.endsWith(".json")) { + dbResp = await makeFileDb(args); + } else { + dbResp = await makeSqliteDb(args); + } + + const myIdbFactory: IDBFactory = dbResp.idbFactory as any as IDBFactory; + + shimIndexedDB(dbResp.idbFactory); const myDb = await openTalerDatabase(myIdbFactory, myVersionChange); @@ -158,6 +199,6 @@ export async function createNativeWalletHost2( } return { wallet: w, - getDbStats: () => myBackend.accessStats, + getDbStats: dbResp.getStats, }; } diff --git a/packages/taler-wallet-core/src/host-impl.qtart.ts b/packages/taler-wallet-core/src/host-impl.qtart.ts index d10914b10..390282f8c 100644 --- a/packages/taler-wallet-core/src/host-impl.qtart.ts +++ b/packages/taler-wallet-core/src/host-impl.qtart.ts @@ -22,11 +22,17 @@ /** * Imports. */ -import type { IDBFactory } from "@gnu-taler/idb-bridge"; +import type { + IDBFactory, + ResultRow, + Sqlite3Interface, + Sqlite3Statement, +} from "@gnu-taler/idb-bridge"; // eslint-disable-next-line no-duplicate-imports import { BridgeIDBFactory, MemoryBackend, + createSqliteBackend, shimIndexedDB, } from "@gnu-taler/idb-bridge"; import { AccessStats } from "@gnu-taler/idb-bridge"; @@ -41,12 +47,78 @@ import { DefaultNodeWalletArgs, makeTempfileId } from "./host-common.js"; const logger = new Logger("host-impl.qtart.ts"); -export async function createNativeWalletHost2( +interface MakeDbResult { + idbFactory: BridgeIDBFactory; + getStats: () => AccessStats; +} + +let numStmt = 0; + +export async function createQtartSqlite3Impl(): Promise { + const tart: any = (globalThis as any)._tart; + if (!tart) { + throw Error("globalThis._qtart not defined"); + } + return { + open(filename: string) { + const internalDbHandle = tart.sqlite3Open(filename); + return { + internalDbHandle, + close() { + tart.sqlite3Close(internalDbHandle); + }, + prepare(stmtStr): Sqlite3Statement { + const stmtHandle = tart.sqlite3Prepare(internalDbHandle, stmtStr); + return { + internalStatement: stmtHandle, + getAll(params): ResultRow[] { + numStmt++; + return tart.sqlite3StmtGetAll(stmtHandle, params); + }, + getFirst(params): ResultRow | undefined { + numStmt++; + return tart.sqlite3StmtGetFirst(stmtHandle, params); + }, + run(params) { + numStmt++; + return tart.sqlite3StmtRun(stmtHandle, params); + }, + }; + }, + exec(sqlStr): void { + numStmt++; + tart.sqlite3Exec(internalDbHandle, sqlStr); + }, + }; + }, + }; +} + +async function makeSqliteDb( + args: DefaultNodeWalletArgs, +): Promise { + BridgeIDBFactory.enableTracing = false; + const imp = await createQtartSqlite3Impl(); + const myBackend = await createSqliteBackend(imp, { + filename: args.persistentStoragePath ?? ":memory:", + }); + myBackend.trackStats = true; + myBackend.enableTracing = false; + const myBridgeIdbFactory = new BridgeIDBFactory(myBackend); + return { + getStats() { + return { + ...myBackend.accessStats, + primitiveStatements: numStmt, + } + }, + idbFactory: myBridgeIdbFactory, + }; +} + +async function makeFileDb( args: DefaultNodeWalletArgs = {}, -): Promise<{ - wallet: Wallet; - getDbStats: () => AccessStats; -}> { +): Promise { BridgeIDBFactory.enableTracing = false; const myBackend = new MemoryBackend(); myBackend.enableTracing = false; @@ -78,12 +150,34 @@ export async function createNativeWalletHost2( }; } - logger.info("done processing storage path"); + const myBridgeIdbFactory = new BridgeIDBFactory(myBackend); + return { + idbFactory: myBridgeIdbFactory, + getStats: () => myBackend.accessStats, + }; +} +export async function createNativeWalletHost2( + args: DefaultNodeWalletArgs = {}, +): Promise<{ + wallet: Wallet; + getDbStats: () => AccessStats; +}> { BridgeIDBFactory.enableTracing = false; - const myBridgeIdbFactory = new BridgeIDBFactory(myBackend); - const myIdbFactory: IDBFactory = myBridgeIdbFactory as any as IDBFactory; + let dbResp: MakeDbResult; + + if (args.persistentStoragePath && args.persistentStoragePath.endsWith(".json")) { + logger.info("using JSON file backend (slow!)"); + dbResp = await makeFileDb(args); + } else { + logger.info("using JSON file backend (experimental!)"); + dbResp = await makeSqliteDb(args) + } + + const myIdbFactory: IDBFactory = dbResp.idbFactory as any as IDBFactory; + + shimIndexedDB(dbResp.idbFactory); let myHttpLib; if (args.httpLib) { @@ -102,8 +196,6 @@ export async function createNativeWalletHost2( ); }; - shimIndexedDB(myBridgeIdbFactory); - const myDb = await openTalerDatabase(myIdbFactory, myVersionChange); let workerFactory; @@ -124,6 +216,6 @@ export async function createNativeWalletHost2( } return { wallet: w, - getDbStats: () => myBackend.accessStats, + getDbStats: dbResp.getStats, }; } diff --git a/packages/taler-wallet-core/src/host.ts b/packages/taler-wallet-core/src/host.ts index 4b319f081..feccf42a6 100644 --- a/packages/taler-wallet-core/src/host.ts +++ b/packages/taler-wallet-core/src/host.ts @@ -16,7 +16,6 @@ import { DefaultNodeWalletArgs } from "./host-common.js"; import { Wallet } from "./index.js"; - import * as hostImpl from "#host-impl"; import { AccessStats } from "@gnu-taler/idb-bridge"; diff --git a/packages/taler-wallet-core/src/operations/pending.ts b/packages/taler-wallet-core/src/operations/pending.ts index cc9217d67..6c6546f83 100644 --- a/packages/taler-wallet-core/src/operations/pending.ts +++ b/packages/taler-wallet-core/src/operations/pending.ts @@ -34,13 +34,24 @@ import { WithdrawalGroupStatus, RewardRecordStatus, DepositOperationStatus, + RefreshGroupRecord, + WithdrawalGroupRecord, + DepositGroupRecord, + RewardRecord, + PurchaseRecord, + PeerPullPaymentInitiationRecord, + PeerPullPaymentIncomingRecord, + PeerPushPaymentInitiationRecord, + PeerPushPaymentIncomingRecord, + RefundGroupRecord, + RefundGroupStatus, } from "../db.js"; import { PendingOperationsResponse, PendingTaskType, TaskId, } from "../pending-types.js"; -import { AbsoluteTime } from "@gnu-taler/taler-util"; +import { AbsoluteTime, TransactionRecordFilter } from "@gnu-taler/taler-util"; import { InternalWalletState } from "../internal-wallet-state.js"; import { GetReadOnlyAccess } from "../util/query.js"; import { GlobalIDB } from "@gnu-taler/idb-bridge"; @@ -105,6 +116,32 @@ async function gatherExchangePending( }); } +/** + * Iterate refresh records based on a filter. + */ +export async function iterRecordsForRefresh( + tx: GetReadOnlyAccess<{ + refreshGroups: typeof WalletStoresV1.refreshGroups; + }>, + filter: TransactionRecordFilter, + f: (r: RefreshGroupRecord) => Promise, +): Promise { + let refreshGroups: RefreshGroupRecord[]; + if (filter.onlyState === "nonfinal") { + const keyRange = GlobalIDB.KeyRange.bound( + OperationStatusRange.ACTIVE_START, + OperationStatusRange.ACTIVE_END, + ); + refreshGroups = await tx.refreshGroups.indexes.byStatus.getAll(keyRange); + } else { + refreshGroups = await tx.refreshGroups.indexes.byStatus.getAll(); + } + + for (const r of refreshGroups) { + await f(r); + } +} + async function gatherRefreshPending( ws: InternalWalletState, tx: GetReadOnlyAccess<{ @@ -114,22 +151,13 @@ async function gatherRefreshPending( now: AbsoluteTime, resp: PendingOperationsResponse, ): Promise { - const keyRange = GlobalIDB.KeyRange.bound( - OperationStatusRange.ACTIVE_START, - OperationStatusRange.ACTIVE_END, - ); - const refreshGroups = await tx.refreshGroups.indexes.byStatus.getAll( - keyRange, - ); - for (const r of refreshGroups) { + await iterRecordsForRefresh(tx, { onlyState: "nonfinal" }, async (r) => { if (r.timestampFinished) { return; } const opId = TaskIdentifiers.forRefresh(r); const retryRecord = await tx.operationRetries.get(opId); - const timestampDue = retryRecord?.retryInfo.nextRetry ?? AbsoluteTime.now(); - resp.pendingOperations.push({ type: PendingTaskType.Refresh, ...getPendingCommon(ws, opId, timestampDue), @@ -140,6 +168,30 @@ async function gatherRefreshPending( ), retryInfo: retryRecord?.retryInfo, }); + }); +} + +export async function iterRecordsForWithdrawal( + tx: GetReadOnlyAccess<{ + withdrawalGroups: typeof WalletStoresV1.withdrawalGroups; + }>, + filter: TransactionRecordFilter, + f: (r: WithdrawalGroupRecord) => Promise, +): Promise { + let withdrawalGroupRecords: WithdrawalGroupRecord[]; + if (filter.onlyState === "nonfinal") { + const range = GlobalIDB.KeyRange.bound( + WithdrawalGroupStatus.PendingRegisteringBank, + WithdrawalGroupStatus.PendingAml, + ); + withdrawalGroupRecords = + await tx.withdrawalGroups.indexes.byStatus.getAll(range); + } else { + withdrawalGroupRecords = + await tx.withdrawalGroups.indexes.byStatus.getAll(); + } + for (const wgr of withdrawalGroupRecords) { + await f(wgr); } } @@ -153,12 +205,7 @@ async function gatherWithdrawalPending( now: AbsoluteTime, resp: PendingOperationsResponse, ): Promise { - const range = GlobalIDB.KeyRange.bound( - WithdrawalGroupStatus.PendingRegisteringBank, - WithdrawalGroupStatus.PendingAml, - ); - const wsrs = await tx.withdrawalGroups.indexes.byStatus.getAll(range); - for (const wsr of wsrs) { + await iterRecordsForWithdrawal(tx, { onlyState: "nonfinal" }, async (wsr) => { const opTag = TaskIdentifiers.forWithdrawal(wsr); let opr = await tx.operationRetries.get(opTag); const now = AbsoluteTime.now(); @@ -184,6 +231,30 @@ async function gatherWithdrawalPending( lastError: opr.lastError, retryInfo: opr.retryInfo, }); + }); +} + +export async function iterRecordsForDeposit( + tx: GetReadOnlyAccess<{ + depositGroups: typeof WalletStoresV1.depositGroups; + }>, + filter: TransactionRecordFilter, + f: (r: DepositGroupRecord) => Promise, +): Promise { + let dgs: DepositGroupRecord[]; + if (filter.onlyState === "nonfinal") { + dgs = await tx.depositGroups.indexes.byStatus.getAll( + GlobalIDB.KeyRange.bound( + DepositOperationStatus.PendingDeposit, + DepositOperationStatus.PendingKyc, + ), + ); + } else { + dgs = await tx.depositGroups.indexes.byStatus.getAll(); + } + + for (const dg of dgs) { + await f(dg); } } @@ -196,16 +267,7 @@ async function gatherDepositPending( now: AbsoluteTime, resp: PendingOperationsResponse, ): Promise { - const dgs = await tx.depositGroups.indexes.byStatus.getAll( - GlobalIDB.KeyRange.bound( - DepositOperationStatus.PendingDeposit, - DepositOperationStatus.PendingKyc, - ), - ); - for (const dg of dgs) { - if (dg.timestampFinished) { - return; - } + await iterRecordsForDeposit(tx, { onlyState: "nonfinal" }, async (dg) => { let deposited = true; for (const d of dg.depositedPerCoin) { if (!d) { @@ -226,10 +288,28 @@ async function gatherDepositPending( lastError: retryRecord?.lastError, retryInfo: retryRecord?.retryInfo, }); + }); +} + +export async function iterRecordsForReward( + tx: GetReadOnlyAccess<{ + rewards: typeof WalletStoresV1.rewards; + }>, + filter: TransactionRecordFilter, + f: (r: RewardRecord) => Promise, +): Promise { + if (filter.onlyState === "nonfinal") { + const range = GlobalIDB.KeyRange.bound( + RewardRecordStatus.PendingPickup, + RewardRecordStatus.PendingPickup, + ); + await tx.rewards.indexes.byStatus.iter(range).forEachAsync(f); + } else { + await tx.rewards.indexes.byStatus.iter().forEachAsync(f); } } -async function gatherTipPending( +async function gatherRewardPending( ws: InternalWalletState, tx: GetReadOnlyAccess<{ rewards: typeof WalletStoresV1.rewards; @@ -238,15 +318,7 @@ async function gatherTipPending( now: AbsoluteTime, resp: PendingOperationsResponse, ): Promise { - const range = GlobalIDB.KeyRange.bound( - RewardRecordStatus.PendingPickup, - RewardRecordStatus.PendingPickup, - ); - await tx.rewards.indexes.byStatus.iter(range).forEachAsync(async (tip) => { - // FIXME: The tip record needs a proper status field! - if (tip.pickedUpTimestamp) { - return; - } + await iterRecordsForReward(tx, { onlyState: "nonfinal" }, async (tip) => { const opId = TaskIdentifiers.forTipPickup(tip); const retryRecord = await tx.operationRetries.get(opId); const timestampDue = retryRecord?.retryInfo.nextRetry ?? AbsoluteTime.now(); @@ -264,6 +336,43 @@ async function gatherTipPending( }); } +export async function iterRecordsForRefund( + tx: GetReadOnlyAccess<{ + refundGroups: typeof WalletStoresV1.refundGroups; + }>, + filter: TransactionRecordFilter, + f: (r: RefundGroupRecord) => Promise, +): Promise { + if (filter.onlyState === "nonfinal") { + const keyRange = GlobalIDB.KeyRange.only( + RefundGroupStatus.Pending + ); + await tx.refundGroups.indexes.byStatus + .iter(keyRange) + .forEachAsync(f); + } else { + await tx.refundGroups.iter().forEachAsync(f); + } +} + +export async function iterRecordsForPurchase( + tx: GetReadOnlyAccess<{ + purchases: typeof WalletStoresV1.purchases; + }>, + filter: TransactionRecordFilter, + f: (r: PurchaseRecord) => Promise, +): Promise { + if (filter.onlyState === "nonfinal") { + const keyRange = GlobalIDB.KeyRange.bound( + PurchaseStatus.PendingDownloadingProposal, + PurchaseStatus.PendingAcceptRefund, + ); + await tx.purchases.indexes.byStatus.iter(keyRange).forEachAsync(f); + } else { + await tx.purchases.indexes.byStatus.iter().forEachAsync(f); + } +} + async function gatherPurchasePending( ws: InternalWalletState, tx: GetReadOnlyAccess<{ @@ -273,27 +382,20 @@ async function gatherPurchasePending( now: AbsoluteTime, resp: PendingOperationsResponse, ): Promise { - const keyRange = GlobalIDB.KeyRange.bound( - PurchaseStatus.PendingDownloadingProposal, - PurchaseStatus.PendingAcceptRefund, - ); - await tx.purchases.indexes.byStatus - .iter(keyRange) - .forEachAsync(async (pr) => { - const opId = TaskIdentifiers.forPay(pr); - const retryRecord = await tx.operationRetries.get(opId); - const timestampDue = - retryRecord?.retryInfo.nextRetry ?? AbsoluteTime.now(); - resp.pendingOperations.push({ - type: PendingTaskType.Purchase, - ...getPendingCommon(ws, opId, timestampDue), - givesLifeness: true, - statusStr: PurchaseStatus[pr.purchaseStatus], - proposalId: pr.proposalId, - retryInfo: retryRecord?.retryInfo, - lastError: retryRecord?.lastError, - }); + await iterRecordsForPurchase(tx, { onlyState: "nonfinal" }, async (pr) => { + const opId = TaskIdentifiers.forPay(pr); + const retryRecord = await tx.operationRetries.get(opId); + const timestampDue = retryRecord?.retryInfo.nextRetry ?? AbsoluteTime.now(); + resp.pendingOperations.push({ + type: PendingTaskType.Purchase, + ...getPendingCommon(ws, opId, timestampDue), + givesLifeness: true, + statusStr: PurchaseStatus[pr.purchaseStatus], + proposalId: pr.proposalId, + retryInfo: retryRecord?.retryInfo, + lastError: retryRecord?.lastError, }); + }); } async function gatherRecoupPending( @@ -362,6 +464,26 @@ async function gatherBackupPending( }); } +export async function iterRecordsForPeerPullInitiation( + tx: GetReadOnlyAccess<{ + peerPullPaymentInitiations: typeof WalletStoresV1.peerPullPaymentInitiations; + }>, + filter: TransactionRecordFilter, + f: (r: PeerPullPaymentInitiationRecord) => Promise, +): Promise { + if (filter.onlyState === "nonfinal") { + const keyRange = GlobalIDB.KeyRange.bound( + PeerPullPaymentInitiationStatus.PendingCreatePurse, + PeerPullPaymentInitiationStatus.AbortingDeletePurse, + ); + await tx.peerPullPaymentInitiations.indexes.byStatus + .iter(keyRange) + .forEachAsync(f); + } else { + await tx.peerPullPaymentInitiations.indexes.byStatus.iter().forEachAsync(f); + } +} + async function gatherPeerPullInitiationPending( ws: InternalWalletState, tx: GetReadOnlyAccess<{ @@ -371,13 +493,10 @@ async function gatherPeerPullInitiationPending( now: AbsoluteTime, resp: PendingOperationsResponse, ): Promise { - const keyRange = GlobalIDB.KeyRange.bound( - PeerPullPaymentInitiationStatus.PendingCreatePurse, - PeerPullPaymentInitiationStatus.AbortingDeletePurse, - ); - await tx.peerPullPaymentInitiations.indexes.byStatus - .iter(keyRange) - .forEachAsync(async (pi) => { + await iterRecordsForPeerPullInitiation( + tx, + { onlyState: "nonfinal" }, + async (pi) => { const opId = TaskIdentifiers.forPeerPullPaymentInitiation(pi); const retryRecord = await tx.operationRetries.get(opId); const timestampDue = @@ -389,7 +508,28 @@ async function gatherPeerPullInitiationPending( retryInfo: retryRecord?.retryInfo, pursePub: pi.pursePub, }); - }); + }, + ); +} + +export async function iterRecordsForPeerPullDebit( + tx: GetReadOnlyAccess<{ + peerPullPaymentIncoming: typeof WalletStoresV1.peerPullPaymentIncoming; + }>, + filter: TransactionRecordFilter, + f: (r: PeerPullPaymentIncomingRecord) => Promise, +): Promise { + if (filter.onlyState === "nonfinal") { + const keyRange = GlobalIDB.KeyRange.bound( + PeerPullDebitRecordStatus.PendingDeposit, + PeerPullDebitRecordStatus.AbortingRefresh, + ); + await tx.peerPullPaymentIncoming.indexes.byStatus + .iter(keyRange) + .forEachAsync(f); + } else { + await tx.peerPullPaymentIncoming.indexes.byStatus.iter().forEachAsync(f); + } } async function gatherPeerPullDebitPending( @@ -401,13 +541,10 @@ async function gatherPeerPullDebitPending( now: AbsoluteTime, resp: PendingOperationsResponse, ): Promise { - const keyRange = GlobalIDB.KeyRange.bound( - PeerPullDebitRecordStatus.PendingDeposit, - PeerPullDebitRecordStatus.AbortingRefresh, - ); - await tx.peerPullPaymentIncoming.indexes.byStatus - .iter(keyRange) - .forEachAsync(async (pi) => { + await iterRecordsForPeerPullDebit( + tx, + { onlyState: "nonfinal" }, + async (pi) => { const opId = TaskIdentifiers.forPeerPullPaymentDebit(pi); const retryRecord = await tx.operationRetries.get(opId); const timestampDue = @@ -419,7 +556,28 @@ async function gatherPeerPullDebitPending( retryInfo: retryRecord?.retryInfo, peerPullPaymentIncomingId: pi.peerPullPaymentIncomingId, }); - }); + }, + ); +} + +export async function iterRecordsForPeerPushInitiation( + tx: GetReadOnlyAccess<{ + peerPushPaymentInitiations: typeof WalletStoresV1.peerPushPaymentInitiations; + }>, + filter: TransactionRecordFilter, + f: (r: PeerPushPaymentInitiationRecord) => Promise, +): Promise { + if (filter.onlyState === "nonfinal") { + const keyRange = GlobalIDB.KeyRange.bound( + PeerPushPaymentInitiationStatus.PendingCreatePurse, + PeerPushPaymentInitiationStatus.AbortingRefresh, + ); + await tx.peerPushPaymentInitiations.indexes.byStatus + .iter(keyRange) + .forEachAsync(f); + } else { + await tx.peerPushPaymentInitiations.indexes.byStatus.iter().forEachAsync(f); + } } async function gatherPeerPushInitiationPending( @@ -431,13 +589,10 @@ async function gatherPeerPushInitiationPending( now: AbsoluteTime, resp: PendingOperationsResponse, ): Promise { - const keyRange = GlobalIDB.KeyRange.bound( - PeerPushPaymentInitiationStatus.PendingCreatePurse, - PeerPushPaymentInitiationStatus.AbortingRefresh, - ); - await tx.peerPushPaymentInitiations.indexes.byStatus - .iter(keyRange) - .forEachAsync(async (pi) => { + await iterRecordsForPeerPushInitiation( + tx, + { onlyState: "nonfinal" }, + async (pi) => { const opId = TaskIdentifiers.forPeerPushPaymentInitiation(pi); const retryRecord = await tx.operationRetries.get(opId); const timestampDue = @@ -449,7 +604,28 @@ async function gatherPeerPushInitiationPending( retryInfo: retryRecord?.retryInfo, pursePub: pi.pursePub, }); - }); + }, + ); +} + +export async function iterRecordsForPeerPushCredit( + tx: GetReadOnlyAccess<{ + peerPushPaymentIncoming: typeof WalletStoresV1.peerPushPaymentIncoming; + }>, + filter: TransactionRecordFilter, + f: (r: PeerPushPaymentIncomingRecord) => Promise, +): Promise { + if (filter.onlyState === "nonfinal") { + const keyRange = GlobalIDB.KeyRange.bound( + PeerPushPaymentIncomingStatus.PendingMerge, + PeerPushPaymentIncomingStatus.PendingWithdrawing, + ); + await tx.peerPushPaymentIncoming.indexes.byStatus + .iter(keyRange) + .forEachAsync(f); + } else { + await tx.peerPushPaymentIncoming.indexes.byStatus.iter().forEachAsync(f); + } } async function gatherPeerPushCreditPending( @@ -465,9 +641,10 @@ async function gatherPeerPushCreditPending( PeerPushPaymentIncomingStatus.PendingMerge, PeerPushPaymentIncomingStatus.PendingWithdrawing, ); - await tx.peerPushPaymentIncoming.indexes.byStatus - .iter(keyRange) - .forEachAsync(async (pi) => { + await iterRecordsForPeerPushCredit( + tx, + { onlyState: "nonfinal" }, + async (pi) => { const opId = TaskIdentifiers.forPeerPushCredit(pi); const retryRecord = await tx.operationRetries.get(opId); const timestampDue = @@ -479,7 +656,8 @@ async function gatherPeerPushCreditPending( retryInfo: retryRecord?.retryInfo, peerPushPaymentIncomingId: pi.peerPushPaymentIncomingId, }); - }); + }, + ); } export async function getPendingOperations( @@ -513,7 +691,7 @@ export async function getPendingOperations( await gatherRefreshPending(ws, tx, now, resp); await gatherWithdrawalPending(ws, tx, now, resp); await gatherDepositPending(ws, tx, now, resp); - await gatherTipPending(ws, tx, now, resp); + await gatherRewardPending(ws, tx, now, resp); await gatherPurchasePending(ws, tx, now, resp); await gatherRecoupPending(ws, tx, now, resp); await gatherBackupPending(ws, tx, now, resp); diff --git a/packages/taler-wallet-core/src/operations/testing.ts b/packages/taler-wallet-core/src/operations/testing.ts index ea373e914..3090549d5 100644 --- a/packages/taler-wallet-core/src/operations/testing.ts +++ b/packages/taler-wallet-core/src/operations/testing.ts @@ -472,12 +472,15 @@ export async function waitUntilDone(ws: InternalWalletState): Promise { p = openPromise(); const txs = await getTransactions(ws, { includeRefreshes: true, + filterByState: "nonfinal", }); let finished = true; for (const tx of txs.transactions) { switch (tx.txState.major) { case TransactionMajorState.Pending: case TransactionMajorState.Aborting: + case TransactionMajorState.Suspended: + case TransactionMajorState.SuspendedAborting: finished = false; logger.info( `continuing waiting, ${tx.transactionId} in ${tx.txState.major}(${tx.txState.minor})`, diff --git a/packages/taler-wallet-core/src/operations/transactions.ts b/packages/taler-wallet-core/src/operations/transactions.ts index a16809b36..af04cb161 100644 --- a/packages/taler-wallet-core/src/operations/transactions.ts +++ b/packages/taler-wallet-core/src/operations/transactions.ts @@ -36,6 +36,7 @@ import { TransactionByIdRequest, TransactionIdStr, TransactionMajorState, + TransactionRecordFilter, TransactionsRequest, TransactionsResponse, TransactionState, @@ -153,6 +154,7 @@ import { resumePeerPushDebitTransaction, abortPeerPushDebitTransaction, } from "./pay-peer-push-debit.js"; +import { iterRecordsForDeposit, iterRecordsForPeerPullDebit, iterRecordsForPeerPullInitiation, iterRecordsForPeerPushCredit, iterRecordsForPeerPushInitiation, iterRecordsForPurchase, iterRecordsForRefresh, iterRecordsForRefund, iterRecordsForReward, iterRecordsForWithdrawal } from "./pending.js"; const logger = new Logger("taler-wallet-core:transactions.ts"); @@ -929,6 +931,11 @@ export async function getTransactions( ): Promise { const transactions: Transaction[] = []; + const filter: TransactionRecordFilter = {}; + if (transactionsRequest?.filterByState) { + filter.onlyState = transactionsRequest.filterByState; + } + await ws.db .mktx((x) => [ x.coins, @@ -952,7 +959,7 @@ export async function getTransactions( x.refundGroups, ]) .runReadOnly(async (tx) => { - tx.peerPushPaymentInitiations.iter().forEachAsync(async (pi) => { + await iterRecordsForPeerPushInitiation(tx, filter, async (pi) => { const amount = Amounts.parseOrThrow(pi.amount); if (shouldSkipCurrency(transactionsRequest, amount.currency)) { @@ -968,7 +975,7 @@ export async function getTransactions( ); }); - tx.peerPullPaymentIncoming.iter().forEachAsync(async (pi) => { + await iterRecordsForPeerPullDebit(tx, filter, async (pi) => { const amount = Amounts.parseOrThrow(pi.contractTerms.amount); if (shouldSkipCurrency(transactionsRequest, amount.currency)) { return; @@ -986,7 +993,7 @@ export async function getTransactions( transactions.push(buildTransactionForPullPaymentDebit(pi)); }); - tx.peerPushPaymentIncoming.iter().forEachAsync(async (pi) => { + await iterRecordsForPeerPushCredit(tx, filter, async (pi) => { if (!pi.currency) { // Legacy transaction return; @@ -1026,8 +1033,8 @@ export async function getTransactions( ), ); }); - - tx.peerPullPaymentInitiations.iter().forEachAsync(async (pi) => { + + await iterRecordsForPeerPullInitiation(tx, filter, async (pi) => { const currency = Amounts.currencyOf(pi.amount); if (shouldSkipCurrency(transactionsRequest, currency)) { return; @@ -1060,7 +1067,7 @@ export async function getTransactions( ); }); - tx.refundGroups.iter().forEachAsync(async (refundGroup) => { + await iterRecordsForRefund(tx, filter, async (refundGroup) => { const currency = Amounts.currencyOf(refundGroup.amountRaw); if (shouldSkipCurrency(transactionsRequest, currency)) { return; @@ -1071,8 +1078,8 @@ export async function getTransactions( ); transactions.push(buildTransactionForRefund(refundGroup, contractData)); }); - - tx.refreshGroups.iter().forEachAsync(async (rg) => { + + await iterRecordsForRefresh(tx, filter, async (rg) => { if (shouldSkipCurrency(transactionsRequest, rg.currency)) { return; } @@ -1092,7 +1099,7 @@ export async function getTransactions( } }); - tx.withdrawalGroups.iter().forEachAsync(async (wsr) => { + await iterRecordsForWithdrawal(tx, filter ,async (wsr) => { if ( shouldSkipCurrency( transactionsRequest, @@ -1146,7 +1153,7 @@ export async function getTransactions( } }); - tx.depositGroups.iter().forEachAsync(async (dg) => { + await iterRecordsForDeposit(tx, filter, async (dg) => { const amount = Amounts.parseOrThrow(dg.contractTermsRaw.amount); if (shouldSkipCurrency(transactionsRequest, amount.currency)) { return; @@ -1157,7 +1164,7 @@ export async function getTransactions( transactions.push(buildTransactionForDeposit(dg, retryRecord)); }); - tx.purchases.iter().forEachAsync(async (purchase) => { + await iterRecordsForPurchase(tx, filter, async (purchase) => { const download = purchase.download; if (!download) { return; @@ -1200,7 +1207,7 @@ export async function getTransactions( ); }); - tx.rewards.iter().forEachAsync(async (tipRecord) => { + await iterRecordsForReward(tx, filter, async (tipRecord) => { if ( shouldSkipCurrency( transactionsRequest, diff --git a/packages/taler-wallet-core/src/util/query.ts b/packages/taler-wallet-core/src/util/query.ts index 1de1e9a0d..527cbdf63 100644 --- a/packages/taler-wallet-core/src/util/query.ts +++ b/packages/taler-wallet-core/src/util/query.ts @@ -338,7 +338,7 @@ interface IndexReadOnlyAccessor { iter(query?: IDBKeyRange | IDBValidKey): ResultStream; get(query: IDBValidKey): Promise; getAll( - query: IDBKeyRange | IDBValidKey, + query?: IDBKeyRange | IDBValidKey, count?: number, ): Promise; } @@ -351,7 +351,7 @@ interface IndexReadWriteAccessor { iter(query: IDBKeyRange | IDBValidKey): ResultStream; get(query: IDBValidKey): Promise; getAll( - query: IDBKeyRange | IDBValidKey, + query?: IDBKeyRange | IDBValidKey, count?: number, ): Promise; } diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts index 796a96f14..8cd9bb8c3 100644 --- a/packages/taler-wallet-core/src/wallet.ts +++ b/packages/taler-wallet-core/src/wallet.ts @@ -479,6 +479,7 @@ async function runTaskLoop( // Wait until either the timeout, or we are notified (via the latch) // that more work might be available. await Promise.race([timeout, ws.workAvailable.wait()]); + logger.trace(`done waiting for available work`); } else { logger.trace( `running ${pending.pendingOperations.length} pending operations`, -- cgit v1.2.3 From f9d1c4a89e2a686f0c82f8dc63ab3f1008763759 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Tue, 22 Aug 2023 08:54:05 +0200 Subject: wallet-core: wake up task loop on tx status changes --- packages/taler-wallet-core/src/operations/transactions.ts | 1 + 1 file changed, 1 insertion(+) (limited to 'packages/taler-wallet-core') diff --git a/packages/taler-wallet-core/src/operations/transactions.ts b/packages/taler-wallet-core/src/operations/transactions.ts index af04cb161..7f5302b25 100644 --- a/packages/taler-wallet-core/src/operations/transactions.ts +++ b/packages/taler-wallet-core/src/operations/transactions.ts @@ -1916,4 +1916,5 @@ export function notifyTransition( transactionId, }); } + ws.workAvailable.trigger(); } -- cgit v1.2.3 From 8c670bd06d62bb82f714f4ca8a8730b2abacc013 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Tue, 22 Aug 2023 08:54:28 +0200 Subject: wallet-core: simplify/optimize async condition --- .../taler-wallet-core/src/util/promiseUtils.ts | 24 +++++++++++----------- 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'packages/taler-wallet-core') diff --git a/packages/taler-wallet-core/src/util/promiseUtils.ts b/packages/taler-wallet-core/src/util/promiseUtils.ts index d409686d9..23f1c06a5 100644 --- a/packages/taler-wallet-core/src/util/promiseUtils.ts +++ b/packages/taler-wallet-core/src/util/promiseUtils.ts @@ -23,6 +23,8 @@ export interface OpenedPromise { /** * Get an unresolved promise together with its extracted resolve / reject * function. + * + * Recent ECMAScript proposals also call this a promise capability. */ export function openPromise(): OpenedPromise { let resolve: ((x?: any) => void) | null = null; @@ -39,22 +41,20 @@ export function openPromise(): OpenedPromise { } export class AsyncCondition { - private _waitPromise: Promise; - private _resolveWaitPromise: (val: void) => void; - constructor() { - const op = openPromise(); - this._waitPromise = op.promise; - this._resolveWaitPromise = op.resolve; - } + private promCap?: OpenedPromise = undefined; + constructor() {} wait(): Promise { - return this._waitPromise; + if (!this.promCap) { + this.promCap = openPromise(); + } + return this.promCap.promise; } trigger(): void { - this._resolveWaitPromise(); - const op = openPromise(); - this._waitPromise = op.promise; - this._resolveWaitPromise = op.resolve; + if (this.promCap) { + this.promCap.resolve(); + } + this.promCap = undefined; } } -- cgit v1.2.3 From 828e4ad3efd34df5e327cdcedaacab75ef2eff08 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Tue, 22 Aug 2023 08:55:33 +0200 Subject: wallet-core: use sqlite for in-memory DB --- packages/taler-wallet-core/src/host-impl.node.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'packages/taler-wallet-core') diff --git a/packages/taler-wallet-core/src/host-impl.node.ts b/packages/taler-wallet-core/src/host-impl.node.ts index ceda7243f..6a4f21d79 100644 --- a/packages/taler-wallet-core/src/host-impl.node.ts +++ b/packages/taler-wallet-core/src/host-impl.node.ts @@ -148,9 +148,11 @@ export async function createNativeWalletHost2( let dbResp: MakeDbResult; - if (!args.persistentStoragePath || args.persistentStoragePath.endsWith(".json")) { + if (args.persistentStoragePath &&args.persistentStoragePath.endsWith(".json")) { + logger.info("using legacy file-based DB backend"); dbResp = await makeFileDb(args); } else { + logger.info("using sqlite3 DB backend"); dbResp = await makeSqliteDb(args); } -- cgit v1.2.3 From b9f908db58c43d739e343dda250c5857ec893968 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Tue, 22 Aug 2023 16:37:16 +0200 Subject: -logging --- packages/taler-wallet-core/src/host-impl.qtart.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'packages/taler-wallet-core') diff --git a/packages/taler-wallet-core/src/host-impl.qtart.ts b/packages/taler-wallet-core/src/host-impl.qtart.ts index 390282f8c..720f5affb 100644 --- a/packages/taler-wallet-core/src/host-impl.qtart.ts +++ b/packages/taler-wallet-core/src/host-impl.qtart.ts @@ -168,10 +168,10 @@ export async function createNativeWalletHost2( let dbResp: MakeDbResult; if (args.persistentStoragePath && args.persistentStoragePath.endsWith(".json")) { - logger.info("using JSON file backend (slow!)"); + logger.info("using JSON file DB backend (slow!)"); dbResp = await makeFileDb(args); } else { - logger.info("using JSON file backend (experimental!)"); + logger.info("using sqlite3 DB backend (experimental!)"); dbResp = await makeSqliteDb(args) } -- cgit v1.2.3 From 0a05f6d9030b5a2ce201a98553fa4e6ff13eb907 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Tue, 22 Aug 2023 16:37:27 +0200 Subject: wallet-core: always use batch withdrawal --- packages/taler-harness/src/bench1.ts | 5 +- packages/taler-harness/src/bench3.ts | 6 +-- .../src/integrationtests/testrunner.ts | 2 + packages/taler-wallet-cli/src/index.ts | 1 - .../taler-wallet-core/src/operations/withdraw.ts | 55 ---------------------- packages/taler-wallet-core/src/wallet-api-types.ts | 1 - packages/taler-wallet-core/src/wallet.ts | 1 - .../src/hooks/useSettings.ts | 1 - .../taler-wallet-webextension/src/platform/api.ts | 1 - .../src/wallet/Settings.tsx | 4 -- .../taler-wallet-webextension/src/wxBackend.ts | 1 - 11 files changed, 4 insertions(+), 74 deletions(-) (limited to 'packages/taler-wallet-core') diff --git a/packages/taler-harness/src/bench1.ts b/packages/taler-harness/src/bench1.ts index fb7cc9e1f..6aa444e0a 100644 --- a/packages/taler-harness/src/bench1.ts +++ b/packages/taler-harness/src/bench1.ts @@ -68,7 +68,6 @@ export async function runBench1(configJson: any): Promise { } else { logger.info("not trusting exchange (validating signatures)"); } - const batchWithdrawal = !!process.env["TALER_WALLET_BATCH_WITHDRAWAL"]; let wallet = {} as Wallet; let getDbStats: () => AccessStats; @@ -91,9 +90,7 @@ export async function runBench1(configJson: any): Promise { testing: { insecureTrustExchange: trustExchange, }, - features: { - batchWithdrawal, - }, + features: {}, }, }); wallet = res.wallet; diff --git a/packages/taler-harness/src/bench3.ts b/packages/taler-harness/src/bench3.ts index ffafc75d2..c7eca90a8 100644 --- a/packages/taler-harness/src/bench3.ts +++ b/packages/taler-harness/src/bench3.ts @@ -76,8 +76,6 @@ export async function runBench3(configJson: any): Promise { } else { logger.info("not trusting exchange (validating signatures)"); } - const batchWithdrawal = !!process.env["TALER_WALLET_BATCH_WITHDRAWAL"]; - let wallet = {} as Wallet; let getDbStats: () => AccessStats; @@ -96,9 +94,7 @@ export async function runBench3(configJson: any): Promise { persistentStoragePath: undefined, httpLib: myHttpLib, config: { - features: { - batchWithdrawal, - }, + features: {}, testing: { insecureTrustExchange: trustExchange, }, diff --git a/packages/taler-harness/src/integrationtests/testrunner.ts b/packages/taler-harness/src/integrationtests/testrunner.ts index 67572f0f7..58e2a20f7 100644 --- a/packages/taler-harness/src/integrationtests/testrunner.ts +++ b/packages/taler-harness/src/integrationtests/testrunner.ts @@ -103,6 +103,7 @@ import { runPaymentTemplateTest } from "./test-payment-template.js"; import { runExchangeDepositTest } from "./test-exchange-deposit.js"; import { runPeerRepairTest } from "./test-peer-repair.js"; import { runPaymentShareTest } from "./test-payment-share.js"; +import { runSimplePaymentTest } from "./test-simple-payment.js"; /** * Test runner. @@ -129,6 +130,7 @@ const allTests: TestMainFunction[] = [ runClauseSchnorrTest, runDenomUnofferedTest, runDepositTest, + runSimplePaymentTest, runExchangeManagementTest, runExchangeTimetravelTest, runFeeRegressionTest, diff --git a/packages/taler-wallet-cli/src/index.ts b/packages/taler-wallet-cli/src/index.ts index e2787db66..9d840e5bb 100644 --- a/packages/taler-wallet-cli/src/index.ts +++ b/packages/taler-wallet-cli/src/index.ts @@ -258,7 +258,6 @@ async function createLocalWallet( cryptoWorkerType: walletCliArgs.wallet.cryptoWorker as any, config: { features: { - batchWithdrawal: checkEnvFlag("TALER_WALLET_BATCH_WITHDRAWAL"), }, testing: { devModeActive: checkEnvFlag("TALER_WALLET_DEV_MODE"), diff --git a/packages/taler-wallet-core/src/operations/withdraw.ts b/packages/taler-wallet-core/src/operations/withdraw.ts index a1cb29e07..673129928 100644 --- a/packages/taler-wallet-core/src/operations/withdraw.ts +++ b/packages/taler-wallet-core/src/operations/withdraw.ts @@ -710,12 +710,6 @@ async function processPlanchetGenerate( } interface WithdrawalRequestBatchArgs { - /** - * Use the batched request on the network level. - * Not supported by older exchanges. - */ - useBatchRequest: boolean; - coinStartIndex: number; batchSize: number; @@ -923,7 +917,6 @@ async function processPlanchetExchangeBatchRequest( // FIXME: handle individual error codes better! - if (args.useBatchRequest) { const reqUrl = new URL( `reserves/${withdrawalGroup.reservePub}/batch-withdraw`, withdrawalGroup.exchangeBaseUrl, @@ -949,53 +942,6 @@ async function processPlanchetExchangeBatchRequest( coinIdxs: [], }; } - } else { - // We emulate the batch response here by making multiple individual requests - const responses: ExchangeWithdrawBatchResponse = { - ev_sigs: [], - }; - const responseCoinIdxs: number[] = []; - for (let i = 0; i < batchReq.planchets.length; i++) { - try { - const p = batchReq.planchets[i]; - const reqUrl = new URL( - `reserves/${withdrawalGroup.reservePub}/withdraw`, - withdrawalGroup.exchangeBaseUrl, - ).href; - const resp = await ws.http.fetch(reqUrl, { method: "POST", body: p }); - if (resp.status === HttpStatusCode.UnavailableForLegalReasons) { - await handleKycRequired( - ws, - withdrawalGroup, - resp, - i, - requestCoinIdxs, - ); - // We still return blinded coins that we could actually withdraw. - return { - coinIdxs: responseCoinIdxs, - batchResp: responses, - }; - } - const r = await readSuccessResponseJsonOrThrow( - resp, - codecForWithdrawResponse(), - ); - responses.ev_sigs.push(r); - responseCoinIdxs.push(requestCoinIdxs[i]); - } catch (e) { - if (e instanceof TalerError) { - logger.warn(`withdrawing planchet failed: ${j2s(e.errorDetail)}`); - logger.warn(`planchet denom pub hash: ${batchReq.planchets[i].denom_pub_hash}`); - } - await storeCoinError(e, requestCoinIdxs[i]); - } - } - return { - coinIdxs: responseCoinIdxs, - batchResp: responses, - }; - } } async function processPlanchetVerifyAndStoreCoin( @@ -1548,7 +1494,6 @@ async function processWithdrawalGroupPendingReady( const resp = await processPlanchetExchangeBatchRequest(ws, wgContext, { batchSize: maxBatchSize, coinStartIndex: i, - useBatchRequest: ws.config.features.batchWithdrawal, }); let work: Promise[] = []; work = []; diff --git a/packages/taler-wallet-core/src/wallet-api-types.ts b/packages/taler-wallet-core/src/wallet-api-types.ts index 36c4809af..2a7c96ad1 100644 --- a/packages/taler-wallet-core/src/wallet-api-types.ts +++ b/packages/taler-wallet-core/src/wallet-api-types.ts @@ -272,7 +272,6 @@ export interface WalletConfig { * Configurations values that may be safe to show to the user */ features: { - batchWithdrawal: boolean; allowHttp: boolean; }; } diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts index 8cd9bb8c3..b967571d0 100644 --- a/packages/taler-wallet-core/src/wallet.ts +++ b/packages/taler-wallet-core/src/wallet.ts @@ -1696,7 +1696,6 @@ export class Wallet { ], }, features: { - batchWithdrawal: false, allowHttp: false, }, testing: { diff --git a/packages/taler-wallet-webextension/src/hooks/useSettings.ts b/packages/taler-wallet-webextension/src/hooks/useSettings.ts index 5c1ed7924..7332c15bb 100644 --- a/packages/taler-wallet-webextension/src/hooks/useSettings.ts +++ b/packages/taler-wallet-webextension/src/hooks/useSettings.ts @@ -34,7 +34,6 @@ function parse_json_or_undefined(str: string | undefined): T | undefined { export const codecForSettings = (): Codec => buildCodecForObject() .property("walletAllowHttp", codecForBoolean()) - .property("walletBatchWithdrawal", codecForBoolean()) .property("injectTalerSupport", codecForBoolean()) .property("advanceMode", codecForBoolean()) .property("backup", codecForBoolean()) diff --git a/packages/taler-wallet-webextension/src/platform/api.ts b/packages/taler-wallet-webextension/src/platform/api.ts index 2537b16c2..ae57b8faf 100644 --- a/packages/taler-wallet-webextension/src/platform/api.ts +++ b/packages/taler-wallet-webextension/src/platform/api.ts @@ -119,7 +119,6 @@ export const defaultSettings: Settings = { showJsonOnError: false, extendedAccountTypes: false, walletAllowHttp: false, - walletBatchWithdrawal: false, }; /** diff --git a/packages/taler-wallet-webextension/src/wallet/Settings.tsx b/packages/taler-wallet-webextension/src/wallet/Settings.tsx index 4098fd55b..071d2a594 100644 --- a/packages/taler-wallet-webextension/src/wallet/Settings.tsx +++ b/packages/taler-wallet-webextension/src/wallet/Settings.tsx @@ -316,10 +316,6 @@ function AdvanceSettings(): VNode { label: i18n.str`Allow HTTP connections`, description: i18n.str`Using HTTP connection may be faster but unsafe (wallet restart required)`, }, - walletBatchWithdrawal: { - label: i18n.str`Allow batch withdrawals`, - description: i18n.str`Using the batch withdrawal API allows faster withdrawals (wallet restart required)`, - }, langSelector: { label: i18n.str`Lang selector`, description: i18n.str`Allows to manually change the language of the UI. Otherwise it will be automatically selected by your browser configuration.`, diff --git a/packages/taler-wallet-webextension/src/wxBackend.ts b/packages/taler-wallet-webextension/src/wxBackend.ts index dfdb1b0d5..95af1a3a4 100644 --- a/packages/taler-wallet-webextension/src/wxBackend.ts +++ b/packages/taler-wallet-webextension/src/wxBackend.ts @@ -332,7 +332,6 @@ async function reinitWallet(): Promise { { features: { allowHttp: settings.walletAllowHttp, - batchWithdrawal: settings.walletBatchWithdrawal, }, }, ); -- cgit v1.2.3 From 2051aded501cddac1a4c869fb1f9731ac4523a1e Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Wed, 23 Aug 2023 14:06:37 +0200 Subject: -formatting / don't use deprecated method --- .../src/operations/pay-peer-pull-credit.ts | 42 +++++++++++----------- 1 file changed, 21 insertions(+), 21 deletions(-) (limited to 'packages/taler-wallet-core') diff --git a/packages/taler-wallet-core/src/operations/pay-peer-pull-credit.ts b/packages/taler-wallet-core/src/operations/pay-peer-pull-credit.ts index ac501aae2..88b441cdd 100644 --- a/packages/taler-wallet-core/src/operations/pay-peer-pull-credit.ts +++ b/packages/taler-wallet-core/src/operations/pay-peer-pull-credit.ts @@ -420,10 +420,10 @@ async function handlePeerPullCreditCreatePurse( pullIni.exchangeBaseUrl, ); - const httpResp = await ws.http.postJson( - reservePurseMergeUrl.href, - reservePurseReqBody, - ); + const httpResp = await ws.http.fetch(reservePurseMergeUrl.href, { + method: "POST", + body: reservePurseReqBody, + }); if (httpResp.status === HttpStatusCode.UnavailableForLegalReasons) { const respJson = await httpResp.json(); @@ -759,23 +759,23 @@ export async function initiatePeerPullPayment( .mktx((x) => [x.peerPullPaymentInitiations, x.contractTerms]) .runReadWrite(async (tx) => { const ppi: PeerPullPaymentInitiationRecord = { - amount: req.partialContractTerms.amount, - contractTermsHash: hContractTerms, - exchangeBaseUrl: exchangeBaseUrl, - pursePriv: pursePair.priv, - pursePub: pursePair.pub, - mergePriv: mergePair.priv, - mergePub: mergePair.pub, - status: PeerPullPaymentInitiationStatus.PendingCreatePurse, - contractTerms: contractTerms, - mergeTimestamp, - contractEncNonce, - mergeReserveRowId: mergeReserveRowId, - contractPriv: contractKeyPair.priv, - contractPub: contractKeyPair.pub, - withdrawalGroupId, - estimatedAmountEffective: wi.withdrawalAmountEffective, - } + amount: req.partialContractTerms.amount, + contractTermsHash: hContractTerms, + exchangeBaseUrl: exchangeBaseUrl, + pursePriv: pursePair.priv, + pursePub: pursePair.pub, + mergePriv: mergePair.priv, + mergePub: mergePair.pub, + status: PeerPullPaymentInitiationStatus.PendingCreatePurse, + contractTerms: contractTerms, + mergeTimestamp, + contractEncNonce, + mergeReserveRowId: mergeReserveRowId, + contractPriv: contractKeyPair.priv, + contractPub: contractKeyPair.pub, + withdrawalGroupId, + estimatedAmountEffective: wi.withdrawalAmountEffective, + }; await tx.peerPullPaymentInitiations.put(ppi); const oldTxState: TransactionState = { major: TransactionMajorState.None, -- cgit v1.2.3