gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-wallet-core] 02/03: wallet-core: consistently use usec timestamps


From: gnunet
Subject: [taler-wallet-core] 02/03: wallet-core: consistently use usec timestamps in DB
Date: Thu, 14 Sep 2023 19:18:13 +0200

This is an automated email from the git hooks/post-receive script.

dold pushed a commit to branch master
in repository wallet-core.

commit 1ce53e1c211296233f2f683c64e156e4d3a79678
Author: Florian Dold <florian@dold.me>
AuthorDate: Thu Sep 14 17:36:15 2023 +0200

    wallet-core: consistently use usec timestamps in DB
---
 packages/taler-util/src/transactions-types.ts      |  24 +++--
 .../src/crypto/cryptoImplementation.ts             |  22 +++-
 packages/taler-wallet-core/src/db.ts               |  97 ++++++++++++------
 .../taler-wallet-core/src/operations/attention.ts  |   6 +-
 .../taler-wallet-core/src/operations/common.ts     |  45 ++++----
 .../taler-wallet-core/src/operations/deposits.ts   |   8 +-
 .../taler-wallet-core/src/operations/exchanges.ts  |  56 +++++++---
 .../src/operations/pay-merchant.ts                 |  22 ++--
 .../src/operations/pay-peer-push-debit.ts          |   8 +-
 .../taler-wallet-core/src/operations/pending.ts    | 113 ++++++++++++--------
 .../taler-wallet-core/src/operations/refresh.ts    |  14 +--
 .../taler-wallet-core/src/operations/reward.ts     |   6 +-
 .../src/operations/transactions.ts                 |  17 ++-
 .../src/operations/withdraw.test.ts                | 114 +++++++++++----------
 packages/taler-wallet-core/src/pending-types.ts    |  14 +--
 .../taler-wallet-core/src/util/denominations.ts    |   9 +-
 .../src/util/instructedAmountConversion.ts         |  17 +--
 17 files changed, 365 insertions(+), 227 deletions(-)

diff --git a/packages/taler-util/src/transactions-types.ts 
b/packages/taler-util/src/transactions-types.ts
index 304183ceb..63db206bd 100644
--- a/packages/taler-util/src/transactions-types.ts
+++ b/packages/taler-util/src/transactions-types.ts
@@ -67,7 +67,7 @@ export interface TransactionsRequest {
    */
   includeRefreshes?: boolean;
 
-  filterByState?: TransactionStateFilter
+  filterByState?: TransactionStateFilter;
 }
 
 export interface TransactionState {
@@ -629,6 +629,17 @@ export interface TransactionRefresh extends 
TransactionCommon {
   refreshOutputAmount: AmountString;
 }
 
+export interface DepositTransactionTrackingState {
+  // Raw wire transfer identifier of the deposit.
+  wireTransferId: string;
+  // When was the wire transfer given to the bank.
+  timestampExecuted: TalerProtocolTimestamp;
+  // Total amount transfer for this wtid (including fees)
+  amountRaw: AmountString;
+  // Wire fee amount for this exchange
+  wireFee: AmountString;
+}
+
 /**
  * Deposit transaction, which effectively sends
  * money from this wallet somewhere else.
@@ -662,16 +673,7 @@ export interface TransactionDeposit extends 
TransactionCommon {
    */
   deposited: boolean;
 
-  trackingState: Array<{
-    // Raw wire transfer identifier of the deposit.
-    wireTransferId: string;
-    // When was the wire transfer given to the bank.
-    timestampExecuted: TalerProtocolTimestamp;
-    // Total amount transfer for this wtid (including fees)
-    amountRaw: AmountString;
-    // Wire fee amount for this exchange
-    wireFee: AmountString;
-  }>;
+  trackingState: Array<DepositTransactionTrackingState>;
 }
 
 export interface TransactionByIdRequest {
diff --git a/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts 
b/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts
index 35777e714..56392f090 100644
--- a/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts
+++ b/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts
@@ -87,7 +87,7 @@ import {
   WithdrawalPlanchet,
 } from "@gnu-taler/taler-util";
 // FIXME: Crypto should not use DB Types!
-import { DenominationRecord } from "../db.js";
+import { DenominationRecord, timestampProtocolFromDb } from "../db.js";
 import {
   CreateRecoupRefreshReqRequest,
   CreateRecoupReqRequest,
@@ -962,10 +962,22 @@ export const nativeCryptoR: TalerCryptoInterfaceR = {
     const value: AmountJson = Amounts.parseOrThrow(denom.value);
     const p = 
buildSigPS(TalerSignaturePurpose.MASTER_DENOMINATION_KEY_VALIDITY)
       .put(decodeCrock(masterPub))
-      .put(timestampRoundedToBuffer(denom.stampStart))
-      .put(timestampRoundedToBuffer(denom.stampExpireWithdraw))
-      .put(timestampRoundedToBuffer(denom.stampExpireDeposit))
-      .put(timestampRoundedToBuffer(denom.stampExpireLegal))
+      .put(timestampRoundedToBuffer(timestampProtocolFromDb(denom.stampStart)))
+      .put(
+        timestampRoundedToBuffer(
+          timestampProtocolFromDb(denom.stampExpireWithdraw),
+        ),
+      )
+      .put(
+        timestampRoundedToBuffer(
+          timestampProtocolFromDb(denom.stampExpireDeposit),
+        ),
+      )
+      .put(
+        timestampRoundedToBuffer(
+          timestampProtocolFromDb(denom.stampExpireLegal),
+        ),
+      )
       .put(amountToBuffer(value))
       .put(amountToBuffer(denom.fees.feeWithdraw))
       .put(amountToBuffer(denom.fees.feeDeposit))
diff --git a/packages/taler-wallet-core/src/db.ts 
b/packages/taler-wallet-core/src/db.ts
index cebe3635b..4fc6db68a 100644
--- a/packages/taler-wallet-core/src/db.ts
+++ b/packages/taler-wallet-core/src/db.ts
@@ -27,6 +27,7 @@ import {
   structuredEncapsulate,
 } from "@gnu-taler/idb-bridge";
 import {
+  AbsoluteTime,
   AgeCommitmentProof,
   AmountString,
   Amounts,
@@ -51,12 +52,13 @@ import {
   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,
@@ -193,6 +195,44 @@ export function timestampPreciseToDb(
   }
 }
 
+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
 
@@ -391,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
@@ -448,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 {
@@ -460,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,
     };
@@ -471,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;
 
@@ -590,11 +630,6 @@ export enum ExchangeEntryDbUpdateStatus {
   ReadyUpdate = 7,
 }
 
-/**
- * Timestamp stored as a IEEE 754 double, in milliseconds.
- */
-export type DbIndexableTimestampMs = number;
-
 /**
  * Exchange record as stored in the wallet's database.
  */
@@ -634,13 +669,8 @@ export interface ExchangeEntryRecord {
 
   /**
    * 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;
 
@@ -650,7 +680,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
@@ -873,7 +903,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.
@@ -1287,7 +1317,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
@@ -1668,7 +1698,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
@@ -1690,7 +1720,7 @@ export interface DepositGroupRecord {
    */
   amount: AmountString;
 
-  wireTransferDeadline: TalerProtocolTimestamp;
+  wireTransferDeadline: DbProtocolTimestamp;
 
   merchantPub: string;
   merchantPriv: string;
@@ -1831,7 +1861,7 @@ export interface PeerPushDebitRecord {
    */
   contractEncNonce: string;
 
-  purseExpiration: TalerProtocolTimestamp;
+  purseExpiration: DbProtocolTimestamp;
 
   timestampCreated: DbPreciseTimestamp;
 
@@ -2077,7 +2107,7 @@ export interface OperationRetryRecord {
 
   lastError?: TalerErrorDetail;
 
-  retryInfo: RetryInfo;
+  retryInfo: DbRetryInfo;
 }
 
 /**
@@ -2130,9 +2160,8 @@ 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.
@@ -2233,7 +2262,7 @@ export interface RefundItemRecord {
   /**
    * Execution time as claimed by the merchant
    */
-  executionTime: TalerProtocolTimestamp;
+  executionTime: DbProtocolTimestamp;
 
   /**
    * Time when the wallet became aware of the refund.
diff --git a/packages/taler-wallet-core/src/operations/attention.ts 
b/packages/taler-wallet-core/src/operations/attention.ts
index 1030db0a6..92d69e93e 100644
--- a/packages/taler-wallet-core/src/operations/attention.ts
+++ b/packages/taler-wallet-core/src/operations/attention.ts
@@ -31,7 +31,7 @@ import {
   UserAttentionUnreadList,
 } from "@gnu-taler/taler-util";
 import { InternalWalletState } from "../internal-wallet-state.js";
-import { timestampPreciseToDb } from "../index.js";
+import { timestampPreciseFromDb, timestampPreciseToDb } from "../index.js";
 
 const logger = new Logger("operations/attention.ts");
 
@@ -75,7 +75,7 @@ export async function getUserAttentions(
           return;
         pending.push({
           info: x.info,
-          when: TalerPreciseTimestamp.fromMilliseconds(x.createdMs),
+          when: timestampPreciseFromDb(x.created),
           read: x.read !== undefined,
         });
       });
@@ -118,7 +118,7 @@ export async function addAttentionRequest(
       await tx.userAttention.put({
         info,
         entityId,
-        createdMs: AbsoluteTime.now().t_ms as number,
+        created: timestampPreciseToDb(TalerPreciseTimestamp.now()),
         read: undefined,
       });
     });
diff --git a/packages/taler-wallet-core/src/operations/common.ts 
b/packages/taler-wallet-core/src/operations/common.ts
index 50dd3dc5c..e8e492c08 100644
--- a/packages/taler-wallet-core/src/operations/common.ts
+++ b/packages/taler-wallet-core/src/operations/common.ts
@@ -40,6 +40,7 @@ import {
   TalerError,
   TalerErrorCode,
   TalerErrorDetail,
+  TalerPreciseTimestamp,
   TombstoneIdStr,
   TransactionIdStr,
   TransactionType,
@@ -49,6 +50,7 @@ import { CryptoApiStoppedError } from 
"../crypto/workers/crypto-dispatcher.js";
 import {
   BackupProviderRecord,
   CoinRecord,
+  DbPreciseTimestamp,
   DepositGroupRecord,
   ExchangeDetailsRecord,
   ExchangeEntryDbRecordStatus,
@@ -62,6 +64,7 @@ import {
   RecoupGroupRecord,
   RefreshGroupRecord,
   RewardRecord,
+  timestampPreciseToDb,
   WalletStoresV1,
   WithdrawalGroupRecord,
 } from "../db.js";
@@ -360,11 +363,11 @@ async function storePendingTaskError(
       retryRecord = {
         id: pendingTaskId,
         lastError: e,
-        retryInfo: RetryInfo.reset(),
+        retryInfo: DbRetryInfo.reset(),
       };
     } else {
       retryRecord.lastError = e;
-      retryRecord.retryInfo = RetryInfo.increment(retryRecord.retryInfo);
+      retryRecord.retryInfo = DbRetryInfo.increment(retryRecord.retryInfo);
     }
     await tx.operationRetries.put(retryRecord);
     return taskToTransactionNotification(ws, tx, pendingTaskId, e);
@@ -383,7 +386,7 @@ export async function resetPendingTaskTimeout(
     if (retryRecord) {
       // Note that we don't reset the lastError, it should still be visible
       // while the retry runs.
-      retryRecord.retryInfo = RetryInfo.reset();
+      retryRecord.retryInfo = DbRetryInfo.reset();
       await tx.operationRetries.put(retryRecord);
     }
     return taskToTransactionNotification(ws, tx, pendingTaskId, undefined);
@@ -403,14 +406,14 @@ async function storePendingTaskPending(
     if (!retryRecord) {
       retryRecord = {
         id: pendingTaskId,
-        retryInfo: RetryInfo.reset(),
+        retryInfo: DbRetryInfo.reset(),
       };
     } else {
       if (retryRecord.lastError) {
         hadError = true;
       }
       delete retryRecord.lastError;
-      retryRecord.retryInfo = RetryInfo.increment(retryRecord.retryInfo);
+      retryRecord.retryInfo = DbRetryInfo.increment(retryRecord.retryInfo);
     }
     await tx.operationRetries.put(retryRecord);
     if (hadError) {
@@ -736,9 +739,9 @@ export interface TaskRunLongpollResult {
   type: TaskRunResultType.Longpoll;
 }
 
-export interface RetryInfo {
-  firstTry: AbsoluteTime;
-  nextRetry: AbsoluteTime;
+export interface DbRetryInfo {
+  firstTry: DbPreciseTimestamp;
+  nextRetry: DbPreciseTimestamp;
   retryCounter: number;
 }
 
@@ -755,7 +758,7 @@ const defaultRetryPolicy: RetryPolicy = {
 };
 
 function updateTimeout(
-  r: RetryInfo,
+  r: DbRetryInfo,
   p: RetryPolicy = defaultRetryPolicy,
 ): void {
   const now = AbsoluteTime.now();
@@ -763,7 +766,9 @@ function updateTimeout(
     throw Error("assertion failed");
   }
   if (p.backoffDelta.d_ms === "forever") {
-    r.nextRetry = AbsoluteTime.never();
+    r.nextRetry = timestampPreciseToDb(
+      AbsoluteTime.toPreciseTimestamp(AbsoluteTime.never()),
+    );
     return;
   }
 
@@ -775,12 +780,12 @@ function updateTimeout(
     (p.maxTimeout.d_ms === "forever"
       ? nextIncrement
       : Math.min(p.maxTimeout.d_ms, nextIncrement));
-  r.nextRetry = AbsoluteTime.fromMilliseconds(t);
+  r.nextRetry = 
timestampPreciseToDb(TalerPreciseTimestamp.fromMilliseconds(t));
 }
 
-export namespace RetryInfo {
+export namespace DbRetryInfo {
   export function getDuration(
-    r: RetryInfo | undefined,
+    r: DbRetryInfo | undefined,
     p: RetryPolicy = defaultRetryPolicy,
   ): Duration {
     if (!r) {
@@ -797,11 +802,11 @@ export namespace RetryInfo {
     };
   }
 
-  export function reset(p: RetryPolicy = defaultRetryPolicy): RetryInfo {
-    const now = AbsoluteTime.now();
-    const info = {
-      firstTry: now,
-      nextRetry: now,
+  export function reset(p: RetryPolicy = defaultRetryPolicy): DbRetryInfo {
+    const now = TalerPreciseTimestamp.now();
+    const info: DbRetryInfo = {
+      firstTry: timestampPreciseToDb(now),
+      nextRetry: timestampPreciseToDb(now),
       retryCounter: 0,
     };
     updateTimeout(info, p);
@@ -809,9 +814,9 @@ export namespace RetryInfo {
   }
 
   export function increment(
-    r: RetryInfo | undefined,
+    r: DbRetryInfo | undefined,
     p: RetryPolicy = defaultRetryPolicy,
-  ): RetryInfo {
+  ): DbRetryInfo {
     if (!r) {
       return reset(p);
     }
diff --git a/packages/taler-wallet-core/src/operations/deposits.ts 
b/packages/taler-wallet-core/src/operations/deposits.ts
index cb40f8f22..111d15989 100644
--- a/packages/taler-wallet-core/src/operations/deposits.ts
+++ b/packages/taler-wallet-core/src/operations/deposits.ts
@@ -74,6 +74,8 @@ import {
   createRefreshGroup,
   getTotalRefreshCost,
   timestampPreciseToDb,
+  timestampProtocolFromDb,
+  timestampProtocolToDb,
 } from "../index.js";
 import { InternalWalletState } from "../internal-wallet-state.js";
 import { assertUnreachable } from "../util/assertUnreachable.js";
@@ -800,7 +802,7 @@ async function processDepositGroupPendingTrack(
             amountRaw: Amounts.stringify(raw),
             wireFee: Amounts.stringify(wireFee),
             exchangePub: track.exchange_pub,
-            timestampExecuted: track.execution_time,
+            timestampExecuted: timestampProtocolToDb(track.execution_time),
             wireTransferId: track.wtid,
           },
           id: track.exchange_sig,
@@ -1393,7 +1395,9 @@ export async function createDepositGroup(
     counterpartyEffectiveDepositAmount: Amounts.stringify(
       counterpartyEffectiveDepositAmount,
     ),
-    wireTransferDeadline: contractTerms.wire_transfer_deadline,
+    wireTransferDeadline: timestampProtocolToDb(
+      contractTerms.wire_transfer_deadline,
+    ),
     wire: {
       payto_uri: req.depositPaytoUri,
       salt: wireSalt,
diff --git a/packages/taler-wallet-core/src/operations/exchanges.ts 
b/packages/taler-wallet-core/src/operations/exchanges.ts
index 60d55252a..5e966b719 100644
--- a/packages/taler-wallet-core/src/operations/exchanges.ts
+++ b/packages/taler-wallet-core/src/operations/exchanges.ts
@@ -74,7 +74,9 @@ import {
   ExchangeEntryDbRecordStatus,
   ExchangeEntryDbUpdateStatus,
   isWithdrawableDenom,
+  timestampPreciseFromDb,
   timestampPreciseToDb,
+  timestampProtocolToDb,
   WalletDbReadWriteTransaction,
 } from "../index.js";
 import { InternalWalletState, TrustInfo } from "../internal-wallet-state.js";
@@ -317,8 +319,12 @@ export async function addPresetExchangeEntry(
       detailsPointer: undefined,
       lastUpdate: undefined,
       lastKeysEtag: undefined,
-      nextRefreshCheckStampMs: AbsoluteTime.getStampMsNever(),
-      nextUpdateStampMs: AbsoluteTime.getStampMsNever(),
+      nextRefreshCheckStamp: timestampPreciseToDb(
+        AbsoluteTime.toPreciseTimestamp(AbsoluteTime.never()),
+      ),
+      nextUpdateStamp: timestampPreciseToDb(
+        AbsoluteTime.toPreciseTimestamp(AbsoluteTime.never()),
+      ),
     };
     await tx.exchanges.put(r);
   }
@@ -344,8 +350,12 @@ export async function provideExchangeRecordInTx(
       baseUrl: baseUrl,
       detailsPointer: undefined,
       lastUpdate: undefined,
-      nextUpdateStampMs: AbsoluteTime.getStampMsNever(),
-      nextRefreshCheckStampMs: AbsoluteTime.getStampMsNever(),
+      nextUpdateStamp: timestampPreciseToDb(
+        AbsoluteTime.toPreciseTimestamp(AbsoluteTime.never()),
+      ),
+      nextRefreshCheckStamp: timestampPreciseToDb(
+        AbsoluteTime.toPreciseTimestamp(AbsoluteTime.never()),
+      ),
       lastKeysEtag: undefined,
     };
     await tx.exchanges.put(r);
@@ -446,13 +456,19 @@ async function downloadExchangeKeysInfo(
             isRevoked: false,
             value: Amounts.stringify(value),
             currency: value.currency,
-            stampExpireDeposit: denomIn.stamp_expire_deposit,
-            stampExpireLegal: denomIn.stamp_expire_legal,
-            stampExpireWithdraw: denomIn.stamp_expire_withdraw,
-            stampStart: denomIn.stamp_start,
+            stampExpireDeposit: timestampProtocolToDb(
+              denomIn.stamp_expire_deposit,
+            ),
+            stampExpireLegal: 
timestampProtocolToDb(denomIn.stamp_expire_legal),
+            stampExpireWithdraw: timestampProtocolToDb(
+              denomIn.stamp_expire_withdraw,
+            ),
+            stampStart: timestampProtocolToDb(denomIn.stamp_start),
             verificationStatus: DenominationVerificationStatus.Unverified,
             masterSig: denomIn.master_sig,
-            listIssueDate: exchangeKeysJsonUnchecked.list_issue_date,
+            listIssueDate: timestampProtocolToDb(
+              exchangeKeysJsonUnchecked.list_issue_date,
+            ),
             fees: {
               feeDeposit: Amounts.stringify(denomGroup.fee_deposit),
               feeRefresh: Amounts.stringify(denomGroup.fee_refresh),
@@ -614,7 +630,9 @@ export async function updateExchangeFromUrlHandler(
     !forceNow &&
     exchangeDetails !== undefined &&
     !AbsoluteTime.isExpired(
-      AbsoluteTime.fromStampMs(exchange.nextUpdateStampMs),
+      AbsoluteTime.fromPreciseTimestamp(
+        timestampPreciseFromDb(exchange.nextUpdateStamp),
+      ),
     )
   ) {
     logger.trace("using existing exchange info");
@@ -755,11 +773,15 @@ export async function updateExchangeFromUrlHandler(
         newDetails.rowId = existingDetails.rowId;
       }
       r.lastUpdate = timestampPreciseToDb(TalerPreciseTimestamp.now());
-      r.nextUpdateStampMs = AbsoluteTime.toStampMs(
-        AbsoluteTime.fromProtocolTimestamp(keysInfo.expiry),
+      r.nextUpdateStamp = timestampPreciseToDb(
+        AbsoluteTime.toPreciseTimestamp(
+          AbsoluteTime.fromProtocolTimestamp(keysInfo.expiry),
+        ),
       );
       // New denominations might be available.
-      r.nextRefreshCheckStampMs = AbsoluteTime.getStampMsNow();
+      r.nextRefreshCheckStamp = timestampPreciseToDb(
+        TalerPreciseTimestamp.now(),
+      );
       if (detailsPointerChanged) {
         r.detailsPointer = {
           currency: newDetails.currency,
@@ -777,9 +799,9 @@ export async function updateExchangeFromUrlHandler(
           exchangeDetailsRowId: drRowId.key,
           masterSig: sk.master_sig,
           signkeyPub: sk.key,
-          stampEnd: sk.stamp_end,
-          stampExpire: sk.stamp_expire,
-          stampStart: sk.stamp_start,
+          stampEnd: timestampProtocolToDb(sk.stamp_end),
+          stampExpire: timestampProtocolToDb(sk.stamp_expire),
+          stampStart: timestampProtocolToDb(sk.stamp_start),
         });
       }
 
@@ -814,7 +836,7 @@ export async function updateExchangeFromUrlHandler(
               );
             }
           } else {
-            x.listIssueDate = keysInfo.listIssueDate;
+            x.listIssueDate = timestampProtocolToDb(keysInfo.listIssueDate);
             if (!x.isOffered) {
               x.isOffered = true;
               logger.info(
diff --git a/packages/taler-wallet-core/src/operations/pay-merchant.ts 
b/packages/taler-wallet-core/src/operations/pay-merchant.ts
index 97bf6e2a6..157541ed3 100644
--- a/packages/taler-wallet-core/src/operations/pay-merchant.ts
+++ b/packages/taler-wallet-core/src/operations/pay-merchant.ts
@@ -104,6 +104,8 @@ import {
   RefundItemRecord,
   RefundItemStatus,
   timestampPreciseToDb,
+  timestampProtocolFromDb,
+  timestampProtocolToDb,
 } from "../index.js";
 import {
   EXCHANGE_COINS_LOCK,
@@ -115,7 +117,7 @@ import { checkDbInvariant } from "../util/invariants.js";
 import { GetReadOnlyAccess } from "../util/query.js";
 import {
   constructTaskIdentifier,
-  RetryInfo,
+  DbRetryInfo,
   runLongpollAsync,
   runTaskWithErrorReporting,
   spendCoins,
@@ -217,11 +219,13 @@ async function failProposalPermanently(
   notifyTransition(ws, transactionId, transitionInfo);
 }
 
-function getProposalRequestTimeout(retryInfo?: RetryInfo): Duration {
+function getProposalRequestTimeout(retryInfo?: DbRetryInfo): Duration {
   return Duration.clamp({
     lower: Duration.fromSpec({ seconds: 1 }),
     upper: Duration.fromSpec({ seconds: 60 }),
-    value: retryInfo ? RetryInfo.getDuration(retryInfo) : 
Duration.fromSpec({}),
+    value: retryInfo
+      ? DbRetryInfo.getDuration(retryInfo)
+      : Duration.fromSpec({}),
   });
 }
 
@@ -738,8 +742,10 @@ async function storeFirstPaySuccess(
         const ar = Duration.fromTalerProtocolDuration(protoAr);
         logger.info("auto_refund present");
         purchase.purchaseStatus = PurchaseStatus.PendingQueryingAutoRefund;
-        purchase.autoRefundDeadline = AbsoluteTime.toProtocolTimestamp(
-          AbsoluteTime.addDuration(AbsoluteTime.now(), ar),
+        purchase.autoRefundDeadline = timestampProtocolToDb(
+          AbsoluteTime.toProtocolTimestamp(
+            AbsoluteTime.addDuration(AbsoluteTime.now(), ar),
+          ),
         );
       }
       await tx.purchases.put(purchase);
@@ -2343,7 +2349,9 @@ async function processPurchaseAutoRefund(
     if (
       !purchase.autoRefundDeadline ||
       AbsoluteTime.isExpired(
-        AbsoluteTime.fromProtocolTimestamp(purchase.autoRefundDeadline),
+        AbsoluteTime.fromProtocolTimestamp(
+          timestampProtocolFromDb(purchase.autoRefundDeadline),
+        ),
       )
     ) {
       const transitionInfo = await ws.db
@@ -2804,7 +2812,7 @@ async function storeRefunds(
           const status: RefundItemStatus = getItemStatus(rf);
           const newItem: RefundItemRecord = {
             coinPub: rf.coin_pub,
-            executionTime: rf.execution_time,
+            executionTime: timestampProtocolToDb(rf.execution_time),
             obtainedTime: timestampPreciseToDb(now),
             refundAmount: rf.refund_amount,
             refundGroupId: newGroup.refundGroupId,
diff --git a/packages/taler-wallet-core/src/operations/pay-peer-push-debit.ts 
b/packages/taler-wallet-core/src/operations/pay-peer-push-debit.ts
index b3d0eb132..a7b9f79eb 100644
--- a/packages/taler-wallet-core/src/operations/pay-peer-push-debit.ts
+++ b/packages/taler-wallet-core/src/operations/pay-peer-push-debit.ts
@@ -56,10 +56,13 @@ import {
   RefreshOperationStatus,
   createRefreshGroup,
   timestampPreciseToDb,
+  timestampProtocolFromDb,
+  timestampProtocolToDb,
 } from "../index.js";
 import { InternalWalletState } from "../internal-wallet-state.js";
 import { PendingTaskType } from "../pending-types.js";
 import { assertUnreachable } from "../util/assertUnreachable.js";
+import { PeerCoinRepair, selectPeerCoins } from "../util/coinSelection.js";
 import { checkLogicInvariant } from "../util/invariants.js";
 import {
   TaskRunResult,
@@ -78,7 +81,6 @@ import {
   notifyTransition,
   stopLongpolling,
 } from "./transactions.js";
-import { PeerCoinRepair, selectPeerCoins } from "../util/coinSelection.js";
 
 const logger = new Logger("pay-peer-push-debit.ts");
 
@@ -208,7 +210,7 @@ async function processPeerPushDebitCreateReserve(
     mergePub: peerPushInitiation.mergePub,
     minAge: 0,
     purseAmount: peerPushInitiation.amount,
-    purseExpiration,
+    purseExpiration: timestampProtocolFromDb(purseExpiration),
     pursePriv: peerPushInitiation.pursePriv,
   });
 
@@ -667,7 +669,7 @@ export async function initiatePeerPushDebit(
         exchangeBaseUrl: sel.exchangeBaseUrl,
         mergePriv: mergePair.priv,
         mergePub: mergePair.pub,
-        purseExpiration: purseExpiration,
+        purseExpiration: timestampProtocolToDb(purseExpiration),
         pursePriv: pursePair.priv,
         pursePub: pursePair.pub,
         timestampCreated: timestampPreciseToDb(TalerPreciseTimestamp.now()),
diff --git a/packages/taler-wallet-core/src/operations/pending.ts 
b/packages/taler-wallet-core/src/operations/pending.ts
index 120d316ce..1819aa1b8 100644
--- a/packages/taler-wallet-core/src/operations/pending.ts
+++ b/packages/taler-wallet-core/src/operations/pending.ts
@@ -21,43 +21,46 @@
 /**
  * Imports.
  */
+import { GlobalIDB } from "@gnu-taler/idb-bridge";
+import { AbsoluteTime, TransactionRecordFilter } from "@gnu-taler/taler-util";
 import {
-  PurchaseStatus,
-  WalletStoresV1,
   BackupProviderStateTag,
-  RefreshCoinStatus,
-  PeerPushDebitStatus,
-  PeerPullDebitRecordStatus,
-  PeerPushCreditStatus,
-  PeerPullPaymentCreditStatus,
-  WithdrawalGroupStatus,
-  RewardRecordStatus,
-  DepositOperationStatus,
-  RefreshGroupRecord,
-  WithdrawalGroupRecord,
+  DepositElementStatus,
   DepositGroupRecord,
-  RewardRecord,
-  PurchaseRecord,
+  DepositOperationStatus,
+  ExchangeEntryDbUpdateStatus,
   PeerPullCreditRecord,
+  PeerPullDebitRecordStatus,
+  PeerPullPaymentCreditStatus,
   PeerPullPaymentIncomingRecord,
+  PeerPushCreditStatus,
   PeerPushDebitRecord,
+  PeerPushDebitStatus,
   PeerPushPaymentIncomingRecord,
+  PurchaseRecord,
+  PurchaseStatus,
+  RefreshCoinStatus,
+  RefreshGroupRecord,
+  RefreshOperationStatus,
   RefundGroupRecord,
   RefundGroupStatus,
-  ExchangeEntryDbUpdateStatus,
-  RefreshOperationStatus,
-  DepositElementStatus,
+  RewardRecord,
+  RewardRecordStatus,
+  WalletStoresV1,
+  WithdrawalGroupRecord,
+  WithdrawalGroupStatus,
+  timestampAbsoluteFromDb,
+  timestampOptionalAbsoluteFromDb,
   timestampPreciseFromDb,
+  timestampPreciseToDb,
 } from "../db.js";
+import { InternalWalletState } from "../internal-wallet-state.js";
 import {
   PendingOperationsResponse,
   PendingTaskType,
   TaskId,
 } from "../pending-types.js";
-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";
 import { TaskIdentifiers } from "./common.js";
 
 function getPendingCommon(
@@ -100,12 +103,14 @@ async function gatherExchangePending(
     }
     const opTag = TaskIdentifiers.forExchangeUpdate(exch);
     let opr = await tx.operationRetries.get(opTag);
-    const timestampDue =
-      opr?.retryInfo.nextRetry ??
-      AbsoluteTime.fromStampMs(exch.nextUpdateStampMs);
+    const timestampDue = opr?.retryInfo.nextRetry ?? 
exch.nextRefreshCheckStamp;
     resp.pendingOperations.push({
       type: PendingTaskType.ExchangeUpdate,
-      ...getPendingCommon(ws, opTag, timestampDue),
+      ...getPendingCommon(
+        ws,
+        opTag,
+        
AbsoluteTime.fromPreciseTimestamp(timestampPreciseFromDb(timestampDue)),
+      ),
       givesLifeness: false,
       exchangeBaseUrl: exch.baseUrl,
       lastError: opr?.lastError,
@@ -116,8 +121,16 @@ async function gatherExchangePending(
     if (!opr?.lastError) {
       resp.pendingOperations.push({
         type: PendingTaskType.ExchangeCheckRefresh,
-        ...getPendingCommon(ws, opTag, timestampDue),
-        timestampDue: AbsoluteTime.fromStampMs(exch.nextRefreshCheckStampMs),
+        ...getPendingCommon(
+          ws,
+          opTag,
+          AbsoluteTime.fromPreciseTimestamp(
+            timestampPreciseFromDb(timestampDue),
+          ),
+        ),
+        timestampDue: AbsoluteTime.fromPreciseTimestamp(
+          timestampPreciseFromDb(exch.nextRefreshCheckStamp),
+        ),
         givesLifeness: false,
         exchangeBaseUrl: exch.baseUrl,
       });
@@ -166,7 +179,9 @@ async function gatherRefreshPending(
     }
     const opId = TaskIdentifiers.forRefresh(r);
     const retryRecord = await tx.operationRetries.get(opId);
-    const timestampDue = retryRecord?.retryInfo.nextRetry ?? 
AbsoluteTime.now();
+    const timestampDue =
+      timestampOptionalAbsoluteFromDb(retryRecord?.retryInfo.nextRetry) ??
+      AbsoluteTime.now();
     resp.pendingOperations.push({
       type: PendingTaskType.Refresh,
       ...getPendingCommon(ws, opId, timestampDue),
@@ -223,8 +238,8 @@ async function gatherWithdrawalPending(
       opr = {
         id: opTag,
         retryInfo: {
-          firstTry: now,
-          nextRetry: now,
+          firstTry: timestampPreciseToDb(AbsoluteTime.toPreciseTimestamp(now)),
+          nextRetry: 
timestampPreciseToDb(AbsoluteTime.toPreciseTimestamp(now)),
           retryCounter: 0,
         },
       };
@@ -234,7 +249,8 @@ async function gatherWithdrawalPending(
       ...getPendingCommon(
         ws,
         opTag,
-        opr.retryInfo?.nextRetry ?? AbsoluteTime.now(),
+        timestampOptionalAbsoluteFromDb(opr.retryInfo?.nextRetry) ??
+          AbsoluteTime.now(),
       ),
       givesLifeness: true,
       withdrawalGroupId: wsr.withdrawalGroupId,
@@ -286,7 +302,9 @@ async function gatherDepositPending(
     }
     const opId = TaskIdentifiers.forDeposit(dg);
     const retryRecord = await tx.operationRetries.get(opId);
-    const timestampDue = retryRecord?.retryInfo.nextRetry ?? 
AbsoluteTime.now();
+    const timestampDue =
+      timestampOptionalAbsoluteFromDb(retryRecord?.retryInfo.nextRetry) ??
+      AbsoluteTime.now();
     resp.pendingOperations.push({
       type: PendingTaskType.Deposit,
       ...getPendingCommon(ws, opId, timestampDue),
@@ -331,13 +349,15 @@ async function gatherRewardPending(
   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();
+    const timestampDue =
+      timestampOptionalAbsoluteFromDb(retryRecord?.retryInfo.nextRetry) ??
+      AbsoluteTime.now();
     if (tip.acceptedTimestamp) {
       resp.pendingOperations.push({
         type: PendingTaskType.RewardPickup,
         ...getPendingCommon(ws, opId, timestampDue),
         givesLifeness: true,
-        timestampDue: retryRecord?.retryInfo.nextRetry ?? AbsoluteTime.now(),
+        timestampDue,
         merchantBaseUrl: tip.merchantBaseUrl,
         tipId: tip.walletRewardId,
         merchantTipId: tip.merchantRewardId,
@@ -391,7 +411,9 @@ async function gatherPurchasePending(
   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();
+    const timestampDue =
+      timestampOptionalAbsoluteFromDb(retryRecord?.retryInfo.nextRetry) ??
+      AbsoluteTime.now();
     resp.pendingOperations.push({
       type: PendingTaskType.Purchase,
       ...getPendingCommon(ws, opId, timestampDue),
@@ -420,7 +442,9 @@ async function gatherRecoupPending(
     }
     const opId = TaskIdentifiers.forRecoup(rg);
     const retryRecord = await tx.operationRetries.get(opId);
-    const timestampDue = retryRecord?.retryInfo.nextRetry ?? 
AbsoluteTime.now();
+    const timestampDue =
+      timestampOptionalAbsoluteFromDb(retryRecord?.retryInfo.nextRetry) ??
+      AbsoluteTime.now();
     resp.pendingOperations.push({
       type: PendingTaskType.Recoup,
       ...getPendingCommon(ws, opId, timestampDue),
@@ -445,8 +469,8 @@ async function gatherBackupPending(
     const opId = TaskIdentifiers.forBackup(bp);
     const retryRecord = await tx.operationRetries.get(opId);
     if (bp.state.tag === BackupProviderStateTag.Ready) {
-      const timestampDue = AbsoluteTime.fromPreciseTimestamp(
-        timestampPreciseFromDb(bp.state.nextBackupTimestamp),
+      const timestampDue = timestampAbsoluteFromDb(
+        bp.state.nextBackupTimestamp,
       );
       resp.pendingOperations.push({
         type: PendingTaskType.Backup,
@@ -457,7 +481,8 @@ async function gatherBackupPending(
       });
     } else if (bp.state.tag === BackupProviderStateTag.Retrying) {
       const timestampDue =
-        retryRecord?.retryInfo?.nextRetry ?? AbsoluteTime.now();
+        timestampOptionalAbsoluteFromDb(retryRecord?.retryInfo?.nextRetry) ??
+        AbsoluteTime.now();
       resp.pendingOperations.push({
         type: PendingTaskType.Backup,
         ...getPendingCommon(ws, opId, timestampDue),
@@ -504,7 +529,8 @@ async function gatherPeerPullInitiationPending(
       const opId = TaskIdentifiers.forPeerPullPaymentInitiation(pi);
       const retryRecord = await tx.operationRetries.get(opId);
       const timestampDue =
-        retryRecord?.retryInfo.nextRetry ?? AbsoluteTime.now();
+        timestampOptionalAbsoluteFromDb(retryRecord?.retryInfo.nextRetry) ??
+        AbsoluteTime.now();
       resp.pendingOperations.push({
         type: PendingTaskType.PeerPullCredit,
         ...getPendingCommon(ws, opId, timestampDue),
@@ -550,7 +576,8 @@ async function gatherPeerPullDebitPending(
       const opId = TaskIdentifiers.forPeerPullPaymentDebit(pi);
       const retryRecord = await tx.operationRetries.get(opId);
       const timestampDue =
-        retryRecord?.retryInfo.nextRetry ?? AbsoluteTime.now();
+        timestampOptionalAbsoluteFromDb(retryRecord?.retryInfo.nextRetry) ??
+        AbsoluteTime.now();
       resp.pendingOperations.push({
         type: PendingTaskType.PeerPullDebit,
         ...getPendingCommon(ws, opId, timestampDue),
@@ -596,7 +623,8 @@ async function gatherPeerPushInitiationPending(
       const opId = TaskIdentifiers.forPeerPushPaymentInitiation(pi);
       const retryRecord = await tx.operationRetries.get(opId);
       const timestampDue =
-        retryRecord?.retryInfo.nextRetry ?? AbsoluteTime.now();
+        timestampOptionalAbsoluteFromDb(retryRecord?.retryInfo.nextRetry) ??
+        AbsoluteTime.now();
       resp.pendingOperations.push({
         type: PendingTaskType.PeerPushDebit,
         ...getPendingCommon(ws, opId, timestampDue),
@@ -646,7 +674,8 @@ async function gatherPeerPushCreditPending(
       const opId = TaskIdentifiers.forPeerPushCredit(pi);
       const retryRecord = await tx.operationRetries.get(opId);
       const timestampDue =
-        retryRecord?.retryInfo.nextRetry ?? AbsoluteTime.now();
+        timestampOptionalAbsoluteFromDb(retryRecord?.retryInfo.nextRetry) ??
+        AbsoluteTime.now();
       resp.pendingOperations.push({
         type: PendingTaskType.PeerPushCredit,
         ...getPendingCommon(ws, opId, timestampDue),
diff --git a/packages/taler-wallet-core/src/operations/refresh.ts 
b/packages/taler-wallet-core/src/operations/refresh.ts
index dc1d53627..95aedbbd6 100644
--- a/packages/taler-wallet-core/src/operations/refresh.ts
+++ b/packages/taler-wallet-core/src/operations/refresh.ts
@@ -81,6 +81,7 @@ import {
   PendingTaskType,
   RefreshSessionRecord,
   timestampPreciseToDb,
+  timestampProtocolFromDb,
 } from "../index.js";
 import {
   EXCHANGE_COINS_LOCK,
@@ -1125,10 +1126,10 @@ export async function createRefreshGroup(
  */
 function getAutoRefreshCheckThreshold(d: DenominationRecord): AbsoluteTime {
   const expireWithdraw = AbsoluteTime.fromProtocolTimestamp(
-    d.stampExpireWithdraw,
+    timestampProtocolFromDb(d.stampExpireWithdraw),
   );
   const expireDeposit = AbsoluteTime.fromProtocolTimestamp(
-    d.stampExpireDeposit,
+    timestampProtocolFromDb(d.stampExpireDeposit),
   );
   const delta = AbsoluteTime.difference(expireWithdraw, expireDeposit);
   const deltaDiv = durationMul(delta, 0.75);
@@ -1140,10 +1141,10 @@ function getAutoRefreshCheckThreshold(d: 
DenominationRecord): AbsoluteTime {
  */
 function getAutoRefreshExecuteThreshold(d: DenominationRecord): AbsoluteTime {
   const expireWithdraw = AbsoluteTime.fromProtocolTimestamp(
-    d.stampExpireWithdraw,
+    timestampProtocolFromDb(d.stampExpireWithdraw),
   );
   const expireDeposit = AbsoluteTime.fromProtocolTimestamp(
-    d.stampExpireDeposit,
+    timestampProtocolFromDb(d.stampExpireDeposit),
   );
   const delta = AbsoluteTime.difference(expireWithdraw, expireDeposit);
   const deltaDiv = durationMul(delta, 0.5);
@@ -1227,8 +1228,9 @@ export async function autoRefresh(
       logger.trace(
         `next refresh check at ${AbsoluteTime.toIsoString(minCheckThreshold)}`,
       );
-      exchange.nextRefreshCheckStampMs =
-        AbsoluteTime.toStampMs(minCheckThreshold);
+      exchange.nextRefreshCheckStamp = timestampPreciseToDb(
+        AbsoluteTime.toPreciseTimestamp(minCheckThreshold),
+      );
       await tx.exchanges.put(exchange);
     });
   return TaskRunResult.finished();
diff --git a/packages/taler-wallet-core/src/operations/reward.ts 
b/packages/taler-wallet-core/src/operations/reward.ts
index 3681dc4f5..ddcfb20ac 100644
--- a/packages/taler-wallet-core/src/operations/reward.ts
+++ b/packages/taler-wallet-core/src/operations/reward.ts
@@ -52,6 +52,8 @@ import {
   RewardRecordStatus,
   timestampPreciseFromDb,
   timestampPreciseToDb,
+  timestampProtocolFromDb,
+  timestampProtocolToDb,
 } from "../db.js";
 import { makeErrorDetail } from "@gnu-taler/taler-util";
 import { InternalWalletState } from "../internal-wallet-state.js";
@@ -201,7 +203,7 @@ export async function prepareTip(
       acceptedTimestamp: undefined,
       status: RewardRecordStatus.DialogAccept,
       rewardAmountRaw: Amounts.stringify(amount),
-      rewardExpiration: tipPickupStatus.expiration,
+      rewardExpiration: timestampProtocolToDb(tipPickupStatus.expiration),
       exchangeBaseUrl: tipPickupStatus.exchange_url,
       next_url: tipPickupStatus.next_url,
       merchantBaseUrl: res.merchantBaseUrl,
@@ -231,7 +233,7 @@ export async function prepareTip(
     rewardAmountRaw: Amounts.stringify(tipRecord.rewardAmountRaw),
     exchangeBaseUrl: tipRecord.exchangeBaseUrl,
     merchantBaseUrl: tipRecord.merchantBaseUrl,
-    expirationTimestamp: tipRecord.rewardExpiration,
+    expirationTimestamp: timestampProtocolFromDb(tipRecord.rewardExpiration),
     rewardAmountEffective: Amounts.stringify(tipRecord.rewardAmountEffective),
     walletRewardId: tipRecord.walletRewardId,
     transactionId,
diff --git a/packages/taler-wallet-core/src/operations/transactions.ts 
b/packages/taler-wallet-core/src/operations/transactions.ts
index 41bdae249..cf2006406 100644
--- a/packages/taler-wallet-core/src/operations/transactions.ts
+++ b/packages/taler-wallet-core/src/operations/transactions.ts
@@ -20,6 +20,7 @@
 import {
   AbsoluteTime,
   Amounts,
+  DepositTransactionTrackingState,
   j2s,
   Logger,
   NotificationType,
@@ -69,6 +70,7 @@ import {
   GetReadOnlyAccess,
   timestampOptionalPreciseFromDb,
   timestampPreciseFromDb,
+  timestampProtocolFromDb,
   WalletStoresV1,
 } from "../index.js";
 import { InternalWalletState } from "../internal-wallet-state.js";
@@ -809,6 +811,17 @@ function buildTransactionForDeposit(
     }
   }
 
+  const trackingState: DepositTransactionTrackingState[] = [];
+
+  for (const ts of Object.values(dg.trackingState ?? {})) {
+    trackingState.push({
+      amountRaw: ts.amountRaw,
+      timestampExecuted: timestampProtocolFromDb(ts.timestampExecuted),
+      wireFee: ts.wireFee,
+      wireTransferId: ts.wireTransferId,
+    });
+  }
+
   return {
     type: TransactionType.Deposit,
     txState: computeDepositTransactionStatus(dg),
@@ -817,7 +830,7 @@ function buildTransactionForDeposit(
     amountEffective: Amounts.stringify(dg.totalPayCost),
     timestamp: timestampPreciseFromDb(dg.timestampCreated),
     targetPaytoUri: dg.wire.payto_uri,
-    wireTransferDeadline: dg.wireTransferDeadline,
+    wireTransferDeadline: timestampProtocolFromDb(dg.wireTransferDeadline),
     transactionId: constructTransactionIdentifier({
       tag: TransactionType.Deposit,
       depositGroupId: dg.depositGroupId,
@@ -830,7 +843,7 @@ function buildTransactionForDeposit(
         )) /
       dg.statusPerCoin.length,
     depositGroupId: dg.depositGroupId,
-    trackingState: Object.values(dg.trackingState ?? {}),
+    trackingState,
     deposited,
     ...(ort?.lastError ? { error: ort.lastError } : {}),
   };
diff --git a/packages/taler-wallet-core/src/operations/withdraw.test.ts 
b/packages/taler-wallet-core/src/operations/withdraw.test.ts
index 2d9286610..cb8aa5e81 100644
--- a/packages/taler-wallet-core/src/operations/withdraw.test.ts
+++ b/packages/taler-wallet-core/src/operations/withdraw.test.ts
@@ -16,7 +16,11 @@
 
 import { Amounts, DenomKeyType } from "@gnu-taler/taler-util";
 import test from "ava";
-import { DenominationRecord, DenominationVerificationStatus } from "../db.js";
+import {
+  DenominationRecord,
+  DenominationVerificationStatus,
+  timestampProtocolToDb,
+} from "../db.js";
 import { selectWithdrawalDenominations } from "../util/coinSelection.js";
 
 test("withdrawal selection bug repro", (t) => {
@@ -64,22 +68,22 @@ test("withdrawal selection bug repro", (t) => {
       isRevoked: false,
       masterSig:
         
"4F0P456CNNTTWK8BFJHGM3JTD6FVVNZY8EP077GYAHDJ5Y81S5RQ3SMS925NXMDVG9A88JAAP0E2GDZBC21PP5NHFFVWHAW3AVT8J3R",
-      stampExpireDeposit: {
+      stampExpireDeposit: timestampProtocolToDb({
         t_s: 1742909388,
-      },
-      stampExpireLegal: {
+      }),
+      stampExpireLegal: timestampProtocolToDb({
         t_s: 1900589388,
-      },
-      stampExpireWithdraw: {
+      }),
+      stampExpireWithdraw: timestampProtocolToDb({
         t_s: 1679837388,
-      },
-      stampStart: {
+      }),
+      stampStart: timestampProtocolToDb({
         t_s: 1585229388,
-      },
+      }),
       verificationStatus: DenominationVerificationStatus.Unverified,
       currency: "KUDOS",
       value: "KUDOS:1000",
-      listIssueDate: { t_s: 0 },
+      listIssueDate: timestampProtocolToDb({ t_s: 0 }),
     },
     {
       denomPub: {
@@ -119,22 +123,22 @@ test("withdrawal selection bug repro", (t) => {
       isRevoked: false,
       masterSig:
         
"P99AW82W46MZ0AKW7Z58VQPXFNTJQM9DVTYPBDF6KVYF38PPVDAZTV7JQ8TY7HGEC7JJJAY4E7AY7J3W1WV10DAZZQHHKTAVTSRAC20",
-      stampExpireDeposit: {
+      stampExpireDeposit: timestampProtocolToDb({
         t_s: 1742909388,
-      },
-      stampExpireLegal: {
+      }),
+      stampExpireLegal: timestampProtocolToDb({
         t_s: 1900589388,
-      },
-      stampExpireWithdraw: {
+      }),
+      stampExpireWithdraw: timestampProtocolToDb({
         t_s: 1679837388,
-      },
-      stampStart: {
+      }),
+      stampStart: timestampProtocolToDb({
         t_s: 1585229388,
-      },
+      }),
       verificationStatus: DenominationVerificationStatus.Unverified,
       value: "KUDOS:10",
       currency: "KUDOS",
-      listIssueDate: { t_s: 0 },
+      listIssueDate: timestampProtocolToDb({ t_s: 0 }),
     },
     {
       denomPub: {
@@ -173,22 +177,22 @@ test("withdrawal selection bug repro", (t) => {
       isRevoked: false,
       masterSig:
         
"8S4VZGHE5WE0N5ZVCHYW9KZZR4YAKK15S46MV1HR1QB9AAMH3NWPW4DCR4NYGJK33Q8YNFY80SWNS6XKAP5DEVK933TM894FJ2VGE3G",
-      stampExpireDeposit: {
+      stampExpireDeposit: timestampProtocolToDb({
         t_s: 1742909388,
-      },
-      stampExpireLegal: {
+      }),
+      stampExpireLegal: timestampProtocolToDb({
         t_s: 1900589388,
-      },
-      stampExpireWithdraw: {
+      }),
+      stampExpireWithdraw: timestampProtocolToDb({
         t_s: 1679837388,
-      },
-      stampStart: {
+      }),
+      stampStart: timestampProtocolToDb({
         t_s: 1585229388,
-      },
+      }),
       verificationStatus: DenominationVerificationStatus.Unverified,
       value: "KUDOS:5",
       currency: "KUDOS",
-      listIssueDate: { t_s: 0 },
+      listIssueDate: timestampProtocolToDb({ t_s: 0 }),
     },
     {
       denomPub: {
@@ -228,22 +232,22 @@ test("withdrawal selection bug repro", (t) => {
       isRevoked: false,
       masterSig:
         
"E3AWGAG8VB42P3KXM8B04Z6M483SX59R3Y4T53C3NXCA2NPB6C7HVCMVX05DC6S58E9X40NGEBQNYXKYMYCF3ASY2C4WP1WCZ4ME610",
-      stampExpireDeposit: {
+      stampExpireDeposit: timestampProtocolToDb({
         t_s: 1742909388,
-      },
-      stampExpireLegal: {
+      }),
+      stampExpireLegal: timestampProtocolToDb({
         t_s: 1900589388,
-      },
-      stampExpireWithdraw: {
+      }),
+      stampExpireWithdraw: timestampProtocolToDb({
         t_s: 1679837388,
-      },
-      stampStart: {
+      }),
+      stampStart: timestampProtocolToDb({
         t_s: 1585229388,
-      },
+      }),
       verificationStatus: DenominationVerificationStatus.Unverified,
       value: "KUDOS:1",
       currency: "KUDOS",
-      listIssueDate: { t_s: 0 },
+      listIssueDate: timestampProtocolToDb({ t_s: 0 }),
     },
     {
       denomPub: {
@@ -282,18 +286,18 @@ test("withdrawal selection bug repro", (t) => {
       isRevoked: false,
       masterSig:
         
"0ES1RKV002XB4YP21SN0QB7RSDHGYT0XAE65JYN8AVJAA6H7JZFN7JADXT521DJS89XMGPZGR8GCXF1516Y0Q9QDV00E6NMFA6CF838",
-      stampExpireDeposit: {
+      stampExpireDeposit: timestampProtocolToDb({
         t_s: 1742909388,
-      },
-      stampExpireLegal: {
+      }),
+      stampExpireLegal: timestampProtocolToDb({
         t_s: 1900589388,
-      },
-      stampExpireWithdraw: {
+      }),
+      stampExpireWithdraw: timestampProtocolToDb({
         t_s: 1679837388,
-      },
-      stampStart: {
+      }),
+      stampStart: timestampProtocolToDb({
         t_s: 1585229388,
-      },
+      }),
       verificationStatus: DenominationVerificationStatus.Unverified,
       value: Amounts.stringify({
         currency: "KUDOS",
@@ -301,7 +305,7 @@ test("withdrawal selection bug repro", (t) => {
         value: 0,
       }),
       currency: "KUDOS",
-      listIssueDate: { t_s: 0 },
+      listIssueDate: timestampProtocolToDb({ t_s: 0 }),
     },
     {
       denomPub: {
@@ -340,22 +344,22 @@ test("withdrawal selection bug repro", (t) => {
       isRevoked: false,
       masterSig:
         
"58QEB6C6N7602E572E3JYANVVJ9BRW0V9E2ZFDW940N47YVQDK9SAFPWBN5YGT3G1742AFKQ0CYR4DM2VWV0Z0T1XMEKWN6X2EZ9M0R",
-      stampExpireDeposit: {
+      stampExpireDeposit: timestampProtocolToDb({
         t_s: 1742909388,
-      },
-      stampExpireLegal: {
+      }),
+      stampExpireLegal: timestampProtocolToDb({
         t_s: 1900589388,
-      },
-      stampExpireWithdraw: {
+      }),
+      stampExpireWithdraw: timestampProtocolToDb({
         t_s: 1679837388,
-      },
-      stampStart: {
+      }),
+      stampStart: timestampProtocolToDb({
         t_s: 1585229388,
-      },
+      }),
       verificationStatus: DenominationVerificationStatus.Unverified,
       value: "KUDOS:2",
       currency: "KUDOS",
-      listIssueDate: { t_s: 0 },
+      listIssueDate: timestampProtocolToDb({ t_s: 0 }),
     },
   ];
 
diff --git a/packages/taler-wallet-core/src/pending-types.ts 
b/packages/taler-wallet-core/src/pending-types.ts
index 627888b4d..e7a40e81b 100644
--- a/packages/taler-wallet-core/src/pending-types.ts
+++ b/packages/taler-wallet-core/src/pending-types.ts
@@ -25,7 +25,7 @@
  * Imports.
  */
 import { TalerErrorDetail, AbsoluteTime } from "@gnu-taler/taler-util";
-import { RetryInfo } from "./operations/common.js";
+import { DbRetryInfo } from "./operations/common.js";
 
 export enum PendingTaskType {
   ExchangeUpdate = "exchange-update",
@@ -137,7 +137,7 @@ export interface PendingRefreshTask {
   lastError?: TalerErrorDetail;
   refreshGroupId: string;
   finishedPerCoin: boolean[];
-  retryInfo?: RetryInfo;
+  retryInfo?: DbRetryInfo;
 }
 
 /**
@@ -156,7 +156,7 @@ export interface PendingTipPickupTask {
 export interface PendingPurchaseTask {
   type: PendingTaskType.Purchase;
   proposalId: string;
-  retryInfo?: RetryInfo;
+  retryInfo?: DbRetryInfo;
   /**
    * Status of the payment as string, used only for debugging.
    */
@@ -167,7 +167,7 @@ export interface PendingPurchaseTask {
 export interface PendingRecoupTask {
   type: PendingTaskType.Recoup;
   recoupGroupId: string;
-  retryInfo?: RetryInfo;
+  retryInfo?: DbRetryInfo;
   lastError: TalerErrorDetail | undefined;
 }
 
@@ -177,7 +177,7 @@ export interface PendingRecoupTask {
 export interface PendingWithdrawTask {
   type: PendingTaskType.Withdraw;
   lastError: TalerErrorDetail | undefined;
-  retryInfo?: RetryInfo;
+  retryInfo?: DbRetryInfo;
   withdrawalGroupId: string;
 }
 
@@ -187,7 +187,7 @@ export interface PendingWithdrawTask {
 export interface PendingDepositTask {
   type: PendingTaskType.Deposit;
   lastError: TalerErrorDetail | undefined;
-  retryInfo: RetryInfo | undefined;
+  retryInfo: DbRetryInfo | undefined;
   depositGroupId: string;
 }
 
@@ -233,7 +233,7 @@ export interface PendingTaskInfoCommon {
    * Retry info.  Currently used to stop the wallet after any operation
    * exceeds a number of retries.
    */
-  retryInfo?: RetryInfo;
+  retryInfo?: DbRetryInfo;
 }
 
 /**
diff --git a/packages/taler-wallet-core/src/util/denominations.ts 
b/packages/taler-wallet-core/src/util/denominations.ts
index 76716cf7a..db6e69956 100644
--- a/packages/taler-wallet-core/src/util/denominations.ts
+++ b/packages/taler-wallet-core/src/util/denominations.ts
@@ -26,10 +26,9 @@ import {
   FeeDescriptionPair,
   TalerProtocolTimestamp,
   TimePoint,
-  WireFee,
 } from "@gnu-taler/taler-util";
 import { DenominationRecord } from "../db.js";
-import { WalletConfig } from "../index.js";
+import { timestampProtocolFromDb } from "../index.js";
 
 /**
  * Given a list of denominations with the same value and same period of time:
@@ -457,9 +456,11 @@ export function isWithdrawableDenom(
   denomselAllowLate?: boolean,
 ): boolean {
   const now = AbsoluteTime.now();
-  const start = AbsoluteTime.fromProtocolTimestamp(d.stampStart);
+  const start = AbsoluteTime.fromProtocolTimestamp(
+    timestampProtocolFromDb(d.stampStart),
+  );
   const withdrawExpire = AbsoluteTime.fromProtocolTimestamp(
-    d.stampExpireWithdraw,
+    timestampProtocolFromDb(d.stampExpireWithdraw),
   );
   const started = AbsoluteTime.cmp(now, start) >= 0;
   let lastPossibleWithdraw: AbsoluteTime;
diff --git a/packages/taler-wallet-core/src/util/instructedAmountConversion.ts 
b/packages/taler-wallet-core/src/util/instructedAmountConversion.ts
index 54c08eee4..a0394a687 100644
--- a/packages/taler-wallet-core/src/util/instructedAmountConversion.ts
+++ b/packages/taler-wallet-core/src/util/instructedAmountConversion.ts
@@ -14,6 +14,7 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
+import { GlobalIDB } from "@gnu-taler/idb-bridge";
 import {
   AbsoluteTime,
   AgeRestriction,
@@ -29,14 +30,14 @@ import {
   parsePaytoUri,
   strcmp,
 } from "@gnu-taler/taler-util";
-import { checkDbInvariant } from "./invariants.js";
 import {
   DenominationRecord,
   InternalWalletState,
   getExchangeDetails,
+  timestampProtocolFromDb,
 } from "../index.js";
 import { CoinInfo } from "./coinSelection.js";
-import { GlobalIDB } from "@gnu-taler/idb-bridge";
+import { checkDbInvariant } from "./invariants.js";
 
 /**
  * If the operation going to be plan subtracts
@@ -224,10 +225,10 @@ async function getAvailableDenoms(
           );
           for (const denom of ds) {
             const expiresWithdraw = AbsoluteTime.fromProtocolTimestamp(
-              denom.stampExpireWithdraw,
+              timestampProtocolFromDb(denom.stampExpireWithdraw),
             );
             const expiresDeposit = AbsoluteTime.fromProtocolTimestamp(
-              denom.stampExpireDeposit,
+              timestampProtocolFromDb(denom.stampExpireDeposit),
             );
             creditDeadline = AbsoluteTime.min(deadline, expiresWithdraw);
             debitDeadline = AbsoluteTime.min(deadline, expiresDeposit);
@@ -270,10 +271,10 @@ async function getAvailableDenoms(
               continue;
             }
             const expiresWithdraw = AbsoluteTime.fromProtocolTimestamp(
-              denom.stampExpireWithdraw,
+              timestampProtocolFromDb(denom.stampExpireWithdraw),
             );
             const expiresDeposit = AbsoluteTime.fromProtocolTimestamp(
-              denom.stampExpireDeposit,
+              timestampProtocolFromDb(denom.stampExpireDeposit),
             );
             creditDeadline = AbsoluteTime.min(deadline, expiresWithdraw);
             debitDeadline = AbsoluteTime.min(deadline, expiresDeposit);
@@ -318,7 +319,9 @@ function buildCoinInfoFromDenom(
     exchangeBaseUrl: denom.exchangeBaseUrl,
     duration: AbsoluteTime.difference(
       AbsoluteTime.now(),
-      AbsoluteTime.fromProtocolTimestamp(denom.stampExpireDeposit),
+      AbsoluteTime.fromProtocolTimestamp(
+        timestampProtocolFromDb(denom.stampExpireDeposit),
+      ),
     ),
     totalAvailable: total,
     value: Amounts.parseOrThrow(denom.value),

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]