gnunet-svn
[Top][All Lists]
Advanced

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

[taler-wallet-core] branch master updated: prevent conflicting coin allo


From: gnunet
Subject: [taler-wallet-core] branch master updated: prevent conflicting coin allocation with concurrent payments
Date: Tue, 22 Jun 2021 18:43:17 +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 09d1dd83 prevent conflicting coin allocation with concurrent payments
09d1dd83 is described below

commit 09d1dd83ec1bf9ca16841d0afb18b9a7da705bcb
Author: Florian Dold <florian@dold.me>
AuthorDate: Tue Jun 22 18:43:11 2021 +0200

    prevent conflicting coin allocation with concurrent payments
---
 packages/taler-wallet-core/src/db.ts               | 13 +++++++++
 .../taler-wallet-core/src/operations/deposits.ts   | 12 ++++++--
 packages/taler-wallet-core/src/operations/pay.ts   | 33 ++++++++++++++--------
 3 files changed, 44 insertions(+), 14 deletions(-)

diff --git a/packages/taler-wallet-core/src/db.ts 
b/packages/taler-wallet-core/src/db.ts
index 2d2c0615..36b4e086 100644
--- a/packages/taler-wallet-core/src/db.ts
+++ b/packages/taler-wallet-core/src/db.ts
@@ -848,6 +848,17 @@ export interface CoinRecord {
    * Status of the coin.
    */
   status: CoinStatus;
+
+  /**
+   * Information about what the coin has been allocated for.
+   * Used to prevent allocation of the same coin for two different payments.
+   */
+  allocation?: CoinAllocation;
+}
+
+export interface CoinAllocation {
+  id: string;
+  amount: AmountString;
 }
 
 export enum ProposalStatus {
@@ -1643,6 +1654,8 @@ export interface DepositGroupRecord {
 
   payCoinSelection: PayCoinSelection;
 
+  payCoinSelectionUid: string;
+
   totalPayCost: AmountJson;
 
   effectiveDepositAmount: AmountJson;
diff --git a/packages/taler-wallet-core/src/operations/deposits.ts 
b/packages/taler-wallet-core/src/operations/deposits.ts
index 9dee7557..c788a9ea 100644
--- a/packages/taler-wallet-core/src/operations/deposits.ts
+++ b/packages/taler-wallet-core/src/operations/deposits.ts
@@ -36,7 +36,7 @@ import {
   timestampTruncateToSecond,
   TrackDepositGroupRequest,
   TrackDepositGroupResponse,
-  URL
+  URL,
 } from "@gnu-taler/taler-util";
 import { InternalWalletState } from "../common.js";
 import { kdf } from "../crypto/primitives/kdf.js";
@@ -433,7 +433,8 @@ export async function createDepositGroup(
     timestampCreated: timestamp,
     timestampFinished: undefined,
     payCoinSelection: payCoinSel,
-    depositedPerCoin: payCoinSel.coinPubs.map((x) => false),
+    payCoinSelectionUid: encodeCrock(getRandomBytes(32)),
+    depositedPerCoin: payCoinSel.coinPubs.map(() => false),
     merchantPriv: merchantPair.priv,
     merchantPub: merchantPair.pub,
     totalPayCost: totalDepositCost,
@@ -454,7 +455,12 @@ export async function createDepositGroup(
       denominations: x.denominations,
     }))
     .runReadWrite(async (tx) => {
-      await applyCoinSpend(ws, tx, payCoinSel);
+      await applyCoinSpend(
+        ws,
+        tx,
+        payCoinSel,
+        `deposit-group:${depositGroup.depositGroupId}`,
+      );
       await tx.depositGroups.put(depositGroup);
     });
 
diff --git a/packages/taler-wallet-core/src/operations/pay.ts 
b/packages/taler-wallet-core/src/operations/pay.ts
index 71f11c96..280586c3 100644
--- a/packages/taler-wallet-core/src/operations/pay.ts
+++ b/packages/taler-wallet-core/src/operations/pay.ts
@@ -385,24 +385,34 @@ export async function applyCoinSpend(
     denominations: typeof WalletStoresV1.denominations;
   }>,
   coinSelection: PayCoinSelection,
+  allocationId: string,
 ) {
   for (let i = 0; i < coinSelection.coinPubs.length; i++) {
     const coin = await tx.coins.get(coinSelection.coinPubs[i]);
     if (!coin) {
       throw Error("coin allocated for payment doesn't exist anymore");
     }
+    const contrib = coinSelection.coinContributions[i];
     if (coin.status !== CoinStatus.Fresh) {
-      // applyCoinSpend was called again, probably
-      // because of a coin re-selection to recover after
-      // accidental double spending.
-      // Ignore coins we already marked as spent.
-      continue;
+      const alloc = coin.allocation;
+      if (!alloc) {
+        continue;
+      }
+      if (alloc.id !== allocationId) {
+        // FIXME: assign error code
+        throw Error("conflicting coin allocation (id)");
+      }
+      if (0 !== Amounts.cmp(alloc.amount, contrib)) {
+        // FIXME: assign error code
+        throw Error("conflicting coin allocation (contrib)");
+      }
     }
     coin.status = CoinStatus.Dormant;
-    const remaining = Amounts.sub(
-      coin.currentAmount,
-      coinSelection.coinContributions[i],
-    );
+    coin.allocation = {
+      id: allocationId,
+      amount: Amounts.stringify(contrib),
+    };
+    const remaining = Amounts.sub(coin.currentAmount, contrib);
     if (remaining.saturated) {
       throw Error("not enough remaining balance on coin for payment");
     }
@@ -482,7 +492,7 @@ async function recordConfirmPay(
         await tx.proposals.put(p);
       }
       await tx.purchases.put(t);
-      await applyCoinSpend(ws, tx, coinSelection);
+      await applyCoinSpend(ws, tx, coinSelection, `proposal:${t.proposalId}`);
     });
 
   ws.notify({
@@ -1082,9 +1092,10 @@ async function handleInsufficientFunds(
         return;
       }
       p.payCoinSelection = res;
+      p.payCoinSelectionUid = encodeCrock(getRandomBytes(32));
       p.coinDepositPermissions = undefined;
       await tx.purchases.put(p);
-      await applyCoinSpend(ws, tx, res);
+      await applyCoinSpend(ws, tx, res, `proposal:${p.proposalId}`);
     });
 }
 

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