summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2023-04-21 22:02:34 +0200
committerFlorian Dold <florian@dold.me>2023-04-21 22:02:40 +0200
commite81ae0f3e5a510424076b611ac32385057cbdaed (patch)
tree1583ae253ec979f6dfdef5cd4581db6a7d33818a
parentfc2adae6bd34164b4a13b270be4c585f090afb61 (diff)
downloadwallet-core-e81ae0f3e5a510424076b611ac32385057cbdaed.tar.gz
wallet-core-e81ae0f3e5a510424076b611ac32385057cbdaed.tar.bz2
wallet-core-e81ae0f3e5a510424076b611ac32385057cbdaed.zip
wallet-harness: make sure events are not lost in deposit test
-rw-r--r--packages/taler-harness/src/harness/harness.ts1
-rw-r--r--packages/taler-harness/src/integrationtests/test-deposit.ts15
-rw-r--r--packages/taler-util/src/wallet-types.ts8
-rw-r--r--packages/taler-wallet-core/src/db.ts2
-rw-r--r--packages/taler-wallet-core/src/operations/deposits.ts46
-rw-r--r--packages/taler-wallet-core/src/operations/pay-merchant.ts4
-rw-r--r--packages/taler-wallet-core/src/operations/transactions.ts3
-rw-r--r--packages/taler-wallet-core/src/wallet.ts4
8 files changed, 69 insertions, 14 deletions
diff --git a/packages/taler-harness/src/harness/harness.ts b/packages/taler-harness/src/harness/harness.ts
index 840149e7c..0a898414d 100644
--- a/packages/taler-harness/src/harness/harness.ts
+++ b/packages/taler-harness/src/harness/harness.ts
@@ -2062,6 +2062,7 @@ export class WalletService {
[
"--wallet-db",
dbPath,
+ "-LDEBUG", // FIXME: Make this configurable?
"--no-throttle", // FIXME: Optionally do throttling for some tests?
"advanced",
"serve",
diff --git a/packages/taler-harness/src/integrationtests/test-deposit.ts b/packages/taler-harness/src/integrationtests/test-deposit.ts
index 1b46daf5f..6aa086107 100644
--- a/packages/taler-harness/src/integrationtests/test-deposit.ts
+++ b/packages/taler-harness/src/integrationtests/test-deposit.ts
@@ -45,9 +45,17 @@ export async function runDepositTest(t: GlobalTestState) {
await withdrawalResult.withdrawalFinishedCond;
- const depositDone = await walletClient.waitForNotificationCond(
+ const dgIdResp = await walletClient.client.call(
+ WalletApiOperation.GenerateDepositGroupTxId,
+ {},
+ );
+
+ const depositTxId = dgIdResp.transactionId;
+
+ const depositDone = walletClient.waitForNotificationCond(
(n) =>
n.type == NotificationType.TransactionStateTransition &&
+ n.transactionId == depositTxId &&
n.newTxState == TransactionState.Done,
);
@@ -56,9 +64,14 @@ export async function runDepositTest(t: GlobalTestState) {
{
amount: "TESTKUDOS:10",
depositPaytoUri: getPayto("foo"),
+ transactionId: depositTxId,
},
);
+ t.assertDeepEqual(depositGroupResult.transactionId, depositTxId);
+
+ await depositDone;
+
const transactions = await walletClient.client.call(
WalletApiOperation.GetTransactions,
{},
diff --git a/packages/taler-util/src/wallet-types.ts b/packages/taler-util/src/wallet-types.ts
index 5979f14b4..4297e838d 100644
--- a/packages/taler-util/src/wallet-types.ts
+++ b/packages/taler-util/src/wallet-types.ts
@@ -1708,6 +1708,13 @@ export interface DepositGroupFees {
}
export interface CreateDepositGroupRequest {
+ /**
+ * Pre-allocated transaction ID.
+ * Allows clients to easily handle notifications
+ * that occur while the operation has been created but
+ * before the creation request has returned.
+ */
+ transactionId?: string;
depositPaytoUri: string;
amount: AmountString;
}
@@ -1733,6 +1740,7 @@ export const codecForCreateDepositGroupRequest =
buildCodecForObject<CreateDepositGroupRequest>()
.property("amount", codecForAmountString())
.property("depositPaytoUri", codecForString())
+ .property("transactionId", codecOptional(codecForString()))
.build("CreateDepositGroupRequest");
export interface CreateDepositGroupResponse {
diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts
index 4e9228c6d..f5342b4cd 100644
--- a/packages/taler-wallet-core/src/db.ts
+++ b/packages/taler-wallet-core/src/db.ts
@@ -865,6 +865,7 @@ export enum DepositGroupOperationStatus {
AbortingWithRefresh = 11 /* ACTIVE_START + 1 */,
}
+// FIXME: Improve name! This enum is very specific to deposits.
export enum TransactionStatus {
Unknown = 10,
Accepted = 20,
@@ -1380,6 +1381,7 @@ export type WgInfo =
| WgInfoBankRecoup;
export type KycUserType = "individual" | "business";
+
export interface KycPendingInfo {
paytoHash: string;
requirementRow: number;
diff --git a/packages/taler-wallet-core/src/operations/deposits.ts b/packages/taler-wallet-core/src/operations/deposits.ts
index 700b875d3..f5ea41e01 100644
--- a/packages/taler-wallet-core/src/operations/deposits.ts
+++ b/packages/taler-wallet-core/src/operations/deposits.ts
@@ -67,7 +67,7 @@ import { getTotalRefreshCost, KycPendingInfo, KycUserType } from "../index.js";
import { InternalWalletState } from "../internal-wallet-state.js";
import { readSuccessResponseJsonOrThrow } from "@gnu-taler/taler-util/http";
import { OperationAttemptResult } from "../util/retries.js";
-import { makeTransactionId, spendCoins } from "./common.js";
+import { spendCoins } from "./common.js";
import { getExchangeDetails } from "./exchanges.js";
import {
extractContractData,
@@ -75,13 +75,20 @@ import {
getTotalPaymentCost,
} from "./pay-merchant.js";
import { selectPayCoinsNew } from "../util/coinSelection.js";
-import { constructTransactionIdentifier } from "./transactions.js";
+import {
+ constructTransactionIdentifier,
+ parseTransactionIdentifier,
+} from "./transactions.js";
/**
* Logger.
*/
const logger = new Logger("deposits.ts");
+/**
+ * Get the (DD37-style) transaction status based on the
+ * database record of a deposit group.
+ */
export async function computeDepositTransactionStatus(
ws: InternalWalletState,
dg: DepositGroupRecord,
@@ -151,7 +158,8 @@ export async function abortDepositGroup(
}
/**
- * Check KYC status with the exchange, throw an appropriate exception when KYC is required.
+ * Check KYC status with the exchange, throw an appropriate exception when KYC
+ * is required.
*
* FIXME: Why does this throw an exception when KYC is required?
* Should we not return some proper result record here?
@@ -221,6 +229,7 @@ export async function processDepositGroup(
// Check for cancellation before expensive operations.
options.cancellationToken?.throwIfCancelled();
+ // FIXME: Cache these!
const depositPermissions = await generateDepositPermissions(
ws,
depositGroup.payCoinSelection,
@@ -438,7 +447,7 @@ async function trackDepositPermission(
wireHash,
});
url.searchParams.set("merchant_sig", sigResp.sig);
- const httpResp = await ws.http.get(url.href);
+ const httpResp = await ws.http.fetch(url.href, { method: "GET" });
switch (httpResp.status) {
case HttpStatusCode.Accepted: {
const accepted = await readSuccessResponseJsonOrThrow(
@@ -463,6 +472,9 @@ async function trackDepositPermission(
}
/**
+ * Check if creating a deposit group is possible and calculate
+ * the associated fees.
+ *
* FIXME: This should be renamed to checkDepositGroup,
* as it doesn't prepare anything
*/
@@ -671,9 +683,18 @@ export async function createDepositGroup(
const totalDepositCost = await getTotalPaymentCost(ws, payCoinSel.coinSel);
- const depositGroupId = encodeCrock(getRandomBytes(32));
+ let depositGroupId: string;
+ if (req.transactionId) {
+ const txId = parseTransactionIdentifier(req.transactionId);
+ if (!txId || txId.tag !== TransactionType.Deposit) {
+ throw Error("invalid transaction ID");
+ }
+ depositGroupId = txId.depositGroupId;
+ } else {
+ depositGroupId = encodeCrock(getRandomBytes(32));
+ }
- const countarpartyEffectiveDepositAmount =
+ const counterpartyEffectiveDepositAmount =
await getCounterpartyEffectiveDepositAmount(
ws,
p.targetType,
@@ -698,7 +719,7 @@ export async function createDepositGroup(
merchantPub: merchantPair.pub,
totalPayCost: Amounts.stringify(totalDepositCost),
effectiveDepositAmount: Amounts.stringify(
- countarpartyEffectiveDepositAmount,
+ counterpartyEffectiveDepositAmount,
),
wire: {
payto_uri: req.depositPaytoUri,
@@ -707,6 +728,11 @@ export async function createDepositGroup(
operationStatus: OperationStatus.Pending,
};
+ const transactionId = constructTransactionIdentifier({
+ tag: TransactionType.Deposit,
+ depositGroupId,
+ });
+
await ws.db
.mktx((x) => [
x.depositGroups,
@@ -718,7 +744,7 @@ export async function createDepositGroup(
])
.runReadWrite(async (tx) => {
await spendCoins(ws, tx, {
- allocationId: `txn:deposit:${depositGroup.depositGroupId}`,
+ allocationId: transactionId,
coinPubs: payCoinSel.coinSel.coinPubs,
contributions: payCoinSel.coinSel.coinContributions.map((x) =>
Amounts.parseOrThrow(x),
@@ -729,8 +755,8 @@ export async function createDepositGroup(
});
return {
- depositGroupId: depositGroupId,
- transactionId: makeTransactionId(TransactionType.Deposit, depositGroupId),
+ depositGroupId,
+ transactionId,
};
}
diff --git a/packages/taler-wallet-core/src/operations/pay-merchant.ts b/packages/taler-wallet-core/src/operations/pay-merchant.ts
index 2419d32a2..e79314416 100644
--- a/packages/taler-wallet-core/src/operations/pay-merchant.ts
+++ b/packages/taler-wallet-core/src/operations/pay-merchant.ts
@@ -1459,7 +1459,9 @@ export async function processPurchasePay(
);
const resp = await ws.runSequentialized([EXCHANGE_COINS_LOCK], () =>
- ws.http.postJson(payUrl, reqBody, {
+ ws.http.fetch(payUrl, {
+ method: "POST",
+ body: reqBody,
timeout: getPayRequestTimeout(purchase),
}),
);
diff --git a/packages/taler-wallet-core/src/operations/transactions.ts b/packages/taler-wallet-core/src/operations/transactions.ts
index 3ace5bf71..6a71b5c1e 100644
--- a/packages/taler-wallet-core/src/operations/transactions.ts
+++ b/packages/taler-wallet-core/src/operations/transactions.ts
@@ -34,6 +34,7 @@ import {
TalerProtocolTimestamp,
Transaction,
TransactionByIdRequest,
+ TransactionIdStr,
TransactionsRequest,
TransactionsResponse,
TransactionState,
@@ -1428,7 +1429,7 @@ export type ParsedTransactionIdentifier =
export function constructTransactionIdentifier(
pTxId: ParsedTransactionIdentifier,
-): string {
+): TransactionIdStr {
switch (pTxId.tag) {
case TransactionType.Deposit:
return `txn:${pTxId.tag}:${pTxId.depositGroupId}`;
diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts
index d554e5b83..435a4e241 100644
--- a/packages/taler-wallet-core/src/wallet.ts
+++ b/packages/taler-wallet-core/src/wallet.ts
@@ -1335,7 +1335,9 @@ async function dispatchRequestInternal<Op extends WalletApiOperation>(
return await prepareDepositGroup(ws, req);
}
case WalletApiOperation.GenerateDepositGroupTxId:
- return generateDepositGroupTxId();
+ return {
+ transactionId: generateDepositGroupTxId(),
+ };
case WalletApiOperation.CreateDepositGroup: {
const req = codecForCreateDepositGroupRequest().decode(payload);
return await createDepositGroup(ws, req);