Diagnosis
Based on analysis of the currencyservice logs and the server.js file, I've identified a critical issue in the currency conversion logic that's causing frequent errors.
The application is repeatedly logging:
Currency conversion resulted in zero amount, switching back to original currency
Root Cause
The issue is in the convert function in src/currencyservice/server.js (lines 178-215). The problem occurs during the two-step conversion process:
- Convert from_currency → EUR: The code divides by the exchange rate
- Convert EUR → to_currency: The code multiplies by the target exchange rate
However, there are precision issues with the handling of the nanos field (which represents fractional currency units in nanoseconds). Specifically:
- The conversion calculations use floating-point arithmetic on both
units and nanos
- The final results are floored using
Math.floor() which can round small positive values down to zero
- Small amounts or currencies with large exchange rate differences are particularly affected
Impact
- Currency conversions frequently result in zero amounts
- The service falls back to the original currency, but this creates inconsistent user experience
- Error logs are generated repeatedly, indicating this is a widespread issue
- The Slack notification system is being triggered frequently (with cooldown protection)
Recommended Fix
-
Improve precision handling: Use a proper decimal arithmetic library (like decimal.js or big.js) instead of native JavaScript floating-point arithmetic for currency calculations.
-
Add minimum amount validation: Before performing the conversion, check if the input amount is meaningful and handle edge cases appropriately.
-
Fix the nanos calculation: The current approach of dividing/multiplying nanos directly by exchange rates is incorrect. Nanos should be handled as part of the total amount calculation.
Example fix for the conversion logic:
const Decimal = require('decimal.js');
// Convert the full amount to a decimal for precise calculation
const fromAmount = new Decimal(from.units).plus(new Decimal(from.nanos).div(1e9));
const euroAmount = fromAmount.div(data[from.currency_code]);
const resultAmount = euroAmount.mul(data[request.to_code]);
// Convert back to units/nanos
result.units = Math.floor(resultAmount.toNumber());
result.nanos = Math.floor((resultAmount.minus(result.units)).mul(1e9).toNumber());
- Add better error handling and logging: Include more details about the conversion amounts and rates when errors occur to help with debugging.
This fix will resolve the precision issues causing zero-amount conversions and improve the reliability of the currency service.
Diagnosis
Based on analysis of the currencyservice logs and the
server.jsfile, I've identified a critical issue in the currency conversion logic that's causing frequent errors.The application is repeatedly logging:
Root Cause
The issue is in the
convertfunction insrc/currencyservice/server.js(lines 178-215). The problem occurs during the two-step conversion process:However, there are precision issues with the handling of the
nanosfield (which represents fractional currency units in nanoseconds). Specifically:unitsandnanosMath.floor()which can round small positive values down to zeroImpact
Recommended Fix
Improve precision handling: Use a proper decimal arithmetic library (like
decimal.jsorbig.js) instead of native JavaScript floating-point arithmetic for currency calculations.Add minimum amount validation: Before performing the conversion, check if the input amount is meaningful and handle edge cases appropriately.
Fix the nanos calculation: The current approach of dividing/multiplying nanos directly by exchange rates is incorrect. Nanos should be handled as part of the total amount calculation.
Example fix for the conversion logic:
This fix will resolve the precision issues causing zero-amount conversions and improve the reliability of the currency service.