gnunet-svn
[Top][All Lists]
Advanced

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

[taler-wallet-core] branch master updated: move denom selection to separ


From: gnunet
Subject: [taler-wallet-core] branch master updated: move denom selection to separate file
Date: Wed, 06 Mar 2024 21:00:40 +0100

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 618caa117 move denom selection to separate file
618caa117 is described below

commit 618caa117111b9fed6a792b6816fc724483eb349
Author: Florian Dold <florian@dold.me>
AuthorDate: Wed Mar 6 21:00:34 2024 +0100

    move denom selection to separate file
---
 packages/taler-wallet-core/src/coinSelection.ts  | 205 ++++++-----------------
 packages/taler-wallet-core/src/denomSelection.ts | 150 +++++++++++++++++
 packages/taler-wallet-core/src/refresh.ts        |   2 +-
 packages/taler-wallet-core/src/withdraw.test.ts  |   2 +-
 packages/taler-wallet-core/src/withdraw.ts       |   2 +-
 5 files changed, 205 insertions(+), 156 deletions(-)

diff --git a/packages/taler-wallet-core/src/coinSelection.ts 
b/packages/taler-wallet-core/src/coinSelection.ts
index c44ca3d17..1208e7c37 100644
--- a/packages/taler-wallet-core/src/coinSelection.ts
+++ b/packages/taler-wallet-core/src/coinSelection.ts
@@ -1,6 +1,6 @@
 /*
  This file is part of GNU Taler
- (C) 2021 Taler Systems S.A.
+ (C) 2021-2024 Taler Systems S.A.
 
  GNU Taler is free software; you can redistribute it and/or modify it under the
  terms of the GNU General Public License as published by the Free Software
@@ -39,10 +39,8 @@ import {
   CoinPublicKeyString,
   CoinStatus,
   DenominationInfo,
-  DenomSelectionState,
   Duration,
   ForcedCoinSel,
-  ForcedDenomSel,
   InternationalizedString,
   j2s,
   Logger,
@@ -59,7 +57,6 @@ import {
 } from "./balance.js";
 import { getAutoRefreshExecuteThreshold } from "./common.js";
 import { DenominationRecord, WalletDbReadOnlyTransaction } from "./db.js";
-import { isWithdrawableDenom } from "./denominations.js";
 import {
   ExchangeWireDetails,
   getExchangeWireDetailsInTx,
@@ -292,49 +289,65 @@ export async function selectPayCoins(
         } satisfies SelectPayCoinsResult;
       }
 
-      const finalSel = selectedDenom;
-
-      logger.trace(`coin selection request ${j2s(req)}`);
-      logger.trace(`selected coins (via denoms) for payment: 
${j2s(finalSel)}`);
-
-      for (const dph of Object.keys(finalSel)) {
-        const selInfo = finalSel[dph];
-        const numRequested = selInfo.contributions.length;
-        const query = [
-          selInfo.exchangeBaseUrl,
-          selInfo.denomPubHash,
-          selInfo.maxAge,
-          CoinStatus.Fresh,
-        ];
-        logger.trace(`query: ${j2s(query)}`);
-        const coins =
-          await tx.coins.indexes.byExchangeDenomPubHashAndAgeAndStatus.getAll(
-            query,
-            numRequested,
-          );
-        if (coins.length != numRequested) {
-          throw Error(
-            `coin selection failed (not available anymore, got only 
${coins.length}/${numRequested})`,
-          );
-        }
-        coinPubs.push(...coins.map((x) => x.coinPub));
-        coinContributions.push(...selInfo.contributions);
-      }
+      const coinSel = await assembleSelectPayCoinsSuccessResult(
+        tx,
+        selectedDenom,
+        coinPubs,
+        coinContributions,
+        req.contractTermsAmount,
+        tally,
+      );
 
       return {
         type: "success",
-        coinSel: {
-          paymentAmount: Amounts.stringify(contractTermsAmount),
-          coinContributions: coinContributions.map((x) => 
Amounts.stringify(x)),
-          coinPubs,
-          customerDepositFees: Amounts.stringify(tally.customerDepositFees),
-          customerWireFees: Amounts.stringify(tally.customerWireFees),
-        },
+        coinSel,
       };
     },
   );
 }
 
+async function assembleSelectPayCoinsSuccessResult(
+  tx: WalletDbReadOnlyTransaction<["coins"]>,
+  finalSel: SelResult,
+  coinPubs: string[],
+  coinContributions: AmountJson[],
+  contractTermsAmount: AmountJson,
+  tally: CoinSelectionTally,
+): Promise<PayCoinSelection> {
+  for (const dph of Object.keys(finalSel)) {
+    const selInfo = finalSel[dph];
+    const numRequested = selInfo.contributions.length;
+    const query = [
+      selInfo.exchangeBaseUrl,
+      selInfo.denomPubHash,
+      selInfo.maxAge,
+      CoinStatus.Fresh,
+    ];
+    logger.trace(`query: ${j2s(query)}`);
+    const coins =
+      await tx.coins.indexes.byExchangeDenomPubHashAndAgeAndStatus.getAll(
+        query,
+        numRequested,
+      );
+    if (coins.length != numRequested) {
+      throw Error(
+        `coin selection failed (not available anymore, got only 
${coins.length}/${numRequested})`,
+      );
+    }
+    coinPubs.push(...coins.map((x) => x.coinPub));
+    coinContributions.push(...selInfo.contributions);
+  }
+
+  return {
+    // FIXME: Why do we return this?!
+    paymentAmount: Amounts.stringify(contractTermsAmount),
+    coinContributions: coinContributions.map((x) => Amounts.stringify(x)),
+    coinPubs,
+    customerDepositFees: Amounts.stringify(tally.customerDepositFees),
+    customerWireFees: Amounts.stringify(tally.customerWireFees),
+  };
+}
+
 interface ReportInsufficientBalanceRequest {
   instructedAmount: AmountJson;
   requiredMinimumAge: number | undefined;
@@ -783,120 +796,6 @@ async function selectPayCandidates(
   return [denoms, wfPerExchange];
 }
 
-/**
- * Get a list of denominations (with repetitions possible)
- * whose total value is as close as possible to the available
- * amount, but never larger.
- */
-export function selectWithdrawalDenominations(
-  amountAvailable: AmountJson,
-  denoms: DenominationRecord[],
-  denomselAllowLate: boolean = false,
-): DenomSelectionState {
-  let remaining = Amounts.copy(amountAvailable);
-
-  const selectedDenoms: {
-    count: number;
-    denomPubHash: string;
-  }[] = [];
-
-  let totalCoinValue = Amounts.zeroOfCurrency(amountAvailable.currency);
-  let totalWithdrawCost = Amounts.zeroOfCurrency(amountAvailable.currency);
-
-  denoms = denoms.filter((d) => isWithdrawableDenom(d, denomselAllowLate));
-  denoms.sort((d1, d2) => Amounts.cmp(d2.value, d1.value));
-
-  for (const d of denoms) {
-    const cost = Amounts.add(d.value, d.fees.feeWithdraw).amount;
-    const res = Amounts.divmod(remaining, cost);
-    const count = res.quotient;
-    remaining = Amounts.sub(remaining, Amounts.mult(cost, 
count).amount).amount;
-    if (count > 0) {
-      totalCoinValue = Amounts.add(
-        totalCoinValue,
-        Amounts.mult(d.value, count).amount,
-      ).amount;
-      totalWithdrawCost = Amounts.add(
-        totalWithdrawCost,
-        Amounts.mult(cost, count).amount,
-      ).amount;
-      selectedDenoms.push({
-        count,
-        denomPubHash: d.denomPubHash,
-      });
-    }
-
-    if (Amounts.isZero(remaining)) {
-      break;
-    }
-  }
-
-  if (logger.shouldLogTrace()) {
-    logger.trace(
-      `selected withdrawal denoms for ${Amounts.stringify(totalCoinValue)}`,
-    );
-    for (const sd of selectedDenoms) {
-      logger.trace(`denom_pub_hash=${sd.denomPubHash}, count=${sd.count}`);
-    }
-    logger.trace("(end of withdrawal denom list)");
-  }
-
-  return {
-    selectedDenoms,
-    totalCoinValue: Amounts.stringify(totalCoinValue),
-    totalWithdrawCost: Amounts.stringify(totalWithdrawCost),
-  };
-}
-
-export function selectForcedWithdrawalDenominations(
-  amountAvailable: AmountJson,
-  denoms: DenominationRecord[],
-  forcedDenomSel: ForcedDenomSel,
-  denomselAllowLate: boolean,
-): DenomSelectionState {
-  const selectedDenoms: {
-    count: number;
-    denomPubHash: string;
-  }[] = [];
-
-  let totalCoinValue = Amounts.zeroOfCurrency(amountAvailable.currency);
-  let totalWithdrawCost = Amounts.zeroOfCurrency(amountAvailable.currency);
-
-  denoms = denoms.filter((d) => isWithdrawableDenom(d, denomselAllowLate));
-  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.fees.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: Amounts.stringify(totalCoinValue),
-    totalWithdrawCost: Amounts.stringify(totalWithdrawCost),
-  };
-}
-
 export interface CoinInfo {
   id: string;
   value: AmountJson;
diff --git a/packages/taler-wallet-core/src/denomSelection.ts 
b/packages/taler-wallet-core/src/denomSelection.ts
new file mode 100644
index 000000000..12f8f8971
--- /dev/null
+++ b/packages/taler-wallet-core/src/denomSelection.ts
@@ -0,0 +1,150 @@
+/*
+ This file is part of GNU Taler
+ (C) 2021-2024 Taler Systems S.A.
+
+ GNU Taler is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+
+/**
+ * Selection of denominations for withdrawals.
+ *
+ * @author Florian Dold
+ */
+
+/**
+ * Imports.
+ */
+import {
+  AmountJson,
+  Amounts,
+  DenomSelectionState,
+  ForcedDenomSel,
+  Logger,
+} from "@gnu-taler/taler-util";
+import { DenominationRecord } from "./db.js";
+import { isWithdrawableDenom } from "./denominations.js";
+
+const logger = new Logger("denomSelection.ts");
+
+/**
+ * Get a list of denominations (with repetitions possible)
+ * whose total value is as close as possible to the available
+ * amount, but never larger.
+ */
+export function selectWithdrawalDenominations(
+  amountAvailable: AmountJson,
+  denoms: DenominationRecord[],
+  denomselAllowLate: boolean = false,
+): DenomSelectionState {
+  let remaining = Amounts.copy(amountAvailable);
+
+  const selectedDenoms: {
+    count: number;
+    denomPubHash: string;
+  }[] = [];
+
+  let totalCoinValue = Amounts.zeroOfCurrency(amountAvailable.currency);
+  let totalWithdrawCost = Amounts.zeroOfCurrency(amountAvailable.currency);
+
+  denoms = denoms.filter((d) => isWithdrawableDenom(d, denomselAllowLate));
+  denoms.sort((d1, d2) => Amounts.cmp(d2.value, d1.value));
+
+  for (const d of denoms) {
+    const cost = Amounts.add(d.value, d.fees.feeWithdraw).amount;
+    const res = Amounts.divmod(remaining, cost);
+    const count = res.quotient;
+    remaining = Amounts.sub(remaining, Amounts.mult(cost, 
count).amount).amount;
+    if (count > 0) {
+      totalCoinValue = Amounts.add(
+        totalCoinValue,
+        Amounts.mult(d.value, count).amount,
+      ).amount;
+      totalWithdrawCost = Amounts.add(
+        totalWithdrawCost,
+        Amounts.mult(cost, count).amount,
+      ).amount;
+      selectedDenoms.push({
+        count,
+        denomPubHash: d.denomPubHash,
+      });
+    }
+
+    if (Amounts.isZero(remaining)) {
+      break;
+    }
+  }
+
+  if (logger.shouldLogTrace()) {
+    logger.trace(
+      `selected withdrawal denoms for ${Amounts.stringify(totalCoinValue)}`,
+    );
+    for (const sd of selectedDenoms) {
+      logger.trace(`denom_pub_hash=${sd.denomPubHash}, count=${sd.count}`);
+    }
+    logger.trace("(end of withdrawal denom list)");
+  }
+
+  return {
+    selectedDenoms,
+    totalCoinValue: Amounts.stringify(totalCoinValue),
+    totalWithdrawCost: Amounts.stringify(totalWithdrawCost),
+  };
+}
+
+export function selectForcedWithdrawalDenominations(
+  amountAvailable: AmountJson,
+  denoms: DenominationRecord[],
+  forcedDenomSel: ForcedDenomSel,
+  denomselAllowLate: boolean,
+): DenomSelectionState {
+  const selectedDenoms: {
+    count: number;
+    denomPubHash: string;
+  }[] = [];
+
+  let totalCoinValue = Amounts.zeroOfCurrency(amountAvailable.currency);
+  let totalWithdrawCost = Amounts.zeroOfCurrency(amountAvailable.currency);
+
+  denoms = denoms.filter((d) => isWithdrawableDenom(d, denomselAllowLate));
+  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.fees.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: Amounts.stringify(totalCoinValue),
+    totalWithdrawCost: Amounts.stringify(totalWithdrawCost),
+  };
+}
diff --git a/packages/taler-wallet-core/src/refresh.ts 
b/packages/taler-wallet-core/src/refresh.ts
index 9c272ad18..c6a7b768d 100644
--- a/packages/taler-wallet-core/src/refresh.ts
+++ b/packages/taler-wallet-core/src/refresh.ts
@@ -61,7 +61,7 @@ import {
   readSuccessResponseJsonOrThrow,
   readUnexpectedResponseDetails,
 } from "@gnu-taler/taler-util/http";
