gnunet-svn
[Top][All Lists]
Advanced

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

[taler-wallet-core] branch master updated (5d31803c9 -> 4649469b5)


From: gnunet
Subject: [taler-wallet-core] branch master updated (5d31803c9 -> 4649469b5)
Date: Wed, 21 Sep 2022 22:50:49 +0200

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

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

    from 5d31803c9 pretty
     new 7d6bcd42e wallet-core: use numeric status field to allow range queries
     new a39895967 wallet-core: use more numeric fields
     new 4649469b5 wallet-core: DB improvements

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 packages/idb-bridge/src/bridge-idb.ts              | 37 ++++-----
 packages/taler-wallet-core/src/db-utils.ts         |  1 +
 packages/taler-wallet-core/src/db.ts               | 95 ++++++++++++++--------
 .../src/operations/backup/export.ts                |  4 +-
 .../src/operations/backup/import.ts                | 17 ++--
 .../src/operations/peer-to-peer.ts                 |  6 +-
 .../taler-wallet-core/src/operations/pending.ts    |  7 +-
 .../taler-wallet-core/src/operations/recoup.ts     |  8 +-
 .../taler-wallet-core/src/operations/refresh.ts    |  1 +
 packages/taler-wallet-core/src/operations/tip.ts   |  1 +
 .../src/operations/transactions.ts                 |  2 -
 .../taler-wallet-core/src/operations/withdraw.ts   | 92 ++++++++++-----------
 packages/taler-wallet-core/src/util/invariants.ts  |  7 ++
 packages/taler-wallet-core/src/util/query.ts       | 42 ++++++++--
 14 files changed, 191 insertions(+), 129 deletions(-)

diff --git a/packages/idb-bridge/src/bridge-idb.ts 
b/packages/idb-bridge/src/bridge-idb.ts
index 35cedb1db..128a6900d 100644
--- a/packages/idb-bridge/src/bridge-idb.ts
+++ b/packages/idb-bridge/src/bridge-idb.ts
@@ -57,16 +57,17 @@ import {
   TransactionInactiveError,
   VersionError,
 } from "./util/errors.js";
-import { FakeDOMStringList, fakeDOMStringList } from 
"./util/fakeDOMStringList.js";
+import {
+  FakeDOMStringList,
+  fakeDOMStringList,
+} from "./util/fakeDOMStringList.js";
 import FakeEvent from "./util/FakeEvent.js";
 import FakeEventTarget from "./util/FakeEventTarget.js";
 import { makeStoreKeyValue } from "./util/makeStoreKeyValue.js";
 import { normalizeKeyPath } from "./util/normalizeKeyPath.js";
 import { openPromise } from "./util/openPromise.js";
 import queueTask from "./util/queueTask.js";
-import {
-  checkStructuredCloneOrThrow,
-} from "./util/structuredClone.js";
+import { checkStructuredCloneOrThrow } from "./util/structuredClone.js";
 import { validateKeyPath } from "./util/validateKeyPath.js";
 import { valueToKey } from "./util/valueToKey.js";
 
@@ -933,9 +934,8 @@ export class BridgeIDBFactory {
         );
 
         // We need to expose the new version number to the upgrade transaction.
