gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-merchant] branch master updated: -cache /keys in merchant DB


From: gnunet
Subject: [taler-merchant] branch master updated: -cache /keys in merchant DB
Date: Tue, 11 Jul 2023 09:09:31 +0200

This is an automated email from the git hooks/post-receive script.

grothoff pushed a commit to branch master
in repository merchant.

The following commit(s) were added to refs/heads/master by this push:
     new dc90a82f -cache /keys in merchant DB
dc90a82f is described below

commit dc90a82f72469521ba6d50932c2fd52761e1040e
Author: Christian Grothoff <christian@grothoff.org>
AuthorDate: Tue Jul 11 09:09:27 2023 +0200

    -cache /keys in merchant DB
---
 src/backend/taler-merchant-httpd.c           |  31 +-
 src/backend/taler-merchant-httpd_exchanges.c | 793 +++++++++++++++------------
 src/backenddb/merchant-0001.sql              |   6 +-
 src/backenddb/pg_insert_exchange_keys.c      |   4 +-
 src/backenddb/pg_select_exchange_keys.c      |   2 +-
 5 files changed, 468 insertions(+), 368 deletions(-)

diff --git a/src/backend/taler-merchant-httpd.c 
b/src/backend/taler-merchant-httpd.c
index 1697268b..be0140e1 100644
--- a/src/backend/taler-merchant-httpd.c
+++ b/src/backend/taler-merchant-httpd.c
@@ -325,12 +325,12 @@ do_shutdown (void *cls)
     TMH_db->event_listen_cancel (instance_eh);
     instance_eh = NULL;
   }
+  TMH_EXCHANGES_done ();
   if (NULL != TMH_db)
   {
     TALER_MERCHANTDB_plugin_unload (TMH_db);
     TMH_db = NULL;
   }
-  TMH_EXCHANGES_done ();
   if (NULL != TMH_by_id_map)
   {
     GNUNET_CONTAINER_multihashmap_iterate (TMH_by_id_map,
@@ -1865,8 +1865,6 @@ load_instances (void *cls,
   const char *id = extra;
 
   (void) cls;
-  (void) extra;
-  (void) extra_len;
   if ( (NULL != extra) &&
        ( (0 == extra_len) ||
          ('\0' != id[extra_len - 1]) ) )
@@ -2045,19 +2043,6 @@ run (void *cls,
   }
   /* /static/ is currently not used */
   /* (void) TMH_statics_init (); */
-  elen = TMH_EXCHANGES_init (config);
-  if (GNUNET_SYSERR == elen)
-  {
-    GNUNET_SCHEDULER_shutdown ();
-    return;
-  }
-  if (0 == elen)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "Fatal: no trusted exchanges configured. Exiting.\n");
-    GNUNET_SCHEDULER_shutdown ();
-    return;
-  }
   if (NULL ==
       (TMH_by_id_map = GNUNET_CONTAINER_multihashmap_create (4,
                                                              GNUNET_YES)))
@@ -2079,6 +2064,20 @@ run (void *cls,
     GNUNET_SCHEDULER_shutdown ();
     return;
   }
+  elen = TMH_EXCHANGES_init (config);
+  if (GNUNET_SYSERR == elen)
+  {
+    GNUNET_SCHEDULER_shutdown ();
+    return;
+  }
+  if (0 == elen)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Fatal: no trusted exchanges configured. Exiting.\n");
+    GNUNET_SCHEDULER_shutdown ();
+    return;
+  }
+
   {
     struct GNUNET_DB_EventHeaderP es = {
       .size = ntohs (sizeof (es)),
diff --git a/src/backend/taler-merchant-httpd_exchanges.c 
b/src/backend/taler-merchant-httpd_exchanges.c
index d5737369..5fca3c34 100644
--- a/src/backend/taler-merchant-httpd_exchanges.c
+++ b/src/backend/taler-merchant-httpd_exchanges.c
@@ -21,6 +21,7 @@
  */
 #include "platform.h"
 #include <taler/taler_json_lib.h>
+#include <taler/taler_dbevents.h>
 #include "taler-merchant-httpd_exchanges.h"
 #include "taler-merchant-httpd.h"
 #include <regex.h>
@@ -403,6 +404,12 @@ static struct TMH_Exchange *exchange_head;
  */
 static struct TMH_Exchange *exchange_tail;
 
+/**
+ * Our event handler listening for /keys downloads
+ * being put into the database.
+ */
+static struct GNUNET_DB_EventHandler *keys_eh;
+
 /**
  * How many exchanges do we trust (for our configured
  * currency) as per our configuration? Used for a
@@ -477,6 +484,7 @@ static struct TMH_Exchange *
 lookup_exchange (const char *exchange_url)
 {
   struct TMH_Exchange *exchange;
+  enum GNUNET_DB_QueryStatus qs;
 
   for (exchange = exchange_head;
        NULL != exchange;
@@ -489,6 +497,10 @@ lookup_exchange (const char *exchange_url)
   GNUNET_CONTAINER_DLL_insert (exchange_head,
                                exchange_tail,
                                exchange);
+  qs = TMH_db->select_exchange_keys (TMH_db->cls,
+                                     exchange->url,
+                                     &exchange->keys);
+  GNUNET_break (qs >= 0);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "The exchange `%s' is new\n",
               exchange_url);
@@ -572,50 +584,6 @@ keys_mgmt_cb (
   struct TALER_EXCHANGE_Keys *keys);
 
 
-/**
- * Retry getting keys from the given exchange in the closure.
- *
- * @param cls the `struct TMH_Exchange *`
- */
-static void
-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)
-    return; /* already trying */
-  if ( (NULL != exchange->keys) &&
-       (GNUNET_TIME_absolute_is_future (
-          exchange->keys->key_data_expiration.abs_time)) )
-    return; /* still have a valid reply */
-  /* increment exponential-backoff */
-  exchange->retry_delay
-    = RETRY_BACKOFF (exchange->retry_delay);
-  /* No download until both backoff and #FORCED_RELOAD_DELAY
-     are satisfied again */
-  exchange->first_retry
-    = GNUNET_TIME_relative_to_absolute (
-        GNUNET_TIME_relative_max (
-          exchange->retry_delay,
-          FORCED_RELOAD_DELAY));
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Fetching /keys from exchange %s in retry_exchange()\n",
-              exchange->url);
-  exchange->conn
-    = TALER_EXCHANGE_get_keys (
-        TMH_curl_ctx,
-        exchange->url,
-        exchange->keys,
-        &keys_mgmt_cb,
-        exchange);
-  /* Note: while the API spec says 'returns NULL on error', the implementation
-     actually never returns NULL. */
-  GNUNET_break (NULL != exchange->conn);
-}
-
-
 /**
  * Check if we have any remaining pending requests for the
  * given @a exchange, and if we have the required data, call
@@ -713,99 +681,17 @@ process_find_operations (struct TMH_Exchange *exchange)
 
 
 /**
- * Task to asynchronously return keys operation result to caller.
+ * 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.
  *
- * @param cls a `struct TMH_EXCHANGES_KeysOperation`
+ * Must only be called if 'exchange->keys' is non-NULL.
+ *
+ * @param cls a `struct TMH_Exchange` to check
  */
 static void
-return_keys (void *cls)
-{
-  struct TMH_EXCHANGES_KeysOperation *fo = cls;
-  struct TMH_Exchange *exchange = fo->my_exchange;
-
-  fo->at = NULL;
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-              "Returning key data for %s instantly\n",
-              exchange->url);
-  process_find_operations (exchange);
-}
-
-
-struct TMH_EXCHANGES_KeysOperation *
-TMH_EXCHANGES_keys4exchange (
-  const char *chosen_exchange,
-  TMH_EXCHANGES_Find2Continuation fc,
-  void *fc_cls)
-{
-  struct TMH_Exchange *exchange;
-  struct TMH_EXCHANGES_KeysOperation *fo;
-
-  if (NULL == TMH_curl_ctx)
-  {
-    GNUNET_break (0);
-    return NULL;
-  }
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-              "Trying to find chosen exchange `%s'\n",
-              chosen_exchange);
-  exchange = lookup_exchange (chosen_exchange);
-  fo = GNUNET_new (struct TMH_EXCHANGES_KeysOperation);
-  fo->fc = fc;
-  fo->fc_cls = fc_cls;
-  fo->my_exchange = exchange;
-  GNUNET_CONTAINER_DLL_insert (exchange->keys_head,
-                               exchange->keys_tail,
-                               fo);
-  if ( (NULL != exchange->keys) &&
-       (GNUNET_TIME_absolute_is_future (
-          exchange->keys->key_data_expiration.abs_time)) )
-  {
-    /* We have a valid reply, immediately return result */
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                "The exchange `%s' is ready\n",
-                exchange->url);
-    GNUNET_assert (NULL == fo->at);
-    fo->at = GNUNET_SCHEDULER_add_now (&return_keys,
-                                       fo);
-    return fo;
-  }
-  if ( (NULL == exchange->retry_task) &&
-       (NULL == exchange->conn) )
-  {
-    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 fo;
-  }
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-              "Next /keys request scheduled for %s\n",
-              GNUNET_TIME_absolute2s (
-                exchange->first_retry));
-  /* No activity to launch, we are already doing so. */
-  return fo;
-}
-
-
-void
-TMH_EXCHANGES_keys4exchange_cancel (
-  struct TMH_EXCHANGES_KeysOperation *fo)
-{
-  struct TMH_Exchange *exchange = fo->my_exchange;
-
-  if (NULL != fo->at)
-  {
-    GNUNET_SCHEDULER_cancel (fo->at);
-    fo->at = NULL;
-  }
-  GNUNET_CONTAINER_DLL_remove (exchange->keys_head,
-                               exchange->keys_tail,
-                               fo);
-  GNUNET_free (fo);
-}
+wire_task_cb (void *cls);
 
 
 /**
@@ -1006,10 +892,11 @@ add_restriction (json_t *restrictions,
  * @return #TALER_EC_NONE on success
  */
 static enum TALER_ErrorCode
-process_wire_accounts (struct TMH_Exchange *exchange,
-                       const struct TALER_MasterPublicKeyP *master_pub,
-                       unsigned int accounts_len,
-                       const struct TALER_EXCHANGE_WireAccount *accounts)
+process_wire_accounts (
+  struct TMH_Exchange *exchange,
+  const struct TALER_MasterPublicKeyP *master_pub,
+  unsigned int accounts_len,
+  const struct TALER_EXCHANGE_WireAccount accounts[static accounts_len])
 {
   for (unsigned int r = 0; r<MAX_RETRIES; r++)
   {
@@ -1106,61 +993,6 @@ outer:;
 }
 
 
-/**
- * Obtain applicable fees for @a exchange and @a wire_method.
- *
- * @param exchange the exchange to query
- * @param now current time
- * @param wire_method the wire method we want the fees for
- * @return NULL if we do not have fees for this method yet
- */
-static const struct FeesByWireMethod *
-get_wire_fees (struct TMH_Exchange *exchange,
-               struct GNUNET_TIME_Timestamp now,
-               const char *wire_method)
-{
-  for (struct FeesByWireMethod *fbw = exchange->wire_fees_head;
-       NULL != fbw;
-       fbw = fbw->next)
-  {
-    if (0 == strcasecmp (fbw->wire_method,
-                         wire_method) )
-    {
-      struct TALER_EXCHANGE_WireAggregateFees *af;
-
-      /* Advance through list up to current time */
-      while ( (NULL != (af = fbw->af)) &&
-              (GNUNET_TIME_timestamp_cmp (now,
-                                          >=,
-                                          af->end_date)) )
-      {
-        fbw->af = af->next;
-        GNUNET_free (af);
-      }
-      return fbw;
-    }
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                "Exchange supports `%s' as a wire method (but we do not use 
that one)\n",
-                fbw->wire_method);
-  }
-  return NULL;
-}
-
-
-/**
- * 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);
-
-
 /**
  * Callbacks of this type are used to serve the result of submitting a
  * wire format inquiry request to a exchange.
@@ -1254,57 +1086,260 @@ handle_wire_data (void *cls,
 }
 
 
-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.
+ * Retry getting keys from the given exchange in the closure.
  *
- * @param[in] exchange entry to free
+ * @param cls the `struct TMH_Exchange *`
  */
 static void
-free_exchange_entry (struct TMH_Exchange *exchange)
+retry_exchange (void *cls)
 {
-  struct FeesByWireMethod *f;
+  struct TMH_Exchange *exchange = cls;
 
-  GNUNET_CONTAINER_DLL_remove (exchange_head,
-                               exchange_tail,
-                               exchange);
-  purge_exchange_accounts (exchange);
-  while (NULL != (f = exchange->wire_fees_head))
+  /* might be a scheduled reload and not our first attempt */
+  exchange->retry_task = NULL;
+  if (NULL != exchange->conn)
   {
-    struct TALER_EXCHANGE_WireAggregateFees *af;
-
-    GNUNET_CONTAINER_DLL_remove (exchange->wire_fees_head,
-                                 exchange->wire_fees_tail,
-                                 f);
-    while (NULL != (af = f->af))
-    {
-      f->af = af->next;
-      GNUNET_free (af);
-    }
-    GNUNET_free (f->wire_method);
-    GNUNET_free (f);
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "Already trying /keys\n");
+    return; /* already trying */
   }
-  if (NULL != exchange->wire_request)
-  {
+  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 */
+  exchange->retry_delay
+    = RETRY_BACKOFF (exchange->retry_delay);
+  /* No download until both backoff and #FORCED_RELOAD_DELAY
+     are satisfied again */
+  exchange->first_retry
+    = GNUNET_TIME_relative_to_absolute (
+        GNUNET_TIME_relative_max (
+          exchange->retry_delay,
+          FORCED_RELOAD_DELAY));
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "Fetching /keys from exchange %s in retry_exchange()\n",
+              exchange->url);
+  exchange->conn
+    = TALER_EXCHANGE_get_keys (
+        TMH_curl_ctx,
+        exchange->url,
+        exchange->keys,
+        &keys_mgmt_cb,
+        exchange);
+  /* Note: while the API spec says 'returns NULL on error', the implementation
+     actually never returns NULL. */
+  GNUNET_break (NULL != exchange->conn);
+}
+
+
+/**
+ * Task to asynchronously return keys operation result to caller.
+ *
+ * @param cls a `struct TMH_EXCHANGES_KeysOperation`
+ */
+static void
+return_keys (void *cls)
+{
+  struct TMH_EXCHANGES_KeysOperation *fo = cls;
+  struct TMH_Exchange *exchange = fo->my_exchange;
+
+  fo->at = NULL;
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "Returning key data for %s instantly\n",
+              exchange->url);
+  process_find_operations (exchange);
+}
+
+
+struct TMH_EXCHANGES_KeysOperation *
+TMH_EXCHANGES_keys4exchange (
+  const char *chosen_exchange,
+  TMH_EXCHANGES_Find2Continuation fc,
+  void *fc_cls)
+{
+  struct TMH_Exchange *exchange;
+  struct TMH_EXCHANGES_KeysOperation *fo;
+
+  if (NULL == TMH_curl_ctx)
+  {
+    GNUNET_break (0);
+    return NULL;
+  }
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "Trying to find chosen exchange `%s'\n",
+              chosen_exchange);
+  exchange = lookup_exchange (chosen_exchange);
+  fo = GNUNET_new (struct TMH_EXCHANGES_KeysOperation);
+  fo->fc = fc;
+  fo->fc_cls = fc_cls;
+  fo->my_exchange = exchange;
+  GNUNET_CONTAINER_DLL_insert (exchange->keys_head,
+                               exchange->keys_tail,
+                               fo);
+  if ( (NULL != exchange->keys) &&
+       (GNUNET_TIME_absolute_is_future (
+          exchange->keys->key_data_expiration.abs_time)) )
+  {
+    /* We have a valid reply, immediately return result */
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "The exchange `%s' is ready\n",
+                exchange->url);
+    GNUNET_assert (NULL == fo->at);
+    fo->at = GNUNET_SCHEDULER_add_now (&return_keys,
+                                       fo);
+    return fo;
+  }
+  if ( (NULL == exchange->retry_task) &&
+       (NULL == exchange->conn) )
+  {
+    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 fo;
+  }
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "Next /keys request scheduled for %s\n",
+              GNUNET_TIME_absolute2s (
+                exchange->first_retry));
+  /* No activity to launch, we are already doing so. */
+  return fo;
+}
+
+
+void
+TMH_EXCHANGES_keys4exchange_cancel (
+  struct TMH_EXCHANGES_KeysOperation *fo)
+{
+  struct TMH_Exchange *exchange = fo->my_exchange;
+
+  if (NULL != fo->at)
+  {
+    GNUNET_SCHEDULER_cancel (fo->at);
+    fo->at = NULL;
+  }
+  GNUNET_CONTAINER_DLL_remove (exchange->keys_head,
+                               exchange->keys_tail,
+                               fo);
+  GNUNET_free (fo);
+}
+
+
+/**
+ * Obtain applicable fees for @a exchange and @a wire_method.
+ *
+ * @param exchange the exchange to query
+ * @param now current time
+ * @param wire_method the wire method we want the fees for
+ * @return NULL if we do not have fees for this method yet
+ */
+static const struct FeesByWireMethod *
+get_wire_fees (struct TMH_Exchange *exchange,
+               struct GNUNET_TIME_Timestamp now,
+               const char *wire_method)
+{
+  for (struct FeesByWireMethod *fbw = exchange->wire_fees_head;
+       NULL != fbw;
+       fbw = fbw->next)
+  {
+    if (0 == strcasecmp (fbw->wire_method,
+                         wire_method) )
+    {
+      struct TALER_EXCHANGE_WireAggregateFees *af;
+
+      /* Advance through list up to current time */
+      while ( (NULL != (af = fbw->af)) &&
+              (GNUNET_TIME_timestamp_cmp (now,
+                                          >=,
+                                          af->end_date)) )
+      {
+        fbw->af = af->next;
+        GNUNET_free (af);
+      }
+      return fbw;
+    }
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "Exchange supports `%s' as a wire method (but we do not use 
that one)\n",
+                fbw->wire_method);
+  }
+  return NULL;
+}
+
+
+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.
+ *
+ * @param[in] exchange entry to free
+ */
+static void
+free_exchange_entry (struct TMH_Exchange *exchange)
+{
+  struct FeesByWireMethod *f;
+
+  GNUNET_CONTAINER_DLL_remove (exchange_head,
+                               exchange_tail,
+                               exchange);
+  purge_exchange_accounts (exchange);
+  while (NULL != (f = exchange->wire_fees_head))
+  {
+    struct TALER_EXCHANGE_WireAggregateFees *af;
+
+    GNUNET_CONTAINER_DLL_remove (exchange->wire_fees_head,
+                                 exchange->wire_fees_tail,
+                                 f);
+    while (NULL != (af = f->af))
+    {
+      f->af = af->next;
+      GNUNET_free (af);
+    }
+    GNUNET_free (f->wire_method);
+    GNUNET_free (f);
+  }
+  if (NULL != exchange->wire_request)
+  {
     TALER_EXCHANGE_wire_cancel (exchange->wire_request);
     exchange->wire_request = NULL;
   }
@@ -1339,11 +1374,9 @@ free_exchange_entry (struct TMH_Exchange *exchange)
  * about our failure, abort pending operations and retry later.
  *
  * @param exchange exchange that failed
- * @param hr details about the HTTP reply
  */
 static void
-fail_and_retry (struct TMH_Exchange *exchange,
-                const struct TALER_EXCHANGE_HttpResponse *hr)
+fail_and_retry (struct TMH_Exchange *exchange)
 {
   struct TMH_EXCHANGES_KeysOperation *keys;
   struct TMH_EXCHANGES_WireOperation *w;
@@ -1370,18 +1403,10 @@ fail_and_retry (struct TMH_Exchange *exchange,
            NULL);
     TMH_EXCHANGES_wire4exchange_cancel (w);
   }
-  if (TALER_EC_GENERIC_CONFIGURATION_INVALID == hr->ec)
-  {
-    /* This can NEVER work, so don't retry */
-    free_exchange_entry (exchange);
-    return;
-  }
   exchange->retry_delay = RETRY_BACKOFF (exchange->retry_delay);
   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-              "Failed to fetch /keys from `%s': %d/%u, retrying in %s\n",
+              "Failed to fetch /keys from `%s'; retrying in %s\n",
               exchange->url,
-              (int) hr->ec,
-              hr->http_status,
               GNUNET_STRINGS_relative_time_to_string (exchange->retry_delay,
                                                       true));
   if (NULL != exchange->retry_task)
@@ -1402,101 +1427,29 @@ keys_mgmt_cb (void *cls,
               struct TALER_EXCHANGE_Keys *keys)
 {
   struct TMH_Exchange *exchange = cls;
-  struct GNUNET_TIME_Relative delay;
+  enum GNUNET_DB_QueryStatus qs;
 
   exchange->conn = NULL;
   if (MHD_HTTP_OK != kr->hr.http_status)
   {
-    fail_and_retry (exchange,
-                    &kr->hr);
+    fail_and_retry (exchange);
     return;
   }
-  TALER_EXCHANGE_keys_decref (exchange->keys);
-  exchange->keys = keys;
-  if ( (exchange->trusted) &&
-       (0 != GNUNET_memcmp (&exchange->master_pub,
-                            &keys->master_pub)) )
-  {
-    /* master pub differs => do not trust the exchange (without auditor) */
-    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                "Master public key of exchange `%s' differs from our 
configuration. Not trusting exchange.\n",
-                exchange->url);
-    exchange->trusted = false;
-  }
-  if (! exchange->trusted)
-  {
-    exchange->master_pub = keys->master_pub;
-    for (struct TMH_Exchange *e = exchange_head;
-         NULL != e;
-         e = e->next)
-    {
-      if (e == exchange)
-        continue;
-      if (! e->trusted)
-        continue;
-      if (0 ==
-          GNUNET_memcmp (&e->master_pub,
-                         &exchange->master_pub))
-        exchange->trusted = true; /* same exchange, different URL => trust 
applies */
-    }
-  }
-
-  /* store exchange online signing keys in our DB */
-  for (unsigned int i = 0; i<keys->num_sign_keys; i++)
+  qs = TMH_db->insert_exchange_keys (TMH_db->cls,
+                                     keys);
+  TALER_EXCHANGE_keys_decref (keys);
+  GNUNET_break (qs > 0);
+  if (qs > 0)
   {
-    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,
-                      &kr->hr);
-      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);
+    struct GNUNET_DB_EventHeaderP es = {
+      .size = ntohs (sizeof (es)),
+      .type = ntohs (TALER_DBEVENT_MERCHANT_EXCHANGE_KEYS)
+    };
 
-  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);
+    TMH_db->event_notify (TMH_db->cls,
+                          &es,
+                          exchange->url,
+                          strlen (exchange->url) + 1);
   }
 }
 
@@ -1777,8 +1730,8 @@ accept_exchanges (void *cls,
                                "EXCHANGE_BASE_URL");
     return;
   }
-  exchange = GNUNET_new (struct TMH_Exchange);
-  exchange->url = url;
+  exchange = lookup_exchange (url);
+  GNUNET_free (url);
   if (GNUNET_OK ==
       GNUNET_CONFIGURATION_get_value_string (cfg,
                                              section,
@@ -1786,10 +1739,10 @@ accept_exchanges (void *cls,
                                              &mks))
   {
     if (GNUNET_OK ==
-        GNUNET_CRYPTO_eddsa_public_key_from_string (mks,
-                                                    strlen (mks),
-                                                    &exchange->master_pub.
-                                                    eddsa_pub))
+        GNUNET_CRYPTO_eddsa_public_key_from_string (
+          mks,
+          strlen (mks),
+          &exchange->master_pub.eddsa_pub))
     {
       exchange->trusted = true;
       trusted_exchange_count++;
@@ -1809,12 +1762,143 @@ accept_exchanges (void *cls,
                 "MASTER_KEY missing in section '%s', not trusting exchange\n",
                 section);
   }
-  GNUNET_CONTAINER_DLL_insert (exchange_head,
-                               exchange_tail,
-                               exchange);
   GNUNET_assert (NULL == exchange->retry_task);
-  exchange->retry_task = GNUNET_SCHEDULER_add_now (&retry_exchange,
-                                                   exchange);
+  exchange->retry_task
+    = GNUNET_SCHEDULER_add_now (&retry_exchange,
+                                exchange);
+}
+
+
+/**
+ * Trigger (re)loading of keys from DB.
+ *
+ * @param cls NULL
+ * @param extra base URL of the exchange that changed
+ * @param extra_len number of bytes in @a extra
+ */
+static void
+update_exchange_keys (void *cls,
+                      const void *extra,
+                      size_t extra_len)
+{
+  enum GNUNET_DB_QueryStatus qs;
+  const char *url = extra;
+  struct TMH_Exchange *exchange;
+  struct TALER_EXCHANGE_Keys *keys;
+  struct GNUNET_TIME_Relative delay;
+
+  if ( (NULL == extra) ||
+       (0 == extra_len) )
+  {
+    GNUNET_break (0);
+    return;
+  }
+  if ('\0' != url[extra_len - 1])
+  {
+    GNUNET_break (0);
+    return;
+  }
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "Received keys change notification: reload `%s'\n",
+              url);
+  exchange = lookup_exchange (url);
+  qs = TMH_db->select_exchange_keys (TMH_db->cls,
+                                     url,
+                                     &keys);
+  if (qs <= 0)
+  {
+    GNUNET_break (0);
+    return;
+  }
+  TALER_EXCHANGE_keys_decref (exchange->keys);
+  exchange->keys = keys;
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "Reloaded /keys of %s from database\n",
+              url);
+  if ( (exchange->trusted) &&
+       (0 != GNUNET_memcmp (&exchange->master_pub,
+                            &keys->master_pub)) )
+  {
+    /* master pub differs => do not trust the exchange (without auditor) */
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "Master public key of exchange `%s' differs from our 
configuration. Not trusting exchange.\n",
+                exchange->url);
+    exchange->trusted = false;
+  }
+  if (! exchange->trusted)
+  {
+    exchange->master_pub = keys->master_pub;
+    for (struct TMH_Exchange *e = exchange_head;
+         NULL != e;
+         e = e->next)
+    {
+      if (e == exchange)
+        continue;
+      if (! e->trusted)
+        continue;
+      if (0 ==
+          GNUNET_memcmp (&e->master_pub,
+                         &exchange->master_pub))
+        exchange->trusted = true; /* same exchange, different URL => trust 
applies */
+    }
+  }
+
+  /* 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);
+  }
 }
 
 
@@ -1822,6 +1906,18 @@ enum GNUNET_GenericReturnValue
 TMH_EXCHANGES_init (const struct GNUNET_CONFIGURATION_Handle *cfg)
 {
   /* get exchanges from the merchant configuration and try to connect to them 
*/
+  {
+    struct GNUNET_DB_EventHeaderP es = {
+      .size = ntohs (sizeof (es)),
+      .type = ntohs (TALER_DBEVENT_MERCHANT_EXCHANGE_KEYS)
+    };
+
+    keys_eh = TMH_db->event_listen (TMH_db->cls,
+                                    &es,
+                                    GNUNET_TIME_UNIT_FOREVER_REL,
+                                    &update_exchange_keys,
+                                    NULL);
+  }
   GNUNET_CONFIGURATION_iterate_sections (cfg,
                                          &accept_exchanges,
                                          (void *) cfg);
@@ -1833,6 +1929,11 @@ TMH_EXCHANGES_init (const struct 
GNUNET_CONFIGURATION_Handle *cfg)
 void
 TMH_EXCHANGES_done ()
 {
+  if (NULL != keys_eh)
+  {
+    TMH_db->event_listen_cancel (keys_eh);
+    keys_eh = NULL;
+  }
   while (NULL != exchange_head)
     free_exchange_entry (exchange_head);
 }
diff --git a/src/backenddb/merchant-0001.sql b/src/backenddb/merchant-0001.sql
index 313d8ee9..7bd8d737 100644
--- a/src/backenddb/merchant-0001.sql
+++ b/src/backenddb/merchant-0001.sql
@@ -763,14 +763,14 @@ COMMENT ON COLUMN 
merchant_exchange_accounts.credit_restrictions
 
 CREATE TABLE IF NOT EXISTS merchant_exchange_keys
   (mek_serial BIGINT GENERATED BY DEFAULT AS IDENTITY UNIQUE
-  ,exchange_url VARCHAR PRIMARY KEY CHECK
+  ,exchange_url VARCHAR PRIMARY KEY
   ,keys_json VARCHAR NOT NULL
   ,expiration_time INT8 NOT NULL
   );
 COMMENT ON TABLE merchant_exchange_keys
  IS 'Here we store the cached /keys response from an exchange in JSON format';
-COMMENT ON COLUMN merchant_exchange_keys.master_pub
- IS 'Master public key of the exchange with these keys';
+COMMENT ON COLUMN merchant_exchange_keys.exchange_url
+ IS 'Base URL of the exchange with these keys';
 COMMENT ON COLUMN merchant_exchange_keys.keys_json
  IS 'JSON string of the /keys as generated by libtalerexchange';
 COMMENT ON COLUMN merchant_exchange_keys.expiration_time
diff --git a/src/backenddb/pg_insert_exchange_keys.c 
b/src/backenddb/pg_insert_exchange_keys.c
index a38c8359..e3e9e84a 100644
--- a/src/backenddb/pg_insert_exchange_keys.c
+++ b/src/backenddb/pg_insert_exchange_keys.c
@@ -33,9 +33,9 @@ TMH_PG_insert_exchange_keys (void *cls,
   struct PostgresClosure *pg = cls;
   json_t *jkeys = TALER_EXCHANGE_keys_to_json (keys);
   struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_string (keys->exchange_url),
-    GNUNET_PQ_query_param_timestamp (&keys->last_denom_issue_date),
     TALER_PQ_query_param_json (jkeys),
+    GNUNET_PQ_query_param_timestamp (&keys->last_denom_issue_date),
+    GNUNET_PQ_query_param_string (keys->exchange_url),
     GNUNET_PQ_query_param_end
   };
   enum GNUNET_DB_QueryStatus qs;
diff --git a/src/backenddb/pg_select_exchange_keys.c 
b/src/backenddb/pg_select_exchange_keys.c
index 9b9aaf60..926319d1 100644
--- a/src/backenddb/pg_select_exchange_keys.c
+++ b/src/backenddb/pg_select_exchange_keys.c
@@ -38,7 +38,7 @@ TMH_PG_select_exchange_keys (void *cls,
   };
   json_t *jkeys;
   struct GNUNET_PQ_ResultSpec rs[] = {
-    TALER_PQ_result_spec_json ("keys",
+    TALER_PQ_result_spec_json ("keys_json",
                                &jkeys),
     GNUNET_PQ_result_spec_end
   };

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]