summaryrefslogtreecommitdiff
path: root/packages/taler-wallet-core/src
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2024-03-07 17:28:14 +0100
committerFlorian Dold <florian@dold.me>2024-03-07 17:28:42 +0100
commitc22b13eebe0577c2b948a99e42670580d49d60ce (patch)
tree9497f6edba090d03139490d279f233057a23d69e /packages/taler-wallet-core/src
parent284df1fb5d3e255ef802de389e3fd9ba11a3184f (diff)
downloadwallet-core-c22b13eebe0577c2b948a99e42670580d49d60ce.tar.gz
wallet-core-c22b13eebe0577c2b948a99e42670580d49d60ce.tar.bz2
wallet-core-c22b13eebe0577c2b948a99e42670580d49d60ce.zip
wallet-core: implement and test lost flag for denominations
Diffstat (limited to 'packages/taler-wallet-core/src')
-rw-r--r--packages/taler-wallet-core/src/db.ts7
-rw-r--r--packages/taler-wallet-core/src/denominations.ts5
-rw-r--r--packages/taler-wallet-core/src/exchanges.ts11
-rw-r--r--packages/taler-wallet-core/src/wallet-api-types.ts13
-rw-r--r--packages/taler-wallet-core/src/wallet.ts25
5 files changed, 58 insertions, 3 deletions
diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts
index 14621c2d5..b59efe034 100644
--- a/packages/taler-wallet-core/src/db.ts
+++ b/packages/taler-wallet-core/src/db.ts
@@ -486,6 +486,13 @@ export interface DenominationRecord {
isRevoked: boolean;
/**
+ * If set to true, the exchange announced that the private key for this
+ * denomination is lost. Thus it can't be used to sign new coins
+ * during withdrawal/refresh/..., but the coins can still be spent.
+ */
+ isLost?: boolean;
+
+ /**
* Base URL of the exchange.
*/
exchangeBaseUrl: string;
diff --git a/packages/taler-wallet-core/src/denominations.ts b/packages/taler-wallet-core/src/denominations.ts
index a539918de..d41307d5d 100644
--- a/packages/taler-wallet-core/src/denominations.ts
+++ b/packages/taler-wallet-core/src/denominations.ts
@@ -24,7 +24,6 @@ import {
AmountString,
DenominationInfo,
Duration,
- durationFromSpec,
FeeDescription,
FeeDescriptionPair,
TalerProtocolTimestamp,
@@ -471,10 +470,10 @@ export function isWithdrawableDenom(
} else {
lastPossibleWithdraw = AbsoluteTime.subtractDuraction(
withdrawExpire,
- durationFromSpec({ minutes: 5 }),
+ Duration.fromSpec({ minutes: 5 }),
);
}
const remaining = Duration.getRemaining(lastPossibleWithdraw, now);
const stillOkay = remaining.d_ms !== 0;
- return started && stillOkay && !d.isRevoked && d.isOffered;
+ return started && stillOkay && !d.isRevoked && d.isOffered && !d.isLost;
}
diff --git a/packages/taler-wallet-core/src/exchanges.ts b/packages/taler-wallet-core/src/exchanges.ts
index 335caff62..c44178de8 100644
--- a/packages/taler-wallet-core/src/exchanges.ts
+++ b/packages/taler-wallet-core/src/exchanges.ts
@@ -779,6 +779,7 @@ async function downloadExchangeKeysInfo(
exchangeMasterPub: exchangeKeysJsonUnchecked.master_public_key,
isOffered: true,
isRevoked: false,
+ isLost: denomIn.lost ?? false,
value: Amounts.stringify(value),
currency: value.currency,
stampExpireDeposit: timestampProtocolToDb(
@@ -1432,6 +1433,16 @@ export async function updateExchangeFromUrlHandler(
]);
if (oldDenom) {
// FIXME: Do consistency check, report to auditor if necessary.
+ // See https://bugs.taler.net/n/8594
+
+ // Mark lost denominations as lost.
+ if (currentDenom.isLost && !oldDenom.isLost) {
+ logger.warn(
+ `marking denomination ${currentDenom.denomPubHash} of ${exchangeBaseUrl} as lost`,
+ );
+ oldDenom.isLost = true;
+ await tx.denominations.put(currentDenom);
+ }
} else {
await tx.denominations.put(currentDenom);
}
diff --git a/packages/taler-wallet-core/src/wallet-api-types.ts b/packages/taler-wallet-core/src/wallet-api-types.ts
index ace702e88..4f4b24b62 100644
--- a/packages/taler-wallet-core/src/wallet-api-types.ts
+++ b/packages/taler-wallet-core/src/wallet-api-types.ts
@@ -117,6 +117,8 @@ import {
StoredBackupList,
TestPayArgs,
TestPayResult,
+ TestingGetDenomStatsRequest,
+ TestingGetDenomStatsResponse,
TestingListTasksForTransactionRequest,
TestingListTasksForTransactionsResponse,
TestingSetTimetravelRequest,
@@ -255,6 +257,7 @@ export enum WalletApiOperation {
RemoveGlobalCurrencyAuditor = "removeGlobalCurrencyAuditor",
ListAssociatedRefreshes = "listAssociatedRefreshes",
TestingListTaskForTransaction = "testingListTasksForTransaction",
+ TestingGetDenomStats = "testingGetDenomStats",
}
// group: Initialization
@@ -1114,6 +1117,15 @@ export type TestingWaitTransactionStateOp = {
};
/**
+ * Get stats about an exchange denomination.
+ */
+export type TestingGetDenomStatsOp = {
+ op: WalletApiOperation.TestingGetDenomStats;
+ request: TestingGetDenomStatsRequest;
+ response: TestingGetDenomStatsResponse;
+};
+
+/**
* Set a coin as (un-)suspended.
* Suspended coins won't be used for payments.
*/
@@ -1238,6 +1250,7 @@ export type WalletOperations = {
[WalletApiOperation.RemoveGlobalCurrencyExchange]: RemoveGlobalCurrencyExchangeOp;
[WalletApiOperation.ListAssociatedRefreshes]: ListAssociatedRefreshesOp;
[WalletApiOperation.TestingListTaskForTransaction]: TestingListTasksForTransactionOp;
+ [WalletApiOperation.TestingGetDenomStats]: TestingGetDenomStatsOp;
};
export type WalletCoreRequestType<
diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts
index 8c9eee009..46f58ec81 100644
--- a/packages/taler-wallet-core/src/wallet.ts
+++ b/packages/taler-wallet-core/src/wallet.ts
@@ -57,6 +57,7 @@ import {
TalerErrorCode,
TalerProtocolTimestamp,
TalerUriAction,
+ TestingGetDenomStatsResponse,
TestingListTasksForTransactionsResponse,
TestingWaitTransactionRequest,
TimerAPI,
@@ -126,6 +127,7 @@ import {
codecForStartRefundQueryRequest,
codecForSuspendTransaction,
codecForTestPayArgs,
+ codecForTestingGetDenomStatsRequest,
codecForTestingListTasksForTransactionRequest,
codecForTestingSetTimetravelRequest,
codecForTransactionByIdRequest,
@@ -799,6 +801,29 @@ async function dispatchRequestInternal<Op extends WalletApiOperation>(
});
return {};
}
+ case WalletApiOperation.TestingGetDenomStats: {
+ const req = codecForTestingGetDenomStatsRequest().decode(payload);
+ const denomStats: TestingGetDenomStatsResponse = {
+ numKnown: 0,
+ numLost: 0,
+ numOffered: 0,
+ };
+ await wex.db.runReadOnlyTx(["denominations"], async (tx) => {
+ const denoms = await tx.denominations.indexes.byExchangeBaseUrl.getAll(
+ req.exchangeBaseUrl,
+ );
+ for (const d of denoms) {
+ denomStats.numKnown++;
+ if (d.isOffered) {
+ denomStats.numOffered++;
+ }
+ if (d.isLost) {
+ denomStats.numLost++;
+ }
+ }
+ });
+ return denomStats;
+ }
case WalletApiOperation.ListExchanges: {
return await listExchanges(wex);
}