-        db._schema = this.backend.getCurrentTransactionSchema(
-          backendTransaction,
-        );
+        db._schema =
+          this.backend.getCurrentTransactionSchema(backendTransaction);
 
         const transaction = db._internalTransaction(
           [],
@@ -1110,9 +1110,8 @@ export class BridgeIDBIndex implements IDBIndex {
 
     this._backend.renameIndex(btx, this._objectStore.name, oldName, newName);
 
-    this._objectStore._transaction._db._schema = 
this._backend.getCurrentTransactionSchema(
-      btx,
-    );
+    this._objectStore._transaction._db._schema =
+      this._backend.getCurrentTransactionSchema(btx);
 
     this._objectStore._indexesCache.delete(oldName);
     this._objectStore._indexesCache.set(newName, this);
@@ -1629,9 +1628,8 @@ export class BridgeIDBObjectStore implements 
IDBObjectStore {
     }
 
     this._backend.renameObjectStore(btx, oldName, newName);
-    this._transaction._db._schema = this._backend.getCurrentTransactionSchema(
-      btx,
-    );
+    this._transaction._db._schema =
+      this._backend.getCurrentTransactionSchema(btx);
 
     // We don't modify scope, as the scope of the transaction
     // doesn't matter if we're in an upgrade transaction.
@@ -2235,11 +2233,8 @@ export class BridgeIDBRequest extends FakeEventTarget 
implements IDBRequest {
     }
     return this._source;
   }
-  _source:
-    | BridgeIDBCursor
-    | BridgeIDBIndex
-    | BridgeIDBObjectStore
-    | null = null;
+  _source: BridgeIDBCursor | BridgeIDBIndex | BridgeIDBObjectStore | null =
+    null;
   transaction: BridgeIDBTransaction | null = null;
   readyState: "done" | "pending" = "pending";
   onsuccess: EventListener | null = null;
@@ -2302,7 +2297,8 @@ export class BridgeIDBRequest extends FakeEventTarget 
implements IDBRequest {
 /** @public */
 export class BridgeIDBOpenDBRequest
   extends BridgeIDBRequest
-  implements IDBOpenDBRequest {
+  implements IDBOpenDBRequest
+{
   public onupgradeneeded: EventListener | null = null;
   public onblocked: EventListener | null = null;
 
@@ -2350,7 +2346,8 @@ function waitMacroQueue(): Promise<void> {
 /** @public */
 export class BridgeIDBTransaction
   extends FakeEventTarget
-  implements IDBTransaction {
+  implements IDBTransaction
+{
   _committed: boolean = false;
   /**
    * A transaction is active as long as new operations can be
diff --git a/packages/taler-wallet-core/src/db-utils.ts 
b/packages/taler-wallet-core/src/db-utils.ts
index b32b3d585..7f4b0de45 100644
--- a/packages/taler-wallet-core/src/db-utils.ts
+++ b/packages/taler-wallet-core/src/db-utils.ts
@@ -60,6 +60,7 @@ function upgradeFromStoreMap(
         const indexDesc: IndexDescriptor = swi.indexMap[indexName];
         s.createIndex(indexDesc.name, indexDesc.keyPath, {
           multiEntry: indexDesc.multiEntry,
+          unique: indexDesc.unique,
         });
       }
     }
diff --git a/packages/taler-wallet-core/src/db.ts 
b/packages/taler-wallet-core/src/db.ts
index 078060297..8b96dd5be 100644
--- a/packages/taler-wallet-core/src/db.ts
+++ b/packages/taler-wallet-core/src/db.ts
@@ -62,7 +62,11 @@ import { Event, IDBDatabase } from "@gnu-taler/idb-bridge";
  *   will have an index.
  * - Amounts are stored as strings, except when they are needed for
  *   indexing.
+ * - Every record that has a corresponding transaction item must have
+ *   an index for a mandatory timestamp field.
  * - Optional fields should be avoided, use "T | undefined" instead.
+ * - Do all records have some obvious, indexed field that can
+ *   be used for range queries?
  *
  * @author Florian Dold <dold@taler.net>
  */
@@ -94,38 +98,45 @@ export const CURRENT_DB_CONFIG_KEY = "currentMainDbName";
  */
 export const WALLET_DB_MINOR_VERSION = 1;
 
+export namespace OperationStatusRange {
+  export const ACTIVE_START = 10;
+  export const ACTIVE_END = 29;
+  export const DORMANT_START = 50;
+  export const DORMANT_END = 69;
+}
+
 /**
  * Status of a withdrawal.
  */
-export enum ReserveRecordStatus {
+export enum WithdrawalGroupStatus {
   /**
    * Reserve must be registered with the bank.
    */
-  RegisteringBank = "registering-bank",
+  RegisteringBank = OperationStatusRange.ACTIVE_START,
 
   /**
    * We've registered reserve's information with the bank
    * and are now waiting for the user to confirm the withdraw
    * with the bank (typically 2nd factor auth).
    */
-  WaitConfirmBank = "wait-confirm-bank",
+  WaitConfirmBank = OperationStatusRange.ACTIVE_START + 1,
 
   /**
    * Querying reserve status with the exchange.
    */
-  QueryingStatus = "querying-status",
+  QueryingStatus = OperationStatusRange.ACTIVE_START + 2,
 
   /**
    * The corresponding withdraw record has been created.
    * No further processing is done, unless explicitly requested
    * by the user.
    */
-  Dormant = "dormant",
+  Finished = OperationStatusRange.DORMANT_START,
 
   /**
    * The bank aborted the withdrawal.
    */
-  BankAborted = "bank-aborted",
+  BankAborted = OperationStatusRange.DORMANT_START + 1,
 }
 
 /**
@@ -139,7 +150,7 @@ export interface ReserveBankInfo {
    * URL that the user can be redirected to, and allows
    * them to confirm (or abort) the bank-integrated withdrawal.
    */
-  confirmUrl?: string;
+  confirmUrl: string | undefined;
 
   /**
    * Exchange payto URI that the bank will use to fund the reserve.
@@ -153,14 +164,14 @@ export interface ReserveBankInfo {
    *
    * Set to undefined if that hasn't happened yet.
    */
-  timestampReserveInfoPosted?: TalerProtocolTimestamp;
+  timestampReserveInfoPosted: TalerProtocolTimestamp | undefined;
 
   /**
    * Time when the reserve was confirmed by the bank.
    *
    * Set to undefined if not confirmed yet.
    */
-  timestampBankConfirmed?: TalerProtocolTimestamp;
+  timestampBankConfirmed: TalerProtocolTimestamp | undefined;
 }
 
 /**
@@ -186,6 +197,8 @@ export interface AuditorTrustRecord {
   /**
    * UIDs for the operation of adding this auditor
    * as a trusted auditor.
+   *
+   * (Used for backup/sync merging and tombstones.)
    */
   uids: string[];
 }
@@ -223,15 +236,17 @@ export enum DenominationVerificationStatus {
   /**
    * Verification was delayed.
    */
-  Unverified = "unverified",
+  Unverified = OperationStatusRange.ACTIVE_START,
+
   /**
    * Verified as valid.
    */
-  VerifiedGood = "verified-good",
+  VerifiedGood = OperationStatusRange.DORMANT_START,
+
   /**
    * Verified as invalid.
    */
-  VerifiedBad = "verified-bad",
+  VerifiedBad = OperationStatusRange.DORMANT_START + 1,
 }
 
 export interface DenomFees {
@@ -512,6 +527,8 @@ export interface ExchangeRecord {
   /**
    * Public key of the reserve that we're currently using for
    * receiving P2P payments.
+   *
+   * FIXME: Make this a rowId of reserves!
    */
   currentMergeReserveInfo?: MergeReserveInfo;
 }
@@ -554,6 +571,8 @@ export interface PlanchetRecord {
    *
    * Can be the empty string (non-null/undefined for DB indexing)
    * if this is a tipping reserve.
+   *
+   * FIXME: Where is this used?
    */
   reservePub: string;
 
@@ -696,13 +715,16 @@ export interface CoinRecord {
 
   /**
    * Information about what the coin has been allocated for.
-   * Used to prevent allocation of the same coin for two different payments.
+   *
+   * Used for:
+   * - Diagnostics
+   * - Idempotency of applying a coin selection (e.g. after re-selection)
    */
-  allocation?: CoinAllocation;
+  allocation: CoinAllocation | undefined;
 
   maxAge: number;
 
-  ageCommitmentProof?: AgeCommitmentProof;
+  ageCommitmentProof: AgeCommitmentProof | undefined;
 }
 
 export interface CoinAllocation {
@@ -745,6 +767,8 @@ export interface ProposalDownload {
 
   /**
    * Extracted / parsed data from the contract terms.
+   *
+   * FIXME: Do we need to store *all* that data in duplicate?
    */
   contractData: WalletContractData;
 }
@@ -792,7 +816,7 @@ export interface ProposalRecord {
   /**
    * Session ID we got when downloading the contract.
    */
-  downloadSessionId?: string;
+  downloadSessionId: string | undefined;
 }
 
 /**
@@ -866,19 +890,19 @@ export interface TipRecord {
 }
 
 export enum RefreshCoinStatus {
-  Pending = "pending",
-  Finished = "finished",
+  Pending = OperationStatusRange.ACTIVE_START,
+  Finished = OperationStatusRange.DORMANT_START,
 
   /**
    * The refresh for this coin has been frozen, because of a permanent error.
    * More info in lastErrorPerCoin.
    */
-  Frozen = "frozen",
+  Frozen = OperationStatusRange.DORMANT_START + 1,
 }
 
 export enum OperationStatus {
-  Finished = "finished",
-  Pending = "pending",
+  Finished = OperationStatusRange.DORMANT_START,
+  Pending = OperationStatusRange.ACTIVE_START,
 }
 
 export interface RefreshGroupRecord {
@@ -1354,20 +1378,12 @@ export interface WithdrawalGroupRecord {
    */
   timestampFinish?: TalerProtocolTimestamp;
 
-  /**
-   * Operation status of the withdrawal group.
-   * Used for indexing in the database.
-   *
-   * FIXME: Redundant with reserveStatus
-   */
-  operationStatus: OperationStatus;
-
   /**
    * Current status of the reserve.
    *
    * FIXME: Wrong name!
    */
-  reserveStatus: ReserveRecordStatus;
+  status: WithdrawalGroupStatus;
 
   /**
    * Amount that was sent by the user to fund the reserve.
@@ -1752,9 +1768,14 @@ export interface PeerPullPaymentIncomingRecord {
   contractPriv: string;
 }
 
-// FIXME: give this some smaller "row ID" to
-// reference in other records?
+/**
+ * Store for extra information about a reserve.
+ *
+ * Mostly used to store the private key for a reserve and to allow
+ * other records to reference the reserve key pair via a small row ID.
+ */
 export interface ReserveRecord {
+  rowId?: number;
   reservePub: string;
   reservePriv: string;
 }
@@ -1834,9 +1855,12 @@ export const WalletStoresV1 = {
   reserves: describeStore(
     "reserves",
     describeContents<ReserveRecord>({
-      keyPath: "reservePub",
+      keyPath: "rowId",
+      autoIncrement: true,
     }),
-    {},
+    {
+      byReservePub: describeIndex("byReservePub", "reservePub", {}),
+    },
   ),
   config: describeStore(
     "config",
@@ -1946,8 +1970,7 @@ export const WalletStoresV1 = {
       keyPath: "withdrawalGroupId",
     }),
     {
-      byReservePub: describeIndex("byReservePub", "reservePub"),
-      byStatus: describeIndex("byStatus", "operationStatus"),
+      byStatus: describeIndex("byStatus", "status"),
       byTalerWithdrawUri: describeIndex(
         "byTalerWithdrawUri",
         "wgInfo.bankInfo.talerWithdrawUri",
diff --git a/packages/taler-wallet-core/src/operations/backup/export.ts 
b/packages/taler-wallet-core/src/operations/backup/export.ts
index b39e6dc27..c8454a62f 100644
--- a/packages/taler-wallet-core/src/operations/backup/export.ts
+++ b/packages/taler-wallet-core/src/operations/backup/export.ts
@@ -71,6 +71,7 @@ import {
   RefreshCoinStatus,
   RefundState,
   WALLET_BACKUP_STATE_KEY,
+  WithdrawalGroupStatus,
   WithdrawalRecordType,
 } from "../../db.js";
 import { InternalWalletState } from "../../internal-wallet-state.js";
@@ -167,8 +168,9 @@ export async function exportBackup(
           instructed_amount: Amounts.stringify(wg.instructedAmount),
           reserve_priv: wg.reservePriv,
           restrict_age: wg.restrictAge,
+          // FIXME: proper status conversion!
           operation_status:
-            wg.operationStatus == OperationStatus.Finished
+            wg.status == WithdrawalGroupStatus.Finished
               ? BackupOperationStatus.Finished
               : BackupOperationStatus.Pending,
           selected_denoms_uid: wg.denomSelUid,
diff --git a/packages/taler-wallet-core/src/operations/backup/import.ts 
b/packages/taler-wallet-core/src/operations/backup/import.ts
index 20c7316c1..9997dd09d 100644
--- a/packages/taler-wallet-core/src/operations/backup/import.ts
+++ b/packages/taler-wallet-core/src/operations/backup/import.ts
@@ -52,7 +52,7 @@ import {
   RefreshSessionRecord,
   RefundState,
   ReserveBankInfo,
-  ReserveRecordStatus,
+  WithdrawalGroupStatus,
   WalletContractData,
   WalletRefundItem,
   WalletStoresV1,
@@ -285,6 +285,10 @@ export async function importCoin(
       coinSource,
       // FIXME!
       maxAge: AgeRestriction.AGE_UNRESTRICTED,
+      // FIXME!
+      ageCommitmentProof: undefined,
+      // FIXME!
+      allocation: undefined,
     };
     if (coinRecord.status === CoinStatus.Fresh) {
       await makeCoinAvailable(ws, tx, coinRecord);
@@ -531,9 +535,6 @@ export async function importBackup(
             exchangeBaseUrl: backupWg.exchange_base_url,
             instructedAmount: Amounts.parseOrThrow(backupWg.instructed_amount),
             secretSeed: backupWg.secret_seed,
-            operationStatus: backupWg.timestamp_finish
-              ? OperationStatus.Finished
-              : OperationStatus.Pending,
             denomsSel: await getDenomSelStateFromBackup(
               tx,
               backupWg.exchange_base_url,
@@ -545,9 +546,9 @@ export async function importBackup(
             ),
             reservePriv: backupWg.reserve_priv,
             reservePub,
-            reserveStatus: backupWg.timestamp_finish
-              ? ReserveRecordStatus.Dormant
-              : ReserveRecordStatus.QueryingStatus, // FIXME!
+            status: backupWg.timestamp_finish
+              ? WithdrawalGroupStatus.Finished
+              : WithdrawalGroupStatus.QueryingStatus, // FIXME!
             timestampStart: backupWg.timestamp_created,
             wgInfo,
             restrictAge: backupWg.restrict_age,
@@ -658,6 +659,8 @@ export async function importBackup(
             repurchaseProposalId: backupProposal.repurchase_proposal_id,
             download,
             proposalStatus,
+            // FIXME!
+            downloadSessionId: undefined,
           });
         }
       }
diff --git a/packages/taler-wallet-core/src/operations/peer-to-peer.ts 
b/packages/taler-wallet-core/src/operations/peer-to-peer.ts
index 48d422e0b..d30cb294d 100644
--- a/packages/taler-wallet-core/src/operations/peer-to-peer.ts
+++ b/packages/taler-wallet-core/src/operations/peer-to-peer.ts
@@ -65,7 +65,7 @@ import {
 import {
   CoinStatus,
   MergeReserveInfo,
-  ReserveRecordStatus,
+  WithdrawalGroupStatus,
   WalletStoresV1,
   WithdrawalRecordType,
 } from "../db.js";
@@ -544,7 +544,7 @@ export async function acceptPeerPushPayment(
       contractTerms: peerInc.contractTerms,
     },
     exchangeBaseUrl: peerInc.exchangeBaseUrl,
-    reserveStatus: ReserveRecordStatus.QueryingStatus,
+    reserveStatus: WithdrawalGroupStatus.QueryingStatus,
     reserveKeyPair: {
       priv: mergeReserveInfo.reservePriv,
       pub: mergeReserveInfo.reservePub,
@@ -828,7 +828,7 @@ export async function initiatePeerRequestForPay(
       contractPriv: econtractResp.contractPriv,
     },
     exchangeBaseUrl: req.exchangeBaseUrl,
-    reserveStatus: ReserveRecordStatus.QueryingStatus,
+    reserveStatus: WithdrawalGroupStatus.QueryingStatus,
     reserveKeyPair: {
       priv: mergeReserveInfo.reservePriv,
       pub: mergeReserveInfo.reservePub,
diff --git a/packages/taler-wallet-core/src/operations/pending.ts 
b/packages/taler-wallet-core/src/operations/pending.ts
index 9ba532ab7..0dcd09e25 100644
--- a/packages/taler-wallet-core/src/operations/pending.ts
+++ b/packages/taler-wallet-core/src/operations/pending.ts
@@ -28,6 +28,7 @@ import {
   BackupProviderStateTag,
   RefreshCoinStatus,
   OperationStatus,
+  OperationStatusRange,
 } from "../db.js";
 import {
   PendingOperationsResponse,
@@ -38,6 +39,7 @@ import { InternalWalletState } from 
"../internal-wallet-state.js";
 import { GetReadOnlyAccess } from "../util/query.js";
 import { RetryTags } from "../util/retries.js";
 import { Wallet } from "../wallet.js";
+import { GlobalIDB } from "@gnu-taler/idb-bridge";
 
 async function gatherExchangePending(
   tx: GetReadOnlyAccess<{
@@ -120,7 +122,10 @@ async function gatherWithdrawalPending(
   resp: PendingOperationsResponse,
 ): Promise<void> {
   const wsrs = await tx.withdrawalGroups.indexes.byStatus.getAll(
-    OperationStatus.Pending,
+    GlobalIDB.KeyRange.bound(
+      OperationStatusRange.ACTIVE_START,
+      OperationStatusRange.ACTIVE_END,
+    ),
   );
   for (const wsr of wsrs) {
     if (wsr.timestampFinish) {
diff --git a/packages/taler-wallet-core/src/operations/recoup.ts 
b/packages/taler-wallet-core/src/operations/recoup.ts
index 119119035..2d92ff8ba 100644
--- a/packages/taler-wallet-core/src/operations/recoup.ts
+++ b/packages/taler-wallet-core/src/operations/recoup.ts
@@ -44,7 +44,7 @@ import {
   CoinStatus,
   RecoupGroupRecord,
   RefreshCoinSource,
-  ReserveRecordStatus,
+  WithdrawalGroupStatus,
   WalletStoresV1,
   WithdrawalRecordType,
   WithdrawCoinSource,
@@ -356,7 +356,9 @@ export async function processRecoupGroupHandler(
           throw Error(`Coin ${coinPub} not found, can't request recoup`);
         }
         if (coin.coinSource.type === CoinSourceType.Withdraw) {
-          const reserve = await tx.reserves.get(coin.coinSource.reservePub);
+          const reserve = await tx.reserves.indexes.byReservePub.get(
+            coin.coinSource.reservePub,
+          );
           if (!reserve) {
             return;
           }
@@ -382,7 +384,7 @@ export async function processRecoupGroupHandler(
     await internalCreateWithdrawalGroup(ws, {
       amount: Amounts.parseOrThrow(result.balance),
       exchangeBaseUrl: recoupGroup.exchangeBaseUrl,
-      reserveStatus: ReserveRecordStatus.QueryingStatus,
+      reserveStatus: WithdrawalGroupStatus.QueryingStatus,
       reserveKeyPair: {
         pub: reservePub,
         priv: reservePrivMap[reservePub],
diff --git a/packages/taler-wallet-core/src/operations/refresh.ts 
b/packages/taler-wallet-core/src/operations/refresh.ts
index 55070618f..9fe2e6a8f 100644
--- a/packages/taler-wallet-core/src/operations/refresh.ts
+++ b/packages/taler-wallet-core/src/operations/refresh.ts
@@ -682,6 +682,7 @@ async function refreshReveal(
         coinEvHash: pc.coinEvHash,
         maxAge: pc.maxAge,
         ageCommitmentProof: pc.ageCommitmentProof,
+        allocation: undefined,
       };
 
       coins.push(coin);
diff --git a/packages/taler-wallet-core/src/operations/tip.ts 
b/packages/taler-wallet-core/src/operations/tip.ts
index a0fd8d328..bd5ff51e7 100644
--- a/packages/taler-wallet-core/src/operations/tip.ts
+++ b/packages/taler-wallet-core/src/operations/tip.ts
@@ -320,6 +320,7 @@ export async function processTip(
       coinEvHash: planchet.coinEvHash,
       maxAge: AgeRestriction.AGE_UNRESTRICTED,
       ageCommitmentProof: planchet.ageCommitmentProof,
+      allocation: undefined,
     });
   }
 
diff --git a/packages/taler-wallet-core/src/operations/transactions.ts 
b/packages/taler-wallet-core/src/operations/transactions.ts
index 19f6aee64..be1233d2c 100644
--- a/packages/taler-wallet-core/src/operations/transactions.ts
+++ b/packages/taler-wallet-core/src/operations/transactions.ts
@@ -31,11 +31,9 @@ import {
   TalerProtocolTimestamp,
   Transaction,
   TransactionByIdRequest,
-  TransactionRefund,
   TransactionsRequest,
   TransactionsResponse,
   TransactionType,
-  WithdrawalDetails,
   WithdrawalType,
 } from "@gnu-taler/taler-util";
 import {
diff --git a/packages/taler-wallet-core/src/operations/withdraw.ts 
b/packages/taler-wallet-core/src/operations/withdraw.ts
index ad9875400..cedb62361 100644
--- a/packages/taler-wallet-core/src/operations/withdraw.ts
+++ b/packages/taler-wallet-core/src/operations/withdraw.ts
@@ -71,7 +71,7 @@ import {
   ExchangeRecord,
   OperationStatus,
   PlanchetRecord,
-  ReserveRecordStatus,
+  WithdrawalGroupStatus,
   WalletStoresV1,
   WgInfo,
   WithdrawalGroupRecord,
@@ -91,7 +91,11 @@ import {
   readSuccessResponseJsonOrThrow,
   throwUnexpectedRequestError,
 } from "../util/http.js";
-import { checkDbInvariant, checkLogicInvariant } from "../util/invariants.js";
+import {
+  checkDbInvariant,
+  checkLogicInvariant,
+  InvariantViolatedError,
+} from "../util/invariants.js";
 import { DbAccess, GetReadOnlyAccess } from "../util/query.js";
 import {
   OperationAttemptResult,
@@ -830,6 +834,7 @@ async function processPlanchetVerifyAndStoreCoin(
     },
     maxAge: planchet.maxAge,
     ageCommitmentProof: planchet.ageCommitmentProof,
+    allocation: undefined,
   };
 
   const planchetCoinPub = planchet.coinPub;
@@ -962,7 +967,7 @@ async function queryReserve(
     withdrawalGroupId,
   });
   checkDbInvariant(!!withdrawalGroup);
-  if (withdrawalGroup.reserveStatus !== ReserveRecordStatus.QueryingStatus) {
+  if (withdrawalGroup.status !== WithdrawalGroupStatus.QueryingStatus) {
     return { ready: true };
   }
   const reservePub = withdrawalGroup.reservePub;
@@ -1010,7 +1015,7 @@ async function queryReserve(
         logger.warn(`withdrawal group ${withdrawalGroupId} not found`);
         return;
       }
-      wg.reserveStatus = ReserveRecordStatus.Dormant;
+      wg.status = WithdrawalGroupStatus.Finished;
       await tx.withdrawalGroups.put(wg);
     });
 
@@ -1039,13 +1044,13 @@ export async function processWithdrawalGroup(
     throw Error(`withdrawal group ${withdrawalGroupId} not found`);
   }
 
-  switch (withdrawalGroup.reserveStatus) {
-    case ReserveRecordStatus.RegisteringBank:
+  switch (withdrawalGroup.status) {
+    case WithdrawalGroupStatus.RegisteringBank:
       await processReserveBankStatus(ws, withdrawalGroupId);
       return await processWithdrawalGroup(ws, withdrawalGroupId, {
         forceNow: true,
       });
-    case ReserveRecordStatus.QueryingStatus: {
+    case WithdrawalGroupStatus.QueryingStatus: {
       const res = await queryReserve(ws, withdrawalGroupId);
       if (res.ready) {
         return await processWithdrawalGroup(ws, withdrawalGroupId, {
@@ -1057,7 +1062,7 @@ export async function processWithdrawalGroup(
         result: undefined,
       };
     }
-    case ReserveRecordStatus.WaitConfirmBank: {
+    case WithdrawalGroupStatus.WaitConfirmBank: {
       const res = await processReserveBankStatus(ws, withdrawalGroupId);
       switch (res.status) {
         case BankStatusResultCode.Aborted:
@@ -1075,23 +1080,20 @@ export async function processWithdrawalGroup(
       }
       break;
     }
-    case ReserveRecordStatus.BankAborted: {
+    case WithdrawalGroupStatus.BankAborted: {
       // FIXME
       return {
         type: OperationAttemptResultType.Pending,
         result: undefined,
       };
     }
-    case ReserveRecordStatus.Dormant:
+    case WithdrawalGroupStatus.Finished:
       // We can try to withdraw, nothing needs to be done with the reserve.
       break;
     default:
-      logger.warn(
-        "unknown reserve record status:",
-        withdrawalGroup.reserveStatus,
+      throw new InvariantViolatedError(
+        `unknown reserve record status: ${withdrawalGroup.status}`,
       );
-      assertUnreachable(withdrawalGroup.reserveStatus);
-      break;
   }
 
   await ws.exchangeOps.updateExchangeFromUrl(
@@ -1108,7 +1110,7 @@ export async function processWithdrawalGroup(
         if (!wg) {
           return;
         }
-        wg.operationStatus = OperationStatus.Finished;
+        wg.status = WithdrawalGroupStatus.Finished;
         wg.timestampFinish = TalerProtocolTimestamp.now();
         await tx.withdrawalGroups.put(wg);
       });
@@ -1192,7 +1194,7 @@ export async function processWithdrawalGroup(
       if (wg.timestampFinish === undefined && numFinished === numTotalCoins) {
         finishedForFirstTime = true;
         wg.timestampFinish = TalerProtocolTimestamp.now();
-        wg.operationStatus = OperationStatus.Finished;
+        wg.status = WithdrawalGroupStatus.Finished;
       }
 
       await tx.withdrawalGroups.put(wg);
@@ -1508,9 +1510,9 @@ async function registerReserveWithBank(
     .runReadOnly(async (tx) => {
       return await tx.withdrawalGroups.get(withdrawalGroupId);
     });
-  switch (withdrawalGroup?.reserveStatus) {
-    case ReserveRecordStatus.WaitConfirmBank:
-    case ReserveRecordStatus.RegisteringBank:
+  switch (withdrawalGroup?.status) {
+    case WithdrawalGroupStatus.WaitConfirmBank:
+    case WithdrawalGroupStatus.RegisteringBank:
       break;
     default:
       return;
@@ -1544,9 +1546,9 @@ async function registerReserveWithBank(
       if (!r) {
         return;
       }
-      switch (r.reserveStatus) {
-        case ReserveRecordStatus.RegisteringBank:
-        case ReserveRecordStatus.WaitConfirmBank:
+      switch (r.status) {
+        case WithdrawalGroupStatus.RegisteringBank:
+        case WithdrawalGroupStatus.WaitConfirmBank:
           break;
         default:
           return;
@@ -1557,8 +1559,7 @@ async function registerReserveWithBank(
       r.wgInfo.bankInfo.timestampReserveInfoPosted = AbsoluteTime.toTimestamp(
         AbsoluteTime.now(),
       );
-      r.reserveStatus = ReserveRecordStatus.WaitConfirmBank;
-      r.operationStatus = OperationStatus.Pending;
+      r.status = WithdrawalGroupStatus.WaitConfirmBank;
       await tx.withdrawalGroups.put(r);
     });
   ws.notify({ type: NotificationType.ReserveRegisteredWithBank });
@@ -1575,9 +1576,9 @@ async function processReserveBankStatus(
   const withdrawalGroup = await getWithdrawalGroupRecordTx(ws.db, {
     withdrawalGroupId,
   });
-  switch (withdrawalGroup?.reserveStatus) {
-    case ReserveRecordStatus.WaitConfirmBank:
-    case ReserveRecordStatus.RegisteringBank:
+  switch (withdrawalGroup?.status) {
+    case WithdrawalGroupStatus.WaitConfirmBank:
+    case WithdrawalGroupStatus.RegisteringBank:
       break;
     default:
       return {
@@ -1616,9 +1617,9 @@ async function processReserveBankStatus(
         if (!r) {
           return;
         }
-        switch (r.reserveStatus) {
-          case ReserveRecordStatus.RegisteringBank:
-          case ReserveRecordStatus.WaitConfirmBank:
+        switch (r.status) {
+          case WithdrawalGroupStatus.RegisteringBank:
+          case WithdrawalGroupStatus.WaitConfirmBank:
             break;
           default:
             return;
@@ -1628,8 +1629,7 @@ async function processReserveBankStatus(
         }
         const now = AbsoluteTime.toTimestamp(AbsoluteTime.now());
         r.wgInfo.bankInfo.timestampBankConfirmed = now;
-        r.reserveStatus = ReserveRecordStatus.BankAborted;
-        r.operationStatus = OperationStatus.Finished;
+        r.status = WithdrawalGroupStatus.BankAborted;
         await tx.withdrawalGroups.put(r);
       });
     return {
@@ -1644,7 +1644,7 @@ async function processReserveBankStatus(
   }
 
   // FIXME: Why do we do this?!
-  if (withdrawalGroup.reserveStatus === ReserveRecordStatus.RegisteringBank) {
+  if (withdrawalGroup.status === WithdrawalGroupStatus.RegisteringBank) {
     await registerReserveWithBank(ws, withdrawalGroupId);
     return await processReserveBankStatus(ws, withdrawalGroupId);
   }
@@ -1657,9 +1657,9 @@ async function processReserveBankStatus(
         return;
       }
       // Re-check reserve status within transaction
-      switch (r.reserveStatus) {
-        case ReserveRecordStatus.RegisteringBank:
-        case ReserveRecordStatus.WaitConfirmBank:
+      switch (r.status) {
+        case WithdrawalGroupStatus.RegisteringBank:
+        case WithdrawalGroupStatus.WaitConfirmBank:
           break;
         default:
           return;
@@ -1671,8 +1671,7 @@ async function processReserveBankStatus(
         logger.info("withdrawal: transfer confirmed by bank.");
         const now = AbsoluteTime.toTimestamp(AbsoluteTime.now());
         r.wgInfo.bankInfo.timestampBankConfirmed = now;
-        r.reserveStatus = ReserveRecordStatus.QueryingStatus;
-        r.operationStatus = OperationStatus.Pending;
+        r.status = WithdrawalGroupStatus.QueryingStatus;
       } else {
         logger.info("withdrawal: transfer not yet confirmed by bank");
         r.wgInfo.bankInfo.confirmUrl = status.confirm_transfer_url;
@@ -1689,7 +1688,7 @@ async function processReserveBankStatus(
 export async function internalCreateWithdrawalGroup(
   ws: InternalWalletState,
   args: {
-    reserveStatus: ReserveRecordStatus;
+    reserveStatus: WithdrawalGroupStatus;
     amount: AmountJson;
     exchangeBaseUrl: string;
     forcedDenomSel?: ForcedDenomSel;
@@ -1728,12 +1727,11 @@ export async function internalCreateWithdrawalGroup(
     exchangeBaseUrl: canonExchange,
     instructedAmount: amount,
     timestampStart: now,
-    operationStatus: OperationStatus.Pending,
     rawWithdrawalAmount: initialDenomSel.totalWithdrawCost,
     secretSeed,
     reservePriv: reserveKeyPair.priv,
     reservePub: reserveKeyPair.pub,
-    reserveStatus: args.reserveStatus,
+    status: args.reserveStatus,
     withdrawalGroupId,
     restrictAge: args.restrictAge,
     senderWire: undefined,
@@ -1835,11 +1833,13 @@ export async function acceptWithdrawalFromUri(
         exchangePaytoUri,
         talerWithdrawUri: req.talerWithdrawUri,
         confirmUrl: withdrawInfo.confirmTransferUrl,
+        timestampBankConfirmed: undefined,
+        timestampReserveInfoPosted: undefined,
       },
     },
     restrictAge: req.restrictAge,
     forcedDenomSel: req.forcedDenomSel,
-    reserveStatus: ReserveRecordStatus.RegisteringBank,
+    reserveStatus: WithdrawalGroupStatus.RegisteringBank,
   });
 
   const withdrawalGroupId = withdrawalGroup.withdrawalGroupId;
@@ -1850,9 +1850,7 @@ export async function acceptWithdrawalFromUri(
   const processedWithdrawalGroup = await getWithdrawalGroupRecordTx(ws.db, {
     withdrawalGroupId,
   });
-  if (
-    processedWithdrawalGroup?.reserveStatus === ReserveRecordStatus.BankAborted
-  ) {
+  if (processedWithdrawalGroup?.status === WithdrawalGroupStatus.BankAborted) {
     throw TalerError.fromDetail(
       TalerErrorCode.WALLET_WITHDRAWAL_OPERATION_ABORTED_BY_BANK,
       {},
@@ -1898,7 +1896,7 @@ export async function createManualWithdrawal(
     exchangeBaseUrl: req.exchangeBaseUrl,
     forcedDenomSel: req.forcedDenomSel,
     restrictAge: req.restrictAge,
-    reserveStatus: ReserveRecordStatus.QueryingStatus,
+    reserveStatus: WithdrawalGroupStatus.QueryingStatus,
   });
 
   const withdrawalGroupId = withdrawalGroup.withdrawalGroupId;
diff --git a/packages/taler-wallet-core/src/util/invariants.ts 
b/packages/taler-wallet-core/src/util/invariants.ts
index b788d044e..3598d857c 100644
--- a/packages/taler-wallet-core/src/util/invariants.ts
+++ b/packages/taler-wallet-core/src/util/invariants.ts
@@ -14,6 +14,13 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
+export class InvariantViolatedError extends Error {
+  constructor(message?: string) {
+    super(message);
+    Object.setPrototypeOf(this, InvariantViolatedError.prototype);
+  }
+}
+
 /**
  * Helpers for invariants.
  */
diff --git a/packages/taler-wallet-core/src/util/query.ts 
b/packages/taler-wallet-core/src/util/query.ts
index d1aae6fd6..71d7b9783 100644
--- a/packages/taler-wallet-core/src/util/query.ts
+++ b/packages/taler-wallet-core/src/util/query.ts
@@ -36,8 +36,6 @@ import {
   IDBKeyRange,
 } from "@gnu-taler/idb-bridge";
 import { Logger } from "@gnu-taler/taler-util";
-import { performanceNow } from "./timer.js";
-import { access } from "fs";
 
 const logger = new Logger("query.ts");
 
@@ -63,6 +61,13 @@ export interface IndexOptions {
    * undefined if added in the first version.
    */
   versionAdded?: number;
+
+  /**
+   * Does this index enforce unique keys?
+   *
+   * Defaults to false.
+   */
+  unique?: boolean;
 }
 
 function requestToPromise(req: IDBRequest): Promise<any> {
@@ -278,6 +283,7 @@ export interface IndexDescriptor {
   name: string;
   keyPath: IDBKeyPath | IDBKeyPath[];
   multiEntry?: boolean;
+  unique?: boolean;
 }
 
 export interface StoreDescriptor<RecordType> {
@@ -294,7 +300,11 @@ export interface StoreOptions {
 export function describeContents<RecordType = never>(
   options: StoreOptions,
 ): StoreDescriptor<RecordType> {
-  return { keyPath: options.keyPath, _dummy: undefined as any };
+  return {
+    keyPath: options.keyPath,
+    _dummy: undefined as any,
+    autoIncrement: options.autoIncrement,
+  };
 }
 
 export function describeIndex(
@@ -306,6 +316,7 @@ export function describeIndex(
     keyPath,
     name,
     multiEntry: options.multiEntry,
+    unique: options.unique,
   };
 }
 
@@ -341,11 +352,18 @@ export interface StoreReadOnlyAccessor<RecordType, 
IndexMap> {
   indexes: GetIndexReadOnlyAccess<RecordType, IndexMap>;
 }
 
+export interface InsertResponse {
+  /**
+   * Key of the newly inserted (via put/add) record.
+   */
+  key: IDBValidKey;
+}
+
 export interface StoreReadWriteAccessor<RecordType, IndexMap> {
   get(key: IDBValidKey): Promise<RecordType | undefined>;
   iter(query?: IDBValidKey): ResultStream<RecordType>;
-  put(r: RecordType): Promise<void>;
-  add(r: RecordType): Promise<void>;
+  put(r: RecordType): Promise<InsertResponse>;
+  add(r: RecordType): Promise<InsertResponse>;
   delete(key: IDBValidKey): Promise<void>;
   indexes: GetIndexReadWriteAccess<RecordType, IndexMap>;
 }
@@ -579,13 +597,19 @@ function makeWriteContext(
         const req = tx.objectStore(storeName).openCursor(query);
         return new ResultStream<any>(req);
       },
-      add(r) {
+      async add(r) {
         const req = tx.objectStore(storeName).add(r);
-        return requestToPromise(req);
+        const key = await requestToPromise(req);
+        return {
+          key: key,
+        };
       },
-      put(r) {
+      async put(r) {
         const req = tx.objectStore(storeName).put(r);
-        return requestToPromise(req);
+        const key = await requestToPromise(req);
+        return {
+          key: key,
+        };
       },
       delete(k) {
         const req = tx.objectStore(storeName).delete(k);

-- 
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]