gnunet-svn
[Top][All Lists]
Advanced

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

[taler-wallet-core] branch master updated: wallet: allow forced denom se


From: gnunet
Subject: [taler-wallet-core] branch master updated: wallet: allow forced denom selection for tests
Date: Tue, 29 Mar 2022 21:22:09 +0200

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

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

The following commit(s) were added to refs/heads/master by this push:
     new bbd6ccf1 wallet: allow forced denom selection for tests
bbd6ccf1 is described below

commit bbd6ccf1c7c0baea44234863967e640f5cb10a3a
Author: Florian Dold <florian@dold.me>
AuthorDate: Tue Mar 29 21:21:57 2022 +0200

    wallet: allow forced denom selection for tests
---
 packages/taler-util/src/walletTypes.ts             |  17 ++-
 .../taler-wallet-core/src/operations/refresh.ts    |   5 +-
 .../taler-wallet-core/src/operations/reserves.ts   |  17 +--
 packages/taler-wallet-core/src/operations/tip.ts   |   3 +-
 .../taler-wallet-core/src/operations/withdraw.ts   | 114 +++++++++++++--------
 packages/taler-wallet-core/src/wallet.ts           |  17 +--
 6 files changed, 105 insertions(+), 68 deletions(-)

diff --git a/packages/taler-util/src/walletTypes.ts 
b/packages/taler-util/src/walletTypes.ts
index 552087fb..818ba37f 100644
--- a/packages/taler-util/src/walletTypes.ts
+++ b/packages/taler-util/src/walletTypes.ts
@@ -212,6 +212,12 @@ export interface CreateReserveRequest {
    * URL to fetch the withdraw status from the bank.
    */
   bankWithdrawStatusUrl?: string;
+
+  /**
+   * Forced denomination selection for the first withdrawal
+   * from this reserve, only used for testing.
+   */
+  forcedDenomSel?: ForcedDenomSel;
 }
 
 export const codecForCreateReserveRequest = (): Codec<CreateReserveRequest> =>
