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

View File

@ -17,6 +17,7 @@
/**
* Imports.
*/
import { CoinConfig } from "./denomStructures";
import {
GlobalTestState,
ExchangeService,
@ -28,7 +29,6 @@ import {
withdrawViaBank,
makeTestPayment,
} from "./helpers";
import { CoinDumpJson } from "taler-wallet-core";
async function revokeAllWalletCoins(req: {
wallet: WalletCli;
@ -45,7 +45,9 @@ async function revokeAllWalletCoins(req: {
for (const x of usedDenomHashes.values()) {
await exchange.revokeDenomination(x);
}
await exchange.stop();
await exchange.start();
await exchange.pingUntilAvailable();
await exchange.keyup();
await exchange.pingUntilAvailable();
await merchant.stop();
@ -59,12 +61,25 @@ async function revokeAllWalletCoins(req: {
export async function runRevocationTest(t: GlobalTestState) {
// 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 {
wallet,
bank,
exchange,
merchant,
} = await createSimpleTestkudosEnvironment(t);
} = await createSimpleTestkudosEnvironment(t, [coin_u1]);
// Withdraw digital cash into the wallet.

View File

@ -170,7 +170,7 @@ export async function runTests(spec: TestRunSpec) {
testRootDir,
};
currentChild = child_process.fork(__filename, {
currentChild = child_process.fork(__filename, ["__TWCLI_TESTWORKER"], {
env: {
TWCLI_RUN_TEST_INSTRUCTION: JSON.stringify(testInstr),
...process.env,
@ -251,9 +251,9 @@ export function getTestInfo(): TestInfo[] {
}
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.
delete process.env["TWCLI_RUN_TEST_NAME"];
delete process.env["TWCLI_RUN_TEST_INSTRUCTION"];
const { testRootDir, testName } = JSON.parse(
runTestInstrStr,
) as RunTestChildInstruction;

View File

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

View File

@ -604,37 +604,50 @@ async function updateReserve(
denoms,
);
if (denomSelInfo.selectedDenoms.length > 0) {
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)),
};
logger.trace(
`Remaining unclaimed amount in reseve is ${Amounts.stringify(
remainingAmount,
)} and can be withdrawn with ${
denomSelInfo.selectedDenoms.length
} coins`,
);
if (denomSelInfo.selectedDenoms.length === 0) {
newReserve.reserveStatus = ReserveRecordStatus.DORMANT;
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;
return;
}
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,
});
await processWithdrawGroup(ws, newWithdrawalGroup.withdrawalGroupId);
} else {
console.trace("withdraw session already existed");
}
return { ready: true };