From f1cba79c656875af0c6a09fd8e03b2c94fb2ac44 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Fri, 14 Oct 2022 21:00:13 +0200 Subject: wallet-core: DB tweaks --- packages/taler-wallet-core/src/db.ts | 63 ++++++++++++++-------- .../src/operations/backup/export.ts | 2 +- .../src/operations/backup/import.ts | 7 +-- .../taler-wallet-core/src/operations/exchanges.ts | 2 +- .../taler-wallet-core/src/operations/pending.ts | 9 ++-- .../taler-wallet-core/src/operations/refresh.ts | 10 ++-- .../taler-wallet-core/src/operations/withdraw.ts | 23 ++++---- 7 files changed, 71 insertions(+), 45 deletions(-) (limited to 'packages/taler-wallet-core/src') diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts index 8f7f22292..6dfb06c15 100644 --- a/packages/taler-wallet-core/src/db.ts +++ b/packages/taler-wallet-core/src/db.ts @@ -101,11 +101,21 @@ export const CURRENT_DB_CONFIG_KEY = "currentMainDbName"; */ export const WALLET_DB_MINOR_VERSION = 2; +/** + * Ranges for operation status fields. + * + * All individual enums should make sure that the values they + * defined are in the right range. + */ export enum OperationStatusRange { + // Operations that need to be actively processed. ACTIVE_START = 10, ACTIVE_END = 29, + // Operations that need user input, but nothing can be done + // automatically. USER_ATTENTION_START = 30, USER_ATTENTION_END = 49, + // Operations that don't need any attention or processing. DORMANT_START = 50, DORMANT_END = 69, } @@ -150,7 +160,7 @@ export enum WithdrawalGroupStatus { } /** - * Extra info about a reserve that is used + * Extra info about a withdrawal that is used * with a bank-integrated withdrawal. */ export interface ReserveBankInfo { @@ -397,13 +407,9 @@ export namespace DenominationRecord { } /** - * Information about one of the exchange's bank accounts. + * Exchange details for a particular + * (exchangeBaseUrl, masterPublicKey, currency) tuple. */ -export interface ExchangeBankAccount { - payto_uri: string; - master_sig: string; -} - export interface ExchangeDetailsRecord { /** * Master public key of the exchange. @@ -425,7 +431,7 @@ export interface ExchangeDetailsRecord { /** * Last observed protocol version. */ - protocolVersion: string; + protocolVersionRange: string; reserveClosingDelay: TalerProtocolDuration; @@ -513,6 +519,10 @@ export interface ExchangeRecord { /** * Pointer to the current exchange details. + * + * Should usually not change. Only changes when the + * exchange advertises a different master public key and/or + * currency. */ detailsPointer: ExchangeDetailsPointer | undefined; @@ -554,6 +564,11 @@ export interface ExchangeRecord { currentMergeReserveInfo?: MergeReserveInfo; } +export enum PlanchetStatus { + Pending = 10 /* ACTIVE_START */, + WithdrawalDone = 50 /* DORMANT_START */, +} + /** * A coin that isn't yet signed by an exchange. */ @@ -579,10 +594,7 @@ export interface PlanchetRecord { */ coinIdx: number; - /** - * FIXME: make this an enum! - */ - withdrawalDone: boolean; + planchetStatus: PlanchetStatus; lastError: TalerErrorDetail | undefined; @@ -743,12 +755,21 @@ export interface CoinRecord { */ allocation: CoinAllocation | undefined; + /** + * Maximum age of purchases that can be made with this coin. + * + * FIXME: Not used for indexing, isn't it redundant? + */ maxAge: number; ageCommitmentProof: AgeCommitmentProof | undefined; } +/** + * Coin allocation, i.e. what a coin has been used for. + */ export interface CoinAllocation { + // FIXME: Specify format! id: string; amount: AmountString; } @@ -839,8 +860,14 @@ export enum OperationStatus { Pending = OperationStatusRange.ACTIVE_START, } +export enum RefreshOperationStatus { + Pending = 10 /* ACTIVE_START */, + Finished = 50 /* DORMANT_START */, + FinishedWithError = 51 /* DORMANT_START + 1 */, +} + export interface RefreshGroupRecord { - operationStatus: OperationStatus; + operationStatus: RefreshOperationStatus; // FIXME: Put this into a different object store? lastErrorPerCoin: { [coinIndex: number]: TalerErrorDetail }; @@ -880,13 +907,6 @@ export interface RefreshGroupRecord { * Timestamp when the refresh session finished. */ timestampFinished: TalerProtocolTimestamp | undefined; - - /** - * No coins are pending, but at least one is frozen. - * - * FIXME: What does this mean? - */ - frozen?: boolean; } /** @@ -1128,7 +1148,8 @@ export interface PurchasePayInfo { * Record that stores status information about one purchase, starting from when * the customer accepts a proposal. Includes refund status if applicable. * - * FIXME: Should have a single "status" field. + * Key: {@link proposalId} + * Operation status: {@link purchaseStatus} */ export interface PurchaseRecord { /** diff --git a/packages/taler-wallet-core/src/operations/backup/export.ts b/packages/taler-wallet-core/src/operations/backup/export.ts index c7890b5d8..3ba0d85e6 100644 --- a/packages/taler-wallet-core/src/operations/backup/export.ts +++ b/packages/taler-wallet-core/src/operations/backup/export.ts @@ -336,7 +336,7 @@ export async function exportBackup( })), master_public_key: ex.masterPublicKey, currency: ex.currency, - protocol_version: ex.protocolVersion, + protocol_version: ex.protocolVersionRange, wire_fees: wireFees, signing_keys: ex.signingKeys.map((x) => ({ key: x.key, diff --git a/packages/taler-wallet-core/src/operations/backup/import.ts b/packages/taler-wallet-core/src/operations/backup/import.ts index f4e6ab5eb..59fd3c398 100644 --- a/packages/taler-wallet-core/src/operations/backup/import.ts +++ b/packages/taler-wallet-core/src/operations/backup/import.ts @@ -57,6 +57,7 @@ import { WgInfo, WithdrawalGroupStatus, WithdrawalRecordType, + RefreshOperationStatus, } from "../../db.js"; import { InternalWalletState } from "../../internal-wallet-state.js"; import { assertUnreachable } from "../../util/assertUnreachable.js"; @@ -403,7 +404,7 @@ export async function importBackup( denomination_keys: x.denomination_keys, })), masterPublicKey: backupExchangeDetails.master_public_key, - protocolVersion: backupExchangeDetails.protocol_version, + protocolVersionRange: backupExchangeDetails.protocol_version, reserveClosingDelay: backupExchangeDetails.reserve_closing_delay, globalFees: backupExchangeDetails.global_fees.map((x) => ({ accountFee: Amounts.parseOrThrow(x.accountFee), @@ -773,8 +774,8 @@ export async function importBackup( : RefreshCoinStatus.Pending, ), operationStatus: backupRefreshGroup.timestamp_finish - ? OperationStatus.Finished - : OperationStatus.Pending, + ? RefreshOperationStatus.Finished + : RefreshOperationStatus.Pending, inputPerCoin: backupRefreshGroup.old_coins.map((x) => Amounts.parseOrThrow(x.input_amount), ), diff --git a/packages/taler-wallet-core/src/operations/exchanges.ts b/packages/taler-wallet-core/src/operations/exchanges.ts index 3da16e303..d3905b74b 100644 --- a/packages/taler-wallet-core/src/operations/exchanges.ts +++ b/packages/taler-wallet-core/src/operations/exchanges.ts @@ -641,7 +641,7 @@ export async function updateExchangeFromUrlHandler( auditors: keysInfo.auditors, currency: keysInfo.currency, masterPublicKey: keysInfo.masterPublicKey, - protocolVersion: keysInfo.protocolVersion, + protocolVersionRange: keysInfo.protocolVersion, signingKeys: keysInfo.signingKeys, reserveClosingDelay: keysInfo.reserveClosingDelay, globalFees, diff --git a/packages/taler-wallet-core/src/operations/pending.ts b/packages/taler-wallet-core/src/operations/pending.ts index 285cef534..d2066d4fc 100644 --- a/packages/taler-wallet-core/src/operations/pending.ts +++ b/packages/taler-wallet-core/src/operations/pending.ts @@ -106,16 +106,17 @@ 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( - OperationStatus.Pending, + keyRange, ); for (const r of refreshGroups) { if (r.timestampFinished) { return; } - if (r.frozen) { - return; - } const opId = RetryTags.forRefresh(r); const retryRecord = await tx.operationRetries.get(opId); diff --git a/packages/taler-wallet-core/src/operations/refresh.ts b/packages/taler-wallet-core/src/operations/refresh.ts index a5951ea53..83ab32f20 100644 --- a/packages/taler-wallet-core/src/operations/refresh.ts +++ b/packages/taler-wallet-core/src/operations/refresh.ts @@ -60,6 +60,7 @@ import { OperationStatus, RefreshCoinStatus, RefreshGroupRecord, + RefreshOperationStatus, WalletStoresV1, } from "../db.js"; import { TalerError } from "../errors.js"; @@ -139,10 +140,11 @@ function updateGroupStatus(rg: RefreshGroupRecord): void { ); if (allDone) { if (anyFrozen) { - rg.frozen = true; + rg.timestampFinished = AbsoluteTime.toTimestamp(AbsoluteTime.now()); + rg.operationStatus = RefreshOperationStatus.FinishedWithError; } else { rg.timestampFinished = AbsoluteTime.toTimestamp(AbsoluteTime.now()); - rg.operationStatus = OperationStatus.Finished; + rg.operationStatus = RefreshOperationStatus.Finished; } } } @@ -917,7 +919,7 @@ export async function createRefreshGroup( } const refreshGroup: RefreshGroupRecord = { - operationStatus: OperationStatus.Pending, + operationStatus: RefreshOperationStatus.Pending, timestampFinished: undefined, statusPerCoin: oldCoinPubs.map(() => RefreshCoinStatus.Pending), lastErrorPerCoin: {}, @@ -933,7 +935,7 @@ export async function createRefreshGroup( if (oldCoinPubs.length == 0) { logger.warn("created refresh group with zero coins"); refreshGroup.timestampFinished = TalerProtocolTimestamp.now(); - refreshGroup.operationStatus = OperationStatus.Finished; + refreshGroup.operationStatus = RefreshOperationStatus.Finished; } await tx.refreshGroups.put(refreshGroup); diff --git a/packages/taler-wallet-core/src/operations/withdraw.ts b/packages/taler-wallet-core/src/operations/withdraw.ts index e4bf6cd11..145a2d9c7 100644 --- a/packages/taler-wallet-core/src/operations/withdraw.ts +++ b/packages/taler-wallet-core/src/operations/withdraw.ts @@ -70,6 +70,7 @@ import { DenominationRecord, DenominationVerificationStatus, PlanchetRecord, + PlanchetStatus, WalletStoresV1, WgInfo, WithdrawalGroupRecord, @@ -430,7 +431,7 @@ async function processPlanchetGenerate( coinPub: r.coinPub, denomPubHash: r.denomPubHash, reservePub: r.reservePub, - withdrawalDone: false, + planchetStatus: PlanchetStatus.Pending, withdrawSig: r.withdrawSig, withdrawalGroupId: withdrawalGroup.withdrawalGroupId, maxAge: withdrawalGroup.restrictAge ?? AgeRestriction.AGE_UNRESTRICTED, @@ -481,7 +482,7 @@ async function processPlanchetExchangeRequest( if (!planchet) { return; } - if (planchet.withdrawalDone) { + if (planchet.planchetStatus === PlanchetStatus.WithdrawalDone) { logger.warn("processPlanchet: planchet already withdrawn"); return; } @@ -593,7 +594,7 @@ async function processPlanchetExchangeBatchRequest( if (!planchet) { return; } - if (planchet.withdrawalDone) { + if (planchet.planchetStatus === PlanchetStatus.WithdrawalDone) { logger.warn("processPlanchet: planchet already withdrawn"); return; } @@ -652,7 +653,7 @@ async function processPlanchetVerifyAndStoreCoin( if (!planchet) { return; } - if (planchet.withdrawalDone) { + if (planchet.planchetStatus === PlanchetStatus.WithdrawalDone) { logger.warn("processPlanchet: planchet already withdrawn"); return; } @@ -767,10 +768,10 @@ async function processPlanchetVerifyAndStoreCoin( ]) .runReadWrite(async (tx) => { const p = await tx.planchets.get(planchetCoinPub); - if (!p || p.withdrawalDone) { + if (!p || p.planchetStatus === PlanchetStatus.WithdrawalDone) { return false; } - p.withdrawalDone = true; + p.planchetStatus = PlanchetStatus.WithdrawalDone; await tx.planchets.put(p); await makeCoinAvailable(ws, tx, coin); return true; @@ -1140,7 +1141,7 @@ export async function processWithdrawalGroup( await tx.planchets.indexes.byGroup .iter(withdrawalGroupId) .forEach((x) => { - if (x.withdrawalDone) { + if (x.planchetStatus === PlanchetStatus.WithdrawalDone) { numFinished++; } if (x.lastError) { @@ -1258,10 +1259,10 @@ export async function getExchangeWithdrawalInfo( }); let versionMatch; - if (exchangeDetails.protocolVersion) { + if (exchangeDetails.protocolVersionRange) { versionMatch = LibtoolVersion.compare( WALLET_EXCHANGE_PROTOCOL_VERSION, - exchangeDetails.protocolVersion, + exchangeDetails.protocolVersionRange, ); if ( @@ -1271,7 +1272,7 @@ export async function getExchangeWithdrawalInfo( ) { logger.warn( `wallet's support for exchange protocol version ${WALLET_EXCHANGE_PROTOCOL_VERSION} might be outdated ` + - `(exchange has ${exchangeDetails.protocolVersion}), checking for updates`, + `(exchange has ${exchangeDetails.protocolVersionRange}), checking for updates`, ); } } @@ -1296,7 +1297,7 @@ export async function getExchangeWithdrawalInfo( earliestDepositExpiration, exchangePaytoUris: paytoUris, exchangeWireAccounts, - exchangeVersion: exchangeDetails.protocolVersion || "unknown", + exchangeVersion: exchangeDetails.protocolVersionRange || "unknown", isAudited, isTrusted, numOfferedDenoms: possibleDenoms.length, -- cgit v1.2.3