commit e733615bc0b754c25215409e299d0e04364e19d7
parent be2c4a1d5926fa9220ff9272cba8b637e4bed8b1
Author: Florian Dold <dold@taler.net>
Date: Mon, 20 Jul 2026 01:21:50 +0200
wallet: say which denomination a visible-coin-count underflow came from
"coin availability inconsistent" named neither the denomination, the age
nor the exchange.
Diffstat:
2 files changed, 20 insertions(+), 2 deletions(-)
diff --git a/packages/taler-wallet-core/src/common.ts b/packages/taler-wallet-core/src/common.ts
@@ -229,8 +229,17 @@ export async function spendCoins(
}
coinAvailability.freshCoinCount--;
if (coin.visible) {
+ // Clamped rather than thrown: the visible count is a display
+ // figure, and refusing to spend a coin over it would be worse
+ // than showing a stale number. The fresh count above is the
+ // one that guards spendability, and that does throw.
if (!coinAvailability.visibleCoinCount) {
- logger.error("coin availability inconsistent");
+ logger.error(
+ `visible coin count underflow for denom ${coin.denomPubHash}` +
+ ` age ${coin.maxAge} at ${coinAvailability.exchangeBaseUrl}:` +
+ ` a visible coin was spent but the count is` +
+ ` ${coinAvailability.visibleCoinCount}`,
+ );
} else {
coinAvailability.visibleCoinCount--;
}
diff --git a/packages/taler-wallet-core/src/refresh.ts b/packages/taler-wallet-core/src/refresh.ts
@@ -1542,8 +1542,17 @@ async function applyRefreshToOldCoins(
);
coinAv.freshCoinCount--;
if (coin.visible) {
+ // Clamped rather than thrown: the visible count is a display
+ // figure, and refusing to spend a coin over it would be worse
+ // than showing a stale number. The fresh count above is the
+ // one that guards spendability, and that does throw.
if (!coinAv.visibleCoinCount) {
- logger.error("coin availability inconsistent");
+ logger.error(
+ `visible coin count underflow for denom ${coin.denomPubHash}` +
+ ` age ${coin.maxAge} at ${coinAv.exchangeBaseUrl}:` +
+ ` a visible coin was spent but the count is` +
+ ` ${coinAv.visibleCoinCount}`,
+ );
} else {
coinAv.visibleCoinCount--;
}