diff options
-rw-r--r-- | src/auditor/taler-auditor.c | 32 | ||||
-rw-r--r-- | src/exchange/taler-exchange-aggregator.c | 35 | ||||
-rw-r--r-- | src/include/taler_amount_lib.h | 7 | ||||
-rw-r--r-- | src/util/amount.c | 13 | ||||
-rw-r--r-- | src/util/test_amount.c | 23 |
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; } |