aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Dold <florian.dold@gmail.com>2020-01-15 15:17:02 +0100
committerFlorian Dold <florian.dold@gmail.com>2020-01-15 15:17:25 +0100
commitda5b3ba8aeb9d47e4f99cd22847c9b539ff8ee2b (patch)
tree6e67e1d08fd941144f464dfe55b8835db65687e6
parentb37fff0d5b08926169633ce8822de7ac616ae169 (diff)
round amounts based on config, do unit test for rounding
-rw-r--r--src/auditor/taler-auditor.c32
-rw-r--r--src/exchange/taler-exchange-aggregator.c35
-rw-r--r--src/include/taler_amount_lib.h7
-rw-r--r--src/util/amount.c13
-rw-r--r--src/util/test_amount.c23
5 files changed, 100 insertions, 10 deletions
diff --git a/src/auditor/taler-auditor.c b/src/auditor/taler-auditor.c
index d4fb84d16..d2bc34046 100644
--- a/src/auditor/taler-auditor.c
+++ b/src/auditor/taler-auditor.c
@@ -86,6 +86,11 @@ static struct TALER_EXCHANGEDB_Plugin *edb;
static char *currency;
/**
+ * How many fractional digits does the currency use?
+ */
+static uint8_t currency_rounding_fractional_digits;
+
+/**
* Our configuration.
*/
static const struct GNUNET_CONFIGURATION_Handle *cfg;
@@ -2895,7 +2900,8 @@ check_wire_out_cb
}
/* Round down to amount supported by wire method */
- GNUNET_break (TALER_amount_round (&final_amount));
+ GNUNET_break (TALER_amount_round_down (&final_amount,
+ currency_rounding_fractional_digits));
/* Calculate the exchange's gain as the fees plus rounding differences! */
if (GNUNET_OK !=
@@ -5204,6 +5210,30 @@ run (void *cls,
global_ret = 1;
return;
}
+ {
+ unsigned long long num;
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_number (cfg,
+ "taler",
+ "CURRENCY_ROUNDING_FRACTIONAL_DIGITS",
+ &num))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "No [taler]/CURRENCY_ROUNDING_FRACTIONAL_DIGITS specified, defaulting to 2 digits.\n");
+ currency_rounding_fractional_digits = 2;
+ }
+ else if (num > TALER_AMOUNT_FRAC_LEN)
+ {
+ global_ret = 1;
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Value of CURRENCY_ROUNDING_FRACTIONAL_DIGITS too big.\n");
+ return;
+ }
+ else
+ {
+ currency_rounding_fractional_digits = (uint8_t) num;
+ }
+ }
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_time (cfg,
"exchangedb",
diff --git a/src/exchange/taler-exchange-aggregator.c b/src/exchange/taler-exchange-aggregator.c
index fe3ef39cc..f1abbe2ba 100644
--- a/src/exchange/taler-exchange-aggregator.c
+++ b/src/exchange/taler-exchange-aggregator.c
@@ -227,6 +227,11 @@ static struct CloseTransferContext *ctc;
static char *exchange_currency_string;
/**
+ * How many fractional digits does the currency use?
+ */
+static uint8_t currency_rounding_fractional_digits;
+
+/**
* What is the base URL of this exchange?
*/
static char *exchange_base_url;
@@ -614,6 +619,30 @@ exchange_serve_process_config ()
return GNUNET_SYSERR;
}
+ {
+ unsigned long long num;
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_number (cfg,
+ "taler",
+ "CURRENCY_ROUNDING_FRACTIONAL_DIGITS",
+ &num))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "No [taler]/CURRENCY_ROUNDING_FRACTIONAL_DIGITS specified, defaulting to 2 digits.\n");
+ currency_rounding_fractional_digits = 2;
+ }
+ else if (num > TALER_AMOUNT_FRAC_LEN)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Value of CURRENCY_ROUNDING_FRACTIONAL_DIGITS too big.\n");
+ return GNUNET_SYSERR;
+ }
+ else
+ {
+ currency_rounding_fractional_digits = (uint8_t) num;
+ }
+ }
+
if (NULL ==
(db_plugin = TALER_EXCHANGEDB_plugin_load (cfg)))
{
@@ -1116,7 +1145,8 @@ expired_reserve_cb (void *cls,
}
/* round down to enable transfer */
if (GNUNET_SYSERR ==
- TALER_amount_round (&amount_without_fee))
+ TALER_amount_round_down (&amount_without_fee,
+ currency_rounding_fractional_digits))
{
GNUNET_break (0);
global_ret = GNUNET_SYSERR;
@@ -1447,7 +1477,8 @@ run_aggregation (void *cls)
&au->total_amount,
&au->wire_fee)) ||
(GNUNET_SYSERR ==
- TALER_amount_round (&au->final_amount)) ||
+ TALER_amount_round_down (&au->final_amount,
+ currency_rounding_fractional_digits)) ||
( (0 == au->final_amount.value) &&
(0 == au->final_amount.fraction) ) )
{
diff --git a/src/include/taler_amount_lib.h b/src/include/taler_amount_lib.h
index 37f42bd99..7118e2ecf 100644
--- a/src/include/taler_amount_lib.h
+++ b/src/include/taler_amount_lib.h
@@ -310,15 +310,16 @@ TALER_amount2s (const struct TALER_Amount *amount);
/**
- * Round the amount to something that can be
- * transferred on the wire.
+ * Round the amount to something that can be transferred on the wire.
*
* @param[in,out] amount amount to round down
+ * @param max_fractional_digits number of fractional digits to round down to
* @return #GNUNET_OK on success, #GNUNET_NO if rounding was unnecessary,
* #GNUNET_SYSERR if the amount or currency was invalid
*/
int
-TALER_amount_round (struct TALER_Amount *amount);
+TALER_amount_round_down (struct TALER_Amount *amount,
+ uint8_t max_fractional_digits);
#if 0 /* keep Emacsens' auto-indent happy */
diff --git a/src/util/amount.c b/src/util/amount.c
index edb9dc060..48f5d9891 100644
--- a/src/util/amount.c
+++ b/src/util/amount.c
@@ -673,19 +673,24 @@ TALER_amount_divide (struct TALER_Amount *result,
/**
- * Round the amount to something that can be
- * transferred on the wire.
+ * Round the amount to something that can be transferred on the wire.
*
* @param[in,out] amount amount to round down
+ * @param max_fractional_digits number of fractional digits to round down to
* @return #GNUNET_OK on success, #GNUNET_NO if rounding was unnecessary,
* #GNUNET_SYSERR if the amount or currency was invalid
*/
int
-TALER_amount_round (struct TALER_Amount *amount)
+TALER_amount_round_down (struct TALER_Amount *amount,
+ uint8_t max_fractional_digits)
{
uint32_t delta;
+ uint32_t divisor = 1;
- delta = amount->fraction % (TALER_AMOUNT_FRAC_BASE / 100);
+ for (unsigned int i = 0; i < max_fractional_digits; i++)
+ divisor *= 10;
+
+ delta = amount->fraction % (TALER_AMOUNT_FRAC_BASE / divisor);
if (0 == delta)
return GNUNET_NO;
amount->fraction -= delta;
diff --git a/src/util/test_amount.c b/src/util/test_amount.c
index d9110eaf8..4eeccd7e0 100644
--- a/src/util/test_amount.c
+++ b/src/util/test_amount.c
@@ -234,6 +234,29 @@ main (int argc,
GNUNET_assert (0 == a2.value);
GNUNET_assert (1 == a2.fraction);
+ /* test rounding #1 */
+
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount ("EUR:4.001",
+ &a1));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount ("EUR:4",
+ &a2));
+
+ GNUNET_assert (GNUNET_OK == TALER_amount_round_down (&a1, 2));
+ GNUNET_assert (GNUNET_NO == TALER_amount_round_down (&a1, 2));
+ GNUNET_assert (0 == TALER_amount_cmp (&a1, &a2));
+
+ /* test rounding #2 */
+
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount ("EUR:4.001",
+ &a1));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount ("EUR:4.001",
+ &a2));
+ GNUNET_assert (GNUNET_NO == TALER_amount_round_down (&a1, 3));
+ GNUNET_assert (0 == TALER_amount_cmp (&a1, &a2));
return 0;
}