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-core: fix revocation,


From: gnunet
Subject: [taler-wallet-core] branch master updated: wallet-core: fix revocation, re-introduce reserves object store
Date: Fri, 26 Aug 2022 01:18:04 +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 30e8fd83 wallet-core: fix revocation, re-introduce reserves object 
store
30e8fd83 is described below

commit 30e8fd83c256826fc995edae499bf8bb6b60b7f2
Author: Florian Dold <florian@dold.me>
AuthorDate: Fri Aug 26 01:18:01 2022 +0200

    wallet-core: fix revocation, re-introduce reserves object store
---
 .../src/integrationtests/test-libeufin-basic.ts    |   2 +-
 .../test-libeufin-nexus-balance.ts                 |  15 ++-
 .../src/integrationtests/testrunner.ts             | 106 ++++++++--------
 packages/taler-wallet-core/src/db.ts               |  29 ++++-
 .../taler-wallet-core/src/internal-wallet-state.ts |   2 +-
 .../taler-wallet-core/src/operations/exchanges.ts  |   1 +
 .../taler-wallet-core/src/operations/pending.ts    |   2 +-
 .../taler-wallet-core/src/operations/recoup.ts     | 134 +++++++++++++++------
 .../taler-wallet-core/src/operations/withdraw.ts   |  23 +++-
 packages/taler-wallet-core/src/pending-types.ts    |   2 +-
 10 files changed, 211 insertions(+), 105 deletions(-)

diff --git 
a/packages/taler-wallet-cli/src/integrationtests/test-libeufin-basic.ts 
b/packages/taler-wallet-cli/src/integrationtests/test-libeufin-basic.ts
index ca7dc33d..83231b35 100644
--- a/packages/taler-wallet-cli/src/integrationtests/test-libeufin-basic.ts
+++ b/packages/taler-wallet-cli/src/integrationtests/test-libeufin-basic.ts
@@ -243,7 +243,7 @@ export async function runLibeufinBasicTest(t: 
GlobalTestState) {
     WalletApiOperation.AcceptManualWithdrawal,
     {
       exchangeBaseUrl: exchange.baseUrl,
-      amount: "EUR:10",
+      amount: "EUR:15",
     },
   );
 
diff --git 
a/packages/taler-wallet-cli/src/integrationtests/test-libeufin-nexus-balance.ts 
b/packages/taler-wallet-cli/src/integrationtests/test-libeufin-nexus-balance.ts
index 23d76081..ff7a50ae 100644
--- 
a/packages/taler-wallet-cli/src/integrationtests/test-libeufin-nexus-balance.ts
+++ 
b/packages/taler-wallet-cli/src/integrationtests/test-libeufin-nexus-balance.ts
@@ -17,12 +17,11 @@
 /**
  * Imports.
  */
-import { GlobalTestState, delayMs } from "../harness/harness.js";
+import { GlobalTestState } from "../harness/harness.js";
 import {
   SandboxUserBundle,
   NexusUserBundle,
   launchLibeufinServices,
-  LibeufinSandboxApi,
   LibeufinNexusApi,
 } from "../harness/libeufin";
 
