fix reserve state machine bug, use simpler denominations in revocation test

This commit is contained in:
Florian Dold 2021-01-14 17:24:44 +01:00
parent 657c4b6377
commit 6293de7bfa
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
5 changed files with 81 additions and 40 deletions

View File

@ -45,8 +45,11 @@ import {
ConfirmPayResultType, ConfirmPayResultType,
ContractTerms, ContractTerms,
} from "taler-wallet-core"; } from "taler-wallet-core";
import { FaultInjectedExchangeService, FaultInjectedMerchantService } from "./faultInjection"; import {
import { defaultCoinConfig } from "./denomStructures"; FaultInjectedExchangeService,
FaultInjectedMerchantService,
} from "./faultInjection";
import { CoinConfig, defaultCoinConfig } from "./denomStructures";
export interface SimpleTestEnvironment { export interface SimpleTestEnvironment {
commonDb: DbInfo; commonDb: DbInfo;
@ -63,6 +66,7 @@ export interface SimpleTestEnvironment {
*/ */
export async function createSimpleTestkudosEnvironment( export async function createSimpleTestkudosEnvironment(
t: GlobalTestState, t: GlobalTestState,
coinConfig: CoinConfig[] = defaultCoinConfig.map((x) => x("TESTKUDOS")),
): Promise<SimpleTestEnvironment> { ): Promise<SimpleTestEnvironment> {
const db = await setupDb(t); const db = await setupDb(t);
@ -99,7 +103,7 @@ export async function createSimpleTestkudosEnvironment(
await bank.pingUntilAvailable(); await bank.pingUntilAvailable();
exchange.addOfferedCoins(defaultCoinConfig); exchange.addCoinConfigList(coinConfig);
await exchange.start(); await exchange.start();
await exchange.pingUntilAvailable(); await exchange.pingUntilAvailable();
@ -139,7 +143,7 @@ export interface FaultyMerchantTestEnvironment {
commonDb: DbInfo; commonDb: DbInfo;
bank: BankService; bank: BankService;
exchange: ExchangeService; exchange: ExchangeService;
faultyExchange: FaultInjectedExchangeService, faultyExchange: FaultInjectedExchangeService;
exchangeBankAccount: ExchangeBankAccount; exchangeBankAccount: ExchangeBankAccount;
merchant: MerchantService; merchant: MerchantService;
faultyMerchant: FaultInjectedMerchantService; faultyMerchant: FaultInjectedMerchantService;
@ -185,7 +189,10 @@ export async function createFaultInjectedMerchantTestkudosEnvironment(
); );
exchange.addBankAccount("1", exchangeBankAccount); exchange.addBankAccount("1", exchangeBankAccount);
bank.setSuggestedExchange(faultyExchange, exchangeBankAccount.accountPaytoUri); bank.setSuggestedExchange(
faultyExchange,
exchangeBankAccount.accountPaytoUri,
);
await bank.start(); await bank.start();

View File

@ -17,6 +17,7 @@
/** /**
* Imports. * Imports.
*/ */
import { CoinConfig } from "./denomStructures";
import { import {
GlobalTestState, GlobalTestState,
ExchangeService, ExchangeService,
@ -28,7 +29,6 @@ import {
withdrawViaBank, withdrawViaBank,
makeTestPayment, makeTestPayment,
} from "./helpers"; } from "./helpers";
import { CoinDumpJson } from "taler-wallet-core";
async function revokeAllWalletCoins(req: { async function revokeAllWalletCoins(req: {
wallet: WalletCli; wallet: WalletCli;
@ -45,7 +45,9 @@ async function revokeAllWalletCoins(req: {
for (const x of usedDenomHashes.values()) { for (const x of usedDenomHashes.values()) {
await exchange.revokeDenomination(x); await exchange.revokeDenomination(x);
} }
await exchange.stop();
await exchange.start();
await exchange.pingUntilAvailable();
await exchange.keyup(); await exchange.keyup();
await exchange.pingUntilAvailable(); await exchange.pingUntilAvailable();
await merchant.stop(); await merchant.stop();
@ -59,12 +61,25 @@ async function revokeAllWalletCoins(req: {
export async function runRevocationTest(t: GlobalTestState) { export async function runRevocationTest(t: GlobalTestState) {
// Set up test environment // Set up test environment
const coin_u1: CoinConfig = {
durationLegal: "3 years",
durationSpend: "2 years",
durationWithdraw: "7 days",
rsaKeySize: 1024,
name: `$TESTKUDOS_u1`,
value: `TESTKUDOS:1`,
feeDeposit: `TESTKUDOS:0`,
feeRefresh: `TESTKUDOS:0`,
feeRefund: `TESTKUDOS:0`,
feeWithdraw: `TESTKUDOS:0`,
};
const { const {
wallet, wallet,
bank, bank,
exchange, exchange,
merchant, merchant,
} = await createSimpleTestkudosEnvironment(t); } = await createSimpleTestkudosEnvironment(t, [coin_u1]);
// Withdraw digital cash into the wallet. // Withdraw digital cash into the wallet.

View File

@ -170,7 +170,7 @@ export async function runTests(spec: TestRunSpec) {
testRootDir, testRootDir,
}; };
currentChild = child_process.fork(__filename, { currentChild = child_process.fork(__filename, ["__TWCLI_TESTWORKER"], {
env: { env: {
TWCLI_RUN_TEST_INSTRUCTION: JSON.stringify(testInstr), TWCLI_RUN_TEST_INSTRUCTION: JSON.stringify(testInstr),
...process.env, ...process.env,
@ -251,9 +251,9 @@ export function getTestInfo(): TestInfo[] {
} }
const runTestInstrStr = process.env["TWCLI_RUN_TEST_INSTRUCTION"]; const runTestInstrStr = process.env["TWCLI_RUN_TEST_INSTRUCTION"];
if (runTestInstrStr) { if (runTestInstrStr && process.argv.includes("__TWCLI_TESTWORKER")) {
// Test will call taler-wallet-cli, so we must not propagate this variable. // Test will call taler-wallet-cli, so we must not propagate this variable.
delete process.env["TWCLI_RUN_TEST_NAME"]; delete process.env["TWCLI_RUN_TEST_INSTRUCTION"];
const { testRootDir, testName } = JSON.parse( const { testRootDir, testName } = JSON.parse(
runTestInstrStr, runTestInstrStr,
) as RunTestChildInstruction; ) as RunTestChildInstruction;

View File

@ -83,6 +83,9 @@ async function putGroupAsFinished(
recoupGroup: RecoupGroupRecord, recoupGroup: RecoupGroupRecord,
coinIdx: number, coinIdx: number,
): Promise<void> { ): Promise<void> {
logger.trace(
`setting coin ${coinIdx} of ${recoupGroup.coinPubs.length} as finished`,
);
if (recoupGroup.timestampFinished) { if (recoupGroup.timestampFinished) {
return; return;
} }
@ -94,6 +97,7 @@ async function putGroupAsFinished(
} }
} }
if (allFinished) { if (allFinished) {
logger.trace("all recoups of recoup group are finished");
recoupGroup.timestampFinished = getTimestampNow(); recoupGroup.timestampFinished = getTimestampNow();
recoupGroup.retryInfo = initRetryInfo(false); recoupGroup.retryInfo = initRetryInfo(false);
recoupGroup.lastError = undefined; recoupGroup.lastError = undefined;
@ -230,7 +234,7 @@ async function recoupRefreshCoin(
const recoupRequest = await ws.cryptoApi.createRecoupRequest(coin); const recoupRequest = await ws.cryptoApi.createRecoupRequest(coin);
const reqUrl = new URL(`/coins/${coin.coinPub}/recoup`, coin.exchangeBaseUrl); const reqUrl = new URL(`/coins/${coin.coinPub}/recoup`, coin.exchangeBaseUrl);
logger.trace("making recoup request"); logger.trace(`making recoup request for ${coin.coinPub}`);
const resp = await ws.http.postJson(reqUrl.href, recoupRequest); const resp = await ws.http.postJson(reqUrl.href, recoupRequest);
const recoupConfirmation = await readSuccessResponseJsonOrThrow( const recoupConfirmation = await readSuccessResponseJsonOrThrow(
@ -244,12 +248,14 @@ async function recoupRefreshCoin(
const exchange = await ws.db.get(Stores.exchanges, coin.exchangeBaseUrl); const exchange = await ws.db.get(Stores.exchanges, coin.exchangeBaseUrl);
if (!exchange) { if (!exchange) {
logger.warn("exchange for recoup does not exist anymore");
// FIXME: report inconsistency? // FIXME: report inconsistency?
return; return;
} }
const exchangeDetails = exchange.details; const exchangeDetails = exchange.details;
if (!exchangeDetails) { if (!exchangeDetails) {
// FIXME: report inconsistency? // FIXME: report inconsistency?
logger.warn("exchange details for recoup not found");
return; return;
} }
@ -272,9 +278,11 @@ async function recoupRefreshCoin(
const oldCoin = await tx.get(Stores.coins, cs.oldCoinPub); const oldCoin = await tx.get(Stores.coins, cs.oldCoinPub);
const revokedCoin = await tx.get(Stores.coins, coin.coinPub); const revokedCoin = await tx.get(Stores.coins, coin.coinPub);
if (!revokedCoin) { if (!revokedCoin) {
logger.warn("revoked coin for recoup not found");
return; return;
} }
if (!oldCoin) { if (!oldCoin) {
logger.warn("refresh old coin for recoup not found");
return; return;
} }
revokedCoin.status = CoinStatus.Dormant; revokedCoin.status = CoinStatus.Dormant;

View File

@ -604,37 +604,50 @@ async function updateReserve(
denoms, denoms,
); );
if (denomSelInfo.selectedDenoms.length > 0) { logger.trace(
let withdrawalGroupId: string; `Remaining unclaimed amount in reseve is ${Amounts.stringify(
remainingAmount,
if (!newReserve.initialWithdrawalStarted) { )} and can be withdrawn with ${
withdrawalGroupId = newReserve.initialWithdrawalGroupId; denomSelInfo.selectedDenoms.length
newReserve.initialWithdrawalStarted = true; } coins`,
} else { );
withdrawalGroupId = encodeCrock(randomBytes(32));
}
const withdrawalRecord: WithdrawalGroupRecord = {
withdrawalGroupId: withdrawalGroupId,
exchangeBaseUrl: reserve.exchangeBaseUrl,
reservePub: reserve.reservePub,
rawWithdrawalAmount: remainingAmount,
timestampStart: getTimestampNow(),
retryInfo: initRetryInfo(),
lastError: undefined,
denomsSel: denomSelectionInfoToState(denomSelInfo),
secretSeed: encodeCrock(getRandomBytes(64)),
};
if (denomSelInfo.selectedDenoms.length === 0) {
newReserve.reserveStatus = ReserveRecordStatus.DORMANT;
newReserve.lastError = undefined; newReserve.lastError = undefined;
newReserve.retryInfo = initRetryInfo(false); newReserve.retryInfo = initRetryInfo(false);
newReserve.reserveStatus = ReserveRecordStatus.DORMANT;
await tx.put(Stores.reserves, newReserve); await tx.put(Stores.reserves, newReserve);
await tx.put(Stores.withdrawalGroups, withdrawalRecord); return;
return withdrawalRecord;
} }
return;
let withdrawalGroupId: string;
if (!newReserve.initialWithdrawalStarted) {
withdrawalGroupId = newReserve.initialWithdrawalGroupId;
newReserve.initialWithdrawalStarted = true;
} else {
withdrawalGroupId = encodeCrock(randomBytes(32));
}
const withdrawalRecord: WithdrawalGroupRecord = {
withdrawalGroupId: withdrawalGroupId,
exchangeBaseUrl: reserve.exchangeBaseUrl,
reservePub: reserve.reservePub,
rawWithdrawalAmount: remainingAmount,
timestampStart: getTimestampNow(),
retryInfo: initRetryInfo(),
lastError: undefined,
denomsSel: denomSelectionInfoToState(denomSelInfo),
secretSeed: encodeCrock(getRandomBytes(64)),
};
newReserve.lastError = undefined;
newReserve.retryInfo = initRetryInfo(false);
newReserve.reserveStatus = ReserveRecordStatus.DORMANT;
await tx.put(Stores.reserves, newReserve);
await tx.put(Stores.withdrawalGroups, withdrawalRecord);
return withdrawalRecord;
}, },
); );
@ -645,8 +658,6 @@ async function updateReserve(
withdrawalGroupId: newWithdrawalGroup.withdrawalGroupId, withdrawalGroupId: newWithdrawalGroup.withdrawalGroupId,
}); });
await processWithdrawGroup(ws, newWithdrawalGroup.withdrawalGroupId); await processWithdrawGroup(ws, newWithdrawalGroup.withdrawalGroupId);
} else {
console.trace("withdraw session already existed");
} }
return { ready: true }; return { ready: true };