@@ -727,6 +733,7 @@ export interface GetWithdrawalDetailsForAmountRequest {
 export interface AcceptBankIntegratedWithdrawalRequest {
   talerWithdrawUri: string;
   exchangeBaseUrl: string;
+  forcedDenomSel?: ForcedDenomSel;
 }
 
 export const codecForAcceptBankIntegratedWithdrawalRequest =
@@ -734,6 +741,7 @@ export const codecForAcceptBankIntegratedWithdrawalRequest =
     buildCodecForObject<AcceptBankIntegratedWithdrawalRequest>()
       .property("exchangeBaseUrl", codecForString())
       .property("talerWithdrawUri", codecForString())
+      .property("forcedDenomSel", codecForAny())
       .build("AcceptBankIntegratedWithdrawalRequest");
 
 export const codecForGetWithdrawalDetailsForAmountRequest =
@@ -1134,6 +1142,9 @@ export const codecForImportDbRequest = (): 
Codec<ImportDb> =>
     .property("dump", codecForAny())
     .build("ImportDbRequest");
 
-
-
-    
\ No newline at end of file
+export interface ForcedDenomSel {
+  denoms: {
+    value: AmountString;
+    count: number;
+  }[];
+}
diff --git a/packages/taler-wallet-core/src/operations/refresh.ts 
b/packages/taler-wallet-core/src/operations/refresh.ts
index 762023d2..cf292061 100644
--- a/packages/taler-wallet-core/src/operations/refresh.ts
+++ b/packages/taler-wallet-core/src/operations/refresh.ts
@@ -106,11 +106,12 @@ export function getTotalRefreshCost(
     amountLeft,
     refreshedDenom.feeRefresh,
   ).amount;
+  const denomMap = Object.fromEntries(denoms.map((x) => [x.denomPubHash, x]));
   const withdrawDenoms = selectWithdrawalDenominations(withdrawAmount, denoms);
   const resultingAmount = Amounts.add(
     Amounts.getZero(withdrawAmount.currency),
     ...withdrawDenoms.selectedDenoms.map(
-      (d) => Amounts.mult(d.denom.value, d.count).amount,
+      (d) => Amounts.mult(denomMap[d.denomPubHash].value, d.count).amount,
     ),
   ).amount;
   const totalCost = Amounts.sub(amountLeft, resultingAmount).amount;
@@ -277,7 +278,7 @@ async function refreshCreateSession(
         sessionSecretSeed: sessionSecretSeed,
         newDenoms: newCoinDenoms.selectedDenoms.map((x) => ({
           count: x.count,
-          denomPubHash: x.denom.denomPubHash,
+          denomPubHash: x.denomPubHash,
         })),
         amountRefreshOutput: newCoinDenoms.totalCoinValue,
       };
diff --git a/packages/taler-wallet-core/src/operations/reserves.ts 
b/packages/taler-wallet-core/src/operations/reserves.ts
index 38a7386b..91c19fbf 100644
--- a/packages/taler-wallet-core/src/operations/reserves.ts
+++ b/packages/taler-wallet-core/src/operations/reserves.ts
@@ -37,6 +37,8 @@ import {
   TalerErrorDetail,
   AbsoluteTime,
   URL,
+  AmountString,
+  ForcedDenomSel,
 } from "@gnu-taler/taler-util";
 import { InternalWalletState } from "../internal-wallet-state.js";
 import {
@@ -68,7 +70,6 @@ import {
   updateExchangeFromUrl,
 } from "./exchanges.js";
 import {
-  denomSelectionInfoToState,
   getBankWithdrawalInfo,
   getCandidateWithdrawalDenoms,
   processWithdrawGroup,
@@ -180,8 +181,7 @@ export async function createReserve(
 
   await updateWithdrawalDenoms(ws, canonExchange);
   const denoms = await getCandidateWithdrawalDenoms(ws, canonExchange);
-  const denomSelInfo = selectWithdrawalDenominations(req.amount, denoms);
-  const initialDenomSel = denomSelectionInfoToState(denomSelInfo);
+  const initialDenomSel = selectWithdrawalDenominations(req.amount, denoms);
 
   const reserveRecord: ReserveRecord = {
     instructedAmount: req.amount,
@@ -630,7 +630,7 @@ async function updateReserve(
         amountReservePlus,
         amountReserveMinus,
       ).amount;
-      const denomSelInfo = selectWithdrawalDenominations(
+      const denomSel = selectWithdrawalDenominations(
         remainingAmount,
         denoms,
       );
@@ -639,11 +639,11 @@ async function updateReserve(
         `Remaining unclaimed amount in reseve is ${Amounts.stringify(
           remainingAmount,
         )} and can be withdrawn with ${
-          denomSelInfo.selectedDenoms.length
+          denomSel.selectedDenoms.length
         } coins`,
       );
 
-      if (denomSelInfo.selectedDenoms.length === 0) {
+      if (denomSel.selectedDenoms.length === 0) {
         newReserve.reserveStatus = ReserveRecordStatus.Dormant;
         newReserve.operationStatus = OperationStatus.Finished;
         delete newReserve.lastError;
@@ -669,7 +669,7 @@ async function updateReserve(
         timestampStart: AbsoluteTime.toTimestamp(AbsoluteTime.now()),
         retryInfo: resetRetryInfo(),
         lastError: undefined,
-        denomsSel: denomSelectionInfoToState(denomSelInfo),
+        denomsSel: denomSel,
         secretSeed: encodeCrock(getRandomBytes(64)),
         denomSelUid: encodeCrock(getRandomBytes(32)),
         operationStatus: OperationStatus.Pending,
@@ -755,6 +755,9 @@ export async function createTalerWithdrawReserve(
   ws: InternalWalletState,
   talerWithdrawUri: string,
   selectedExchange: string,
+  options: {
+    forcedDenomSel?: ForcedDenomSel;
+  } = {},
 ): Promise<AcceptWithdrawalResponse> {
   await updateExchangeFromUrl(ws, selectedExchange);
   const withdrawInfo = await getBankWithdrawalInfo(ws.http, talerWithdrawUri);
diff --git a/packages/taler-wallet-core/src/operations/tip.ts 
b/packages/taler-wallet-core/src/operations/tip.ts
index 8bf85fe9..c0dcae91 100644
--- a/packages/taler-wallet-core/src/operations/tip.ts
+++ b/packages/taler-wallet-core/src/operations/tip.ts
@@ -56,7 +56,6 @@ import {
   updateWithdrawalDenoms,
   getCandidateWithdrawalDenoms,
   selectWithdrawalDenominations,
-  denomSelectionInfoToState,
 } from "./withdraw.js";
 import {
   getHttpResponseErrorDetails,
@@ -133,7 +132,7 @@ export async function prepareTip(
       tipAmountEffective: selectedDenoms.totalCoinValue,
       retryInfo: resetRetryInfo(),
       lastError: undefined,
-      denomsSel: denomSelectionInfoToState(selectedDenoms),
+      denomsSel: selectedDenoms,
       pickedUpTimestamp: undefined,
       secretSeed,
       denomSelUid,
diff --git a/packages/taler-wallet-core/src/operations/withdraw.ts 
b/packages/taler-wallet-core/src/operations/withdraw.ts
index e7dcd078..6d45599d 100644
--- a/packages/taler-wallet-core/src/operations/withdraw.ts
+++ b/packages/taler-wallet-core/src/operations/withdraw.ts
@@ -31,6 +31,7 @@ import {
   durationFromSpec,
   ExchangeListItem,
   ExchangeWithdrawRequest,
+  ForcedDenomSel,
   LibtoolVersion,
   Logger,
   NotificationType,
@@ -68,6 +69,7 @@ import {
   HttpRequestLibrary,
   readSuccessResponseJsonOrThrow,
 } from "../util/http.js";
+import { checkDbInvariant, checkLogicInvariant } from "../util/invariants.js";
 import {
   resetRetryInfo,
   RetryInfo,
@@ -84,21 +86,6 @@ import { guardOperationException } from "./common.js";
  */
 const logger = new Logger("operations/withdraw.ts");
 
-/**
- * FIXME: Eliminate this in favor of DenomSelectionState.
- */
-interface DenominationSelectionInfo {
-  totalCoinValue: AmountJson;
-  totalWithdrawCost: AmountJson;
-  selectedDenoms: {
-    /**
-     * How many times do we withdraw this denomination?
-     */
-    count: number;
-    denom: DenominationRecord;
-  }[];
-}
-
 /**
  * Information about what will happen when creating a reserve.
  *
@@ -122,7 +109,7 @@ export interface ExchangeWithdrawDetails {
   /**
    * Selected denominations for withdraw.
    */
-  selectedDenoms: DenominationSelectionInfo;
+  selectedDenoms: DenomSelectionState;
 
   /**
    * Does the wallet know about an auditor for
@@ -213,12 +200,12 @@ export function isWithdrawableDenom(d: 
DenominationRecord): boolean {
 export function selectWithdrawalDenominations(
   amountAvailable: AmountJson,
   denoms: DenominationRecord[],
-): DenominationSelectionInfo {
+): DenomSelectionState {
   let remaining = Amounts.copy(amountAvailable);
 
   const selectedDenoms: {
     count: number;
-    denom: DenominationRecord;
+    denomPubHash: string;
   }[] = [];
 
   let totalCoinValue = Amounts.getZero(amountAvailable.currency);
@@ -248,7 +235,7 @@ export function selectWithdrawalDenominations(
       ).amount;
       selectedDenoms.push({
         count,
-        denom: d,
+        denomPubHash: d.denomPubHash,
       });
     }
 
@@ -262,9 +249,7 @@ export function selectWithdrawalDenominations(
       `selected withdrawal denoms for ${Amounts.stringify(totalCoinValue)}`,
     );
     for (const sd of selectedDenoms) {
-      logger.trace(
-        `denom_pub_hash=${sd.denom.denomPubHash}, count=${sd.count}`,
-      );
+      logger.trace(`denom_pub_hash=${sd.denomPubHash}, count=${sd.count}`);
     }
     logger.trace("(end of withdrawal denom list)");
   }
@@ -276,6 +261,56 @@ export function selectWithdrawalDenominations(
   };
 }
 
+export function selectForcedWithdrawalDenominations(
+  amountAvailable: AmountJson,
+  denoms: DenominationRecord[],
+  forcedDenomSel: ForcedDenomSel,
+): DenomSelectionState {
+  let remaining = Amounts.copy(amountAvailable);
+
+  const selectedDenoms: {
+    count: number;
+    denomPubHash: string;
+  }[] = [];
+
+  let totalCoinValue = Amounts.getZero(amountAvailable.currency);
+  let totalWithdrawCost = Amounts.getZero(amountAvailable.currency);
+
+  denoms = denoms.filter(isWithdrawableDenom);
+  denoms.sort((d1, d2) => Amounts.cmp(d2.value, d1.value));
+
+  for (const fds of forcedDenomSel.denoms) {
+    const count = fds.count;
+    const denom = denoms.find((x) => {
+      return Amounts.cmp(x.value, fds.value) == 0;
+    });
+    if (!denom) {
+      throw Error(
+        `unable to find denom for forced selection (value ${fds.value})`,
+      );
+    }
+    const cost = Amounts.add(denom.value, denom.feeWithdraw).amount;
+    totalCoinValue = Amounts.add(
+      totalCoinValue,
+      Amounts.mult(denom.value, count).amount,
+    ).amount;
+    totalWithdrawCost = Amounts.add(
+      totalWithdrawCost,
+      Amounts.mult(cost, count).amount,
+    ).amount;
+    selectedDenoms.push({
+      count,
+      denomPubHash: denom.denomPubHash,
+    });
+  }
+
+  return {
+    selectedDenoms,
+    totalCoinValue,
+    totalWithdrawCost,
+  };
+}
+
 /**
  * Get information about a withdrawal from
  * a taler://withdraw URI by asking the bank.
@@ -695,21 +730,6 @@ async function processPlanchetVerifyAndStoreCoin(
   }
 }
 
-export function denomSelectionInfoToState(
-  dsi: DenominationSelectionInfo,
-): DenomSelectionState {
-  return {
-    selectedDenoms: dsi.selectedDenoms.map((x) => {
-      return {
-        count: x.count,
-        denomPubHash: x.denom.denomPubHash,
-      };
-    }),
-    totalCoinValue: dsi.totalCoinValue,
-    totalWithdrawCost: dsi.totalWithdrawCost,
-  };
-}
-
 /**
  * Make sure that denominations that currently can be used for withdrawal
  * are validated, and the result of validation is stored in the database.
@@ -1006,11 +1026,21 @@ export async function getExchangeWithdrawalInfo(
     exchange,
   );
 
-  let earliestDepositExpiration =
-    selectedDenoms.selectedDenoms[0].denom.stampExpireDeposit;
+  let earliestDepositExpiration: TalerProtocolTimestamp | undefined;
   for (let i = 1; i < selectedDenoms.selectedDenoms.length; i++) {
-    const expireDeposit =
-      selectedDenoms.selectedDenoms[i].denom.stampExpireDeposit;
+    const ds = selectedDenoms.selectedDenoms[i];
+    // FIXME: Do in one transaction!
+    const denom = await ws.db
+      .mktx((x) => ({ denominations: x.denominations }))
+      .runReadOnly(async (tx) => {
+        return ws.getDenomInfo(ws, tx, exchangeBaseUrl, ds.denomPubHash);
+      });
+    checkDbInvariant(!!denom);
+    const expireDeposit = denom.stampExpireDeposit;
+    if (!earliestDepositExpiration) {
+      earliestDepositExpiration = expireDeposit;
+      continue;
+    }
     if (
       AbsoluteTime.cmp(
         AbsoluteTime.fromTimestamp(expireDeposit),
@@ -1021,6 +1051,8 @@ export async function getExchangeWithdrawalInfo(
     }
   }
 
+  checkLogicInvariant(!!earliestDepositExpiration);
+
   const possibleDenoms = await ws.db
     .mktx((x) => ({ denominations: x.denominations }))
     .runReadOnly(async (tx) => {
diff --git a/packages/taler-wallet-core/src/wallet.ts 
b/packages/taler-wallet-core/src/wallet.ts
index b0bd2a2c..673a8616 100644
--- a/packages/taler-wallet-core/src/wallet.ts
+++ b/packages/taler-wallet-core/src/wallet.ts
@@ -598,18 +598,6 @@ async function getExchanges(
   return { exchanges };
 }
 
-async function acceptWithdrawal(
-  ws: InternalWalletState,
-  talerWithdrawUri: string,
-  selectedExchange: string,
-): Promise<AcceptWithdrawalResponse> {
-  try {
-    return createTalerWithdrawReserve(ws, talerWithdrawUri, selectedExchange);
-  } finally {
-    ws.latch.trigger();
-  }
-}
-
 /**
  * Inform the wallet that the status of a reserve has changed (e.g. due to a
  * confirmation from the bank.).
@@ -849,10 +837,13 @@ async function dispatchRequestInternal(
     case "acceptBankIntegratedWithdrawal": {
       const req =
         codecForAcceptBankIntegratedWithdrawalRequest().decode(payload);
-      return await acceptWithdrawal(
+      return await createTalerWithdrawReserve(
         ws,
         req.talerWithdrawUri,
         req.exchangeBaseUrl,
+        {
+          forcedDenomSel: req.forcedDenomSel,
+        },
       );
     }
     case "getExchangeTos": {

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