/*
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
*/
/**
* Imports.
*/
import {
AmountString,
ExchangeUpdateStatus,
NotificationType,
j2s,
} from "@gnu-taler/taler-util";
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { defaultCoinConfig } from "../harness/denomStructures.js";
import {
BankService,
ExchangeService,
GlobalTestState,
setupDb,
} from "../harness/harness.js";
import {
createWalletDaemonWithClient,
withdrawViaBankV2,
} from "../harness/helpers.js";
/**
* Test how the wallet reacts when an exchange unexpectedly updates
* properties like the master public key.
*/
export async function runWalletExchangeUpdateTest(
t: GlobalTestState,
): Promise {
// Set up test environment
const db = await setupDb(t);
const db2 = await setupDb(t, {
nameSuffix: "two",
});
const bank = await BankService.create(t, {
allowRegistrations: true,
currency: "TESTKUDOS",
database: db.connStr,
httpPort: 8082,
});
const exchangeOne = ExchangeService.create(t, {
name: "testexchange-1",
currency: "TESTKUDOS",
httpPort: 8081,
database: db.connStr,
});
// Danger: The second exchange has the same port!
// That's because we want it to have the same base URL,
// and we'll only start on of them at a time.
const exchangeTwo = ExchangeService.create(t, {
name: "testexchange-2",
currency: "TESTKUDOS",
httpPort: 8081,
database: db2.connStr,
});
const exchangeBankAccount = await bank.createExchangeAccount(
"myexchange",
"x",
);
await exchangeOne.addBankAccount("1", exchangeBankAccount);
await exchangeTwo.addBankAccount("1", exchangeBankAccount);
// Same anyway.
bank.setSuggestedExchange(exchangeOne, exchangeBankAccount.accountPaytoUri);
await bank.start();
exchangeOne.addCoinConfigList(defaultCoinConfig.map((x) => x("TESTKUDOS")));
exchangeTwo.addCoinConfigList(defaultCoinConfig.map((x) => x("TESTKUDOS")));
// Only start first exchange.
await exchangeOne.start();
const { walletClient } = await createWalletDaemonWithClient(t, {
name: "wallet",
persistent: true,
});
// Since the default exchanges can change, we start the wallet in tests
// with no built-in defaults. Thus the list of exchanges is empty here.
const exchangesListResult = await walletClient.call(
WalletApiOperation.ListExchanges,
{},
);
t.assertDeepEqual(exchangesListResult.exchanges.length, 0);
const wres = await withdrawViaBankV2(t, {
walletClient,
bank,
exchange: exchangeOne,
amount: "TESTKUDOS:10",
});
await wres.withdrawalFinishedCond;
await exchangeOne.stop();
console.log("starting second exchange");
await exchangeTwo.start();
console.log("updating exchange entry");
await t.assertThrowsAsync(async () => {
await walletClient.call(WalletApiOperation.UpdateExchangeEntry, {
exchangeBaseUrl: exchangeOne.baseUrl,
force: true,
});
});
const exchangeEntry = await walletClient.call(
WalletApiOperation.GetExchangeEntryByUrl,
{
exchangeBaseUrl: exchangeOne.baseUrl,
},
);
console.log(`exchange entry: ${j2s(exchangeEntry)}`);
await t.assertThrowsAsync(async () => {
await walletClient.call(WalletApiOperation.GetWithdrawalDetailsForAmount, {
amount: "TESTKUDOS:10" as AmountString,
exchangeBaseUrl: exchangeOne.baseUrl,
});
});
const exchangeAvailableCond = walletClient.waitForNotificationCond((n) => {
console.log(`got notif ${j2s(n)}`);
return (
n.type === NotificationType.ExchangeStateTransition &&
n.newExchangeState.exchangeUpdateStatus === ExchangeUpdateStatus.Ready
);
});
await exchangeTwo.stop();
console.log("starting first exchange");
await exchangeOne.start();
await exchangeAvailableCond;
}
runWalletExchangeUpdateTest.suites = ["wallet"];