From 7378b5a081a0d839c3bd63f6ddd359bca50be695 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Fri, 17 Jan 2020 18:59:15 +0100 Subject: amount rounding a la Christian --- src/auditor/taler-auditor.c | 31 ++++++++++++++++--------------- src/exchange/taler-exchange-aggregator.c | 32 +++++++++++++++++--------------- src/include/taler_amount_lib.h | 7 +++++-- src/util/amount.c | 16 ++++++++++------ src/util/test_amount.c | 15 ++++++++++++--- 5 files changed, 60 insertions(+), 41 deletions(-) (limited to 'src') diff --git a/src/auditor/taler-auditor.c b/src/auditor/taler-auditor.c index 8b2c2c37e..f3bb0e2b7 100644 --- a/src/auditor/taler-auditor.c +++ b/src/auditor/taler-auditor.c @@ -88,7 +88,7 @@ static char *currency; /** * How many fractional digits does the currency use? */ -static uint8_t currency_rounding_fractional_digits; +static struct TALER_Amount currency_round_unit; /** * Our configuration. @@ -2894,7 +2894,7 @@ check_wire_out_cb /* Round down to amount supported by wire method */ GNUNET_break (TALER_amount_round_down (&final_amount, - currency_rounding_fractional_digits)); + ¤cy_round_unit)); /* Calculate the exchange's gain as the fees plus rounding differences! */ if (GNUNET_OK != @@ -5205,28 +5205,29 @@ run (void *cls, return; } { - unsigned long long num; + char *rounding_str; if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (cfg, + GNUNET_CONFIGURATION_get_value_string (cfg, "taler", - "CURRENCY_ROUNDING_FRACTIONAL_DIGITS", - &num)) + "CURRENCY_ROUND_UNIT", + &rounding_str)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "No [taler]/CURRENCY_ROUNDING_FRACTIONAL_DIGITS specified, defaulting to 2 digits.\n"); - currency_rounding_fractional_digits = 2; + "No [taler]/CURRENCY_ROUND_UNIT specified, defaulting to '0.01'.\n"); + TALER_amount_get_zero (currency, ¤cy_round_unit); + currency_round_unit.fraction = TALER_AMOUNT_FRAC_BASE / 100; } - else if (num > TALER_AMOUNT_FRAC_LEN) + else if (GNUNET_OK != + TALER_string_to_amount (rounding_str, + ¤cy_round_unit)) { - global_ret = 1; GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Value of CURRENCY_ROUNDING_FRACTIONAL_DIGITS too big.\n"); + "Invalid amount `%s' specified in `TALER' under `CURRENCY_ROUND_UNIT'\n", + rounding_str); + GNUNET_free (rounding_str); + global_ret = 1; return; } - else - { - currency_rounding_fractional_digits = (uint8_t) num; - } } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg, diff --git a/src/exchange/taler-exchange-aggregator.c b/src/exchange/taler-exchange-aggregator.c index 9032cd5e3..338e979e4 100644 --- a/src/exchange/taler-exchange-aggregator.c +++ b/src/exchange/taler-exchange-aggregator.c @@ -224,7 +224,7 @@ static char *exchange_currency_string; /** * How many fractional digits does the currency use? */ -static uint8_t currency_rounding_fractional_digits; +static struct TALER_Amount currency_round_unit; /** * What is the base URL of this exchange? @@ -615,29 +615,31 @@ exchange_serve_process_config () } { - unsigned long long num; + char *rounding_str; if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (cfg, + GNUNET_CONFIGURATION_get_value_string (cfg, "taler", - "CURRENCY_ROUNDING_FRACTIONAL_DIGITS", - &num)) + "CURRENCY_ROUND_UNIT", + &rounding_str)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "No [taler]/CURRENCY_ROUNDING_FRACTIONAL_DIGITS specified, defaulting to 2 digits.\n"); - currency_rounding_fractional_digits = 2; + "No [taler]/CURRENCY_ROUND_UNIT specified, defaulting to '0.01'.\n"); + TALER_amount_get_zero (exchange_currency_string, ¤cy_round_unit); + currency_round_unit.fraction = TALER_AMOUNT_FRAC_BASE / 100; } - else if (num > TALER_AMOUNT_FRAC_LEN) + else if (GNUNET_OK != + TALER_string_to_amount (rounding_str, + ¤cy_round_unit)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Value of CURRENCY_ROUNDING_FRACTIONAL_DIGITS too big.\n"); + "Invalid amount `%s' specified in `TALER' under `CURRENCY_ROUND_UNIT'\n", + rounding_str); + GNUNET_free (rounding_str); return GNUNET_SYSERR; } - else - { - currency_rounding_fractional_digits = (uint8_t) num; - } } + if (NULL == (db_plugin = TALER_EXCHANGEDB_plugin_load (cfg))) { @@ -1120,7 +1122,7 @@ expired_reserve_cb (void *cls, /* round down to enable transfer */ if (GNUNET_SYSERR == TALER_amount_round_down (&amount_without_fee, - currency_rounding_fractional_digits)) + ¤cy_round_unit)) { GNUNET_break (0); global_ret = GNUNET_SYSERR; @@ -1456,7 +1458,7 @@ run_aggregation (void *cls) &au->wire_fee)) || (GNUNET_SYSERR == TALER_amount_round_down (&au->final_amount, - currency_rounding_fractional_digits)) || + ¤cy_round_unit)) || ( (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 7118e2ecf..df1cf06f9 100644 --- a/src/include/taler_amount_lib.h +++ b/src/include/taler_amount_lib.h @@ -311,15 +311,18 @@ TALER_amount2s (const struct TALER_Amount *amount); /** * Round the amount to something that can be transferred on the wire. + * The rounding mode is specified via the smallest transferable unit, + * which must only have a fractional part. * * @param[in,out] amount amount to round down - * @param max_fractional_digits number of fractional digits to round down to + * @param[in] round_unit unit that should be rounded down to, + * the value part of this amount must be zero * @return #GNUNET_OK on success, #GNUNET_NO if rounding was unnecessary, * #GNUNET_SYSERR if the amount or currency was invalid */ int TALER_amount_round_down (struct TALER_Amount *amount, - uint8_t max_fractional_digits); + const struct TALER_Amount *round_unit); #if 0 /* keep Emacsens' auto-indent happy */ diff --git a/src/util/amount.c b/src/util/amount.c index 48f5d9891..1f00b1d6e 100644 --- a/src/util/amount.c +++ b/src/util/amount.c @@ -674,23 +674,27 @@ TALER_amount_divide (struct TALER_Amount *result, /** * Round the amount to something that can be transferred on the wire. + * The rounding mode is specified via the smallest transferable unit, + * which must only have a fractional part. * * @param[in,out] amount amount to round down - * @param max_fractional_digits number of fractional digits to round down to + * @param[in] round_unit unit that should be rounded down to, + * the value part of this amount must be zero * @return #GNUNET_OK on success, #GNUNET_NO if rounding was unnecessary, * #GNUNET_SYSERR if the amount or currency was invalid */ int TALER_amount_round_down (struct TALER_Amount *amount, - uint8_t max_fractional_digits) + const struct TALER_Amount *round_unit) { uint32_t delta; - uint32_t divisor = 1; - for (unsigned int i = 0; i < max_fractional_digits; i++) - divisor *= 10; + GNUNET_break (0 == round_unit->value); - delta = amount->fraction % (TALER_AMOUNT_FRAC_BASE / divisor); + if (0 == round_unit->fraction) + return GNUNET_OK; + + delta = amount->fraction % round_unit->fraction; if (0 == delta) return GNUNET_NO; amount->fraction -= delta; diff --git a/src/util/test_amount.c b/src/util/test_amount.c index 4eeccd7e0..3bf8e6fb0 100644 --- a/src/util/test_amount.c +++ b/src/util/test_amount.c @@ -31,6 +31,7 @@ main (int argc, struct TALER_Amount a1; struct TALER_Amount a2; struct TALER_Amount a3; + struct TALER_Amount r; char *c; GNUNET_log_setup ("test-amout", @@ -236,6 +237,10 @@ main (int argc, /* test rounding #1 */ + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount ("EUR:0.01", + &r)); + GNUNET_assert (GNUNET_OK == TALER_string_to_amount ("EUR:4.001", &a1)); @@ -243,19 +248,23 @@ main (int argc, 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 (GNUNET_OK == TALER_amount_round_down (&a1, &r)); + GNUNET_assert (GNUNET_NO == TALER_amount_round_down (&a1, &r)); GNUNET_assert (0 == TALER_amount_cmp (&a1, &a2)); /* test rounding #2 */ + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount ("EUR:0.001", + &r)); + 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 (GNUNET_NO == TALER_amount_round_down (&a1, &r)); GNUNET_assert (0 == TALER_amount_cmp (&a1, &a2)); return 0; -- cgit v1.2.3