aboutsummaryrefslogtreecommitdiff
path: root/packages/taler-harness/src/integrationtests/test-withdrawal-idempotent.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/taler-harness/src/integrationtests/test-withdrawal-idempotent.ts')
-rw-r--r--packages/taler-harness/src/integrationtests/test-withdrawal-idempotent.ts175
1 files changed, 113 insertions, 62 deletions
diff --git a/packages/taler-harness/src/integrationtests/test-withdrawal-idempotent.ts b/packages/taler-harness/src/integrationtests/test-withdrawal-idempotent.ts
index a7f9f51ea..0daa53f64 100644
--- a/packages/taler-harness/src/integrationtests/test-withdrawal-idempotent.ts
+++ b/packages/taler-harness/src/integrationtests/test-withdrawal-idempotent.ts
@@ -17,18 +17,33 @@
/**
* Imports.
*/
-import { AmountString, j2s, TalerError } from "@gnu-taler/taler-util";
+import {
+ AgeRestriction,
+ Amounts,
+ AmountString,
+ codecForExchangeWithdrawBatchResponse,
+ encodeCrock,
+ ExchangeBatchWithdrawRequest,
+ getRandomBytes,
+} from "@gnu-taler/taler-util";
+import {
+ HttpRequestLibrary,
+ readSuccessResponseJsonOrThrow,
+} from "@gnu-taler/taler-util/http";
import {
CryptoDispatcher,
SynchronousCryptoWorkerFactoryPlain,
+ TalerCryptoInterface,
} from "@gnu-taler/taler-wallet-core";
import {
checkReserve,
+ CoinInfo,
downloadExchangeInfo,
findDenomOrThrow,
+ ReserveKeypair,
topupReserveWithBank,
- withdrawCoin,
} from "@gnu-taler/taler-wallet-core/dbless";
+import { DenominationRecord } from "../../../taler-wallet-core/src/db.js";
import { GlobalTestState, harnessHttpLib } from "../harness/harness.js";
import { createSimpleTestkudosEnvironmentV2 } from "../harness/helpers.js";
@@ -46,76 +61,112 @@ export async function runWithdrawalIdempotentTest(t: GlobalTestState) {
);
const cryptoApi = cryptiDisp.cryptoApi;
- try {
- // Withdraw digital cash into the wallet.
+ const exchangeInfo = await downloadExchangeInfo(exchange.baseUrl, http);
- const exchangeInfo = await downloadExchangeInfo(exchange.baseUrl, http);
+ const reserveKeyPair = await cryptoApi.createEddsaKeypair({});
- const reserveKeyPair = await cryptoApi.createEddsaKeypair({});
+ let reserveUrl = new URL(`reserves/${reserveKeyPair.pub}`, exchange.baseUrl);
+ reserveUrl.searchParams.set("timeout_ms", "30000");
+ const longpollReq = http.fetch(reserveUrl.href, {
+ method: "GET",
+ });
- let reserveUrl = new URL(
- `reserves/${reserveKeyPair.pub}`,
- exchange.baseUrl,
- );
- reserveUrl.searchParams.set("timeout_ms", "30000");
- const longpollReq = http.fetch(reserveUrl.href, {
- method: "GET",
- });
-
- await topupReserveWithBank({
- amount: "TESTKUDOS:10" as AmountString,
- http,
- reservePub: reserveKeyPair.pub,
- corebankApiBaseUrl: bank.corebankApiBaseUrl,
- exchangeInfo,
- });
+ await topupReserveWithBank({
+ amount: "TESTKUDOS:10" as AmountString,
+ http,
+ reservePub: reserveKeyPair.pub,
+ corebankApiBaseUrl: bank.corebankApiBaseUrl,
+ exchangeInfo,
+ });
- console.log("waiting for longpoll request");
- const resp = await longpollReq;
- console.log(`got response, status ${resp.status}`);
+ console.log("waiting for longpoll request");
+ const resp = await longpollReq;
+ console.log(`got response, status ${resp.status}`);
- console.log(exchangeInfo);
+ console.log(exchangeInfo);
- await checkReserve(http, exchange.baseUrl, reserveKeyPair.pub);
- const denomselAllowLate = false;
+ await checkReserve(http, exchange.baseUrl, reserveKeyPair.pub);
+ const denomselAllowLate = false;
- const d1 = findDenomOrThrow(exchangeInfo, "TESTKUDOS:8" as AmountString, {
- denomselAllowLate,
- });
+ const d1 = findDenomOrThrow(exchangeInfo, "TESTKUDOS:8" as AmountString, {
+ denomselAllowLate,
+ });
- const coin = await withdrawCoin({
- http,
- cryptoApi,
- reserveKeyPair: {
- reservePriv: reserveKeyPair.priv,
- reservePub: reserveKeyPair.pub,
+ await myWithdrawCoin({
+ http,
+ cryptoApi,
+ reserveKeyPair: {
+ reservePriv: reserveKeyPair.priv,
+ reservePub: reserveKeyPair.pub,
+ },
+ denom: d1,
+ exchangeBaseUrl: exchange.baseUrl,
+ });
+}
+
+async function myWithdrawCoin(args: {
+ http: HttpRequestLibrary;
+ cryptoApi: TalerCryptoInterface;
+ reserveKeyPair: ReserveKeypair;
+ denom: DenominationRecord;
+ exchangeBaseUrl: string;
+}): Promise<CoinInfo> {
+ const { http, cryptoApi, reserveKeyPair, denom, exchangeBaseUrl } = args;
+ const planchet = await cryptoApi.createPlanchet({
+ coinIndex: 0,
+ denomPub: denom.denomPub,
+ feeWithdraw: Amounts.parseOrThrow(denom.fees.feeWithdraw),
+ reservePriv: reserveKeyPair.reservePriv,
+ reservePub: reserveKeyPair.reservePub,
+ secretSeed: encodeCrock(getRandomBytes(32)),
+ value: Amounts.parseOrThrow(denom.value),
+ });
+
+ const reqBody: ExchangeBatchWithdrawRequest = {
+ planchets: [
+ {
+ denom_pub_hash: planchet.denomPubHash,
+ reserve_sig: planchet.withdrawSig,
+ coin_ev: planchet.coinEv,
},
- denom: d1,
- exchangeBaseUrl: exchange.baseUrl,
- });
-
- {
- // Do it again for idempotency!
- const coin2 = await withdrawCoin({
- http,
- cryptoApi,
- reserveKeyPair: {
- reservePriv: reserveKeyPair.priv,
- reservePub: reserveKeyPair.pub,
- },
- denom: d1,
- exchangeBaseUrl: exchange.baseUrl,
- });
- }
- } catch (e) {
- if (e instanceof TalerError) {
- console.log(e);
- console.log(j2s(e.errorDetail));
- } else {
- console.log(e);
- }
- throw e;
+ ],
+ };
+ const reqUrl = new URL(
+ `reserves/${planchet.reservePub}/batch-withdraw`,
+ exchangeBaseUrl,
+ ).href;
+
+ const resp = await http.fetch(reqUrl, { method: "POST", body: reqBody });
+ const rBatch = await readSuccessResponseJsonOrThrow(
+ resp,
+ codecForExchangeWithdrawBatchResponse(),
+ );
+
+ {
+ // Check for idempotency!
+ const resp2 = await http.fetch(reqUrl, { method: "POST", body: reqBody });
+ await readSuccessResponseJsonOrThrow(
+ resp2,
+ codecForExchangeWithdrawBatchResponse(),
+ );
}
+
+ const ubSig = await cryptoApi.unblindDenominationSignature({
+ planchet,
+ evSig: rBatch.ev_sigs[0].ev_sig,
+ });
+
+ return {
+ coinPriv: planchet.coinPriv,
+ coinPub: planchet.coinPub,
+ denomSig: ubSig,
+ denomPub: denom.denomPub,
+ denomPubHash: denom.denomPubHash,
+ feeDeposit: Amounts.stringify(denom.fees.feeDeposit),
+ feeRefresh: Amounts.stringify(denom.fees.feeRefresh),
+ exchangeBaseUrl: args.exchangeBaseUrl,
+ maxAge: AgeRestriction.AGE_UNRESTRICTED,
+ };
}
runWithdrawalIdempotentTest.suites = ["wallet"];