@@ -73,7 +72,7 @@ export async function runLibeufinNexusBalanceTest(t: 
GlobalTestState) {
     user02sandbox.ebicsBankAccount.label, // debit
     user01sandbox.ebicsBankAccount.label, // credit
     "EUR:10",
-    "first payment",
+    "second payment",
   );
 
   await LibeufinNexusApi.fetchTransactions(
@@ -82,13 +81,13 @@ export async function runLibeufinNexusBalanceTest(t: 
GlobalTestState) {
     "all", // range
     "report", // level
   );
-  
+
   // Check that user 01 has 20, via Nexus.
   let accountInfo = await LibeufinNexusApi.getBankAccount(
     libeufinServices.libeufinNexus,
-    user01nexus.localAccountName
+    user01nexus.localAccountName,
   );
-  t.assertTrue(accountInfo.data.lastSeenBalance == "EUR:20");
+  t.assertAmountEquals(accountInfo.data.lastSeenBalance, "EUR:20");
 
   // user 01 gives 30
   await libeufinServices.libeufinSandbox.makeTransaction(
@@ -107,8 +106,8 @@ export async function runLibeufinNexusBalanceTest(t: 
GlobalTestState) {
 
   let accountInfoDebit = await LibeufinNexusApi.getBankAccount(
     libeufinServices.libeufinNexus,
-    user01nexus.localAccountName
+    user01nexus.localAccountName,
   );
-  t.assertTrue(accountInfoDebit.data.lastSeenBalance == "-EUR:10");
+  t.assertDeepEqual(accountInfoDebit.data.lastSeenBalance, "-EUR:10");
 }
 runLibeufinNexusBalanceTest.suites = ["libeufin"];
diff --git a/packages/taler-wallet-cli/src/integrationtests/testrunner.ts 
b/packages/taler-wallet-cli/src/integrationtests/testrunner.ts
index 88e67a8b..74aa6600 100644
--- a/packages/taler-wallet-cli/src/integrationtests/testrunner.ts
+++ b/packages/taler-wallet-cli/src/integrationtests/testrunner.ts
@@ -26,71 +26,71 @@ import {
   TestRunResult,
 } from "../harness/harness.js";
 import { runAgeRestrictionsTest } from "./test-age-restrictions.js";
-import { runBankApiTest } from "./test-bank-api";
-import { runClaimLoopTest } from "./test-claim-loop";
+import { runBankApiTest } from "./test-bank-api.js";
+import { runClaimLoopTest } from "./test-claim-loop.js";
 import { runClauseSchnorrTest } from "./test-clause-schnorr.js";
 import { runDenomUnofferedTest } from "./test-denom-unoffered.js";
-import { runDepositTest } from "./test-deposit";
-import { runExchangeManagementTest } from "./test-exchange-management";
+import { runDepositTest } from "./test-deposit.js";
+import { runExchangeManagementTest } from "./test-exchange-management.js";
 import { runExchangeTimetravelTest } from "./test-exchange-timetravel.js";
-import { runFeeRegressionTest } from "./test-fee-regression";
+import { runFeeRegressionTest } from "./test-fee-regression.js";
 import { runForcedSelectionTest } from "./test-forced-selection.js";
-import { runLibeufinApiBankaccountTest } from 
"./test-libeufin-api-bankaccount";
-import { runLibeufinApiBankconnectionTest } from 
"./test-libeufin-api-bankconnection";
-import { runLibeufinApiFacadeTest } from "./test-libeufin-api-facade";
-import { runLibeufinApiFacadeBadRequestTest } from 
"./test-libeufin-api-facade-bad-request";
-import { runLibeufinApiPermissionsTest } from 
"./test-libeufin-api-permissions";
-import { runLibeufinApiSandboxCamtTest } from 
"./test-libeufin-api-sandbox-camt";
-import { runLibeufinApiSandboxTransactionsTest } from 
"./test-libeufin-api-sandbox-transactions";
-import { runLibeufinApiSchedulingTest } from "./test-libeufin-api-scheduling";
-import { runLibeufinApiUsersTest } from "./test-libeufin-api-users";
-import { runLibeufinBadGatewayTest } from "./test-libeufin-bad-gateway";
-import { runLibeufinBasicTest } from "./test-libeufin-basic";
-import { runLibeufinC5xTest } from "./test-libeufin-c5x";
-import { runLibeufinAnastasisFacadeTest } from 
"./test-libeufin-facade-anastasis";
-import { runLibeufinKeyrotationTest } from "./test-libeufin-keyrotation";
-import { runLibeufinNexusBalanceTest } from "./test-libeufin-nexus-balance";
-import { runLibeufinRefundTest } from "./test-libeufin-refund";
-import { runLibeufinRefundMultipleUsersTest } from 
"./test-libeufin-refund-multiple-users";
-import { runLibeufinSandboxWireTransferCliTest } from 
"./test-libeufin-sandbox-wire-transfer-cli";
-import { runLibeufinTutorialTest } from "./test-libeufin-tutorial";
-import { runMerchantExchangeConfusionTest } from 
"./test-merchant-exchange-confusion";
-import { runMerchantInstancesTest } from "./test-merchant-instances";
+import { runLibeufinApiBankaccountTest } from 
"./test-libeufin-api-bankaccount.js";
+import { runLibeufinApiBankconnectionTest } from 
"./test-libeufin-api-bankconnection.js";
+import { runLibeufinApiFacadeTest } from "./test-libeufin-api-facade.js";
+import { runLibeufinApiFacadeBadRequestTest } from 
"./test-libeufin-api-facade-bad-request.js";
+import { runLibeufinApiPermissionsTest } from 
"./test-libeufin-api-permissions.js";
+import { runLibeufinApiSandboxCamtTest } from 
"./test-libeufin-api-sandbox-camt.js";
+import { runLibeufinApiSandboxTransactionsTest } from 
"./test-libeufin-api-sandbox-transactions.js";
+import { runLibeufinApiSchedulingTest } from 
"./test-libeufin-api-scheduling.js";
+import { runLibeufinApiUsersTest } from "./test-libeufin-api-users.js";
+import { runLibeufinBadGatewayTest } from "./test-libeufin-bad-gateway.js";
+import { runLibeufinBasicTest } from "./test-libeufin-basic.js";
+import { runLibeufinC5xTest } from "./test-libeufin-c5x.js";
+import { runLibeufinAnastasisFacadeTest } from 
"./test-libeufin-facade-anastasis.js";
+import { runLibeufinKeyrotationTest } from "./test-libeufin-keyrotation.js";
+import { runLibeufinNexusBalanceTest } from "./test-libeufin-nexus-balance.js";
+import { runLibeufinRefundTest } from "./test-libeufin-refund.js";
+import { runLibeufinRefundMultipleUsersTest } from 
"./test-libeufin-refund-multiple-users.js";
+import { runLibeufinSandboxWireTransferCliTest } from 
"./test-libeufin-sandbox-wire-transfer-cli.js";
+import { runLibeufinTutorialTest } from "./test-libeufin-tutorial.js";
+import { runMerchantExchangeConfusionTest } from 
"./test-merchant-exchange-confusion.js";
+import { runMerchantInstancesTest } from "./test-merchant-instances.js";
 import { runMerchantInstancesDeleteTest } from 
"./test-merchant-instances-delete";
-import { runMerchantInstancesUrlsTest } from "./test-merchant-instances-urls";
-import { runMerchantLongpollingTest } from "./test-merchant-longpolling";
-import { runMerchantRefundApiTest } from "./test-merchant-refund-api";
+import { runMerchantInstancesUrlsTest } from 
"./test-merchant-instances-urls.js";
+import { runMerchantLongpollingTest } from "./test-merchant-longpolling.js";
+import { runMerchantRefundApiTest } from "./test-merchant-refund-api.js";
 import { runMerchantSpecPublicOrdersTest } from 
"./test-merchant-spec-public-orders.js";
-import { runPayAbortTest } from "./test-pay-abort";
-import { runPayPaidTest } from "./test-pay-paid";
-import { runPaymentTest } from "./test-payment";
-import { runPaymentClaimTest } from "./test-payment-claim";
-import { runPaymentFaultTest } from "./test-payment-fault";
+import { runPayAbortTest } from "./test-pay-abort.js";
+import { runPayPaidTest } from "./test-pay-paid.js";
+import { runPaymentTest } from "./test-payment.js";
+import { runPaymentClaimTest } from "./test-payment-claim.js";
+import { runPaymentFaultTest } from "./test-payment-fault.js";
 import { runPaymentForgettableTest } from "./test-payment-forgettable.js";
-import { runPaymentIdempotencyTest } from "./test-payment-idempotency";
-import { runPaymentMultipleTest } from "./test-payment-multiple";
-import { runPaymentDemoTest } from "./test-payment-on-demo";
-import { runPaymentTransientTest } from "./test-payment-transient";
+import { runPaymentIdempotencyTest } from "./test-payment-idempotency.js";
+import { runPaymentMultipleTest } from "./test-payment-multiple.js";
+import { runPaymentDemoTest } from "./test-payment-on-demo.js";
+import { runPaymentTransientTest } from "./test-payment-transient.js";
 import { runPaymentZeroTest } from "./test-payment-zero.js";
-import { runPaywallFlowTest } from "./test-paywall-flow";
+import { runPaywallFlowTest } from "./test-paywall-flow.js";
 import { runPeerToPeerPullTest } from "./test-peer-to-peer-pull.js";
 import { runPeerToPeerPushTest } from "./test-peer-to-peer-push.js";
-import { runRefundTest } from "./test-refund";
-import { runRefundAutoTest } from "./test-refund-auto";
-import { runRefundGoneTest } from "./test-refund-gone";
-import { runRefundIncrementalTest } from "./test-refund-incremental";
-import { runRevocationTest } from "./test-revocation";
-import { runTimetravelAutorefreshTest } from "./test-timetravel-autorefresh";
-import { runTimetravelWithdrawTest } from "./test-timetravel-withdraw";
-import { runTippingTest } from "./test-tipping";
-import { runWalletBackupBasicTest } from "./test-wallet-backup-basic";
-import { runWalletBackupDoublespendTest } from 
"./test-wallet-backup-doublespend";
+import { runRefundTest } from "./test-refund.js";
+import { runRefundAutoTest } from "./test-refund-auto.js";
+import { runRefundGoneTest } from "./test-refund-gone.js";
+import { runRefundIncrementalTest } from "./test-refund-incremental.js";
+import { runRevocationTest } from "./test-revocation.js";
+import { runTimetravelAutorefreshTest } from 
"./test-timetravel-autorefresh.js";
+import { runTimetravelWithdrawTest } from "./test-timetravel-withdraw.js";
+import { runTippingTest } from "./test-tipping.js";
+import { runWalletBackupBasicTest } from "./test-wallet-backup-basic.js";
+import { runWalletBackupDoublespendTest } from 
"./test-wallet-backup-doublespend.js";
 import { runWalletDblessTest } from "./test-wallet-dbless.js";
-import { runWallettestingTest } from "./test-wallettesting";
-import { runWithdrawalAbortBankTest } from "./test-withdrawal-abort-bank";
-import { runWithdrawalBankIntegratedTest } from 
"./test-withdrawal-bank-integrated";
+import { runWallettestingTest } from "./test-wallettesting.js";
+import { runWithdrawalAbortBankTest } from "./test-withdrawal-abort-bank.js";
+import { runWithdrawalBankIntegratedTest } from 
"./test-withdrawal-bank-integrated.js";
 import { runWithdrawalFakebankTest } from "./test-withdrawal-fakebank.js";
-import { runTestWithdrawalManualTest } from "./test-withdrawal-manual";
+import { runTestWithdrawalManualTest } from "./test-withdrawal-manual.js";
 
 /**
  * Test runner.
diff --git a/packages/taler-wallet-core/src/db.ts 
b/packages/taler-wallet-core/src/db.ts
index 7ba0fadc..3f97be04 100644
--- a/packages/taler-wallet-core/src/db.ts
+++ b/packages/taler-wallet-core/src/db.ts
@@ -1224,6 +1224,7 @@ export const enum WithdrawalRecordType {
   BankIntegrated = "bank-integrated",
   PeerPullCredit = "peer-pull-credit",
   PeerPushCredit = "peer-push-credit",
+  Recoup = "recoup",
 }
 
 export interface WgInfoBankIntegrated {
@@ -1253,11 +1254,16 @@ export interface WgInfoBankPeerPush {
   withdrawalType: WithdrawalRecordType.PeerPushCredit;
 }
 
+export interface WgInfoBankRecoup {
+  withdrawalType: WithdrawalRecordType.Recoup;
+}
+
 export type WgInfo =
   | WgInfoBankIntegrated
   | WgInfoBankManual
   | WgInfoBankPeerPull
-  | WgInfoBankPeerPush;
+  | WgInfoBankPeerPush
+  | WgInfoBankRecoup;
 
 /**
  * Group of withdrawal operations that need to be executed.
@@ -1287,6 +1293,8 @@ export interface WithdrawalGroupRecord {
 
   /**
    * The reserve private key.
+   *
+   * FIXME: Already in the reserves object store, redundant!
    */
   reservePriv: string;
 
@@ -1355,9 +1363,9 @@ export interface WithdrawalGroupRecord {
   denomSelUid: string;
 
   /**
-   * Retry info, always present even on completed operations so that indexing 
works.
+   * Retry info.
    */
-  retryInfo: RetryInfo;
+  retryInfo?: RetryInfo;
 
   lastError: TalerErrorDetail | undefined;
 }
@@ -1386,6 +1394,8 @@ export interface RecoupGroupRecord {
    */
   recoupGroupId: string;
 
+  exchangeBaseUrl: string;
+
   timestampStarted: TalerProtocolTimestamp;
 
   timestampFinished: TalerProtocolTimestamp | undefined;
@@ -1724,6 +1734,13 @@ export interface PeerPullPaymentIncomingRecord {
   contractPriv: string;
 }
 
+// FIXME: give this some smaller "row ID" to
+// reference in other records?
+export interface ReserveRecord {
+  reservePub: string;
+  reservePriv: string;
+}
+
 export const WalletStoresV1 = {
   coins: describeStore(
     describeContents<CoinRecord>("coins", {
@@ -1735,6 +1752,12 @@ export const WalletStoresV1 = {
       byCoinEvHash: describeIndex("byCoinEvHash", "coinEvHash"),
     },
   ),
+  reserves: describeStore(
+    describeContents<ReserveRecord>("reserves", {
+      keyPath: "reservePub",
+    }),
+    {},
+  ),
   config: describeStore(
     describeContents<ConfigRecord>("config", { keyPath: "key" }),
     {},
diff --git a/packages/taler-wallet-core/src/internal-wallet-state.ts 
b/packages/taler-wallet-core/src/internal-wallet-state.ts
index 0650ed04..e82bc139 100644
--- a/packages/taler-wallet-core/src/internal-wallet-state.ts
+++ b/packages/taler-wallet-core/src/internal-wallet-state.ts
@@ -73,7 +73,6 @@ export interface MerchantOperations {
   ): Promise<MerchantInfo>;
 }
 
-
 /**
  * Interface for exchange-related operations.
  */
@@ -113,6 +112,7 @@ export interface RecoupOperations {
       refreshGroups: typeof WalletStoresV1.refreshGroups;
       coins: typeof WalletStoresV1.coins;
     }>,
+    exchangeBaseUrl: string,
     coinPubs: string[],
   ): Promise<string>;
   processRecoupGroup(
diff --git a/packages/taler-wallet-core/src/operations/exchanges.ts 
b/packages/taler-wallet-core/src/operations/exchanges.ts
index 94ea2cb9..b75bdfd7 100644
--- a/packages/taler-wallet-core/src/operations/exchanges.ts
+++ b/packages/taler-wallet-core/src/operations/exchanges.ts
@@ -743,6 +743,7 @@ async function updateExchangeFromUrlImpl(
         recoupGroupId = await ws.recoupOps.createRecoupGroup(
           ws,
           tx,
+          exchange.baseUrl,
           newlyRevokedCoinPubs,
         );
       }
diff --git a/packages/taler-wallet-core/src/operations/pending.ts 
b/packages/taler-wallet-core/src/operations/pending.ts
index ae93711f..38146f72 100644
--- a/packages/taler-wallet-core/src/operations/pending.ts
+++ b/packages/taler-wallet-core/src/operations/pending.ts
@@ -126,7 +126,7 @@ async function gatherWithdrawalPending(
     resp.pendingOperations.push({
       type: PendingTaskType.Withdraw,
       givesLifeness: true,
-      timestampDue: wsr.retryInfo.nextRetry,
+      timestampDue: wsr.retryInfo?.nextRetry ?? AbsoluteTime.now(),
       withdrawalGroupId: wsr.withdrawalGroupId,
       lastError: wsr.lastError,
       retryInfo: wsr.retryInfo,
diff --git a/packages/taler-wallet-core/src/operations/recoup.ts 
b/packages/taler-wallet-core/src/operations/recoup.ts
index 7c0f79da..28370794 100644
--- a/packages/taler-wallet-core/src/operations/recoup.ts
+++ b/packages/taler-wallet-core/src/operations/recoup.ts
@@ -36,16 +36,17 @@ import {
   TalerErrorDetail,
   TalerProtocolTimestamp,
   URL,
+  codecForReserveStatus,
 } from "@gnu-taler/taler-util";
 import {
   CoinRecord,
   CoinSourceType,
   CoinStatus,
-  OperationStatus,
   RecoupGroupRecord,
   RefreshCoinSource,
   ReserveRecordStatus,
   WalletStoresV1,
+  WithdrawalRecordType,
   WithdrawCoinSource,
 } from "../db.js";
 import { InternalWalletState } from "../internal-wallet-state.js";
@@ -109,6 +110,10 @@ async function reportRecoupError(
   ws.notify({ type: NotificationType.RecoupOperationError, error: err });
 }
 
+/**
+ * Store a recoup group record in the database after marking
+ * a coin in the group as finished.
+ */
 async function putGroupAsFinished(
   ws: InternalWalletState,
   tx: GetReadWriteAccess<{
@@ -127,29 +132,6 @@ async function putGroupAsFinished(
     return;
   }
   recoupGroup.recoupFinishedPerCoin[coinIdx] = true;
-  let allFinished = true;
-  for (const b of recoupGroup.recoupFinishedPerCoin) {
-    if (!b) {
-      allFinished = false;
-    }
-  }
-  if (allFinished) {
-    logger.info("all recoups of recoup group are finished");
-    recoupGroup.timestampFinished = TalerProtocolTimestamp.now();
-    recoupGroup.retryInfo = RetryInfo.reset();
-    recoupGroup.lastError = undefined;
-    if (recoupGroup.scheduleRefreshCoins.length > 0) {
-      const refreshGroupId = await createRefreshGroup(
-        ws,
-        tx,
-        recoupGroup.scheduleRefreshCoins.map((x) => ({ coinPub: x })),
-        RefreshReason.Recoup,
-      );
-      processRefreshGroup(ws, refreshGroupId.refreshGroupId).catch((e) => {
-        logger.error(`error while refreshing after recoup ${e}`);
-      });
-    }
-  }
   await tx.recoupGroups.put(recoupGroup);
 }
 
@@ -258,8 +240,6 @@ async function recoupWithdrawCoin(
       const currency = updatedCoin.currentAmount.currency;
       updatedCoin.currentAmount = Amounts.getZero(currency);
       await tx.coins.put(updatedCoin);
-      // FIXME: Actually withdraw here!
-      // await internalCreateWithdrawalGroup(ws, {...});
       await putGroupAsFinished(ws, tx, recoupGroup, coinIdx);
     });
 
@@ -392,7 +372,7 @@ async function processRecoupGroupImpl(
 ): Promise<void> {
   const forceNow = options.forceNow ?? false;
   await setupRecoupRetry(ws, recoupGroupId, { reset: forceNow });
-  const recoupGroup = await ws.db
+  let recoupGroup = await ws.db
     .mktx((x) => ({
       recoupGroups: x.recoupGroups,
     }))
@@ -416,23 +396,105 @@ async function processRecoupGroupImpl(
   });
   await Promise.all(ps);
 
+  recoupGroup = await ws.db
+    .mktx((x) => ({
+      recoupGroups: x.recoupGroups,
+    }))
+    .runReadOnly(async (tx) => {
+      return tx.recoupGroups.get(recoupGroupId);
+    });
+  if (!recoupGroup) {
+    return;
+  }
+
+  for (const b of recoupGroup.recoupFinishedPerCoin) {
+    if (!b) {
+      return;
+    }
+  }
+
+  logger.info("all recoups of recoup group are finished");
+
   const reserveSet = new Set<string>();
+  const reservePrivMap: Record<string, string> = {};
   for (let i = 0; i < recoupGroup.coinPubs.length; i++) {
     const coinPub = recoupGroup.coinPubs[i];
-    const coin = await ws.db
+    await ws.db
       .mktx((x) => ({
         coins: x.coins,
+        reserves: x.reserves,
       }))
       .runReadOnly(async (tx) => {
-        return tx.coins.get(coinPub);
+        const coin = await tx.coins.get(coinPub);
+        if (!coin) {
+          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);
+          if (!reserve) {
+            return;
+          }
+          reserveSet.add(coin.coinSource.reservePub);
+          reservePrivMap[coin.coinSource.reservePub] = reserve.reservePriv;
+        }
       });
-    if (!coin) {
-      throw Error(`Coin ${coinPub} not found, can't request recoup`);
-    }
-    if (coin.coinSource.type === CoinSourceType.Withdraw) {
-      reserveSet.add(coin.coinSource.reservePub);
-    }
   }
+
+  for (const reservePub of reserveSet) {
+    const reserveUrl = new URL(
+      `reserves/${reservePub}`,
+      recoupGroup.exchangeBaseUrl,
+    );
+    logger.info(`querying reserve status for recoup via ${reserveUrl}`);
+
+    const resp = await ws.http.get(reserveUrl.href);
+
+    const result = await readSuccessResponseJsonOrThrow(
+      resp,
+      codecForReserveStatus(),
+    );
+    await internalCreateWithdrawalGroup(ws, {
+      amount: Amounts.parseOrThrow(result.balance),
+      exchangeBaseUrl: recoupGroup.exchangeBaseUrl,
+      reserveStatus: ReserveRecordStatus.QueryingStatus,
+      reserveKeyPair: {
+        pub: reservePub,
+        priv: reservePrivMap[reservePub],
+      },
+      wgInfo: {
+        withdrawalType: WithdrawalRecordType.Recoup,
+      },
+    });
+  }
+
+  await ws.db
+    .mktx((x) => ({
+      recoupGroups: x.recoupGroups,
+      denominations: WalletStoresV1.denominations,
+      refreshGroups: WalletStoresV1.refreshGroups,
+      coins: WalletStoresV1.coins,
+    }))
+    .runReadWrite(async (tx) => {
+      const rg2 = await tx.recoupGroups.get(recoupGroupId);
+      if (!rg2) {
+        return;
+      }
+      rg2.timestampFinished = TalerProtocolTimestamp.now();
+      rg2.retryInfo = RetryInfo.reset();
+      rg2.lastError = undefined;
+      if (rg2.scheduleRefreshCoins.length > 0) {
+        const refreshGroupId = await createRefreshGroup(
+          ws,
+          tx,
+          rg2.scheduleRefreshCoins.map((x) => ({ coinPub: x })),
+          RefreshReason.Recoup,
+        );
+        processRefreshGroup(ws, refreshGroupId.refreshGroupId).catch((e) => {
+          logger.error(`error while refreshing after recoup ${e}`);
+        });
+      }
+      await tx.recoupGroups.put(rg2);
+    });
 }
 
 export async function createRecoupGroup(
@@ -443,12 +505,14 @@ export async function createRecoupGroup(
     refreshGroups: typeof WalletStoresV1.refreshGroups;
     coins: typeof WalletStoresV1.coins;
   }>,
+  exchangeBaseUrl: string,
   coinPubs: string[],
 ): Promise<string> {
   const recoupGroupId = encodeCrock(getRandomBytes(32));
 
   const recoupGroup: RecoupGroupRecord = {
     recoupGroupId,
+    exchangeBaseUrl: exchangeBaseUrl,
     coinPubs: coinPubs,
     lastError: undefined,
     timestampFinished: undefined,
diff --git a/packages/taler-wallet-core/src/operations/withdraw.ts 
b/packages/taler-wallet-core/src/operations/withdraw.ts
index a33f5916..84890a04 100644
--- a/packages/taler-wallet-core/src/operations/withdraw.ts
+++ b/packages/taler-wallet-core/src/operations/withdraw.ts
@@ -1135,6 +1135,22 @@ async function processWithdrawGroupImpl(
     withdrawalGroup.exchangeBaseUrl,
   );
 
+  if (withdrawalGroup.denomsSel.selectedDenoms.length === 0) {
+    await ws.db
+      .mktx((x) => ({ withdrawalGroups: x.withdrawalGroups }))
+      .runReadWrite(async (tx) => {
+        const wg = await tx.withdrawalGroups.get(withdrawalGroupId);
+        if (!wg) {
+          return;
+        }
+        wg.operationStatus = OperationStatus.Finished;
+        delete wg.lastError;
+        delete wg.retryInfo;
+        await tx.withdrawalGroups.put(wg);
+      });
+    return;
+  }
+
   const numTotalCoins = withdrawalGroup.denomsSel.selectedDenoms
     .map((x) => x.count)
     .reduce((a, b) => a + b);
@@ -1709,7 +1725,6 @@ export async function internalCreateWithdrawalGroup(
   args: {
     reserveStatus: ReserveRecordStatus;
     amount: AmountJson;
-    bankInfo?: ReserveBankInfo;
     exchangeBaseUrl: string;
     forcedDenomSel?: ForcedDenomSel;
     reserveKeyPair?: EddsaKeypair;
@@ -1776,12 +1791,17 @@ export async function internalCreateWithdrawalGroup(
   await ws.db
     .mktx((x) => ({
       withdrawalGroups: x.withdrawalGroups,
+      reserves: x.reserves,
       exchanges: x.exchanges,
       exchangeDetails: x.exchangeDetails,
       exchangeTrust: x.exchangeTrust,
     }))
     .runReadWrite(async (tx) => {
       await tx.withdrawalGroups.add(withdrawalGroup);
+      await tx.reserves.put({
+        reservePub: withdrawalGroup.reservePub,
+        reservePriv: withdrawalGroup.reservePriv,
+      });
 
       if (!isAudited && !isTrusted) {
         await tx.exchangeTrust.put({
@@ -1906,7 +1926,6 @@ export async function createManualWithdrawal(
       withdrawalType: WithdrawalRecordType.BankManual,
     },
     exchangeBaseUrl: req.exchangeBaseUrl,
-    bankInfo: undefined,
     forcedDenomSel: req.forcedDenomSel,
     restrictAge: req.restrictAge,
     reserveStatus: ReserveRecordStatus.QueryingStatus,
diff --git a/packages/taler-wallet-core/src/pending-types.ts 
b/packages/taler-wallet-core/src/pending-types.ts
index e372a593..39df9d0c 100644
--- a/packages/taler-wallet-core/src/pending-types.ts
+++ b/packages/taler-wallet-core/src/pending-types.ts
@@ -182,7 +182,7 @@ export interface PendingRecoupTask {
 export interface PendingWithdrawTask {
   type: PendingTaskType.Withdraw;
   lastError: TalerErrorDetail | undefined;
-  retryInfo: RetryInfo;
+  retryInfo?: RetryInfo;
   withdrawalGroupId: string;
 }
 

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