diff options
Diffstat (limited to 'packages/taler-wallet-core/src/db.ts')
-rw-r--r-- | packages/taler-wallet-core/src/db.ts | 263 |
1 files changed, 163 insertions, 100 deletions
diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts index 239a6d4a4..46a073156 100644 --- a/packages/taler-wallet-core/src/db.ts +++ b/packages/taler-wallet-core/src/db.ts @@ -27,8 +27,8 @@ import { structuredEncapsulate, } from "@gnu-taler/idb-bridge"; import { + AbsoluteTime, AgeCommitmentProof, - AmountJson, AmountString, Amounts, AttentionInfo, @@ -45,23 +45,20 @@ import { ExchangeAuditor, ExchangeGlobalFees, HashCodeString, - InternationalizedString, Logger, - MerchantContractTerms, - MerchantInfo, PayCoinSelection, - PeerContractTerms, RefreshReason, TalerErrorDetail, TalerPreciseTimestamp, TalerProtocolDuration, TalerProtocolTimestamp, + //TalerProtocolTimestamp, TransactionIdStr, UnblindedSignature, WireInfo, codecForAny, } from "@gnu-taler/taler-util"; -import { RetryInfo, TaskIdentifiers } from "./operations/common.js"; +import { DbRetryInfo, TaskIdentifiers } from "./operations/common.js"; import { DbAccess, DbReadOnlyTransaction, @@ -151,6 +148,91 @@ export const CURRENT_DB_CONFIG_KEY = "currentMainDbName"; */ export const WALLET_DB_MINOR_VERSION = 1; +declare const symDbProtocolTimestamp: unique symbol; + +declare const symDbPreciseTimestamp: unique symbol; + +/** + * Timestamp, stored as microseconds. + * + * Always rounded to a full second. + */ +export type DbProtocolTimestamp = number & { [symDbProtocolTimestamp]: true }; + +/** + * Timestamp, stored as microseconds. + */ +export type DbPreciseTimestamp = number & { [symDbPreciseTimestamp]: true }; + +const DB_TIMESTAMP_FOREVER = Number.MAX_SAFE_INTEGER; + +export function timestampPreciseFromDb( + dbTs: DbPreciseTimestamp, +): TalerPreciseTimestamp { + return TalerPreciseTimestamp.fromMilliseconds(Math.floor(dbTs / 1000)); +} + +export function timestampOptionalPreciseFromDb( + dbTs: DbPreciseTimestamp | undefined, +): TalerPreciseTimestamp | undefined { + if (!dbTs) { + return undefined; + } + return TalerPreciseTimestamp.fromMilliseconds(Math.floor(dbTs / 1000)); +} + +export function timestampPreciseToDb( + stamp: TalerPreciseTimestamp, +): DbPreciseTimestamp { + if (stamp.t_s === "never") { + return DB_TIMESTAMP_FOREVER as DbPreciseTimestamp; + } else { + let tUs = stamp.t_s * 1000000; + if (stamp.off_us) { + tUs == stamp.off_us; + } + return tUs as DbPreciseTimestamp; + } +} + +export function timestampProtocolToDb( + stamp: TalerProtocolTimestamp, +): DbProtocolTimestamp { + if (stamp.t_s === "never") { + return DB_TIMESTAMP_FOREVER as DbProtocolTimestamp; + } else { + let tUs = stamp.t_s * 1000000; + return tUs as DbProtocolTimestamp; + } +} + +export function timestampProtocolFromDb( + stamp: DbProtocolTimestamp, +): TalerProtocolTimestamp { + return TalerProtocolTimestamp.fromSeconds(Math.floor(stamp / 1000000)); +} + +export function timestampAbsoluteFromDb( + stamp: DbProtocolTimestamp | DbPreciseTimestamp, +): AbsoluteTime { + if (stamp >= DB_TIMESTAMP_FOREVER) { + return AbsoluteTime.never(); + } + return AbsoluteTime.fromMilliseconds(Math.floor(stamp / 1000)); +} + +export function timestampOptionalAbsoluteFromDb( + stamp: DbProtocolTimestamp | DbPreciseTimestamp | undefined, +): AbsoluteTime | undefined { + if (stamp == null) { + return undefined; + } + if (stamp >= DB_TIMESTAMP_FOREVER) { + return AbsoluteTime.never(); + } + return AbsoluteTime.fromMilliseconds(Math.floor(stamp / 1000)); +} + /** * Format of the operation status code: 0x0abc_nnnn @@ -217,7 +299,7 @@ export enum WithdrawalGroupStatus { * Exchange is doing AML checks. */ PendingAml = 0x0100_0006, - SuspendedAml = 0x0100_0006, + SuspendedAml = 0x0110_0006, /** * The corresponding withdraw record has been created. @@ -268,14 +350,14 @@ export interface ReserveBankInfo { * * Set to undefined if that hasn't happened yet. */ - timestampReserveInfoPosted: TalerPreciseTimestamp | undefined; + timestampReserveInfoPosted: DbPreciseTimestamp | undefined; /** * Time when the reserve was confirmed by the bank. * * Set to undefined if not confirmed yet. */ - timestampBankConfirmed: TalerPreciseTimestamp | undefined; + timestampBankConfirmed: DbPreciseTimestamp | undefined; } /** @@ -349,22 +431,22 @@ export interface DenominationRecord { /** * Validity start date of the denomination. */ - stampStart: TalerProtocolTimestamp; + stampStart: DbProtocolTimestamp; /** * Date after which the currency can't be withdrawn anymore. */ - stampExpireWithdraw: TalerProtocolTimestamp; + stampExpireWithdraw: DbProtocolTimestamp; /** * Date after the denomination officially doesn't exist anymore. */ - stampExpireLegal: TalerProtocolTimestamp; + stampExpireLegal: DbProtocolTimestamp; /** * Data after which coins of this denomination can't be deposited anymore. */ - stampExpireDeposit: TalerProtocolTimestamp; + stampExpireDeposit: DbProtocolTimestamp; /** * Signature by the exchange's master key over the denomination @@ -406,7 +488,7 @@ export interface DenominationRecord { * Latest list issue date of the "/keys" response * that includes this denomination. */ - listIssueDate: TalerProtocolTimestamp; + listIssueDate: DbProtocolTimestamp; } export namespace DenominationRecord { @@ -418,10 +500,10 @@ export namespace DenominationRecord { feeRefresh: Amounts.stringify(d.fees.feeRefresh), feeRefund: Amounts.stringify(d.fees.feeRefund), feeWithdraw: Amounts.stringify(d.fees.feeWithdraw), - stampExpireDeposit: d.stampExpireDeposit, - stampExpireLegal: d.stampExpireLegal, - stampExpireWithdraw: d.stampExpireWithdraw, - stampStart: d.stampStart, + stampExpireDeposit: timestampProtocolFromDb(d.stampExpireDeposit), + stampExpireLegal: timestampProtocolFromDb(d.stampExpireLegal), + stampExpireWithdraw: timestampProtocolFromDb(d.stampExpireWithdraw), + stampStart: timestampProtocolFromDb(d.stampStart), value: Amounts.stringify(d.value), exchangeBaseUrl: d.exchangeBaseUrl, }; @@ -429,9 +511,9 @@ export namespace DenominationRecord { } export interface ExchangeSignkeysRecord { - stampStart: TalerProtocolTimestamp; - stampExpire: TalerProtocolTimestamp; - stampEnd: TalerProtocolTimestamp; + stampStart: DbProtocolTimestamp; + stampExpire: DbProtocolTimestamp; + stampEnd: DbProtocolTimestamp; signkeyPub: EddsaPublicKeyString; masterSig: EddsaSignatureString; @@ -488,7 +570,7 @@ export interface ExchangeDetailsRecord { tosAccepted: | { etag: string; - timestamp: TalerPreciseTimestamp; + timestamp: DbPreciseTimestamp; } | undefined; @@ -500,25 +582,6 @@ export interface ExchangeDetailsRecord { ageMask?: number; } -export interface ExchangeTosRecord { - exchangeBaseUrl: string; - - etag: string; - - /** - * Terms of service text or undefined if not downloaded yet. - * - * This is just used as a cache of the last downloaded ToS. - * - */ - termsOfServiceText: string | undefined; - - /** - * Content-type of the last downloaded termsOfServiceText. - */ - termsOfServiceContentType: string | undefined; -} - export interface ExchangeDetailsPointer { masterPublicKey: string; @@ -528,7 +591,7 @@ export interface ExchangeDetailsPointer { * Timestamp when the (masterPublicKey, currency) pointer * has been updated. */ - updateClock: TalerPreciseTimestamp; + updateClock: DbPreciseTimestamp; } export enum ExchangeEntryDbRecordStatus { @@ -549,11 +612,6 @@ export enum ExchangeEntryDbUpdateStatus { } /** - * Timestamp stored as a IEEE 754 double, in milliseconds. - */ -export type DbIndexableTimestampMs = number; - -/** * Exchange record as stored in the wallet's database. */ export interface ExchangeEntryRecord { @@ -563,11 +621,17 @@ export interface ExchangeEntryRecord { baseUrl: string; /** + * Currency hint for a preset exchange, relevant + * when we didn't contact a preset exchange yet. + */ + presetCurrencyHint?: string; + + /** * When did we confirm the last withdrawal from this exchange? * * Used mostly in the UI to suggest exchanges. */ - lastWithdrawal?: TalerPreciseTimestamp; + lastWithdrawal?: DbPreciseTimestamp; /** * Pointer to the current exchange details. @@ -588,17 +652,12 @@ export interface ExchangeEntryRecord { /** * Last time when the exchange /keys info was updated. */ - lastUpdate: TalerPreciseTimestamp | undefined; + lastUpdate: DbPreciseTimestamp | undefined; /** * Next scheduled update for the exchange. - * - * (This field must always be present, so we can index on the timestamp.) - * - * FIXME: To index on the timestamp, this needs to be a number of - * binary timestamp! */ - nextUpdateStampMs: DbIndexableTimestampMs; + nextUpdateStamp: DbPreciseTimestamp; lastKeysEtag: string | undefined; @@ -608,7 +667,7 @@ export interface ExchangeEntryRecord { * Updated whenever the exchange's denominations are updated or when * the refresh check has been done. */ - nextRefreshCheckStampMs: DbIndexableTimestampMs; + nextRefreshCheckStamp: DbPreciseTimestamp; /** * Public key of the reserve that we're currently using for @@ -823,7 +882,7 @@ export interface RewardRecord { * Has the user accepted the tip? Only after the tip has been accepted coins * withdrawn from the tip may be used. */ - acceptedTimestamp: TalerPreciseTimestamp | undefined; + acceptedTimestamp: DbPreciseTimestamp | undefined; /** * The tipped amount. @@ -838,7 +897,7 @@ export interface RewardRecord { /** * Timestamp, the tip can't be picked up anymore after this deadline. */ - rewardExpiration: TalerProtocolTimestamp; + rewardExpiration: DbProtocolTimestamp; /** * The exchange that will sign our coins, chosen by the merchant. @@ -876,7 +935,7 @@ export interface RewardRecord { */ merchantRewardId: string; - createdTimestamp: TalerPreciseTimestamp; + createdTimestamp: DbPreciseTimestamp; /** * The url to be redirected after the tip is accepted. @@ -887,7 +946,7 @@ export interface RewardRecord { * Timestamp for when the wallet finished picking up the tip * from the merchant. */ - pickedUpTimestamp: TalerPreciseTimestamp | undefined; + pickedUpTimestamp: DbPreciseTimestamp | undefined; status: RewardRecordStatus; } @@ -985,12 +1044,12 @@ export interface RefreshGroupRecord { */ statusPerCoin: RefreshCoinStatus[]; - timestampCreated: TalerPreciseTimestamp; + timestampCreated: DbPreciseTimestamp; /** * Timestamp when the refresh session finished. */ - timestampFinished: TalerPreciseTimestamp | undefined; + timestampFinished: DbPreciseTimestamp | undefined; } /** @@ -1215,7 +1274,7 @@ export interface PurchaseRecord { * Timestamp of the first time that sending a payment to the merchant * for this purchase was successful. */ - timestampFirstSuccessfulPay: TalerPreciseTimestamp | undefined; + timestampFirstSuccessfulPay: DbPreciseTimestamp | undefined; merchantPaySig: string | undefined; @@ -1230,19 +1289,19 @@ export interface PurchaseRecord { /** * When was the purchase record created? */ - timestamp: TalerPreciseTimestamp; + timestamp: DbPreciseTimestamp; /** * When was the purchase made? * Refers to the time that the user accepted. */ - timestampAccept: TalerPreciseTimestamp | undefined; + timestampAccept: DbPreciseTimestamp | undefined; /** * When was the last refund made? * Set to 0 if no refund was made on the purchase. */ - timestampLastRefundStatus: TalerPreciseTimestamp | undefined; + timestampLastRefundStatus: DbPreciseTimestamp | undefined; /** * Last session signature that we submitted to /pay (if any). @@ -1252,7 +1311,7 @@ export interface PurchaseRecord { /** * Continue querying the refund status until this deadline has expired. */ - autoRefundDeadline: TalerProtocolTimestamp | undefined; + autoRefundDeadline: DbProtocolTimestamp | undefined; /** * How much merchant has refund to be taken but the wallet @@ -1292,12 +1351,12 @@ export interface WalletBackupConfState { /** * Timestamp stored in the last backup. */ - lastBackupTimestamp?: TalerPreciseTimestamp; + lastBackupTimestamp?: DbPreciseTimestamp; /** * Last time we tried to do a backup. */ - lastBackupCheckTimestamp?: TalerPreciseTimestamp; + lastBackupCheckTimestamp?: DbPreciseTimestamp; lastBackupNonce?: string; } @@ -1405,12 +1464,12 @@ export interface WithdrawalGroupRecord { * When was the withdrawal operation started started? * Timestamp in milliseconds. */ - timestampStart: TalerPreciseTimestamp; + timestampStart: DbPreciseTimestamp; /** * When was the withdrawal operation completed? */ - timestampFinish?: TalerPreciseTimestamp; + timestampFinish?: DbPreciseTimestamp; /** * Current status of the reserve. @@ -1501,9 +1560,9 @@ export interface RecoupGroupRecord { exchangeBaseUrl: string; - timestampStarted: TalerPreciseTimestamp; + timestampStarted: DbPreciseTimestamp; - timestampFinished: TalerPreciseTimestamp | undefined; + timestampFinished: DbPreciseTimestamp | undefined; /** * Public keys that identify the coins being recouped @@ -1537,7 +1596,7 @@ export type BackupProviderState = } | { tag: BackupProviderStateTag.Ready; - nextBackupTimestamp: TalerPreciseTimestamp; + nextBackupTimestamp: DbPreciseTimestamp; } | { tag: BackupProviderStateTag.Retrying; @@ -1582,7 +1641,7 @@ export interface BackupProviderRecord { * Does NOT correspond to the timestamp of the backup, * which only changes when the backup content changes. */ - lastBackupCycleTimestamp?: TalerPreciseTimestamp; + lastBackupCycleTimestamp?: DbPreciseTimestamp; /** * Proposal that we're currently trying to pay for. @@ -1633,7 +1692,7 @@ export interface DepositTrackingInfo { // Raw wire transfer identifier of the deposit. wireTransferId: string; // When was the wire transfer given to the bank. - timestampExecuted: TalerProtocolTimestamp; + timestampExecuted: DbProtocolTimestamp; // Total amount transfer for this wtid (including fees) amountRaw: AmountString; // Wire fee amount for this exchange @@ -1655,7 +1714,7 @@ export interface DepositGroupRecord { */ amount: AmountString; - wireTransferDeadline: TalerProtocolTimestamp; + wireTransferDeadline: DbProtocolTimestamp; merchantPub: string; merchantPriv: string; @@ -1685,9 +1744,9 @@ export interface DepositGroupRecord { */ counterpartyEffectiveDepositAmount: AmountString; - timestampCreated: TalerPreciseTimestamp; + timestampCreated: DbPreciseTimestamp; - timestampFinished: TalerPreciseTimestamp | undefined; + timestampFinished: DbPreciseTimestamp | undefined; operationStatus: DepositOperationStatus; @@ -1796,9 +1855,9 @@ export interface PeerPushDebitRecord { */ contractEncNonce: string; - purseExpiration: TalerProtocolTimestamp; + purseExpiration: DbProtocolTimestamp; - timestampCreated: TalerPreciseTimestamp; + timestampCreated: DbPreciseTimestamp; abortRefreshGroupId?: string; @@ -1871,7 +1930,7 @@ export interface PeerPullCreditRecord { contractEncNonce: string; - mergeTimestamp: TalerPreciseTimestamp; + mergeTimestamp: DbPreciseTimestamp; mergeReserveRowId: number; @@ -1923,7 +1982,7 @@ export interface PeerPushPaymentIncomingRecord { contractPriv: string; - timestamp: TalerPreciseTimestamp; + timestamp: DbPreciseTimestamp; estimatedAmountEffective: AmountString; @@ -1995,7 +2054,7 @@ export interface PeerPullPaymentIncomingRecord { contractTermsHash: string; - timestampCreated: TalerPreciseTimestamp; + timestampCreated: DbPreciseTimestamp; /** * Contract priv that we got from the other party. @@ -2042,7 +2101,7 @@ export interface OperationRetryRecord { lastError?: TalerErrorDetail; - retryInfo: RetryInfo; + retryInfo: DbRetryInfo; } /** @@ -2095,14 +2154,13 @@ export interface UserAttentionRecord { /** * When the notification was created. - * FIXME: This should be a TalerPreciseTimestamp */ - createdMs: number; + created: DbPreciseTimestamp; /** * When the user mark this notification as read. */ - read: TalerPreciseTimestamp | undefined; + read: DbPreciseTimestamp | undefined; } export interface DbExchangeHandle { @@ -2146,7 +2204,7 @@ export interface RefundGroupRecord { /** * Timestamp when the refund group was created. */ - timestampCreated: TalerPreciseTimestamp; + timestampCreated: DbPreciseTimestamp; proposalId: string; @@ -2198,12 +2256,12 @@ export interface RefundItemRecord { /** * Execution time as claimed by the merchant */ - executionTime: TalerProtocolTimestamp; + executionTime: DbProtocolTimestamp; /** * Time when the wallet became aware of the refund. */ - obtainedTime: TalerPreciseTimestamp; + obtainedTime: DbPreciseTimestamp; refundAmount: AmountString; @@ -2389,15 +2447,19 @@ export const WalletStoresV1 = { "planchets", describeContents<PlanchetRecord>({ keyPath: "coinPub" }), { - byGroupAgeCoin: describeIndex("byGroupAgeCoin", [ - "withdrawalGroupId", - "ageWithdrawIdx", - "coinIdx", - ]), - byGroupAndIndex: describeIndex("byGroupAndIndex", [ - "withdrawalGroupId", - "coinIdx", - ]), + byGroupAgeCoin: describeIndex( + "byGroupAgeCoin", [ "withdrawalGroupId", "ageWithdrawIdx", "coinIdx" ], + { + unique: true, + }, + ), + byGroupAndIndex: describeIndex( + "byGroupAndIndex", + ["withdrawalGroupId", "coinIdx"], + { + unique: true, + }, + ), byGroup: describeIndex("byGroup", "withdrawalGroupId"), byCoinEvHash: describeIndex("byCoinEv", "coinEvHash"), }, @@ -3049,6 +3111,7 @@ export async function openTalerDatabase( case "taler-wallet-main-v6": case "taler-wallet-main-v7": case "taler-wallet-main-v8": + case "taler-wallet-main-v9": // We consider this a pre-release // development version, no migration is done. await metaDb |