commit 79fc1f13f908040b209d1ebae785ff3bc8d05729
parent ef1b8fd44acc566cb57f00b887a617ea7b65e111
Author: Florian Dold <dold@taler.net>
Date: Thu, 20 Aug 2026 19:06:40 +0200
wallet-core: continue idempotent token allocation batches
Diffstat:
2 files changed, 43 insertions(+), 4 deletions(-)
diff --git a/packages/taler-wallet-core/src/common.test.ts b/packages/taler-wallet-core/src/common.test.ts
@@ -13,11 +13,16 @@
You should have received a copy of the GNU General Public License along with
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-import { Duration } from "@gnu-taler/taler-util";
+import { Duration, TransactionIdStr } from "@gnu-taler/taler-util";
import assert from "node:assert";
import { test } from "node:test";
-import { augmentTransferOptions, getRetryDuration } from "./common.js";
-import { KycAuthTransferOptionRaw } from "./db-common.js";
+import {
+ augmentTransferOptions,
+ getRetryDuration,
+ spendTokens,
+} from "./common.js";
+import { KycAuthTransferOptionRaw, WalletToken } from "./db-common.js";
+import { WalletDbTransaction } from "./dbtx.js";
test("the retry delay grows but stays bounded", (t) => {
const first = Duration.toMilliseconds(getRetryDuration(0));
@@ -53,3 +58,37 @@ test("augmenting transfer options does not expose internal metadata", () => {
},
]);
});
+
+test("spending tokens continues after an idempotently allocated token", async () => {
+ const transactionId = "txn:payment:proposal" as TransactionIdStr;
+ const tokens = new Map<string, WalletToken>([
+ [
+ "already-allocated",
+ {
+ tokenUsePub: "already-allocated",
+ transactionId,
+ } as unknown as WalletToken,
+ ],
+ [
+ "newly-allocated",
+ {
+ tokenUsePub: "newly-allocated",
+ } as unknown as WalletToken,
+ ],
+ ]);
+ const tx = {
+ async getToken(pub: string): Promise<WalletToken | undefined> {
+ return tokens.get(pub);
+ },
+ async upsertToken(token: WalletToken): Promise<void> {
+ tokens.set(token.tokenUsePub, token);
+ },
+ } as WalletDbTransaction;
+
+ await spendTokens(tx, {
+ transactionId,
+ tokenPubs: ["already-allocated", "newly-allocated"],
+ });
+
+ assert.strictEqual(tokens.get("newly-allocated")?.transactionId, transactionId);
+});
diff --git a/packages/taler-wallet-core/src/common.ts b/packages/taler-wallet-core/src/common.ts
@@ -298,7 +298,7 @@ export async function spendTokens(
if (token.transactionId !== tsi.transactionId) {
throw Error(`token already being spent in a different transaction`);
} else {
- return;
+ continue;
}
}