-import { selectWithdrawalDenominations } from "./coinSelection.js";
+import { selectWithdrawalDenominations } from "./denomSelection.js";
 import {
   constructTaskIdentifier,
   makeCoinAvailable,
diff --git a/packages/taler-wallet-core/src/withdraw.test.ts 
b/packages/taler-wallet-core/src/withdraw.test.ts
index 3e92b1717..d8757d0cf 100644
--- a/packages/taler-wallet-core/src/withdraw.test.ts
+++ b/packages/taler-wallet-core/src/withdraw.test.ts
@@ -21,7 +21,7 @@ import {
   DenominationVerificationStatus,
   timestampProtocolToDb,
 } from "./db.js";
-import { selectWithdrawalDenominations } from "./coinSelection.js";
+import { selectWithdrawalDenominations } from "./denomSelection.js";
 
 test("withdrawal selection bug repro", (t) => {
   const amount = {
diff --git a/packages/taler-wallet-core/src/withdraw.ts 
b/packages/taler-wallet-core/src/withdraw.ts
index 853a5e0df..0f70479a5 100644
--- a/packages/taler-wallet-core/src/withdraw.ts
+++ b/packages/taler-wallet-core/src/withdraw.ts
@@ -97,7 +97,7 @@ import {
 import {
   selectForcedWithdrawalDenominations,
   selectWithdrawalDenominations,
-} from "./coinSelection.js";
+} from "./denomSelection.js";
 import {
   PendingTaskType,
   TaskIdStr,

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