diff options
Diffstat (limited to 'src/exchange/taler-exchange-closer.c')
-rw-r--r-- | src/exchange/taler-exchange-closer.c | 168 |
1 files changed, 97 insertions, 71 deletions
diff --git a/src/exchange/taler-exchange-closer.c b/src/exchange/taler-exchange-closer.c index 91ececc85..779525c4e 100644 --- a/src/exchange/taler-exchange-closer.c +++ b/src/exchange/taler-exchange-closer.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2016-2021 Taler Systems SA + Copyright (C) 2016-2022 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software @@ -204,20 +204,26 @@ commit_or_warn (void) * @param account_payto_uri information about the bank account that initially * caused the reserve to be created * @param expiration_date when did the reserve expire - * @return transaction status code + * @param close_request_row row of request asking for + * closure, 0 for expired reserves + * @return #GNUNET_OK on success (continue) + * #GNUNET_NO on non-fatal errors (try again) + * #GNUNET_SYSERR on fatal errors (abort) */ -static enum GNUNET_DB_QueryStatus +static enum GNUNET_GenericReturnValue expired_reserve_cb (void *cls, const struct TALER_ReservePublicKeyP *reserve_pub, const struct TALER_Amount *left, const char *account_payto_uri, - struct GNUNET_TIME_Absolute expiration_date) + struct GNUNET_TIME_Timestamp expiration_date, + uint64_t close_request_row) { - struct GNUNET_TIME_Absolute now; + struct GNUNET_TIME_Timestamp now; struct TALER_WireTransferIdentifierRawP wtid; struct TALER_Amount amount_without_fee; struct TALER_Amount closing_fee; - int ret; + struct TALER_WireFeeSet fees; + enum TALER_AmountArithmeticResult ret; enum GNUNET_DB_QueryStatus qs; const struct TALER_EXCHANGEDB_AccountInfo *wa; @@ -226,9 +232,8 @@ expired_reserve_cb (void *cls, fetch this: */ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Processing reserve closure at %s\n", - GNUNET_STRINGS_absolute_time_to_string (expiration_date)); - now = GNUNET_TIME_absolute_get (); - (void) GNUNET_TIME_round_abs (&now); + GNUNET_TIME_timestamp2s (expiration_date)); + now = GNUNET_TIME_timestamp_get (); /* lookup account we should use */ wa = TALER_EXCHANGEDB_find_account_by_payto_uri (account_payto_uri); @@ -239,15 +244,14 @@ expired_reserve_cb (void *cls, account_payto_uri); global_ret = EXIT_FAILURE; GNUNET_SCHEDULER_shutdown (); - return GNUNET_DB_STATUS_HARD_ERROR; + return GNUNET_SYSERR; } - /* lookup `closing_fee` from time of actual reserve expiration + /* lookup `fees` from time of actual reserve expiration (we may be lagging behind!) */ { - struct TALER_Amount wire_fee; - struct GNUNET_TIME_Absolute start_date; - struct GNUNET_TIME_Absolute end_date; + struct GNUNET_TIME_Timestamp start_date; + struct GNUNET_TIME_Timestamp end_date; struct TALER_MasterSignatureP master_sig; enum GNUNET_DB_QueryStatus qs; @@ -256,25 +260,34 @@ expired_reserve_cb (void *cls, expiration_date, &start_date, &end_date, - &wire_fee, - &closing_fee, + &fees, &master_sig); - if (0 >= qs) + switch (qs) { + case GNUNET_DB_STATUS_HARD_ERROR: + GNUNET_break (0); + return GNUNET_SYSERR; + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not get wire fees for %s at %s. Aborting run.\n", wa->method, - GNUNET_STRINGS_absolute_time_to_string (expiration_date)); - return GNUNET_DB_STATUS_HARD_ERROR; + GNUNET_TIME_timestamp2s (expiration_date)); + return GNUNET_SYSERR; + case GNUNET_DB_STATUS_SOFT_ERROR: + return GNUNET_NO; + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + /* continued below */ + break; } } /* calculate transfer amount */ + closing_fee = fees.closing; ret = TALER_amount_subtract (&amount_without_fee, left, &closing_fee); - if ( (GNUNET_SYSERR == ret) || - (GNUNET_NO == ret) ) + if ( (TALER_AAR_INVALID_NEGATIVE_RESULT == ret) || + (TALER_AAR_RESULT_ZERO == ret) ) { /* Closing fee higher than or equal to remaining balance, close without wire transfer. */ @@ -282,6 +295,7 @@ expired_reserve_cb (void *cls, GNUNET_assert (GNUNET_OK == TALER_amount_set_zero (left->currency, &amount_without_fee)); + ret = TALER_AAR_RESULT_ZERO; } /* round down to enable transfer */ if (GNUNET_SYSERR == @@ -291,54 +305,56 @@ expired_reserve_cb (void *cls, GNUNET_break (0); global_ret = EXIT_FAILURE; GNUNET_SCHEDULER_shutdown (); - return GNUNET_DB_STATUS_HARD_ERROR; + return GNUNET_SYSERR; } - if ( (0 == amount_without_fee.value) && - (0 == amount_without_fee.fraction) ) - ret = GNUNET_NO; - /* NOTE: sizeof (*reserve_pub) == sizeof (wtid) right now, but to be future-compatible, we use the memset + min construction */ memset (&wtid, 0, sizeof (wtid)); - memcpy (&wtid, - reserve_pub, - GNUNET_MIN (sizeof (wtid), - sizeof (*reserve_pub))); - if (GNUNET_SYSERR != ret) - qs = db_plugin->insert_reserve_closed (db_plugin->cls, - reserve_pub, - now, - account_payto_uri, - &wtid, - left, - &closing_fee); - else - qs = GNUNET_DB_STATUS_HARD_ERROR; + GNUNET_memcpy (&wtid, + reserve_pub, + GNUNET_MIN (sizeof (wtid), + sizeof (*reserve_pub))); + qs = db_plugin->insert_reserve_closed (db_plugin->cls, + reserve_pub, + now, + account_payto_uri, + &wtid, + left, + &closing_fee, + close_request_row); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Closing reserve %s over %s (%d, %d)\n", TALER_B2S (reserve_pub), TALER_amount2s (left), - ret, + (int) ret, qs); /* Check for hard failure */ - if ( (GNUNET_SYSERR == ret) || - (GNUNET_DB_STATUS_HARD_ERROR == qs) ) + if (GNUNET_DB_STATUS_HARD_ERROR == qs) { GNUNET_break (0); global_ret = EXIT_FAILURE; GNUNET_SCHEDULER_shutdown (); - return GNUNET_DB_STATUS_HARD_ERROR; + return GNUNET_SYSERR; } - if ( (GNUNET_OK != ret) || - (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) ) + if (TALER_amount_is_zero (&amount_without_fee)) { - /* Reserve balance was almost zero OR soft error */ + /* Reserve balance was zero OR soft error */ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Reserve was virtually empty, moving on\n"); - (void) commit_or_warn (); - return qs; + qs = commit_or_warn (); + switch (qs) + { + case GNUNET_DB_STATUS_HARD_ERROR: + GNUNET_break (0); + return GNUNET_SYSERR; + case GNUNET_DB_STATUS_SOFT_ERROR: + return GNUNET_NO; + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + return GNUNET_OK; + } } /* success, perform wire transfer */ @@ -359,19 +375,25 @@ expired_reserve_cb (void *cls, buf_size); GNUNET_free (buf); } - if (GNUNET_DB_STATUS_HARD_ERROR == qs) + switch (qs) { + case GNUNET_DB_STATUS_HARD_ERROR: GNUNET_break (0); global_ret = EXIT_FAILURE; GNUNET_SCHEDULER_shutdown (); - return GNUNET_DB_STATUS_HARD_ERROR; - } - if (GNUNET_DB_STATUS_SOFT_ERROR == qs) - { + return GNUNET_SYSERR; + case GNUNET_DB_STATUS_SOFT_ERROR: /* start again */ - return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; + return GNUNET_NO; + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + GNUNET_break (0); + global_ret = EXIT_FAILURE; + GNUNET_SCHEDULER_shutdown (); + return GNUNET_SYSERR; + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + break; } - return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; + return GNUNET_OK; } @@ -385,7 +407,7 @@ static void run_reserve_closures (void *cls) { enum GNUNET_DB_QueryStatus qs; - struct GNUNET_TIME_Absolute now; + struct GNUNET_TIME_Timestamp now; (void) cls; task = NULL; @@ -409,16 +431,22 @@ run_reserve_closures (void *cls) GNUNET_SCHEDULER_shutdown (); return; } - now = GNUNET_TIME_absolute_get (); - (void) GNUNET_TIME_round_abs (&now); + now = GNUNET_TIME_timestamp_get (); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Checking for reserves to close by date %s\n", - GNUNET_STRINGS_absolute_time_to_string (now)); - qs = db_plugin->get_expired_reserves (db_plugin->cls, - now, - &expired_reserve_cb, - NULL); - GNUNET_assert (1 >= qs); + GNUNET_TIME_timestamp2s (now)); + qs = db_plugin->get_unfinished_close_requests (db_plugin->cls, + &expired_reserve_cb, + NULL); + if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) + { + /* Try expired reserves as well */ + qs = db_plugin->get_expired_reserves ( + db_plugin->cls, + now, + &expired_reserve_cb, + NULL); + } switch (qs) { case GNUNET_DB_STATUS_HARD_ERROR: @@ -441,13 +469,11 @@ run_reserve_closures (void *cls) if (GNUNET_YES == test_mode) { GNUNET_SCHEDULER_shutdown (); + return; } - else - { - task = GNUNET_SCHEDULER_add_delayed (closer_idle_sleep_interval, - &run_reserve_closures, - NULL); - } + task = GNUNET_SCHEDULER_add_delayed (closer_idle_sleep_interval, + &run_reserve_closures, + NULL); return; case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: (void) commit_or_warn (); |