commit b9755dd70ae0f0cffe41197fca05ee3794ad3e17
parent fae7e033790d09aca85aeb1de53b2bdc73cb2d0b
Author: Florian Dold <florian@dold.me>
Date: Thu, 19 Mar 2026 22:08:48 +0100
wallet-core: fix pub/priv confusion in deposit heuristic, modernize deposit tests
Diffstat:
8 files changed, 102 insertions(+), 179 deletions(-)
diff --git a/packages/taler-harness/src/integrationtests/test-age-restrictions-deposit.ts b/packages/taler-harness/src/integrationtests/test-age-restrictions-deposit.ts
@@ -59,23 +59,15 @@ export async function runAgeRestrictionsDepositTest(t: GlobalTestState) {
await withdrawalResult.withdrawalFinishedCond;
- const dgIdResp = await walletClient.client.call(
- WalletApiOperation.GenerateDepositGroupTxId,
- {},
- );
-
- const depositTxId = dgIdResp.transactionId;
-
const depositGroupResult = await walletClient.client.call(
WalletApiOperation.CreateDepositGroup,
{
amount: "TESTKUDOS:10" as AmountString,
depositPaytoUri: getTestHarnessPaytoForLabel("foo"),
- transactionId: depositTxId,
},
);
- t.assertDeepEqual(depositGroupResult.transactionId, depositTxId);
+ const depositTxId = depositGroupResult.transactionId;
await walletClient.call(WalletApiOperation.TestingWaitTransactionState, {
transactionId: depositTxId,
diff --git a/packages/taler-harness/src/integrationtests/test-deposit-merge.ts b/packages/taler-harness/src/integrationtests/test-deposit-merge.ts
@@ -18,10 +18,9 @@
* Imports.
*/
import {
+ AbsoluteTime,
AmountString,
Duration,
- NotificationType,
- TransactionIdStr,
TransactionMajorState,
TransactionMinorState,
j2s,
@@ -62,46 +61,31 @@ export async function runDepositMergeTest(t: GlobalTestState) {
/**
* first deposit
*/
- let d1Id: TransactionIdStr;
- let d1Track: Promise<boolean>;
- let d1Done: Promise<boolean>;
- {
- const { transactionId: depositTxId } = await walletClient.client.call(
- WalletApiOperation.GenerateDepositGroupTxId,
- {},
- );
-
- d1Track = walletClient.waitForNotificationCond(
- (n) =>
- n.type == NotificationType.TransactionStateTransition &&
- n.transactionId == depositTxId &&
- n.newTxState.major == TransactionMajorState.Finalizing &&
- n.newTxState.minor == TransactionMinorState.Track,
- );
-
- d1Done = walletClient.waitForNotificationCond(
- (n) =>
- n.type == NotificationType.TransactionStateTransition &&
- n.transactionId == depositTxId &&
- n.newTxState.major == TransactionMajorState.Done,
- );
-
- const depositGroupResult = await walletClient.client.call(
- WalletApiOperation.CreateDepositGroup,
- {
- amount: "TESTKUDOS:3" as AmountString,
- depositPaytoUri,
- transactionId: depositTxId,
- },
- );
-
- t.assertDeepEqual(depositGroupResult.transactionId, depositTxId);
- d1Id = depositGroupResult.transactionId;
- }
+ const depositGroupResult1 = await walletClient.client.call(
+ WalletApiOperation.CreateDepositGroup,
+ {
+ amount: "TESTKUDOS:3" as AmountString,
+ depositPaytoUri,
+ wireDeadline: AbsoluteTime.toProtocolTimestamp(
+ AbsoluteTime.addDuration(
+ AbsoluteTime.now(),
+ Duration.fromSpec({ minutes: 5 }),
+ ),
+ ),
+ },
+ );
+ const d1Id = depositGroupResult1.transactionId;
t.logStep("after first deposit");
- await d1Track;
+ await walletClient.call(WalletApiOperation.TestingWaitTransactionState, {
+ transactionId: d1Id,
+ txState: {
+ major: TransactionMajorState.Finalizing,
+ minor: TransactionMinorState.Track,
+ },
+ });
+
await exchange.stop();
// @ts-ignore duration is not forever
exchange.setTimetravel(Duration.fromSpec({ minutes: 1 }).d_ms);
@@ -114,46 +98,32 @@ export async function runDepositMergeTest(t: GlobalTestState) {
/**
* second deposit after 1 minute
*/
- let d2Id: TransactionIdStr;
- let d2Track: Promise<boolean>;
- let d2Done: Promise<boolean>;
- {
- const { transactionId: depositTxId } = await walletClient.client.call(
- WalletApiOperation.GenerateDepositGroupTxId,
- {},
- );
-
- d2Track = walletClient.waitForNotificationCond(
- (n) =>
- n.type == NotificationType.TransactionStateTransition &&
- n.transactionId == depositTxId &&
- n.newTxState.major == TransactionMajorState.Finalizing &&
- n.newTxState.minor == TransactionMinorState.Track,
- );
- d2Done = walletClient.waitForNotificationCond(
- (n) =>
- n.type == NotificationType.TransactionStateTransition &&
- n.transactionId == depositTxId &&
- n.newTxState.major == TransactionMajorState.Done,
- );
-
- const depositGroupResult = await walletClient.client.call(
- WalletApiOperation.CreateDepositGroup,
- {
- amount: "TESTKUDOS:3" as AmountString,
- depositPaytoUri,
- transactionId: depositTxId,
- },
- );
-
- t.assertDeepEqual(depositGroupResult.transactionId, depositTxId);
- d2Id = depositGroupResult.transactionId;
- }
+ const depositGroupResult2 = await walletClient.client.call(
+ WalletApiOperation.CreateDepositGroup,
+ {
+ amount: "TESTKUDOS:3" as AmountString,
+ depositPaytoUri,
+ wireDeadline: AbsoluteTime.toProtocolTimestamp(
+ AbsoluteTime.addDuration(
+ AbsoluteTime.now(),
+ Duration.fromSpec({ minutes: 5 }),
+ ),
+ ),
+ },
+ );
+
+ const d2Id = depositGroupResult2.transactionId;
t.logStep("done with second deposit");
- await d2Track;
+ await walletClient.call(WalletApiOperation.TestingWaitTransactionState, {
+ transactionId: d2Id,
+ txState: {
+ major: TransactionMajorState.Finalizing,
+ minor: TransactionMinorState.Track,
+ },
+ });
t.logStep("done with second deposit (track)");
await exchange.stop();
@@ -166,44 +136,29 @@ export async function runDepositMergeTest(t: GlobalTestState) {
/**
* third deposit after 2 minute
*/
- let d3Id: TransactionIdStr;
- let d3Track: Promise<boolean>;
- let d3Done: Promise<boolean>;
- {
- const { transactionId: depositTxId } = await walletClient.client.call(
- WalletApiOperation.GenerateDepositGroupTxId,
- {},
- );
-
- d3Track = walletClient.waitForNotificationCond(
- (n) =>
- n.type == NotificationType.TransactionStateTransition &&
- n.transactionId == depositTxId &&
- n.newTxState.major == TransactionMajorState.Finalizing &&
- n.newTxState.minor == TransactionMinorState.Track,
- );
-
- d3Done = walletClient.waitForNotificationCond(
- (n) =>
- n.type == NotificationType.TransactionStateTransition &&
- n.transactionId == depositTxId &&
- n.newTxState.major == TransactionMajorState.Done,
- );
-
- const depositGroupResult = await walletClient.client.call(
- WalletApiOperation.CreateDepositGroup,
- {
- amount: "TESTKUDOS:3" as AmountString,
- depositPaytoUri,
- transactionId: depositTxId,
- },
- );
-
- t.assertDeepEqual(depositGroupResult.transactionId, depositTxId);
- d3Id = depositGroupResult.transactionId;
- }
-
- await d3Track;
+ const depositGroupResult3 = await walletClient.client.call(
+ WalletApiOperation.CreateDepositGroup,
+ {
+ amount: "TESTKUDOS:3" as AmountString,
+ depositPaytoUri,
+ wireDeadline: AbsoluteTime.toProtocolTimestamp(
+ AbsoluteTime.addDuration(
+ AbsoluteTime.now(),
+ Duration.fromSpec({ minutes: 5 }),
+ ),
+ ),
+ },
+ );
+
+ const d3Id = depositGroupResult3.transactionId;
+
+ await walletClient.call(WalletApiOperation.TestingWaitTransactionState, {
+ transactionId: d3Id,
+ txState: {
+ major: TransactionMajorState.Finalizing,
+ minor: TransactionMinorState.Track,
+ },
+ });
await exchange.stop();
// @ts-ignore duration is not forever
exchange.setTimetravel(Duration.fromSpec({ minutes: 3 }).d_ms);
@@ -271,9 +226,24 @@ export async function runDepositMergeTest(t: GlobalTestState) {
transactionId: d3Id,
});
- await d1Done;
- await d2Done;
- await d3Done;
+ await walletClient.call(WalletApiOperation.TestingWaitTransactionState, {
+ transactionId: d1Id,
+ txState: {
+ major: TransactionMajorState.Done,
+ },
+ });
+ await walletClient.call(WalletApiOperation.TestingWaitTransactionState, {
+ transactionId: d2Id,
+ txState: {
+ major: TransactionMajorState.Done,
+ },
+ });
+ await walletClient.call(WalletApiOperation.TestingWaitTransactionState, {
+ transactionId: d3Id,
+ txState: {
+ major: TransactionMajorState.Done,
+ },
+ });
/* check deposit tx after 6 minute, first one should already be wired since default
* wire deadline is 5 minutes
*
diff --git a/packages/taler-harness/src/integrationtests/test-deposit.ts b/packages/taler-harness/src/integrationtests/test-deposit.ts
@@ -71,22 +71,16 @@ export async function runDepositTest(t: GlobalTestState) {
t.assertAmountEquals(maxDepositResp.rawAmount, "TESTKUDOS:19.72");
t.assertAmountEquals(maxDepositResp.effectiveAmount, "TESTKUDOS:19.84");
- const dgIdResp = await walletClient.client.call(
- WalletApiOperation.GenerateDepositGroupTxId,
- {},
- );
-
- const depositTxId = dgIdResp.transactionId;
-
const depositGroupResult = await walletClient.client.call(
WalletApiOperation.CreateDepositGroup,
{
amount: "TESTKUDOS:10" as AmountString,
depositPaytoUri,
- transactionId: depositTxId,
},
);
+ const depositTxId = depositGroupResult.transactionId;
+
t.assertDeepEqual(depositGroupResult.transactionId, depositTxId);
const balDuring = await walletClient.call(WalletApiOperation.GetBalances, {});
diff --git a/packages/taler-harness/src/integrationtests/test-kyc-deposit-kycauth.ts b/packages/taler-harness/src/integrationtests/test-kyc-deposit-kycauth.ts
@@ -124,20 +124,16 @@ export async function runKycDepositKycauthTest(t: GlobalTestState) {
},
});
- const { transactionId: depositTxId } = await w1.walletClient.call(
- WalletApiOperation.GenerateDepositGroupTxId,
- {},
- );
-
const deposit = await w1.walletClient.call(
WalletApiOperation.CreateDepositGroup,
{
amount: "TESTKUDOS:10" as AmountString,
depositPaytoUri: getTestHarnessPaytoForLabel("foo"),
- transactionId: depositTxId,
},
);
+ const depositTxId = deposit.transactionId;
+
await w1.walletClient.call(WalletApiOperation.TestingWaitTransactionState, {
transactionId: depositTxId,
txState: {
diff --git a/packages/taler-util/src/types-taler-wallet.ts b/packages/taler-util/src/types-taler-wallet.ts
@@ -3116,6 +3116,11 @@ export interface CreateDepositGroupRequest {
testingFixedPriv?: string;
/**
+ * Optional wire deadline for the deposits.
+ */
+ wireDeadline?: TalerProtocolTimestamp;
+
+ /**
* Pre-allocated transaction ID.
* Allows clients to easily handle notifications
* that occur while the operation has been created but
@@ -3187,6 +3192,7 @@ export const codecForCreateDepositGroupRequest =
.property("depositPaytoUri", codecForString())
.property("transactionId", codecOptional(codecForTransactionIdStr()))
.property("testingFixedPriv", codecOptional(codecForString()))
+ .property("wireDeadline", codecOptional(codecForTimestamp))
.build("CreateDepositGroupRequest");
/**
diff --git a/packages/taler-wallet-core/src/deposits.ts b/packages/taler-wallet-core/src/deposits.ts
@@ -1236,10 +1236,10 @@ async function provideDepositAccountKeypair(
if (!exchange) {
throw Error("exchange for deposit not found anymore");
}
- if (exchange.currentAccountPriv && exchange.currentAccountPriv) {
+ if (exchange.currentAccountPriv && exchange.currentAccountPub) {
return {
priv: exchange.currentAccountPriv,
- pub: exchange.currentAccountPriv,
+ pub: exchange.currentAccountPub,
};
}
const res = await tryFindAccountKeypair(tx, exchangeBaseUrl);
@@ -2016,14 +2016,6 @@ export async function internalCheckDepositGroup(
};
}
-export function generateDepositGroupTxId(): string {
- const depositGroupId = encodeCrock(getRandomBytes(32));
- return constructTransactionIdentifier({
- tag: TransactionType.Deposit,
- depositGroupId: depositGroupId,
- });
-}
-
export async function createDepositGroup(
wex: WalletExecutionContext,
req: CreateDepositGroupRequest,
@@ -2046,7 +2038,8 @@ export async function createDepositGroup(
}
const now = AbsoluteTime.now();
- const wireDeadline = AbsoluteTime.toProtocolTimestamp(now);
+ const wireDeadline =
+ req.wireDeadline ?? AbsoluteTime.toProtocolTimestamp(now);
const nowRounded = AbsoluteTime.toProtocolTimestamp(now);
const payCoinSel = await selectPayCoins(wex, {
diff --git a/packages/taler-wallet-core/src/wallet-api-types.ts b/packages/taler-wallet-core/src/wallet-api-types.ts
@@ -267,7 +267,6 @@ export enum WalletApiOperation {
ForceRefresh = "forceRefresh",
CheckDeposit = "checkDeposit",
GetVersion = "getVersion",
- GenerateDepositGroupTxId = "generateDepositGroupTxId",
CreateDepositGroup = "createDepositGroup",
ImportDb = "importDb",
ExportDb = "exportDb",
@@ -1087,19 +1086,6 @@ export type GetCurrencySpecificationOp = {
// group: Deposits
/**
- * Generate a fresh transaction ID for a deposit group.
- *
- * The resulting transaction ID can be specified when creating
- * a deposit group, so that the client can already start waiting for notifications
- * on that specific deposit group before the GreateDepositGroup request returns.
- */
-export type GenerateDepositGroupTxIdOp = {
- op: WalletApiOperation.GenerateDepositGroupTxId;
- request: EmptyObject;
- response: TxIdResponse;
-};
-
-/**
* Create a new deposit group.
*
* Deposit groups are used to deposit multiple coins to a bank
@@ -1613,7 +1599,6 @@ export type WalletOperations = {
[WalletApiOperation.GetExchangeDetailedInfo]: GetExchangeDetailedInfoOp;
[WalletApiOperation.GetExchangeEntryByUrl]: GetExchangeEntryByUrlOp;
[WalletApiOperation.CheckDeposit]: CheckDepositOp;
- [WalletApiOperation.GenerateDepositGroupTxId]: GenerateDepositGroupTxIdOp;
[WalletApiOperation.CreateDepositGroup]: CreateDepositGroupOp;
[WalletApiOperation.ExportDbToFile]: ExportDbToFileOp;
[WalletApiOperation.ImportDbFromFile]: ImportDbFromFileOp;
diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts
@@ -150,7 +150,6 @@ import {
TestingSetTimetravelRequest,
TimerAPI,
TimerGroup,
- TransactionIdStr,
TransactionType,
TransactionsResponse,
UpdateExchangeEntryRequest,
@@ -323,11 +322,7 @@ import {
isWithdrawableDenom,
} from "./denominations.js";
import { UnverifiedDenomError } from "./denomSelection.js";
-import {
- checkDepositGroup,
- createDepositGroup,
- generateDepositGroupTxId,
-} from "./deposits.js";
+import { checkDepositGroup, createDepositGroup } from "./deposits.js";
import { DevExperimentHttpLib, applyDevExperiment } from "./dev-experiments.js";
import {
handleGetDonau,
@@ -2513,14 +2508,6 @@ const handlers: { [T in WalletApiOperation]: HandlerWithValidator<T> } = {
codec: codecForCheckDepositRequest(),
handler: checkDepositGroup,
},
- [WalletApiOperation.GenerateDepositGroupTxId]: {
- codec: codecForEmptyObject(),
- handler: async (wex, req) => {
- return {
- transactionId: generateDepositGroupTxId() as TransactionIdStr,
- };
- },
- },
[WalletApiOperation.CreateDepositGroup]: {
codec: codecForCreateDepositGroupRequest(),
handler: createDepositGroup,