taler-typescript-core

Wallet core logic and WebUIs for various components
Log | Files | Refs | Submodules | README | LICENSE

commit bd595927c041e93cd0fb881304abf4fcc0539624
parent 51920edbf7702dfc52a4c55a6471972d50221ece
Author: Florian Dold <florian@dold.me>
Date:   Sat, 14 Feb 2026 00:56:46 +0100

test for refresh redenomination, flight recorder

Diffstat:
Mpackages/taler-harness/src/integrationtests/testrunner.ts | 2++
Mpackages/taler-util/src/types-taler-wallet.ts | 14++++++++++++++
Mpackages/taler-wallet-cli/src/index.ts | 6+++---
Mpackages/taler-wallet-core/src/refresh.ts | 8++++++++
Mpackages/taler-wallet-core/src/wallet-api-types.ts | 17++++++++++++++---
Mpackages/taler-wallet-core/src/wallet.ts | 30+++++++++++++++++++++++++++++-
6 files changed, 70 insertions(+), 7 deletions(-)

diff --git a/packages/taler-harness/src/integrationtests/testrunner.ts b/packages/taler-harness/src/integrationtests/testrunner.ts @@ -218,6 +218,7 @@ import { runWithdrawalManualTest } from "./test-withdrawal-manual.js"; import { runWithdrawalPrepareTest } from "./test-withdrawal-prepare.js"; import { runMerchantBankBadWireTargetTest } from "./test-merchant-bank-bad-wire-target.js"; import { runWebMerchantLoginTest } from "./web/test-merchant-login.js"; +import { runWalletRefreshRedenominateTest } from "./test-wallet-refresh-redenominate.js"; /** * Test runner. @@ -419,6 +420,7 @@ const allTests: TestMainFunction[] = [ runMerchantBankBadWireTargetTest, runWalletBbanTest, runCurrencyScopeSeparationTest, + runWalletRefreshRedenominateTest, ]; export interface TestRunSpec { diff --git a/packages/taler-util/src/types-taler-wallet.ts b/packages/taler-util/src/types-taler-wallet.ts @@ -4077,6 +4077,10 @@ export interface TestingGetDiagnosticsResponse { }[]; } +export interface TestingGetFlightRecordsResponse { + flightRecords: FlightRecordEntry[]; +} + export const codecForTestingGetDenomStatsRequest = (): Codec<TestingGetDenomStatsRequest> => buildCodecForObject<TestingGetDenomStatsRequest>() @@ -4701,3 +4705,13 @@ export const codecForGetDonauStatementsRequest = buildCodecForObject<GetDonauStatementsRequest>() .property("donauBaseUrl", codecOptional(codecForString())) .build("GetDonauStatementsRequest"); + +export interface FlightRecordEntry { + timestamp: TalerPreciseTimestamp; + target: string; + event: FlightRecordEvent; +} + +export enum FlightRecordEvent { + MeltGone = "melt-gone", +} diff --git a/packages/taler-wallet-cli/src/index.ts b/packages/taler-wallet-cli/src/index.ts @@ -1510,7 +1510,7 @@ advancedCli .action(async (args) => { await withWallet(args, { lazyTaskLoop: true }, async (wallet) => { const diagResp = await wallet.client.call( - WalletApiOperation.TestingGetDiagnostics, + WalletApiOperation.GetDiagnostics, {}, ); console.log(j2s(diagResp)); @@ -1520,12 +1520,12 @@ advancedCli advancedCli .subcommand("performanceStats", "performance-stats", { help: "Print performance stats.", -}) + }) .maybeOption("limit", ["--limit"], clk.INT, { help: "Limit each table to n entries.", }) .action(async (args) => { - await withWallet(args, { lazyTaskLoop: true}, async (wallet) => { + await withWallet(args, { lazyTaskLoop: true }, async (wallet) => { const statsResp = await wallet.client.call( WalletApiOperation.TestingGetPerformanceStats, { limit: args.performanceStats.limit }, diff --git a/packages/taler-wallet-core/src/refresh.ts b/packages/taler-wallet-core/src/refresh.ts @@ -43,6 +43,7 @@ import { ExchangeMeltRequestV2, ExchangeRefreshRevealRequestV2, ExchangeRefundRequest, + FlightRecordEvent, fnutil, ForceRefreshRequest, ForceRefreshResponse, @@ -848,6 +849,13 @@ async function handleRefreshMeltGone( // FIXME: Validate signature, possibly even store. + logger.warn(`handling melt Gone response from exchange`); + + ctx.wex.ws.addFdr({ + event: FlightRecordEvent.MeltGone, + target: ctx.transactionId, + }); + await ctx.wex.db.runReadWriteTx( { storeNames: [ diff --git a/packages/taler-wallet-core/src/wallet-api-types.ts b/packages/taler-wallet-core/src/wallet-api-types.ts @@ -180,6 +180,7 @@ import { TestingGetDenomStatsRequest, TestingGetDenomStatsResponse, TestingGetDiagnosticsResponse, + TestingGetFlightRecordsResponse, TestingGetReserveHistoryRequest, TestingPlanMigrateExchangeBaseUrlRequest, TestingSetTimetravelRequest, @@ -368,9 +369,12 @@ export enum WalletApiOperation { TestingWaitExchangeWalletKyc = "testingWaitWalletKyc", TestingPlanMigrateExchangeBaseUrl = "testingPlanMigrateExchangeBaseUrl", TestingRunFixup = "testingRunFixup", - TestingGetDiagnostics = "getDiagnostics", + TestingGetFlightRecords = "testingGetFlightRecords", TestingGetPerformanceStats = "testingGetPerformanceStats", + // Diagnostics + GetDiagnostics = "getDiagnostics", + // Hints HintNetworkAvailability = "hintNetworkAvailability", @@ -1633,11 +1637,17 @@ export type TestingRunFixupOp = { }; export type TestingGetDiagnosticsOp = { - op: WalletApiOperation.TestingGetDiagnostics; + op: WalletApiOperation.GetDiagnostics; request: EmptyObject; response: TestingGetDiagnosticsResponse; }; +export type TestingGetFlightRecordsOp = { + op: WalletApiOperation.TestingGetFlightRecords; + request: EmptyObject; + response: TestingGetFlightRecordsResponse; +}; + /** * Set a coin as (un-)suspended. * Suspended coins won't be used for payments. @@ -1803,8 +1813,9 @@ export type WalletOperations = { [WalletApiOperation.SendTalerUriMailboxMessage]: SendTalerUriMailboxMessageOp; [WalletApiOperation.ConvertIbanAccountFieldToPayto]: ConvertIbanAccountFieldToPaytoOp; [WalletApiOperation.ConvertIbanPaytoToAccountField]: ConvertIbanPaytoToAccountFieldOp; - [WalletApiOperation.TestingGetDiagnostics]: TestingGetDiagnosticsOp; + [WalletApiOperation.GetDiagnostics]: TestingGetDiagnosticsOp; [WalletApiOperation.TestingGetPerformanceStats]: GetPerformanceStatsOp; + [WalletApiOperation.TestingGetFlightRecords]: TestingGetFlightRecordsOp; }; export type WalletCoreRequestType< diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts @@ -72,6 +72,8 @@ import { ExportDbToFileRequest, ExportDbToFileResponse, FailTransactionRequest, + FlightRecordEntry, + FlightRecordEvent, ForgetBankAccountRequest, GetActiveTasksResponse, GetBankAccountByIdRequest, @@ -134,11 +136,13 @@ import { TalerErrorCode, TalerExchangeHttpClient, TalerMerchantInstanceHttpClient, + TalerPreciseTimestamp, TalerProtocolTimestamp, TalerUriAction, TestingGetDenomStatsRequest, TestingGetDenomStatsResponse, TestingGetDiagnosticsResponse, + TestingGetFlightRecordsResponse, TestingGetReserveHistoryRequest, TestingSetTimetravelRequest, TimerAPI, @@ -2037,6 +2041,13 @@ export async function handleConvertIbanPaytoToAccountField( }; } +export async function handleGetFlightRecords( + wex: WalletExecutionContext, + _req: EmptyObject, +): Promise<TestingGetFlightRecordsResponse> { + return { flightRecords: wex.ws.flightRecords }; +} + export async function handleGetDiagnostics( wex: WalletExecutionContext, req: EmptyObject, @@ -2090,7 +2101,11 @@ interface HandlerWithValidator<Tag extends WalletApiOperation> { } const handlers: { [T in WalletApiOperation]: HandlerWithValidator<T> } = { - [WalletApiOperation.TestingGetDiagnostics]: { + [WalletApiOperation.TestingGetFlightRecords]: { + codec: codecForEmptyObject(), + handler: handleGetFlightRecords, + }, + [WalletApiOperation.GetDiagnostics]: { codec: codecForEmptyObject(), handler: handleGetDiagnostics, }, @@ -3276,6 +3291,19 @@ export class InternalWalletState { } } + flightRecords: FlightRecordEntry[] = []; + + addFdr(arg: { target: string; event: FlightRecordEvent }) { + this.flightRecords.push({ + timestamp: TalerPreciseTimestamp.now(), + event: arg.event, + target: arg.target, + }); + if (this.flightRecords.length > 100) { + this.flightRecords.shift(); + } + } + createDbAccessHandle( cancellationToken: CancellationToken, ): DbAccess<typeof WalletStoresV1> {