wallet-harness: make sure events are not lost in deposit test
This commit is contained in:
parent
fc2adae6bd
commit
e81ae0f3e5
@ -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",
|
||||
|
@ -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,
|
||||
{},
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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),
|
||||
}),
|
||||
);
|
||||
|
@ -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}`;
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user