gnunet-svn
[Top][All Lists]
Advanced

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

[taler-wallet-core] branch master updated: fee display regression test


From: gnunet
Subject: [taler-wallet-core] branch master updated: fee display regression test
Date: Tue, 08 Dec 2020 14:25:12 +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 4221cad6 fee display regression test
4221cad6 is described below

commit 4221cad66f942a61445f4b57d3084d11327a08b5
Author: Florian Dold <florian@dold.me>
AuthorDate: Tue Dec 8 14:25:06 2020 +0100

    fee display regression test
---
 packages/taler-integrationtests/src/helpers.ts     |   6 +-
 .../src/test-fee-regression.ts                     | 194 +++++++++++++++++++++
 .../taler-wallet-core/src/operations/backup.ts     | 168 +++++++++---------
 3 files changed, 285 insertions(+), 83 deletions(-)

diff --git a/packages/taler-integrationtests/src/helpers.ts 
b/packages/taler-integrationtests/src/helpers.ts
index f633ea82..f4e676b6 100644
--- a/packages/taler-integrationtests/src/helpers.ts
+++ b/packages/taler-integrationtests/src/helpers.ts
@@ -334,11 +334,7 @@ export async function makeTestPayment(
   const instance = args.instance ?? "default";
 
   const orderResp = await MerchantPrivateApi.createOrder(merchant, instance, {
-    order: {
-      summary: "Buy me!",
-      amount: "TESTKUDOS:5",
-      fulfillment_url: "taler://fulfillment-success/thx",
-    },
+    order: args.order,
   });
 
   let orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(merchant, 
{
diff --git a/packages/taler-integrationtests/src/test-fee-regression.ts 
b/packages/taler-integrationtests/src/test-fee-regression.ts
new file mode 100644
index 00000000..30474469
--- /dev/null
+++ b/packages/taler-integrationtests/src/test-fee-regression.ts
@@ -0,0 +1,194 @@
+/*
+ This file is part of GNU Taler
+ (C) 2020 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/>
+ */
+
+/**
+ * Imports.
+ */
+import { defaultCoinConfig } from './denomStructures';
+import { runTest, GlobalTestState, BankService, ExchangeService, 
MerchantService, setupDb, WalletCli } from "./harness";
+import {
+  withdrawViaBank,
+  makeTestPayment,
+  SimpleTestEnvironment,
+} from "./helpers";
+
+
+/**
+ * Run a test case with a simple TESTKUDOS Taler environment, consisting
+ * of one exchange, one bank and one merchant.
+ */
+export async function createMyTestkudosEnvironment(
+  t: GlobalTestState,
+): Promise<SimpleTestEnvironment> {
+  const db = await setupDb(t);
+
+  const bank = await BankService.create(t, {
+    allowRegistrations: true,
+    currency: "TESTKUDOS",
+    database: db.connStr,
+    httpPort: 8082,
+  });
+
+  const exchange = ExchangeService.create(t, {
+    name: "testexchange-1",
+    currency: "TESTKUDOS",
+    httpPort: 8081,
+    database: db.connStr,
+  });
+
+  const merchant = await MerchantService.create(t, {
+    name: "testmerchant-1",
+    currency: "TESTKUDOS",
+    httpPort: 8083,
+    database: db.connStr,
+  });
+
+  const exchangeBankAccount = await bank.createExchangeAccount(
+    "MyExchange",
+    "x",
+  );
+  exchange.addBankAccount("1", exchangeBankAccount);
+
+  bank.setSuggestedExchange(exchange, exchangeBankAccount.accountPaytoUri);
+
+  await bank.start();
+
+  await bank.pingUntilAvailable();
+
+  const coinCommon = {
+    durationLegal: "3 years",
+    durationSpend: "2 years",
+    durationWithdraw: "7 days",
+    rsaKeySize: 1024,
+    feeDeposit: "TESTKUDOS:0.0025",
+    feeWithdraw: "TESTKUDOS:0",
+    feeRefresh: "TESTKUDOS:0",
+    feeRefund: "TESTKUDOS:0",
+  };
+
+  exchange.addCoinConfigList([
+    {
+      ...coinCommon,
+      name: "c1",
+      value: "TESTKUDOS:1.28"
+    },
+    {
+      ...coinCommon,
+      name: "c2",
+      value: "TESTKUDOS:0.64"
+    },
+    {
+      ...coinCommon,
+      name: "c3",
+      value: "TESTKUDOS:0.32"
+    },
+    {
+      ...coinCommon,
+      name: "c4",
+      value: "TESTKUDOS:0.16"
+    },
+    {
+      ...coinCommon,
+      name: "c5",
+      value: "TESTKUDOS:0.08"
+    },
+    {
+      ...coinCommon,
+      name: "c5",
+      value: "TESTKUDOS:0.04"
+    },
+    {
+      ...coinCommon,
+      name: "c6",
+      value: "TESTKUDOS:0.02"
+    },
+    {
+      ...coinCommon,
+      name: "c7",
+      value: "TESTKUDOS:0.01"
+    },
+  ]);
+
+  await exchange.start();
+  await exchange.pingUntilAvailable();
+
+  merchant.addExchange(exchange);
+
+  await merchant.start();
+  await merchant.pingUntilAvailable();
+
+  await merchant.addInstance({
+    id: "minst1",
+    name: "minst1",
+    paytoUris: ["payto://x-taler-bank/minst1"],
+  });
+
+  await merchant.addInstance({
+    id: "default",
+    name: "Default Instance",
+    paytoUris: [`payto://x-taler-bank/merchant-default`],
+  });
+
+  console.log("setup done!");
+
+  const wallet = new WalletCli(t);
+
+  return {
+    commonDb: db,
+    exchange,
+    merchant,
+    wallet,
+    bank,
+    exchangeBankAccount,
+  };
+}
+
+/**
+ * Run test for basic, bank-integrated withdrawal and payment.
+ */
+runTest(async (t: GlobalTestState) => {
+  // Set up test environment
+
+  const {
+    wallet,
+    bank,
+    exchange,
+    merchant,
+  } = await createMyTestkudosEnvironment(t);
+
+  // Withdraw digital cash into the wallet.
+
+  await withdrawViaBank(t, { wallet, bank, exchange, amount: "TESTKUDOS:1.92" 
});
+
+  const coins = await wallet.dumpCoins();
+
+  // Make sure we really withdraw one 0.64 and one 1.28 coin.
+  t.assertTrue(coins.coins.length === 2);
+
+  const order = {
+    summary: "Buy me!",
+    amount: "TESTKUDOS:1.30",
+    fulfillment_url: "taler://fulfillment-success/thx",
+  };
+
+  await makeTestPayment(t, { wallet, merchant, order });
+
+  await wallet.runUntilDone();
+
+  const txs = await wallet.getTransactions();
+  t.assertAmountEquals(txs.transactions[1].amountEffective, "TESTKUDOS:1.30");
+  console.log(txs);
+});
diff --git a/packages/taler-wallet-core/src/operations/backup.ts 
b/packages/taler-wallet-core/src/operations/backup.ts
index 9f412dc7..cf73de62 100644
--- a/packages/taler-wallet-core/src/operations/backup.ts
+++ b/packages/taler-wallet-core/src/operations/backup.ts
@@ -32,6 +32,7 @@ import {
   BackupDenomination,
   BackupExchange,
   BackupExchangeWireFee,
+  BackupReserve,
   WalletBackupContentV1,
 } from "../types/backupTypes";
 import { TransactionHandle } from "../util/query";
@@ -68,13 +69,13 @@ import {
 } from "../util/http";
 import { Logger } from "../util/logging";
 import { gzipSync } from "fflate";
-import { sign_keyPair_fromSeed } from "../crypto/primitives/nacl-fast";
 import { kdf } from "../crypto/primitives/kdf";
 
 interface WalletBackupConfState {
+  deviceId: string;
   walletRootPub: string;
   walletRootPriv: string;
-  clock: number;
+  clocks: { [device_id: string]: number };
   lastBackupHash?: string;
   lastBackupNonce?: string;
 }
@@ -96,6 +97,10 @@ async function provideBackupState(
   // We need to generate the key outside of the transaction
   // due to how IndexedDB works.
   const k = await ws.cryptoApi.createEddsaKeypair();
+  const d = getRandomBytes(5);
+  // FIXME: device ID should be configured when wallet is initialized
+  // and be based on hostname
+  const deviceId = `wallet-core-${encodeCrock(d)}`;
   return await ws.db.runWithWriteTransaction([Stores.config], async (tx) => {
     let backupStateEntry:
       | ConfigRecord<WalletBackupConfState>
@@ -104,9 +109,10 @@ async function provideBackupState(
       backupStateEntry = {
         key: WALLET_BACKUP_STATE_KEY,
         value: {
+          deviceId,
+          clocks: { [deviceId]: 1},
           walletRootPub: k.pub,
           walletRootPriv: k.priv,
-          clock: 0,
           lastBackupHash: undefined,
         },
       };
@@ -135,8 +141,66 @@ export async function exportBackup(
       const bs = await getWalletBackupState(ws, tx);
 
       const exchanges: BackupExchange[] = [];
-      const coins: BackupCoin[] = [];
-      const denominations: BackupDenomination[] = [];
+      const coinsByDenom: { [dph: string]: BackupCoin[] } = {};
+      const denominationsByExchange: { [url: string]: BackupDenomination[] } = 
{};
+      const reservesByExchange: { [url: string]: BackupReserve[] } = {};
+
+      await tx.iter(Stores.coins).forEach((coin) => {
+        let bcs: BackupCoinSource;
+        switch (coin.coinSource.type) {
+          case CoinSourceType.Refresh:
+            bcs = {
+              type: BackupCoinSourceType.Refresh,
+              old_coin_pub: coin.coinSource.oldCoinPub,
+            };
+            break;
+          case CoinSourceType.Tip:
+            bcs = {
+              type: BackupCoinSourceType.Tip,
+              coin_index: coin.coinSource.coinIndex,
+              wallet_tip_id: coin.coinSource.walletTipId,
+            };
+            break;
+          case CoinSourceType.Withdraw:
+            bcs = {
+              type: BackupCoinSourceType.Withdraw,
+              coin_index: coin.coinSource.coinIndex,
+              reserve_pub: coin.coinSource.reservePub,
+              withdrawal_group_id: coin.coinSource.withdrawalGroupId,
+            };
+            break;
+        }
+
+        const coins = (coinsByDenom[coin.denomPubHash] ??= []);
+        coins.push({
+          blinding_key: coin.blindingKey,
+          coin_priv: coin.coinPriv,
+          coin_source: bcs,
+          current_amount: Amounts.stringify(coin.currentAmount),
+          fresh: coin.status === CoinStatus.Fresh,
+          denom_sig: coin.denomSig,
+        });
+      });
+
+      await tx.iter(Stores.denominations).forEach((denom) => {
+        const backupDenoms = (denominationsByExchange[denom.exchangeBaseUrl] 
??= []);
+        backupDenoms.push({
+          coins: coinsByDenom[denom.denomPubHash] ?? [],
+          denom_pub: denom.denomPub,
+          fee_deposit: Amounts.stringify(denom.feeDeposit),
+          fee_refresh: Amounts.stringify(denom.feeRefresh),
+          fee_refund: Amounts.stringify(denom.feeRefund),
+          fee_withdraw: Amounts.stringify(denom.feeWithdraw),
+          is_offered: denom.isOffered,
+          is_revoked: denom.isRevoked,
+          master_sig: denom.masterSig,
+          stamp_expire_deposit: denom.stampExpireDeposit,
+          stamp_expire_legal: denom.stampExpireLegal,
+          stamp_expire_withdraw: denom.stampExpireWithdraw,
+          stamp_start: denom.stampStart,
+          value: Amounts.stringify(denom.value),
+        });
+      });
 
       await tx.iter(Stores.exchanges).forEach((ex) => {
         // Only back up permanently added exchanges.
@@ -172,12 +236,12 @@ export async function exportBackup(
         exchanges.push({
           base_url: ex.baseUrl,
           accounts: ex.wireInfo.accounts.map((x) => ({
-            paytoUri: x.payto_uri,
+            payto_uri: x.payto_uri,
           })),
           auditors: ex.details.auditors.map((x) => ({
-            auditorPub: x.auditor_pub,
-            auditorUrl: x.auditor_url,
-            denominationKeys: x.denomination_keys,
+            auditor_pub: x.auditor_pub,
+            auditor_url: x.auditor_url,
+            denomination_keys: x.denomination_keys,
           })),
           master_public_key: ex.details.masterPublicKey,
           currency: ex.details.currency,
@@ -185,91 +249,39 @@ export async function exportBackup(
           wire_fees: wireFees,
           signing_keys: ex.details.signingKeys.map((x) => ({
             key: x.key,
-            masterSig: x.master_sig,
-            stampEnd: x.stamp_end,
-            stampExpire: x.stamp_expire,
-            stampStart: x.stamp_start,
+            master_sig: x.master_sig,
+            stamp_end: x.stamp_end,
+            stamp_expire: x.stamp_expire,
+            stamp_start: x.stamp_start,
           })),
           tos_etag_accepted: ex.termsOfServiceAcceptedEtag,
           tos_etag_last: ex.termsOfServiceLastEtag,
-        });
-      });
-
-      await tx.iter(Stores.denominations).forEach((denom) => {
-        denominations.push({
-          denom_pub: denom.denomPub,
-          denom_pub_hash: denom.denomPubHash,
-          exchangeBaseUrl: canonicalizeBaseUrl(denom.exchangeBaseUrl),
-          fee_deposit: Amounts.stringify(denom.feeDeposit),
-          fee_refresh: Amounts.stringify(denom.feeRefresh),
-          fee_refund: Amounts.stringify(denom.feeRefund),
-          fee_withdraw: Amounts.stringify(denom.feeWithdraw),
-          is_offered: denom.isOffered,
-          is_revoked: denom.isRevoked,
-          master_sig: denom.masterSig,
-          stamp_expire_deposit: denom.stampExpireDeposit,
-          stamp_expire_legal: denom.stampExpireLegal,
-          stamp_expire_withdraw: denom.stampExpireWithdraw,
-          stamp_start: denom.stampStart,
-          value: Amounts.stringify(denom.value),
-        });
-      });
-
-      await tx.iter(Stores.coins).forEach((coin) => {
-        let bcs: BackupCoinSource;
-        switch (coin.coinSource.type) {
-          case CoinSourceType.Refresh:
-            bcs = {
-              type: BackupCoinSourceType.Refresh,
-              old_coin_pub: coin.coinSource.oldCoinPub,
-            };
-            break;
-          case CoinSourceType.Tip:
-            bcs = {
-              type: BackupCoinSourceType.Tip,
-              coin_index: coin.coinSource.coinIndex,
-              wallet_tip_id: coin.coinSource.walletTipId,
-            };
-            break;
-          case CoinSourceType.Withdraw:
-            bcs = {
-              type: BackupCoinSourceType.Withdraw,
-              coin_index: coin.coinSource.coinIndex,
-              reserve_pub: coin.coinSource.reservePub,
-              withdrawal_group_id: coin.coinSource.withdrawalGroupId,
-            };
-            break;
-        }
-
-        coins.push({
-          exchangeBaseUrl: coin.exchangeBaseUrl,
-          blinding_key: coin.blindingKey,
-          coin_priv: coin.coinPriv,
-          coin_pub: coin.coinPub,
-          coin_source: bcs,
-          current_amount: Amounts.stringify(coin.currentAmount),
-          fresh: coin.status === CoinStatus.Fresh,
+          denominations: denominationsByExchange[ex.baseUrl] ?? [],
+          reserves: reservesByExchange[ex.baseUrl] ?? [],
         });
       });
 
       const backupBlob: WalletBackupContentV1 = {
-        schema_id: "gnu-taler-wallet-backup",
+        schema_id: "gnu-taler-wallet-backup-content",
         schema_version: 1,
-        clock: bs.clock,
-        coins: coins,
+        clocks: bs.clocks,
         exchanges: exchanges,
-        planchets: [],
-        refreshSessions: [],
-        reserves: [],
-        denominations: [],
         wallet_root_pub: bs.walletRootPub,
+        backup_providers: [],
+        current_device_id: bs.deviceId,
+        proposals: [],
+        purchase_tombstones: [],
+        purchases: [],
+        recoup_groups: [],
+        refresh_groups: [],
+        tips: [],
       };
 
       // If the backup changed, we increment our clock.
 
       let h = encodeCrock(hash(stringToBytes(canonicalJson(backupBlob))));
       if (h != bs.lastBackupHash) {
-        backupBlob.clock = ++bs.clock;
+        backupBlob.clocks[bs.deviceId] = ++bs.clocks[bs.deviceId];
         bs.lastBackupHash = encodeCrock(
           hash(stringToBytes(canonicalJson(backupBlob))),
         );

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