[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.
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [taler-wallet-core] branch master updated: fee display regression test,
gnunet <=