commit ae44f3187c0428ff9c84c881e194df9f1642d06b
parent 540cd68e6ef2d56559d91657ecde3b789a441119
Author: Florian Dold <dold@taler.net>
Date: Thu, 6 Aug 2026 19:02:48 +0200
wallet: only store denominations that can still be withdrawn from
An exchange advertises a denomination until its legal expiration, so most of a
/keys response is denominations no wallet can ever withdraw from -- 952 of 1022
on the demo exchange. Ones already in the database are kept regardless: a coin
in the wallet may refer to them.
Issue: https://bugs.taler.net/n/11334
Diffstat:
1 file changed, 36 insertions(+), 1 deletion(-)
diff --git a/packages/taler-wallet-core/src/exchanges.ts b/packages/taler-wallet-core/src/exchanges.ts
@@ -973,6 +973,22 @@ function denomFamilyParamsKey(p: WalletDenomFamilyParams): string {
}
/**
+ * Is a denomination we have not seen before worth a row in the database?
+ *
+ * Only denominations that can still be withdrawn from are: the wallet gets a
+ * coin of a denomination by withdrawing or refreshing into it, and both pick
+ * from the withdrawable ones. A denomination it already has a row for is
+ * never dropped on this basis -- that row may be what a coin in the wallet
+ * refers to, and losing it would count the coin as vanished.
+ */
+function isDenomWorthStoring(d: DenominationInfo): boolean {
+ const expireWithdraw = AbsoluteTime.fromProtocolTimestamp(
+ d.stampExpireWithdraw,
+ );
+ return !AbsoluteTime.isExpired(expireWithdraw);
+}
+
+/**
* Timestamp (in seconds) to ask the exchange to cherry-pick /keys by, or
* undefined when the whole response should be downloaded.
*
@@ -2181,7 +2197,21 @@ export async function updateExchangeFromUrlHandler(
);
}
+ let numDenomsSkipped = 0;
+
for (const currentDenom of denomInfos) {
+ const oldDenom = oldDenomByDph.get(currentDenom.denomPubHash);
+
+ // A denomination that can no longer be withdrawn from is only of
+ // interest for coins we already hold, and we cannot hold a coin of one
+ // we never stored. Exchanges keep advertising these for years after
+ // they stop issuing them -- on the demo exchange 952 of 1022 -- so not
+ // writing them is most of the cost of adding an exchange.
+ if (!oldDenom && !isDenomWorthStoring(currentDenom)) {
+ numDenomsSkipped++;
+ continue;
+ }
+
const familyParams: WalletDenomFamilyParams = {
exchangeBaseUrl: currentDenom.exchangeBaseUrl,
exchangeMasterPub: currentDenom.exchangeMasterPub,
@@ -2251,7 +2281,6 @@ export async function updateExchangeFromUrlHandler(
isLost: currentDenom.isLost,
};
- const oldDenom = oldDenomByDph.get(currentDenom.denomPubHash);
if (oldDenom) {
// FIXME: Do consistency check, report to auditor if necessary.
// See https://bugs.taler.net/n/8594
@@ -2279,6 +2308,12 @@ export async function updateExchangeFromUrlHandler(
}
}
+ if (numDenomsSkipped > 0) {
+ logger.trace(
+ `did not store ${numDenomsSkipped} of ${denomInfos.length} denominations of ${exchangeBaseUrl}, no longer withdrawable`,
+ );
+ }
+
// Update list issue date for all denominations,
// and mark non-offered denominations as such.
//