commit bf50fc933b8a5a610d5b432a80d1ecd7034852f9
parent 924021844669875d25ea73352ced9d43ef3b16a8
Author: Florian Dold <florian@dold.me>
Date: Fri, 17 Jul 2026 18:21:57 +0200
wallet: be more consistent with state transition on Gone, make tests less timing sensitive
Diffstat:
2 files changed, 27 insertions(+), 33 deletions(-)
diff --git a/packages/taler-harness/src/integrationtests/test-peer-pull.ts b/packages/taler-harness/src/integrationtests/test-peer-pull.ts
@@ -36,6 +36,15 @@ const purse_expiration = AbsoluteTime.toProtocolTimestamp(
AbsoluteTime.addDuration(AbsoluteTime.now(), Duration.fromSpec({ days: 2 })),
);
+const stFailedOrExpired = [
+ {
+ major: TransactionMajorState.Failed,
+ },
+ {
+ major: TransactionMajorState.Expired,
+ },
+];
+
/**
* Run a test for basic peer-pull payments.
*/
@@ -205,9 +214,7 @@ export async function runPeerPullTest(t: GlobalTestState) {
}),
wallet3.call(WalletApiOperation.TestingWaitTransactionState, {
transactionId: prepare3.transactionId,
- txState: {
- major: TransactionMajorState.Failed,
- },
+ txState: stFailedOrExpired,
timeout: { seconds: 10 },
}),
wallet4.call(WalletApiOperation.TestingWaitTransactionState, {
@@ -309,18 +316,14 @@ export async function runPeerPullTest(t: GlobalTestState) {
}),
wallet3.call(WalletApiOperation.TestingWaitTransactionState, {
transactionId: prepare3.transactionId,
- txState: {
- major: TransactionMajorState.Failed,
- },
+ txState: stFailedOrExpired,
timeout: { seconds: 10 },
}),
]),
Promise.all([
wallet2.call(WalletApiOperation.TestingWaitTransactionState, {
transactionId: prepare2.transactionId,
- txState: {
- major: TransactionMajorState.Failed,
- },
+ txState: stFailedOrExpired,
timeout: { seconds: 10 },
}),
wallet3.call(WalletApiOperation.TestingWaitTransactionState, {
diff --git a/packages/taler-wallet-core/src/pay-peer-pull-debit.ts b/packages/taler-wallet-core/src/pay-peer-pull-debit.ts
@@ -61,7 +61,6 @@ import {
encodeCrock,
getRandomBytes,
j2s,
- makeTalerErrorDetail,
} from "@gnu-taler/taler-util";
import { PreviousPayCoins, selectPeerCoins } from "./coinSelection.js";
import {
@@ -77,11 +76,10 @@ import {
import {
PeerPullDebitRecordStatus,
RefreshOperationStatus,
+ WalletPeerPullDebit,
timestampPreciseFromDb,
timestampPreciseToDb,
- WalletPeerPullDebit,
} from "./db-common.js";
-import { WalletIndexedDbTransaction } from "./db-indexeddb.js";
import { getExchangeScopeInfo, getScopeForAllExchanges } from "./exchanges.js";
import {
getTotalPeerPaymentCost,
@@ -217,6 +215,18 @@ export class PeerPullDebitTransactionContext implements TransactionContext {
});
}
+ async expireTransaction(fromSt: PeerPullDebitRecordStatus): Promise<void> {
+ const { wex } = this;
+ await wex.runLegacyWalletDbTx(async (tx) => {
+ const [rec, h] = await this.getRecordHandle(tx);
+ if (rec?.status != fromSt) {
+ return;
+ }
+ rec.status = PeerPullDebitRecordStatus.Expired;
+ await h.update(rec);
+ });
+ }
+
async userDeleteTransaction(): Promise<void> {
await this.wex.runLegacyWalletDbTx(async (tx) => {
await this.deleteTransactionInTx(tx);
@@ -457,20 +467,7 @@ async function processPeerPullDebitDialogProposed(
break;
case HttpStatusCode.Gone:
// Exchange says that purse doesn't exist anymore => expired!
- await ctx.wex.runLegacyWalletDbTx(async (tx) => {
- const [rec, h] = await ctx.getRecordHandle(tx);
- if (!rec) {
- return;
- }
- switch (rec.status) {
- case PeerPullDebitRecordStatus.DialogProposed:
- rec.status = PeerPullDebitRecordStatus.Expired;
- break;
- default:
- return;
- }
- await h.update(rec);
- });
+ await ctx.expireTransaction(PeerPullDebitRecordStatus.DialogProposed);
return TaskRunResult.finished();
case HttpStatusCode.NotFound:
await ctx.failTransaction(pullIni.status, resp.detail);
@@ -611,13 +608,7 @@ async function processPeerPullDebitPendingDeposit(
case "ok":
continue;
case HttpStatusCode.Gone: {
- await ctx.failTransaction(
- peerPullInc.status,
- makeTalerErrorDetail(
- TalerErrorCode.WALLET_PEER_PULL_DEBIT_PURSE_GONE,
- {},
- ),
- );
+ await ctx.expireTransaction(peerPullInc.status);
return TaskRunResult.finished();
}
case HttpStatusCode.Conflict: