aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2023-07-13 23:07:50 +0200
committerChristian Grothoff <christian@grothoff.org>2023-07-13 23:08:23 +0200
commit86f9c6823ec9d92dfbbbc1220655c91b129020cf (patch)
treec2a21180a3b8350ab4a98644bd359139df150c8c /src
parent4e45f3a965d5454b136eaf041d5d523f614343d4 (diff)
merging /keys and /wire API in the exchange
Diffstat (limited to 'src')
-rw-r--r--src/backend/taler-merchant-httpd.c5
-rw-r--r--src/backend/taler-merchant-httpd_exchanges.c681
-rw-r--r--src/backend/taler-merchant-httpd_exchanges.h90
-rw-r--r--src/backend/taler-merchant-httpd_post-orders-ID-abort.c6
-rw-r--r--src/backend/taler-merchant-httpd_post-orders-ID-pay.c208
-rw-r--r--src/backend/taler-merchant-httpd_post-orders-ID-refund.c6
-rw-r--r--src/backend/taler-merchant-httpd_post-rewards-ID-pickup.c12
-rw-r--r--src/backend/taler-merchant-httpd_private-get-instances-ID-kyc.c6
-rw-r--r--src/backend/taler-merchant-httpd_private-get-orders-ID.c6
-rw-r--r--src/backend/taler-merchant-httpd_private-post-orders.c348
-rw-r--r--src/backend/taler-merchant-httpd_private-post-orders.h8
-rw-r--r--src/backend/taler-merchant-httpd_private-post-reserves.c96
-rw-r--r--src/lib/merchant_api_post_order_pay.c4
-rw-r--r--src/testing/test_merchant_api_home/taler/exchange-secmod-cs/keys/coin_eur_1/1688579204bin32 -> 0 bytes
-rw-r--r--src/testing/test_merchant_api_home/taler/exchange-secmod-cs/keys/coin_eur_5/16885792042
-rw-r--r--src/testing/test_merchant_api_home/taler/exchange-secmod-cs/keys/coin_eur_ct_1/16885792041
-rw-r--r--src/testing/test_merchant_api_home/taler/exchange-secmod-cs/keys/coin_eur_ct_10/16885792041
17 files changed, 680 insertions, 800 deletions
diff --git a/src/backend/taler-merchant-httpd.c b/src/backend/taler-merchant-httpd.c
index be0140e1..d8be1edc 100644
--- a/src/backend/taler-merchant-httpd.c
+++ b/src/backend/taler-merchant-httpd.c
@@ -303,6 +303,7 @@ static void
do_shutdown (void *cls)
{
(void) cls;
+ TMH_force_orders_resume ();
TMH_force_reward_resume ();
TMH_force_ac_resume ();
TMH_force_pc_resume ();
@@ -1666,8 +1667,8 @@ url_handler (void *cls,
(! hc->rh->skip_instance) )
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Instance `%s' not known\n",
- hc->infix);
+ "Instance for `%s' not known\n",
+ hc->url);
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_NOT_FOUND,
TALER_EC_MERCHANT_GENERIC_INSTANCE_UNKNOWN,
diff --git a/src/backend/taler-merchant-httpd_exchanges.c b/src/backend/taler-merchant-httpd_exchanges.c
index 5fca3c34..7e99704c 100644
--- a/src/backend/taler-merchant-httpd_exchanges.c
+++ b/src/backend/taler-merchant-httpd_exchanges.c
@@ -32,19 +32,6 @@
#define MAX_RETRIES 3
/**
- * Minimum delay after which we'll re-fetch key information from the exchange.
- */
-#define MIN_RELOAD_DELAY GNUNET_TIME_relative_multiply ( \
- GNUNET_TIME_UNIT_MINUTES, 2)
-
-/**
- * Delay after which we'll allow clients to force us to re-fetch key
- * information from the exchange if we don't know the denomination key.
- */
-#define FORCED_RELOAD_DELAY GNUNET_TIME_relative_multiply ( \
- GNUNET_TIME_UNIT_MINUTES, 15)
-
-/**
* Threshold after which exponential backoff should not increase.
*/
#define RETRY_BACKOFF_THRESHOLD GNUNET_TIME_relative_multiply ( \
@@ -52,19 +39,6 @@
/**
- * Perform our exponential back-off calculation, starting at 1 ms
- * and then going by a factor of 2 up unto a maximum of RETRY_BACKOFF_THRESHOLD.
- *
- * @param r current backoff time, initially zero
- */
-#define RETRY_BACKOFF(r) GNUNET_TIME_relative_min (RETRY_BACKOFF_THRESHOLD, \
- GNUNET_TIME_relative_multiply ( \
- GNUNET_TIME_relative_max ( \
- GNUNET_TIME_UNIT_MILLISECONDS, \
- (r)), 2));
-
-
-/**
* Information we keep for a pending #MMH_EXCHANGES_keys4exchange() operation.
*/
struct TMH_EXCHANGES_KeysOperation
@@ -105,46 +79,6 @@ struct TMH_EXCHANGES_KeysOperation
/**
- * Information we keep for a pending #MMH_EXCHANGES_wire4exchange() operation.
- */
-struct TMH_EXCHANGES_WireOperation
-{
-
- /**
- * Kept in a DLL.
- */
- struct TMH_EXCHANGES_WireOperation *next;
-
- /**
- * Kept in a DLL.
- */
- struct TMH_EXCHANGES_WireOperation *prev;
-
- /**
- * Function to call with the result.
- */
- TMH_EXCHANGES_WireContinuation fc;
-
- /**
- * Closure for @e fc.
- */
- void *fc_cls;
-
- /**
- * Exchange we wait for the /wire for.
- */
- struct TMH_Exchange *my_exchange;
-
- /**
- * Task scheduled to asynchronously return the result to
- * the find continuation.
- */
- struct GNUNET_SCHEDULER_Task *at;
-
-};
-
-
-/**
* Information about wire transfer fees of an exchange, by wire method.
*/
struct FeesByWireMethod
@@ -281,21 +215,6 @@ struct TMH_Exchange
struct TMH_EXCHANGES_KeysOperation *keys_tail;
/**
- * Head of /wire pending for this exchange.
- */
- struct TMH_EXCHANGES_WireOperation *w_head;
-
- /**
- * Tail of /wire pending for this exchange.
- */
- struct TMH_EXCHANGES_WireOperation *w_tail;
-
- /**
- * Request to /keys needed for our /wire operation.
- */
- struct TMH_EXCHANGES_KeysOperation *ko;
-
- /**
* Head of accounts of this exchange.
*/
struct ExchangeAccount *acc_head;
@@ -321,16 +240,6 @@ struct TMH_Exchange
struct TALER_EXCHANGE_Keys *keys;
/**
- * Active /wire request to the exchange, or NULL.
- */
- struct TALER_EXCHANGE_WireHandle *wire_request;
-
- /**
- * Task to re-run /wire after some delay.
- */
- struct GNUNET_SCHEDULER_Task *wire_task;
-
- /**
* Head of wire fees from /wire request.
*/
struct FeesByWireMethod *wire_fees_head;
@@ -372,25 +281,6 @@ struct TMH_Exchange
*/
bool trusted;
- /**
- * true if this exchange did return to use the
- * response from /wire.
- */
- bool have_wire;
-
-};
-
-
-/**
- * Opaque wire details abstraction returned to a client after successfully
- * obtaining /wire.
- */
-struct TMH_ExchangeWireDetails
-{
- /**
- * Internal representation of the exchange
- */
- struct TMH_Exchange *exchange;
};
@@ -418,6 +308,16 @@ static struct GNUNET_DB_EventHandler *keys_eh;
static int trusted_exchange_count;
+const struct TALER_MasterPublicKeyP *
+TMH_EXCHANGES_get_master_pub (
+ const struct TMH_Exchange *exchange)
+{
+ GNUNET_break ( (exchange->trusted) ||
+ (NULL != exchange->keys) );
+ return &exchange->master_pub;
+}
+
+
/**
* Free data structures within @a ea, but not @a ea
* pointer itself.
@@ -590,37 +490,17 @@ keys_mgmt_cb (
* the callback.
*
* @param exchange the exchange to check for pending find operations
- * @return true if we need /wire data from @a exchange
*/
-static bool
+static void
process_find_operations (struct TMH_Exchange *exchange)
{
- struct TMH_EXCHANGES_KeysOperation *fn2;
- struct TMH_EXCHANGES_WireOperation *wn;
struct GNUNET_TIME_Timestamp now;
- fn2 = NULL;
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Processing find operations for `%s'\n",
- exchange->url);
- for (struct TMH_EXCHANGES_KeysOperation *fo = exchange->keys_head;
- NULL != fo;
- fo = fn2)
- {
- fn2 = fo->next;
- fo->fc (fo->fc_cls,
- exchange->keys);
- TMH_EXCHANGES_keys4exchange_cancel (fo);
- }
- if (! exchange->have_wire)
- return true;
now = GNUNET_TIME_timestamp_get ();
for (struct FeesByWireMethod *fbw = exchange->wire_fees_head;
NULL != fbw;
fbw = fbw->next)
{
- bool removed = false;
-
while ( (NULL != fbw->af) &&
(GNUNET_TIME_timestamp_cmp (fbw->af->end_date,
<,
@@ -630,7 +510,6 @@ process_find_operations (struct TMH_Exchange *exchange)
fbw->af = af->next;
GNUNET_free (af);
- removed = true;
}
if (NULL == fbw->af)
{
@@ -638,15 +517,10 @@ process_find_operations (struct TMH_Exchange *exchange)
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Exchange has no wire fees configured for `%s' wire method\n",
fbw->wire_method);
- if (removed)
- {
- exchange->have_wire = false;
- return true; /* We just removed previous fees, try fetching update */
- }
}
- if (GNUNET_TIME_timestamp_cmp (fbw->af->start_date,
- >,
- now))
+ else if (GNUNET_TIME_timestamp_cmp (fbw->af->start_date,
+ >,
+ now))
{
/* Disagreement on the current time */
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@@ -656,45 +530,30 @@ process_find_operations (struct TMH_Exchange *exchange)
fbw->af->start_date.abs_time),
true));
}
- }
+ } /* for all wire methods */
- if (! exchange->have_wire)
- return true; /* need /wire response to continue */
{
- struct TMH_ExchangeWireDetails wd = {
- .exchange = exchange
- };
+ struct TMH_EXCHANGES_KeysOperation *kon;
- wn = NULL;
- for (struct TMH_EXCHANGES_WireOperation *w = exchange->w_head;
- NULL != w;
- w = wn)
+ kon = NULL;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Processing find operations for `%s'\n",
+ exchange->url);
+ for (struct TMH_EXCHANGES_KeysOperation *ko = exchange->keys_head;
+ NULL != ko;
+ ko = kon)
{
- wn = w->next;
- w->fc (w->fc_cls,
- &wd);
- TMH_EXCHANGES_wire4exchange_cancel (w);
+ kon = ko->next;
+ ko->fc (ko->fc_cls,
+ exchange->keys,
+ exchange);
+ TMH_EXCHANGES_keys4exchange_cancel (ko);
}
}
- return false;
}
/**
- * Check if we have any remaining pending requests for the
- * given @a exchange, and if we have the required data, call
- * the callback. If requests without /wire data remain,
- * retry the /wire request after some delay.
- *
- * Must only be called if 'exchange->keys' is non-NULL.
- *
- * @param cls a `struct TMH_Exchange` to check
- */
-static void
-wire_task_cb (void *cls);
-
-
-/**
* Function called with information about the wire fees for each wire method.
* Stores the wire fees with the exchange for later use.
*
@@ -994,99 +853,6 @@ outer:;
/**
- * Callbacks of this type are used to serve the result of submitting a
- * wire format inquiry request to a exchange.
- *
- * If the request fails to generate a valid response from the
- * exchange, @a http_status will also be zero.
- *
- * Must only be called if 'exchange->keys' is non-NULL.
- *
- * @param cls closure, a `struct TMH_Exchange`
- * @param wr response details
- */
-static void
-handle_wire_data (void *cls,
- const struct TALER_EXCHANGE_WireResponse *wr)
-{
- struct TMH_Exchange *exchange = cls;
- const struct TALER_EXCHANGE_Keys *keys;
- enum TALER_ErrorCode ecx;
-
- exchange->wire_request = NULL;
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Received /wire response\n");
- if (MHD_HTTP_OK != wr->hr.http_status)
- {
- struct TMH_EXCHANGES_WireOperation *w;
-
- exchange->have_wire = false;
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Failed to obtain /wire details from `%s': %u/%d\n",
- exchange->url,
- wr->hr.http_status,
- wr->hr.ec);
- while (NULL != (w = exchange->w_head))
- {
- w->fc (w->fc_cls,
- NULL);
- TMH_EXCHANGES_wire4exchange_cancel (w);
- }
- return;
- }
- keys = exchange->keys;
- GNUNET_assert (NULL != keys);
- ecx = process_wire_accounts (exchange,
- &keys->master_pub,
- wr->details.ok.accounts_len,
- wr->details.ok.accounts);
- if (TALER_EC_NONE == ecx)
- ecx = process_wire_fees (exchange,
- &keys->master_pub,
- wr->details.ok.fees_len,
- wr->details.ok.fees);
- if (TALER_EC_NONE != ecx)
- {
- /* Report hard failure to all callbacks! */
- struct TMH_EXCHANGES_KeysOperation *keys;
-
- GNUNET_break_op (0);
- exchange->have_wire = false;
- while (NULL != (keys = exchange->keys_head))
- {
- keys->fc (keys->fc_cls,
- NULL);
- TMH_EXCHANGES_keys4exchange_cancel (keys);
- }
- return;
- }
- exchange->have_wire = true;
- if ( (process_find_operations (exchange)) &&
- (NULL == exchange->wire_task) &&
- (NULL == exchange->wire_request) )
- {
- /* need to run /wire again. But as we DID get a successful reply,
- and as the exchange is unlikely to offer new wire methods very
- frequently, start with some significant delay */
- exchange->wire_retry_delay
- = GNUNET_TIME_relative_max (GNUNET_TIME_UNIT_MINUTES,
- exchange->wire_retry_delay);
- exchange->wire_retry_delay = RETRY_BACKOFF (exchange->wire_retry_delay);
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Need %s/wire, next download attempt in %s\n",
- exchange->url,
- GNUNET_STRINGS_relative_time_to_string (
- exchange->wire_retry_delay,
- true));
- exchange->wire_task
- = GNUNET_SCHEDULER_add_delayed (exchange->wire_retry_delay,
- &wire_task_cb,
- exchange);
- }
-}
-
-
-/**
* Retry getting keys from the given exchange in the closure.
*
* @param cls the `struct TMH_Exchange *`
@@ -1096,46 +862,13 @@ retry_exchange (void *cls)
{
struct TMH_Exchange *exchange = cls;
- /* might be a scheduled reload and not our first attempt */
exchange->retry_task = NULL;
- if (NULL != exchange->conn)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Already trying /keys\n");
- return; /* already trying */
- }
- if ( (NULL != exchange->keys) &&
- (GNUNET_TIME_absolute_is_future (
- exchange->keys->key_data_expiration.abs_time)) )
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Already have valid /keys\n");
- if ( (process_find_operations (exchange)) &&
- (NULL == exchange->wire_request) &&
- (NULL == exchange->wire_task) )
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Got key data, but also need wire data. Will request /wire now\n");
- exchange->wire_request
- = TALER_EXCHANGE_wire (
- TMH_curl_ctx,
- exchange->url,
- exchange->keys,
- &handle_wire_data,
- exchange);
- }
- return; /* still have a valid reply */
- }
- /* increment exponential-backoff */
+ GNUNET_assert (NULL == exchange->conn);
exchange->retry_delay
- = RETRY_BACKOFF (exchange->retry_delay);
- /* No download until both backoff and #FORCED_RELOAD_DELAY
- are satisfied again */
+ = GNUNET_TIME_randomized_backoff (exchange->retry_delay,
+ RETRY_BACKOFF_THRESHOLD);
exchange->first_retry
- = GNUNET_TIME_relative_to_absolute (
- GNUNET_TIME_relative_max (
- exchange->retry_delay,
- FORCED_RELOAD_DELAY));
+ = GNUNET_TIME_relative_to_absolute (exchange->retry_delay);
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Fetching /keys from exchange %s in retry_exchange()\n",
exchange->url);
@@ -1174,6 +907,7 @@ return_keys (void *cls)
struct TMH_EXCHANGES_KeysOperation *
TMH_EXCHANGES_keys4exchange (
const char *chosen_exchange,
+ bool force_download,
TMH_EXCHANGES_Find2Continuation fc,
void *fc_cls)
{
@@ -1197,6 +931,7 @@ TMH_EXCHANGES_keys4exchange (
exchange->keys_tail,
fo);
if ( (NULL != exchange->keys) &&
+ (! force_download) &&
(GNUNET_TIME_absolute_is_future (
exchange->keys->key_data_expiration.abs_time)) )
{
@@ -1257,7 +992,7 @@ TMH_EXCHANGES_keys4exchange_cancel (
* @return NULL if we do not have fees for this method yet
*/
static const struct FeesByWireMethod *
-get_wire_fees (struct TMH_Exchange *exchange,
+get_wire_fees (const struct TMH_Exchange *exchange,
struct GNUNET_TIME_Timestamp now,
const char *wire_method)
{
@@ -1289,26 +1024,6 @@ get_wire_fees (struct TMH_Exchange *exchange,
}
-static void
-wire_task_cb (void *cls)
-{
- struct TMH_Exchange *exchange = cls;
-
- exchange->wire_task = NULL;
- if (! process_find_operations (exchange))
- return; /* no more need */
- GNUNET_assert (NULL == exchange->wire_request);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Initiating /wire download\n");
- exchange->wire_request
- = TALER_EXCHANGE_wire (TMH_curl_ctx,
- exchange->url,
- exchange->keys,
- &handle_wire_data,
- exchange);
-}
-
-
/**
* Free @a exchange.
*
@@ -1319,6 +1034,10 @@ free_exchange_entry (struct TMH_Exchange *exchange)
{
struct FeesByWireMethod *f;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Releasing %s exchange %s\n",
+ exchange->trusted ? "trusted" : "untrusted",
+ exchange->url);
GNUNET_CONTAINER_DLL_remove (exchange_head,
exchange_tail,
exchange);
@@ -1338,16 +1057,6 @@ free_exchange_entry (struct TMH_Exchange *exchange)
GNUNET_free (f->wire_method);
GNUNET_free (f);
}
- if (NULL != exchange->wire_request)
- {
- TALER_EXCHANGE_wire_cancel (exchange->wire_request);
- exchange->wire_request = NULL;
- }
- if (NULL != exchange->wire_task)
- {
- GNUNET_SCHEDULER_cancel (exchange->wire_task);
- exchange->wire_task = NULL;
- }
if (NULL != exchange->conn)
{
TALER_EXCHANGE_get_keys_cancel (exchange->conn);
@@ -1362,8 +1071,6 @@ free_exchange_entry (struct TMH_Exchange *exchange)
}
GNUNET_assert (NULL == exchange->keys_head);
GNUNET_assert (NULL == exchange->keys_tail);
- GNUNET_assert (NULL == exchange->w_head);
- GNUNET_assert (NULL == exchange->w_tail);
GNUNET_free (exchange->url);
GNUNET_free (exchange);
}
@@ -1379,31 +1086,17 @@ static void
fail_and_retry (struct TMH_Exchange *exchange)
{
struct TMH_EXCHANGES_KeysOperation *keys;
- struct TMH_EXCHANGES_WireOperation *w;
- if (NULL != exchange->wire_request)
- {
- TALER_EXCHANGE_wire_cancel (exchange->wire_request);
- exchange->wire_request = NULL;
- }
- if (NULL != exchange->wire_task)
- {
- GNUNET_SCHEDULER_cancel (exchange->wire_task);
- exchange->wire_task = NULL;
- }
while (NULL != (keys = exchange->keys_head))
{
keys->fc (keys->fc_cls,
- NULL);
+ NULL,
+ exchange);
TMH_EXCHANGES_keys4exchange_cancel (keys);
}
- while (NULL != (w = exchange->w_head))
- {
- w->fc (w->fc_cls,
- NULL);
- TMH_EXCHANGES_wire4exchange_cancel (w);
- }
- exchange->retry_delay = RETRY_BACKOFF (exchange->retry_delay);
+ exchange->retry_delay
+ = GNUNET_TIME_randomized_backoff (exchange->retry_delay,
+ RETRY_BACKOFF_THRESHOLD);
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Failed to fetch /keys from `%s'; retrying in %s\n",
exchange->url,
@@ -1435,6 +1128,31 @@ keys_mgmt_cb (void *cls,
fail_and_retry (exchange);
return;
}
+
+ /* store exchange online signing keys in our DB */
+ for (unsigned int i = 0; i<keys->num_sign_keys; i++)
+ {
+ struct TALER_EXCHANGE_SigningPublicKey *sign_key = &keys->sign_keys[i];
+ enum GNUNET_DB_QueryStatus qs;
+
+ TMH_db->preflight (TMH_db->cls);
+ qs = TMH_db->insert_exchange_signkey (
+ TMH_db->cls,
+ &keys->master_pub,
+ &sign_key->key,
+ sign_key->valid_from,
+ sign_key->valid_until,
+ sign_key->valid_legal,
+ &sign_key->master_sig);
+ /* 0 is OK, we may already have the key in the DB! */
+ if (0 > qs)
+ {
+ GNUNET_break (0);
+ fail_and_retry (exchange);
+ return;
+ }
+ }
+
qs = TMH_db->insert_exchange_keys (TMH_db->cls,
keys);
TALER_EXCHANGE_keys_decref (keys);
@@ -1450,129 +1168,20 @@ keys_mgmt_cb (void *cls,
&es,
exchange->url,
strlen (exchange->url) + 1);
+ exchange->retry_delay = GNUNET_TIME_UNIT_ZERO;
}
}
-/**
- * Task to return find operation result asynchronously to caller.
- *
- * @param cls a `struct TMH_EXCHANGES_WireOperation`
- */
-static void
-return_wire_result (void *cls)
-{
- struct TMH_EXCHANGES_WireOperation *w = cls;
- struct TMH_Exchange *exchange = w->my_exchange;
-
- w->at = NULL;
- process_find_operations (exchange);
-}
-
-
-struct TMH_EXCHANGES_WireOperation *
-TMH_EXCHANGES_wire4exchange (
- const char *chosen_exchange,
- TMH_EXCHANGES_WireContinuation fc,
- void *fc_cls)
-{
- struct TMH_Exchange *exchange;
- struct TMH_EXCHANGES_WireOperation *w;
-
- if (NULL == TMH_curl_ctx)
- {
- GNUNET_break (0);
- return NULL;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Trying to find chosen exchange `%s'\n",
- chosen_exchange);
- exchange = lookup_exchange (chosen_exchange);
- w = GNUNET_new (struct TMH_EXCHANGES_WireOperation);
- w->fc = fc;
- w->fc_cls = fc_cls;
- w->my_exchange = exchange;
- GNUNET_CONTAINER_DLL_insert (exchange->w_head,
- exchange->w_tail,
- w);
- if (exchange->have_wire)
- {
- /* We are not currently waiting for a reply, immediately
- return result */
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "The exchange `%s' is ready\n",
- exchange->url);
- GNUNET_assert (NULL == w->at);
- w->at = GNUNET_SCHEDULER_add_now (&return_wire_result,
- w);
- return w;
- }
- if (NULL != exchange->wire_request)
- return w; /* /wire request is active, do nothing */
- if ( (NULL != exchange->keys) &&
- (GNUNET_TIME_absolute_is_future (
- exchange->keys->key_data_expiration.abs_time)) )
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Requesting /wire from `%s'\n",
- exchange->url);
- exchange->wire_request
- = TALER_EXCHANGE_wire (TMH_curl_ctx,
- exchange->url,
- exchange->keys,
- &handle_wire_data,
- exchange);
- return w;
- }
- if ( (NULL == exchange->keys) &&
- ( (NULL != exchange->conn) ||
- (NULL != exchange->retry_task) ) )
- return w; /* /keys request active, do nothing */
-
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "No valid keys, fetching /keys at %s\n",
- GNUNET_TIME_absolute2s (exchange->first_retry));
- exchange->retry_task
- = GNUNET_SCHEDULER_add_at (exchange->first_retry,
- &retry_exchange,
- exchange);
- return w;
-}
-
-
-void
-TMH_EXCHANGES_wire4exchange_cancel (
- struct TMH_EXCHANGES_WireOperation *w)
-{
- struct TMH_Exchange *exchange = w->my_exchange;
-
- if (NULL != w->at)
- {
- GNUNET_SCHEDULER_cancel (w->at);
- w->at = NULL;
- }
- GNUNET_CONTAINER_DLL_remove (exchange->w_head,
- exchange->w_tail,
- w);
- GNUNET_free (w);
-}
-
-
enum GNUNET_GenericReturnValue
TMH_EXCHANGES_lookup_wire_fee (
- const struct TMH_ExchangeWireDetails *wd,
+ const struct TMH_Exchange *exchange,
const char *wire_method,
struct TALER_Amount *wire_fee)
{
- struct TMH_Exchange *exchange = wd->exchange;
const struct FeesByWireMethod *fbm;
const struct TALER_EXCHANGE_WireAggregateFees *af;
- if (! exchange->have_wire)
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
fbm = get_wire_fees (exchange,
GNUNET_TIME_timestamp_get (),
wire_method);
@@ -1586,11 +1195,17 @@ TMH_EXCHANGES_lookup_wire_fee (
enum GNUNET_GenericReturnValue
TMH_exchange_check_debit (
- const struct TMH_ExchangeWireDetails *wd,
+ const struct TMH_Exchange *exchange,
const struct TMH_WireMethod *wm)
{
- struct TMH_Exchange *ex = wd->exchange;
- for (struct ExchangeAccount *acc = ex->acc_head;
+ if (NULL == exchange->acc_head)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "No accounts available for %s\n",
+ exchange->url);
+ return GNUNET_SYSERR;
+ }
+ for (struct ExchangeAccount *acc = exchange->acc_head;
NULL != acc;
acc = acc->next)
{
@@ -1632,48 +1247,25 @@ TMH_exchange_check_debit (
}
-json_t *
-TMH_exchange_get_acceptable (const struct TMH_WireMethod *wm)
+void
+TMH_exchange_get_trusted (TMH_ExchangeCallback cb,
+ void *cb_cls)
{
- json_t *te = json_array ();
-
- GNUNET_assert (NULL != te);
- for (struct TMH_Exchange *exchange = exchange_head;
+ for (const struct TMH_Exchange *exchange = exchange_head;
NULL != exchange;
exchange = exchange->next)
{
- json_t *j_exchange;
- unsigned int priority;
-
if (! exchange->trusted)
- continue;
- priority = 512; /* medium */
- if (exchange->have_wire)
{
- struct TMH_ExchangeWireDetails wd = {
- .exchange = exchange
- };
-
- if (GNUNET_OK ==
- TMH_exchange_check_debit (&wd,
- wm))
- priority = 1024; /* high */
- else
- priority = 0; /* negative response */
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Exchange %s not trusted, skipping!\n",
+ exchange->url);
+ continue;
}
- j_exchange = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_string ("url",
- exchange->url),
- GNUNET_JSON_pack_uint64 ("priority",
- priority),
- GNUNET_JSON_pack_data_auto ("master_pub",
- &exchange->master_pub));
- GNUNET_assert (NULL != j_exchange);
- GNUNET_assert (0 ==
- json_array_append_new (te,
- j_exchange));
+ cb (cb_cls,
+ exchange->url,
+ exchange);
}
- return te;
}
@@ -1762,6 +1354,10 @@ accept_exchanges (void *cls,
"MASTER_KEY missing in section '%s', not trusting exchange\n",
section);
}
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Setup exchange %s as %s\n",
+ exchange->url,
+ exchange->trusted ? "trusted" : "untrusted");
GNUNET_assert (NULL == exchange->retry_task);
exchange->retry_task
= GNUNET_SCHEDULER_add_now (&retry_exchange,
@@ -1785,7 +1381,7 @@ update_exchange_keys (void *cls,
const char *url = extra;
struct TMH_Exchange *exchange;
struct TALER_EXCHANGE_Keys *keys;
- struct GNUNET_TIME_Relative delay;
+ enum TALER_ErrorCode ecx;
if ( (NULL == extra) ||
(0 == extra_len) )
@@ -1810,11 +1406,35 @@ update_exchange_keys (void *cls,
GNUNET_break (0);
return;
}
- TALER_EXCHANGE_keys_decref (exchange->keys);
- exchange->keys = keys;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Loaded /keys from database with %u accounts\n",
+ keys->accounts_len);
+ // FIXME: split into parsing part (do here)
+ // and DB part (do when receiving /keys!)
+ ecx = process_wire_accounts (exchange,
+ &keys->master_pub,
+ keys->accounts_len,
+ keys->accounts);
+ if (TALER_EC_NONE == ecx)
+ ecx = process_wire_fees (exchange,
+ &keys->master_pub,
+ keys->fees_len,
+ keys->fees);
+ if (TALER_EC_NONE != ecx)
+ {
+ /* Report hard failure to all callbacks! */
+ GNUNET_break_op (0);
+ fail_and_retry (exchange);
+ TALER_EXCHANGE_keys_decref (keys);
+ return;
+ }
+
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Reloaded /keys of %s from database\n",
url);
+ TALER_EXCHANGE_keys_decref (exchange->keys);
+ exchange->keys = keys;
if ( (exchange->trusted) &&
(0 != GNUNET_memcmp (&exchange->master_pub,
&keys->master_pub)) )
@@ -1843,62 +1463,7 @@ update_exchange_keys (void *cls,
}
}
- /* store exchange online signing keys in our DB */
- for (unsigned int i = 0; i<keys->num_sign_keys; i++)
- {
- struct TALER_EXCHANGE_SigningPublicKey *sign_key = &keys->sign_keys[i];
- enum GNUNET_DB_QueryStatus qs;
-
- TMH_db->preflight (TMH_db->cls);
- qs = TMH_db->insert_exchange_signkey (
- TMH_db->cls,
- &keys->master_pub,
- &sign_key->key,
- sign_key->valid_from,
- sign_key->valid_until,
- sign_key->valid_legal,
- &sign_key->master_sig);
- /* 0 is OK, we may already have the key in the DB! */
- if (0 > qs)
- {
- GNUNET_break (0);
- fail_and_retry (exchange);
- return;
- }
- }
-
- exchange->first_retry
- = GNUNET_TIME_relative_to_absolute (MIN_RELOAD_DELAY);
- delay = GNUNET_TIME_absolute_get_remaining (
- keys->key_data_expiration.abs_time);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "/keys response expires at %s! Retrying at that time!\n",
- GNUNET_TIME_absolute2s (
- keys->key_data_expiration.abs_time));
- delay = GNUNET_TIME_relative_max (delay,
- MIN_RELOAD_DELAY);
- exchange->retry_delay = GNUNET_TIME_UNIT_ZERO;
- if (NULL != exchange->retry_task)
- GNUNET_SCHEDULER_cancel (exchange->retry_task);
- exchange->retry_task
- = GNUNET_SCHEDULER_add_delayed (delay,
- &retry_exchange,
- exchange);
-
- if ( (process_find_operations (exchange)) &&
- (NULL == exchange->wire_request) &&
- (NULL == exchange->wire_task) )
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Got key data, but also need wire data. Will request /wire now\n");
- exchange->wire_request
- = TALER_EXCHANGE_wire (
- TMH_curl_ctx,
- exchange->url,
- exchange->keys,
- &handle_wire_data,
- exchange);
- }
+ process_find_operations (exchange);
}
diff --git a/src/backend/taler-merchant-httpd_exchanges.h b/src/backend/taler-merchant-httpd_exchanges.h
index 89e5deee..b0f2d879 100644
--- a/src/backend/taler-merchant-httpd_exchanges.h
+++ b/src/backend/taler-merchant-httpd_exchanges.h
@@ -37,19 +37,6 @@ struct TMH_Exchange;
/**
- * Return the list of exchanges we would find
- * acceptable for a payment given the @a wire_method.
- *
- * @param wm wire method the payment should be
- * made with
- * @return list of exchanges we accept for @a wire_method
- * (and that would accept our bank account)
- */
-json_t *
-TMH_exchange_get_acceptable (const struct TMH_WireMethod *wm);
-
-
-/**
* Parses "trusted" exchanges listed in the configuration.
*
* @param cfg the configuration
@@ -73,30 +60,13 @@ TMH_EXCHANGES_done (void);
*
* @param cls closure
* @param keys the keys of the exchange
+ * @param exchange representation of the exchange
*/
typedef void
(*TMH_EXCHANGES_Find2Continuation)(
void *cls,
- struct TALER_EXCHANGE_Keys *keys);
-
-
-/**
- * Abstraction of wire knowledge returned internally.
- */
-struct TMH_ExchangeWireDetails;
-
-
-/**
- * Function called with the result of a #TMH_EXCHANGES_wire4exchange()
- * operation.
- *
- * @param cls closure
- * @param wire the wire data of the exchange
- */
-typedef void
-(*TMH_EXCHANGES_WireContinuation)(
- void *cls,
- const struct TMH_ExchangeWireDetails *wire);
+ struct TALER_EXCHANGE_Keys *keys,
+ struct TMH_Exchange *exchange);
/**
@@ -104,22 +74,19 @@ typedef void
*/
struct TMH_EXCHANGES_KeysOperation;
-/**
- * Information we keep for a pending #MMH_EXCHANGES_wire4exchange() operation.
- */
-struct TMH_EXCHANGES_WireOperation;
-
/**
* Get /keys of the given @a exchange.
*
* @param exchange URL of the exchange we would like to talk to
+ * @param force_download force /keys download now
* @param fc function to call with the handles for the exchange
* @param fc_cls closure for @a fc
*/
struct TMH_EXCHANGES_KeysOperation *
TMH_EXCHANGES_keys4exchange (
const char *exchange,
+ bool force_download,
TMH_EXCHANGES_Find2Continuation fc,
void *fc_cls);
@@ -134,34 +101,47 @@ TMH_EXCHANGES_keys4exchange_cancel (struct TMH_EXCHANGES_KeysOperation *fo);
/**
- * Get /wire of the given @a exchange.
+ * Callback on an exchange known to us. Does not warrant
+ * that the "keys" information is actually available for
+ * @a exchange.
*
- * @param exchange URL of the exchange we would like to talk to
- * @param fc function to call with the handles for the exchange
- * @param fc_cls closure for @a fc
+ * @param cls closure
+ * @param url base URL of the exchange
+ * @param exchange internal handle for the exchange
*/
-struct TMH_EXCHANGES_WireOperation *
-TMH_EXCHANGES_wire4exchange (
- const char *exchange,
- TMH_EXCHANGES_WireContinuation fc,
- void *fc_cls);
+typedef void
+(*TMH_ExchangeCallback)(void *cls,
+ const char *url,
+ const struct TMH_Exchange *exchange);
/**
- * Abort pending wire details lookup operation.
+ * Return all trusted exchanges to @a cb.
*
- * @param fo handle to operation to abort
+ * @param cb function to call
+ * @param cb_cls closure for @a cb
*/
void
-TMH_EXCHANGES_wire4exchange_cancel (
- struct TMH_EXCHANGES_WireOperation *fo);
+TMH_exchange_get_trusted (TMH_ExchangeCallback cb,
+ void *cb_cls);
+/**
+ * Return the master public key of the given @a exchange.
+ * Will be returned from configuration for trusted
+ * exchanges.
+ *
+ * @param exchange exchange to get master public key for
+ * @return the master public key of @a exchange
+ */
+const struct TALER_MasterPublicKeyP *
+TMH_EXCHANGES_get_master_pub (
+ const struct TMH_Exchange *exchange);
/**
* Lookup current wire fee by @a exchange_url and
* @a wire_method.
*
- * @param wd wire details of the exchange
+ * @param exchange the exchange to check
* @param wire_method wire method to lookup fee by
* @param[out] wire_fee set to the wire fee
* @return #GNUNET_OK on success
@@ -170,7 +150,7 @@ TMH_EXCHANGES_wire4exchange_cancel (
*/
enum GNUNET_GenericReturnValue
TMH_EXCHANGES_lookup_wire_fee (
- const struct TMH_ExchangeWireDetails *wd,
+ const struct TMH_Exchange *exchange,
const char *wire_method,
struct TALER_Amount *wire_fee);
@@ -181,13 +161,13 @@ TMH_EXCHANGES_lookup_wire_fee (
* is trusted and that @a ex allows wire transfers
* into the account given in @a wm.
*
- * @param wd the wire details of the exchange to check
+ * @param exchange the exchange to check
* @param wm the wire method to check with
* @return #GNUNET_OK if such a debit can happen
*/
enum GNUNET_GenericReturnValue
TMH_exchange_check_debit (
- const struct TMH_ExchangeWireDetails *wd,
+ const struct TMH_Exchange *exchange,
const struct TMH_WireMethod *wm);
diff --git a/src/backend/taler-merchant-httpd_post-orders-ID-abort.c b/src/backend/taler-merchant-httpd_post-orders-ID-abort.c
index f63404b4..09ac8acb 100644
--- a/src/backend/taler-merchant-httpd_post-orders-ID-abort.c
+++ b/src/backend/taler-merchant-httpd_post-orders-ID-abort.c
@@ -497,13 +497,16 @@ refund_cb (void *cls,
*
* @param cls the `struct AbortContext`
* @param keys keys of the exchange
+ * @param exchange representation of the exchange
*/
static void
process_abort_with_exchange (void *cls,
- struct TALER_EXCHANGE_Keys *keys)
+ struct TALER_EXCHANGE_Keys *keys,
+ struct TMH_Exchange *exchange)
{
struct AbortContext *ac = cls;
+ (void) exchange;
ac->fo = NULL;
GNUNET_assert (GNUNET_YES == ac->suspended);
if (NULL == keys)
@@ -584,6 +587,7 @@ find_next_exchange (struct AbortContext *ac)
{
ac->current_exchange = rdi->exchange_url;
ac->fo = TMH_EXCHANGES_keys4exchange (ac->current_exchange,
+ false,
&process_abort_with_exchange,
ac);
if (NULL == ac->fo)
diff --git a/src/backend/taler-merchant-httpd_post-orders-ID-pay.c b/src/backend/taler-merchant-httpd_post-orders-ID-pay.c
index 75bc4345..d4e620bd 100644
--- a/src/backend/taler-merchant-httpd_post-orders-ID-pay.c
+++ b/src/backend/taler-merchant-httpd_post-orders-ID-pay.c
@@ -176,13 +176,6 @@ struct ExchangeGroup
struct TMH_EXCHANGES_KeysOperation *fo;
/**
- * Handle for operation to lookup /wire from
- * the exchange used for this transaction; NULL if no operation is
- * pending.
- */
- struct TMH_EXCHANGES_WireOperation *gwo;
-
- /**
* URL of the exchange that issued this coin. Aliases
* the exchange URL of one of the coins, do not free!
*/
@@ -692,8 +685,6 @@ pay_context_cleanup (void *cls)
if (NULL != eg->fo)
TMH_EXCHANGES_keys4exchange_cancel (eg->fo);
- if (NULL != eg->gwo)
- TMH_EXCHANGES_wire4exchange_cancel (eg->gwo);
GNUNET_free (eg);
}
GNUNET_free (pc->egs);
@@ -785,14 +776,17 @@ deposit_get_callback (
*
* @param cls the `struct KycContext`
* @param keys NULL if exchange was not found to be acceptable
+ * @param exchange representation of the exchange
*/
static void
process_kyc_with_exchange (
void *cls,
- struct TALER_EXCHANGE_Keys *keys)
+ struct TALER_EXCHANGE_Keys *keys,
+ struct TMH_Exchange *exchange)
{
struct KycContext *kc = cls;
+ (void) exchange;
kc->fo = NULL;
if (NULL == keys)
{
@@ -922,9 +916,11 @@ check_kyc (struct PayContext *pc,
GNUNET_CONTAINER_DLL_insert (kc_head,
kc_tail,
kc);
- kc->fo = TMH_EXCHANGES_keys4exchange (kc->exchange_url,
- &process_kyc_with_exchange,
- kc);
+ kc->fo = TMH_EXCHANGES_keys4exchange (
+ kc->exchange_url,
+ false,
+ &process_kyc_with_exchange,
+ kc);
if (NULL == kc->fo)
{
GNUNET_break (0);
@@ -1146,15 +1142,26 @@ batch_deposit_cb (
/**
+ * Force re-downloading keys for @a eg.
+ *
+ * @param[in,out] eg group to re-download keys for
+ */
+static void
+force_keys (struct ExchangeGroup *eg);
+
+
+/**
* Function called with the result of our exchange keys lookup.
*
* @param cls the `struct ExchangeGroup`
* @param keys the keys of the exchange
+ * @param exchange representation of the exchange
*/
static void
process_pay_with_keys (
void *cls,
- struct TALER_EXCHANGE_Keys *keys)
+ struct TALER_EXCHANGE_Keys *keys,
+ struct TMH_Exchange *exchange)
{
struct ExchangeGroup *eg = cls;
struct PayContext *pc = eg->pc;
@@ -1178,6 +1185,62 @@ process_pay_with_keys (
return;
}
+ if (GNUNET_OK !=
+ TMH_exchange_check_debit (exchange,
+ pc->wm))
+ {
+ if (eg->tried_force_keys)
+ {
+ GNUNET_break_op (0);
+ pc->pending_at_eg--;
+ resume_pay_with_error (
+ pc,
+ TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_WIRE_METHOD_UNSUPPORTED,
+ NULL);
+ return;
+ }
+ eg->tried_force_keys = true;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Forcing /keys download (once) as wire method seems unsupported for debit\n");
+ eg->fo = TMH_EXCHANGES_keys4exchange (
+ eg->exchange_url,
+ true,
+ &process_pay_with_keys,
+ eg);
+ if (NULL == eg->fo)
+ {
+ GNUNET_break (0);
+ pc->pending_at_eg--;
+ resume_pay_with_error (pc,
+ TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_EXCHANGE_LOOKUP_FAILED,
+ "Failed to lookup exchange by URL");
+ return;
+ }
+ return;
+ }
+
+ if (GNUNET_OK !=
+ TMH_EXCHANGES_lookup_wire_fee (exchange,
+ pc->wm->wire_method,
+ &eg->wire_fee))
+ {
+ if (eg->tried_force_keys)
+ {
+ pc->pending_at_eg--;
+ GNUNET_break_op (0);
+ resume_pay_with_error (
+ pc,
+ TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_WIRE_METHOD_UNSUPPORTED,
+ pc->wm->wire_method);
+ return;
+ }
+ force_keys (eg);
+ return;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Got wire data for %s\n",
+ eg->exchange_url);
+
/* Initiate /batch-deposit operation for all coins of
the current exchange (!) */
group_size = 0;
@@ -1198,19 +1261,25 @@ process_pay_with_keys (
&dc->cdd.h_denom_pub);
if (NULL == denom_details)
{
- pc->pending_at_eg--;
- resume_pay_with_response (
- pc,
- MHD_HTTP_BAD_REQUEST,
- TALER_MHD_MAKE_JSON_PACK (
- TALER_JSON_pack_ec (
- TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_DENOMINATION_KEY_NOT_FOUND),
- GNUNET_JSON_pack_data_auto ("h_denom_pub",
- &dc->cdd.h_denom_pub),
- GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_object_steal (
- "exchange_keys",
- TALER_EXCHANGE_keys_to_json (keys)))));
+ if (eg->tried_force_keys)
+ {
+ GNUNET_break_op (0);
+ pc->pending_at_eg--;
+ resume_pay_with_response (
+ pc,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_MHD_MAKE_JSON_PACK (
+ TALER_JSON_pack_ec (
+ TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_DENOMINATION_KEY_NOT_FOUND),
+ GNUNET_JSON_pack_data_auto ("h_denom_pub",
+ &dc->cdd.h_denom_pub),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_object_steal (
+ "exchange_keys",
+ TALER_EXCHANGE_keys_to_json (keys)))));
+ return;
+ }
+ force_keys (eg);
return;
}
dc->deposit_fee = denom_details->fees.deposit;
@@ -1270,6 +1339,7 @@ process_pay_with_keys (
AGE_FAIL:
if (0 < code)
{
+ GNUNET_break_op (0);
pc->pending_at_eg--;
GNUNET_free (dc->age_commitment.keys);
resume_pay_with_response (
@@ -1383,73 +1453,21 @@ AGE_FAIL:
}
-/**
- * Function called with the result of our exchange lookup.
- *
- * @param cls the `struct ExchangeGroup`
- * @param keys the keys of the exchange
- */
static void
-process_pay_with_wire (
- void *cls,
- const struct TMH_ExchangeWireDetails *wire)
+force_keys (struct ExchangeGroup *eg)
{
- struct ExchangeGroup *eg = cls;
- struct PayContext *pc = eg->pc;
- struct TMH_HandlerContext *hc = pc->hc;
- enum GNUNET_GenericReturnValue ret;
-
- eg->gwo = NULL;
- GNUNET_SCHEDULER_begin_async_scope (&hc->async_scope_id);
- if (NULL == wire)
- {
- GNUNET_break_op (0);
- pc->pending_at_eg--;
- /* FIXME: define more specific error code... */
- resume_pay_with_error (
- pc,
- TALER_EC_MERCHANT_GENERIC_EXCHANGE_CONNECT_FAILURE,
- NULL);
- return;
- }
- if (GNUNET_OK !=
- TMH_exchange_check_debit (wire,
- pc->wm))
- {
- GNUNET_break_op (0);
- pc->pending_at_eg--;
- resume_pay_with_error (
- pc,
- TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_WIRE_METHOD_UNSUPPORTED,
- NULL);
- return;
- }
- ret = TMH_EXCHANGES_lookup_wire_fee (wire,
- pc->wm->wire_method,
- &eg->wire_fee);
- if (GNUNET_OK != ret)
- {
- enum TALER_ErrorCode ec;
-
- ec = (GNUNET_NO == ret)
- ? TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_WIRE_METHOD_UNSUPPORTED
- : TALER_EC_MERCHANT_GENERIC_EXCHANGE_WIRE_REQUEST_FAILED;
- pc->pending_at_eg--;
- GNUNET_break_op (0);
- resume_pay_with_error (
- pc,
- ec,
- pc->wm->wire_method);
- return;
- }
+ eg->tried_force_keys = true;
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Got /wire for %s, now going for /keys\n",
- eg->exchange_url);
- eg->fo = TMH_EXCHANGES_keys4exchange (eg->exchange_url,
- &process_pay_with_keys,
- eg);
+ "Forcing /keys download (once) as wire fees are unknown\n");
+ eg->fo = TMH_EXCHANGES_keys4exchange (
+ eg->exchange_url,
+ true,
+ &process_pay_with_keys,
+ eg);
if (NULL == eg->fo)
{
+ struct PayContext *pc = eg->pc;
+
GNUNET_break (0);
pc->pending_at_eg--;
resume_pay_with_error (pc,
@@ -1489,12 +1507,14 @@ start_batch_deposits (struct PayContext *pc)
if (! have_coins)
continue; /* no coins left to deposit at this exchange */
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Getting /wire details for %s\n",
+ "Getting /keys for %s\n",
eg->exchange_url);
- eg->gwo = TMH_EXCHANGES_wire4exchange (eg->exchange_url,
- &process_pay_with_wire,
- eg);
- if (NULL == eg->gwo)
+ eg->fo = TMH_EXCHANGES_keys4exchange (
+ eg->exchange_url,
+ false,
+ &process_pay_with_keys,
+ eg);
+ if (NULL == eg->fo)
{
GNUNET_break (0);
resume_pay_with_error (pc,
diff --git a/src/backend/taler-merchant-httpd_post-orders-ID-refund.c b/src/backend/taler-merchant-httpd_post-orders-ID-refund.c
index ded6ff9d..f71eb17e 100644
--- a/src/backend/taler-merchant-httpd_post-orders-ID-refund.c
+++ b/src/backend/taler-merchant-httpd_post-orders-ID-refund.c
@@ -439,14 +439,17 @@ refund_cb (void *cls,
*
* @param cls a `struct CoinRefund *`
* @param keys keys of exchange, NULL on error
+ * @param exchange representation of the exchange
*/
static void
exchange_found_cb (void *cls,
- struct TALER_EXCHANGE_Keys *keys)
+ struct TALER_EXCHANGE_Keys *keys,
+ struct TMH_Exchange *exchange)
{
struct CoinRefund *cr = cls;
struct PostRefundData *prd = cr->prd;
+ (void) exchange;
cr->fo = NULL;
if (NULL == keys)
{
@@ -707,6 +710,7 @@ TMH_post_orders_ID_refund (const struct TMH_RequestHandler *rh,
{
/* We need to talk to the exchange */
cr->fo = TMH_EXCHANGES_keys4exchange (cr->exchange_url,
+ false,
&exchange_found_cb,
cr);
}
diff --git a/src/backend/taler-merchant-httpd_post-rewards-ID-pickup.c b/src/backend/taler-merchant-httpd_post-rewards-ID-pickup.c
index b7aa31e1..05347c9f 100644
--- a/src/backend/taler-merchant-httpd_post-rewards-ID-pickup.c
+++ b/src/backend/taler-merchant-httpd_post-rewards-ID-pickup.c
@@ -384,14 +384,17 @@ withdraw_cb (void *cls,
*
* @param cls closure, with our `struct PlanchetOperation *`
* @param keys keys for the exchange
+ * @param exchange representation of the exchange
*/
static void
do_withdraw (void *cls,
- struct TALER_EXCHANGE_Keys *keys)
+ struct TALER_EXCHANGE_Keys *keys,
+ struct TMH_Exchange *exchange)
{
struct PlanchetOperation *po = cls;
struct PickupContext *pc = po->pc;
+ (void) exchange;
po->fo = NULL;
TMH_db->preflight (TMH_db->cls);
if (NULL == keys)
@@ -443,6 +446,7 @@ try_withdraw (struct PickupContext *pc,
po->pd = *planchet;
po->offset = offset;
po->fo = TMH_EXCHANGES_keys4exchange (pc->exchange_url,
+ false,
&do_withdraw,
po);
GNUNET_assert (NULL != po->fo);
@@ -484,13 +488,16 @@ do_timeout (void *cls)
*
* @param cls closure, with our `struct PickupContext *`
* @param keys the keys of the exchange
+ * @param exchange representation of the exchange
*/
static void
compute_total_requested (void *cls,
- struct TALER_EXCHANGE_Keys *keys)
+ struct TALER_EXCHANGE_Keys *keys,
+ struct TMH_Exchange *exchange)
{
struct PickupContext *pc = cls;
+ (void) exchange;
pc->fo = NULL;
stop_operations (pc); /* stops timeout job */
if (NULL == keys)
@@ -727,6 +734,7 @@ TMH_post_rewards_ID_pickup (const struct TMH_RequestHandler *rh,
&do_timeout,
pc);
pc->fo = TMH_EXCHANGES_keys4exchange (pc->exchange_url,
+ false,
&compute_total_requested,
pc);
return MHD_YES;
diff --git a/src/backend/taler-merchant-httpd_private-get-instances-ID-kyc.c b/src/backend/taler-merchant-httpd_private-get-instances-ID-kyc.c
index eda0aaa8..d269402b 100644
--- a/src/backend/taler-merchant-httpd_private-get-instances-ID-kyc.c
+++ b/src/backend/taler-merchant-httpd_private-get-instances-ID-kyc.c
@@ -650,15 +650,18 @@ exchange_check_cb (void *cls,
*
* @param cls closure with our `struct ExchangeKycRequest *`
* @param keys keys of the exchange context
+ * @param exchange representation of the exchange
*/
static void
kyc_with_exchange (void *cls,
- struct TALER_EXCHANGE_Keys *keys)
+ struct TALER_EXCHANGE_Keys *keys,
+ struct TMH_Exchange *exchange)
{
struct ExchangeKycRequest *ekr = cls;
struct KycContext *kc = ekr->kc;
struct TALER_PaytoHashP h_payto;
+ (void) exchange;
ekr->fo = NULL;
if (NULL == keys)
{
@@ -738,6 +741,7 @@ kyc_status_cb (void *cls,
ekr->last_check = last_check;
ekr->kc = kc;
ekr->fo = TMH_EXCHANGES_keys4exchange (exchange_url,
+ false,
&kyc_with_exchange,
ekr);
}
diff --git a/src/backend/taler-merchant-httpd_private-get-orders-ID.c b/src/backend/taler-merchant-httpd_private-get-orders-ID.c
index 710194f8..f732dc84 100644
--- a/src/backend/taler-merchant-httpd_private-get-orders-ID.c
+++ b/src/backend/taler-merchant-httpd_private-get-orders-ID.c
@@ -591,14 +591,17 @@ deposit_get_cb (void *cls,
*
* @param cls closure with a `struct GetOrderRequestContext *`
* @param keys keys of the exchange
+ * @param exchange representation of the exchange
*/
static void
exchange_found_cb (void *cls,
- struct TALER_EXCHANGE_Keys *keys)
+ struct TALER_EXCHANGE_Keys *keys,
+ struct TMH_Exchange *exchange)
{
struct TransferQuery *tq = cls;
struct GetOrderRequestContext *gorc = tq->gorc;
+ (void) exchange;
tq->fo = NULL;
if (NULL == keys)
{
@@ -678,6 +681,7 @@ deposit_cb (void *cls,
tq->amount_with_fee = *amount_with_fee;
tq->deposit_fee = *deposit_fee;
tq->fo = TMH_EXCHANGES_keys4exchange (exchange_url,
+ false,
&exchange_found_cb,
tq);
if (NULL == tq->fo)
diff --git a/src/backend/taler-merchant-httpd_private-post-orders.c b/src/backend/taler-merchant-httpd_private-post-orders.c
index 5646af4d..66cf71a5 100644
--- a/src/backend/taler-merchant-httpd_private-post-orders.c
+++ b/src/backend/taler-merchant-httpd_private-post-orders.c
@@ -94,6 +94,40 @@ struct InventoryProduct
/**
+ * Handle for a rekey operation where we (re)request
+ * the /keys from the exchange.
+ */
+struct RekeyExchange
+{
+ /**
+ * Kept in a DLL.
+ */
+ struct RekeyExchange *prev;
+
+ /**
+ * Kept in a DLL.
+ */
+ struct RekeyExchange *next;
+
+ /**
+ * order this is for.
+ */
+ struct OrderContext *oc;
+
+ /**
+ * Base URL of the exchange.
+ */
+ char *url;
+
+ /**
+ * Request for keys.
+ */
+ struct TMH_EXCHANGES_KeysOperation *fo;
+
+};
+
+
+/**
* Information we keep per order we are processing.
*/
struct OrderContext
@@ -105,6 +139,16 @@ struct OrderContext
struct MHD_Connection *connection;
/**
+ * Kept in a DLL while suspended.
+ */
+ struct OrderContext *next;
+
+ /**
+ * Kept in a DLL while suspended.
+ */
+ struct OrderContext *prev;
+
+ /**
* Handler context for the request.
*/
struct TMH_HandlerContext *hc;
@@ -132,6 +176,12 @@ struct OrderContext
json_t *order;
/**
+ * Array of exchanges we find acceptable for this
+ * order.
+ */
+ json_t *exchanges;
+
+ /**
* RFC8905 payment target type to find a matching merchant account
*/
const char *payment_target;
@@ -143,6 +193,18 @@ struct OrderContext
const struct TMH_WireMethod *wm;
/**
+ * Forced requests to /keys to update our exchange
+ * information.
+ */
+ struct RekeyExchange *pending_reload_head;
+
+ /**
+ * Forced requests to /keys to update our exchange
+ * information.
+ */
+ struct RekeyExchange *pending_reload_tail;
+
+ /**
* Claim token for the request.
*/
struct TALER_ClaimTokenP claim_token;
@@ -158,14 +220,19 @@ struct OrderContext
struct InventoryProduct *inventory_products;
/**
- * Length of the @e uuids array.
+ * array of UUIDs used to reserve products from @a inventory_products.
*/
- unsigned int uuids_length;
+ struct GNUNET_Uuid *uuids;
/**
- * array of UUIDs used to reserve products from @a inventory_products.
+ * Shared key to use with @e pos_algorithm.
*/
- struct GNUNET_Uuid *uuids;
+ const char *pos_key;
+
+ /**
+ * Our order ID. Pointer into @e order.
+ */
+ const char *order_id;
/**
* which product (by offset) is out of stock, UINT_MAX if all were in-stock
@@ -173,14 +240,14 @@ struct OrderContext
unsigned int out_of_stock_index;
/**
- * Shared key to use with @e pos_algorithm.
+ * Length of the @e uuids array.
*/
- const char *pos_key;
+ unsigned int uuids_length;
/**
- * Our order ID. Pointer into @e order.
+ * #GNUNET_YES if suspended.
*/
- const char *order_id;
+ enum GNUNET_GenericReturnValue suspended;
/**
* Selected algorithm (by template) when we are to
@@ -212,10 +279,50 @@ struct OrderContext
ORDER_PHASE_FINISHED_MHD_NO
} phase;
+ /**
+ * Set to true once we are sure that we have at
+ * least one good exchange.
+ */
+ bool exchange_good;
+
+ /**
+ * Did we previously force reloading of /keys from
+ * all exchanges? Set to 'true' to prevent us from
+ * doing it again (and again...).
+ */
+ bool forced_reload;
+
};
/**
+ * Kept in a DLL while suspended.
+ */
+static struct OrderContext *oc_head;
+
+/**
+ * Kept in a DLL while suspended.
+ */
+static struct OrderContext *oc_tail;
+
+
+void
+TMH_force_orders_resume ()
+{
+ struct OrderContext *oc;
+
+ while (NULL != (oc = oc_head))
+ {
+ GNUNET_CONTAINER_DLL_remove (oc_head,
+ oc_tail,
+ oc);
+ oc->suspended = GNUNET_SYSERR;
+ MHD_resume_connection (oc->connection);
+ }
+}
+
+
+/**
* Update the phase of @a oc based on @a mret.
*
* @param[in,out] oc order to update phase for
@@ -285,7 +392,22 @@ static void
clean_order (void *cls)
{
struct OrderContext *oc = cls;
+ struct RekeyExchange *rx;
+ while (NULL != (rx = oc->pending_reload_head))
+ {
+ GNUNET_CONTAINER_DLL_remove (oc->pending_reload_head,
+ oc->pending_reload_tail,
+ rx);
+ TMH_EXCHANGES_keys4exchange_cancel (rx->fo);
+ GNUNET_free (rx->url);
+ GNUNET_free (rx);
+ }
+ if (NULL != oc->exchanges)
+ {
+ json_decref (oc->exchanges);
+ oc->exchanges = NULL;
+ }
GNUNET_array_grow (oc->inventory_products,
oc->inventory_products_length,
0);
@@ -734,38 +856,196 @@ check_contract (struct OrderContext *oc)
/**
- * Set list of acceptable exchanges in @a oc.
+ * Compute the set of exchanges that would be acceptable
+ * for this order.
*
- * @param[in,out] oc order context
+ * @param cls our `struct OrderContext`
+ * @param url base URL of an exchange (not used)
+ * @param exchange internal handle for the exchange
*/
static void
-set_exchanges (struct OrderContext *oc)
+get_acceptable (void *cls,
+ const char *url,
+ const struct TMH_Exchange *exchange)
{
- json_t *exchanges;
+ struct OrderContext *oc = cls;
+ unsigned int priority;
+ json_t *j_exchange;
+ enum GNUNET_GenericReturnValue res;
- exchanges = TMH_exchange_get_acceptable (oc->wm);
- if (0 == json_array_size (exchanges))
+ res = TMH_exchange_check_debit (exchange,
+ oc->wm);
+ switch (res)
+ {
+ case GNUNET_OK:
+ priority = 1024; /* high */
+ oc->exchange_good = true;
+ break;
+ case GNUNET_NO:
+ if (oc->forced_reload)
+ priority = 0; /* fresh negative response */
+ else
+ priority = 512; /* stale negative response */
+ break;
+ case GNUNET_SYSERR:
+ if (oc->forced_reload)
+ priority = 256; /* fresh, no accounts yet */
+ else
+ priority = 768; /* stale, no accounts yet */
+ break;
+ }
+ j_exchange = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("url",
+ url),
+ GNUNET_JSON_pack_uint64 ("priority",
+ priority),
+ GNUNET_JSON_pack_data_auto ("master_pub",
+ TMH_EXCHANGES_get_master_pub (exchange)));
+ GNUNET_assert (NULL != j_exchange);
+ GNUNET_assert (0 ==
+ json_array_append_new (oc->exchanges,
+ j_exchange));
+}
+
+
+/**
+ * Function called with the result of a #TMH_EXCHANGES_keys4exchange()
+ * operation.
+ *
+ * @param cls closure with our `struct RekeyExchange *`
+ * @param keys the keys of the exchange
+ * @param exchange representation of the exchange
+ */
+static void
+keys_forced (
+ void *cls,
+ struct TALER_EXCHANGE_Keys *keys,
+ struct TMH_Exchange *exchange)
+{
+ struct RekeyExchange *rx = cls;
+ struct OrderContext *oc = rx->oc;
+
+ rx->fo = NULL;
+ GNUNET_CONTAINER_DLL_remove (oc->pending_reload_head,
+ oc->pending_reload_tail,
+ rx);
+ if (NULL == keys)
{
- json_decref (exchanges);
- /* FIXME: maybe there are exchanges for which we simply
- did not yet get /wire replies. We should *try* to
- run find_exchange() or something to give those
- exchanges a chance to respond => need to suspend! */
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Cannot create order: lacking trusted exchanges for wire method `%s'\n",
- oc->wm->wire_method);
- reply_with_error (
- oc,
- MHD_HTTP_CONFLICT,
- TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_NO_EXCHANGES_FOR_WIRE_METHOD,
- oc->wm->wire_method);
+ "Failed to download %s/keys\n",
+ rx->url);
+ }
+ get_acceptable (oc,
+ rx->url,
+ exchange);
+ GNUNET_free (rx->url);
+ GNUNET_free (rx);
+ if (NULL != oc->pending_reload_head)
return;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Resuming order processing after /keys downloads (now have %u accounts)\n",
+ (unsigned int) json_array_size (oc->exchanges));
+ GNUNET_assert (GNUNET_YES == oc->suspended);
+ GNUNET_CONTAINER_DLL_remove (oc_head,
+ oc_tail,
+ oc);
+ oc->suspended = GNUNET_NO;
+ MHD_resume_connection (oc->connection);
+ TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */
+}
+
+
+/**
+ * Force re-downloading of /keys from @a exchange,
+ * we currently have no acceptable exchange, so we
+ * should try to get one.
+ *
+ * @param cls closure with our `struct OrderContext`
+ * @param url base URL of the exchange
+ * @param exchange internal handle for the exchange
+ */
+static void
+rekey_exchanges (void *cls,
+ const char *url,
+ const struct TMH_Exchange *exchange)
+{
+ struct OrderContext *oc = cls;
+ struct RekeyExchange *rx;
+
+ rx = GNUNET_new (struct RekeyExchange);
+ rx->oc = oc;
+ rx->url = GNUNET_strdup (url);
+ GNUNET_CONTAINER_DLL_insert (oc->pending_reload_head,
+ oc->pending_reload_tail,
+ rx);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Forcing download of %s/keys\n",
+ url);
+ rx->fo = TMH_EXCHANGES_keys4exchange (url,
+ true,
+ &keys_forced,
+ rx);
+}
+
+
+/**
+ * Set list of acceptable exchanges in @a oc.
+ *
+ * @param[in,out] oc order context
+ * @return true to suspend execution
+ */
+static bool
+set_exchanges (struct OrderContext *oc)
+{
+ /* Note: re-building 'oc->exchanges' every time here might be a tad
+ expensive; could likely consider caching the result if it starts to
+ matter. */
+ if (NULL == oc->exchanges)
+ oc->exchanges = json_array ();
+ TMH_exchange_get_trusted (&get_acceptable,
+ oc);
+ if (! oc->exchange_good)
+ {
+ if (! oc->forced_reload)
+ {
+ oc->forced_reload = true;
+ GNUNET_assert (0 ==
+ json_array_clear (oc->exchanges));
+ TMH_exchange_get_trusted (&rekey_exchanges,
+ oc);
+ }
+ if (NULL != oc->pending_reload_head)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Still trying to re-load /keys\n");
+ MHD_suspend_connection (oc->connection);
+ oc->suspended = GNUNET_YES;
+ GNUNET_CONTAINER_DLL_insert (oc_head,
+ oc_tail,
+ oc);
+ return true; /* reloads pending */
+ }
+ if (0 == json_array_size (oc->exchanges))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Cannot create order: lacking trusted exchanges\n");
+ reply_with_error (
+ oc,
+ MHD_HTTP_CONFLICT,
+ TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_NO_EXCHANGES_FOR_WIRE_METHOD,
+ oc->wm->wire_method);
+ return false;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Creating order, but possibly without usable trusted exchanges\n");
}
+ /* 'set' is correct here: reference in oc->exchanges released in cleanup_order() */
GNUNET_assert (0 ==
- json_object_set_new (oc->order,
- "exchanges",
- exchanges));
+ json_object_set (oc->order,
+ "exchanges",
+ oc->exchanges));
oc->phase++;
+ return false;
}
@@ -1603,7 +1883,8 @@ TMH_private_post_orders_with_pos_secrets (
patch_order (oc);
break;
case ORDER_PHASE_SET_EXCHANGES:
- set_exchanges (oc);
+ if (set_exchanges (oc))
+ return MHD_YES;
break;
case ORDER_PHASE_CHECK_CONTRACT:
check_contract (oc);
@@ -1625,9 +1906,10 @@ TMH_private_post_orders_with_pos_secrets (
MHD_RESULT
-TMH_private_post_orders (const struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- struct TMH_HandlerContext *hc)
+TMH_private_post_orders (
+ const struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ struct TMH_HandlerContext *hc)
{
return TMH_private_post_orders_with_pos_secrets (rh,
connection,
diff --git a/src/backend/taler-merchant-httpd_private-post-orders.h b/src/backend/taler-merchant-httpd_private-post-orders.h
index 9d7b1841..cbbb59c0 100644
--- a/src/backend/taler-merchant-httpd_private-post-orders.h
+++ b/src/backend/taler-merchant-httpd_private-post-orders.h
@@ -23,6 +23,14 @@
#include "taler-merchant-httpd.h"
+
+/**
+ * Force resuming all suspended orders on shutdown.
+ */
+void
+TMH_force_orders_resume (void);
+
+
/**
* Generate an order. We add the fields 'exchanges', 'merchant_pub', and
* 'H_wire' to the order gotten from the frontend, as well as possibly other
diff --git a/src/backend/taler-merchant-httpd_private-post-reserves.c b/src/backend/taler-merchant-httpd_private-post-reserves.c
index c6641876..db40b017 100644
--- a/src/backend/taler-merchant-httpd_private-post-reserves.c
+++ b/src/backend/taler-merchant-httpd_private-post-reserves.c
@@ -89,11 +89,6 @@ struct PostReserveContext
struct TMH_EXCHANGES_KeysOperation *fo;
/**
- * Handle for contacting the exchange for /wire.
- */
- struct TMH_EXCHANGES_WireOperation *wo;
-
- /**
* Master public key of the exchange matching
* @e exchange_url.
*/
@@ -127,6 +122,11 @@ struct PostReserveContext
* without a response due to shutdown.
*/
enum GNUNET_GenericReturnValue suspended;
+
+ /**
+ * True if we already force reloaded /keys.
+ */
+ bool force_reload;
};
@@ -168,11 +168,6 @@ TMH_force_rc_resume ()
TMH_EXCHANGES_keys4exchange_cancel (rc->fo);
rc->fo = NULL;
}
- if (NULL != rc->wo)
- {
- TMH_EXCHANGES_wire4exchange_cancel (rc->wo);
- rc->wo = NULL;
- }
}
}
@@ -216,49 +211,17 @@ resume_request (struct PostReserveContext *rc)
/**
- * Function called once we go the /wire response from the exchange.
- *
- * @param cls a `struct PostReserveContext *`
- * @param wire exchange wire details
- */
-static void
-wire_cb (void *cls,
- const struct TMH_ExchangeWireDetails *wire)
-{
- struct PostReserveContext *rc = cls;
-
- rc->wo = NULL;
- rc->accounts = TMH_exchange_accounts_by_method (
- &rc->master_pub,
- rc->wire_method);
- if (NULL == rc->accounts)
- {
- rc->ec = TALER_EC_GENERIC_DB_FETCH_FAILED;
- rc->http_status = MHD_HTTP_CONFLICT;
- resume_request (rc);
- return;
- }
- if (0 == json_array_size (rc->accounts))
- {
- rc->ec = TALER_EC_MERCHANT_PRIVATE_POST_RESERVES_UNSUPPORTED_WIRE_METHOD;
- rc->http_status = MHD_HTTP_CONFLICT;
- resume_request (rc);
- return;
- }
- resume_request (rc);
-}
-
-
-/**
* Function called with the result of a #TMH_EXCHANGES_keys4exchange()
* operation.
*
* @param cls closure with our `struct PostReserveContext *`
* @param keys exchange keys
+ * @param exchange representation of the exchange
*/
static void
handle_exchange (void *cls,
- struct TALER_EXCHANGE_Keys *keys)
+ struct TALER_EXCHANGE_Keys *keys,
+ struct TMH_Exchange *exchange)
{
struct PostReserveContext *rc = cls;
@@ -273,6 +236,18 @@ handle_exchange (void *cls,
}
if (! keys->rewards_allowed)
{
+ if (! rc->force_reload)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Forcing %s/keys reload (rewards not allowed)\n",
+ rc->exchange_url);
+ rc->force_reload = true;
+ rc->fo = TMH_EXCHANGES_keys4exchange (rc->exchange_url,
+ true,
+ &handle_exchange,
+ rc);
+ return;
+ }
rc->ec = TALER_EC_MERCHANT_PRIVATE_POST_RESERVES_REWARDS_NOT_ALLOWED;
rc->http_status = MHD_HTTP_CONFLICT;
resume_request (rc);
@@ -281,9 +256,33 @@ handle_exchange (void *cls,
rc->master_pub = keys->master_pub;
rc->reserve_expiration
= GNUNET_TIME_relative_to_timestamp (keys->reserve_closing_delay);
- rc->wo = TMH_EXCHANGES_wire4exchange (rc->exchange_url,
- &wire_cb,
- rc);
+ rc->accounts = TMH_exchange_accounts_by_method (
+ &rc->master_pub,
+ rc->wire_method);
+ if ( (NULL == rc->accounts) ||
+ (0 == json_array_size (rc->accounts)) )
+ {
+ if (! rc->force_reload)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Forcing %s/keys reload (no accounts)\n",
+ rc->exchange_url);
+ rc->force_reload = true;
+ rc->fo = TMH_EXCHANGES_keys4exchange (rc->exchange_url,
+ true,
+ &handle_exchange,
+ rc);
+ return;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Wire method `%s' not supported\n",
+ rc->wire_method);
+ rc->ec = TALER_EC_MERCHANT_PRIVATE_POST_RESERVES_UNSUPPORTED_WIRE_METHOD;
+ rc->http_status = MHD_HTTP_CONFLICT;
+ resume_request (rc);
+ return;
+ }
+ resume_request (rc);
}
@@ -326,6 +325,7 @@ TMH_private_post_reserves (const struct TMH_RequestHandler *rh,
: MHD_NO;
}
rc->fo = TMH_EXCHANGES_keys4exchange (rc->exchange_url,
+ false,
&handle_exchange,
rc);
rc->suspended = GNUNET_YES;
diff --git a/src/lib/merchant_api_post_order_pay.c b/src/lib/merchant_api_post_order_pay.c
index e48b7cd3..24c1cf61 100644
--- a/src/lib/merchant_api_post_order_pay.c
+++ b/src/lib/merchant_api_post_order_pay.c
@@ -329,6 +329,10 @@ parse_conflict (struct TALER_MERCHANT_OrderPayHandle *oph,
break;
default:
GNUNET_break_op (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected error code %d: %s\n",
+ ec,
+ TALER_ErrorCode_get_hint (ec));
return GNUNET_SYSERR;
}
diff --git a/src/testing/test_merchant_api_home/taler/exchange-secmod-cs/keys/coin_eur_1/1688579204 b/src/testing/test_merchant_api_home/taler/exchange-secmod-cs/keys/coin_eur_1/1688579204
deleted file mode 100644
index 413ac682..00000000
--- a/src/testing/test_merchant_api_home/taler/exchange-secmod-cs/keys/coin_eur_1/1688579204
+++ /dev/null
Binary files differ
diff --git a/src/testing/test_merchant_api_home/taler/exchange-secmod-cs/keys/coin_eur_5/1688579204 b/src/testing/test_merchant_api_home/taler/exchange-secmod-cs/keys/coin_eur_5/1688579204
deleted file mode 100644
index 56735a35..00000000
--- a/src/testing/test_merchant_api_home/taler/exchange-secmod-cs/keys/coin_eur_5/1688579204
+++ /dev/null
@@ -1,2 +0,0 @@
- 0c©ôbL
-n#vìïœãpŒap¡¦(Kó°ÕáC \ No newline at end of file
diff --git a/src/testing/test_merchant_api_home/taler/exchange-secmod-cs/keys/coin_eur_ct_1/1688579204 b/src/testing/test_merchant_api_home/taler/exchange-secmod-cs/keys/coin_eur_ct_1/1688579204
deleted file mode 100644
index 9378dd7b..00000000
--- a/src/testing/test_merchant_api_home/taler/exchange-secmod-cs/keys/coin_eur_ct_1/1688579204
+++ /dev/null
@@ -1 +0,0 @@
-º|žÑ’Óå‹xjÄÕfóß4­½¤3ØÞÜ€òƒ) \ No newline at end of file
diff --git a/src/testing/test_merchant_api_home/taler/exchange-secmod-cs/keys/coin_eur_ct_10/1688579204 b/src/testing/test_merchant_api_home/taler/exchange-secmod-cs/keys/coin_eur_ct_10/1688579204
deleted file mode 100644
index 5388599c..00000000
--- a/src/testing/test_merchant_api_home/taler/exchange-secmod-cs/keys/coin_eur_ct_10/1688579204
+++ /dev/null
@@ -1 +0,0 @@
-P^ÛÃ(‘0B"ijL´u1ðÌɯä?@dÄÿ±  \ No newline at end of file