summaryrefslogtreecommitdiff
path: root/src/exchange/taler-exchange-closer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/exchange/taler-exchange-closer.c')
-rw-r--r--src/exchange/taler-exchange-closer.c170
1 files changed, 98 insertions, 72 deletions
diff --git a/src/exchange/taler-exchange-closer.c b/src/exchange/taler-exchange-closer.c
index 19cc06c70..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
@@ -37,7 +37,7 @@ static struct TALER_Amount currency_round_unit;
/**
* What is the base URL of this exchange? Used in the
- * wire transfer subjects to that merchants and governments
+ * wire transfer subjects so that merchants and governments
* can ask for the list of aggregated deposits.
*/
static char *exchange_base_url;
@@ -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 ();