gnunet-svn
[Top][All Lists]
Advanced

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

[taler-exchange] branch master updated: work on new logic to generate /w


From: gnunet
Subject: [taler-exchange] branch master updated: work on new logic to generate /wire response
Date: Wed, 09 Dec 2020 12:31:17 +0100

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

grothoff pushed a commit to branch master
in repository exchange.

The following commit(s) were added to refs/heads/master by this push:
     new fa1914b2 work on new logic to generate /wire response
fa1914b2 is described below

commit fa1914b26781a9409a35fd6f8bfb54aae09fdd79
Author: Christian Grothoff <christian@grothoff.org>
AuthorDate: Wed Dec 9 12:31:10 2020 +0100

    work on new logic to generate /wire response
---
 contrib/gana                                |   2 +-
 src/exchange/taler-exchange-httpd_wire2.c   | 315 ++++++++++++++++++++++++++++
 src/exchangedb/plugin_exchangedb_postgres.c | 259 +++++++++++++++++++++++
 src/include/taler_exchangedb_plugin.h       |  67 ++++++
 4 files changed, 642 insertions(+), 1 deletion(-)

diff --git a/contrib/gana b/contrib/gana
index 9d38f712..3501eb7b 160000
--- a/contrib/gana
+++ b/contrib/gana
@@ -1 +1 @@
-Subproject commit 9d38f712c153727dbb895673d6d9841be57c12c9
+Subproject commit 3501eb7b857d573258c1ab1c42d7e827c36cec9d
diff --git a/src/exchange/taler-exchange-httpd_wire2.c 
b/src/exchange/taler-exchange-httpd_wire2.c
new file mode 100644
index 00000000..b2f8a2a1
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_wire2.c
@@ -0,0 +1,315 @@
+/*
+  This file is part of TALER
+  Copyright (C) 2015-2020 Taler Systems SA
+
+  TALER is free software; you can redistribute it and/or modify it under the
+  terms of the GNU Affero General Public License as published by the Free 
Software
+  Foundation; either version 3, or (at your option) any later version.
+
+  TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+  A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more 
details.
+
+  You should have received a copy of the GNU Affero General Public License 
along with
+  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file taler-exchange-httpd_wire.c
+ * @brief Handle /wire requests
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <gnunet/gnunet_json_lib.h>
+#include "taler-exchange-httpd_keystate.h"
+#include "taler-exchange-httpd_responses.h"
+#include "taler-exchange-httpd_wire.h"
+#include "taler_json_lib.h"
+#include "taler_mhd_lib.h"
+#include <jansson.h>
+
+
+/**
+ * Thread-local.  Contains a pointer to `struct WireStateHandle` or NULL.
+ * Stores the per-thread latest generation of our wire response.
+ */
+static pthread_key_t wire_state;
+
+/**
+ * Counter incremented whenever we have a reason to re-build the #wire_state
+ * because something external changed (in another thread).  The counter is
+ * manipulated using an atomic update, and thus to ensure that threads notice
+ * when it changes, the variable MUST be volatile.  See #get_wire_state()
+ * and #TEH_wire_update_state() for uses of this variable.
+ */
+static volatile uint64_t wire_generation;
+
+
+/**
+ * State we keep per thread to cache the /wire response.
+ */
+struct WireStateHandle
+{
+  /**
+   * Cached JSON for /wire response.
+   */
+  json_t *wire_reply;
+
+  /**
+   * For which (global) wire_generation was this data structure created?
+   * Used to check when we are outdated and need to be re-generated.
+   */
+  uint64_t wire_generation;
+
+};
+
+
+/**
+ * Free memory assciated with @a wsh
+ *
+ * @param[in] wsh wire state to destroy
+ */
+static void
+destroy_wire_state (struct WireStateHandle *wsh)
+{
+  json_decref (wsh->wire_reply);
+  GNUNET_free (wsh);
+}
+
+
+/**
+ * Add information about a wire account to @a cls.
+ *
+ * @param cls a `json_t *` object to expand with wire account details
+ * @param payto_uri the exchange bank account URI to add
+ * @param master_sig master key signature affirming that this is a bank
+ *                   account of the exchange (of purpose 
#TALER_SIGNATURE_MASTER_WIRE_DETAILS)
+ */
+static void
+add_wire_account (void *cls,
+                  const char *payto_uri,
+                  const struct TALER_MasterSignatureP *master_sig)
+{
+  json_t *a = cls;
+
+  if (0 !=
+      json_array_append_new (
+        a,
+        json_pack ("{s:s, s:o}",
+                   "url", /* "payto_uri" would be better, but this is the name 
in the spec */
+                   payto_uri,
+                   "sig",
+                   GNUNET_JSON_from_data_auto (master_sig))))
+  {
+    GNUNET_break (0);   /* out of memory!? */
+    return;
+  }
+}
+
+
+/**
+ * Add information about a wire account to @a cls.
+ *
+ * @param cls a `json_t *` array to expand with wire account details
+ * @param wire_fee the wire fee we charge
+ * @param closing_fee the closing fee we charge
+ * @param start_date from when are these fees valid (start date)
+ * @param end_date until when are these fees valid (end date, exclusive)
+ * @param master_sig master key signature affirming that this is the corrrect
+ *                   fee (of purpose #TALER_SIGNATURE_MASTER_WIRE_FEES)
+ */
+static void
+add_wire_fee (void *cls,
+              const struct TALER_Amount *wire_fee,
+              const struct TALER_Amount *closing_fee,
+              struct GNUNET_TIME_Absolute start_date,
+              struct GNUNET_TIME_Absolute end_date,
+              const struct TALER_MasterSignatureP *master_sig)
+{
+  json_t *a = cls;
+
+  if (0 !=
+      json_array_append_new (
+        a,
+        json_pack ("{s:o, s:o, s:o, s:o, s:o}",
+                   "wire_fee",
+                   TALER_JSON_from_amount (wire_fee),
+                   "closing_fee",
+                   TALER_JSON_from_amount (closing_fee),
+                   "start_date",
+                   GNUNET_JSON_from_time_abs (start_date),
+                   "end_date",
+                   GNUNET_JSON_from_time_abs (end_date),
+                   "sig",
+                   GNUNET_JSON_from_data_auto (master_sig))))
+  {
+    GNUNET_break (0);   /* out of memory!? */
+    return;
+  }
+}
+
+
+/**
+ * Create the /wire response from our database state.
+ *
+ * @return NULL on error
+ */
+static struct WireStateHandle *
+build_wire_state (void)
+{
+  json_t *wire_accounts_array;
+  json_t *wire_fee_object;
+  json_t *wire_reply;
+  uint64_t wg = wire_generation; /* must be obtained FIRST */
+  enum GNUNET_DB_QueryStatus qs;
+
+  wire_accounts_array = json_array ();
+  GNUNET_assert (NULL != wire_accounts_array);
+  qs = TEH_plugin->get_wire_accounts (TEH_plugin->cls,
+                                      &add_wire_account,
+                                      wire_accounts_array);
+  if (0 > qs)
+  {
+    GNUNET_break (0);
+    json_decref (wire_accounts_array);
+    return NULL;
+  }
+  wire_fee_object = json_object ();
+  GNUNET_assert (NULL != wire_fee_object);
+  {
+    json_t *account;
+    size_t index;
+
+    json_array_foreach (wire_accounts_array, index, account) {
+      char *wire_method;
+      const char *payto_uri = json_string_value (json_object_get (account,
+                                                                  "url"));
+      GNUNET_assert (NULL != payto_uri);
+      wire_method = TALER_payto_get_method (payto_uri);
+      if (NULL == json_object_get (wire_fee_object,
+                                   wire_method))
+      {
+        json_t *a = json_array ();
+
+        GNUNET_assert (NULL != a);
+        qs = TEH_plugin->get_wire_fees (TEH_plugin->cls,
+                                        wire_method,
+                                        &add_wire_fee,
+                                        a);
+        if (0 > qs)
+        {
+          GNUNET_break (0);
+          json_decref (a);
+          json_decref (wire_fee_object);
+          json_decref (wire_accounts_array);
+          return NULL;
+        }
+        GNUNET_assert (0 ==
+                       json_object_set_new (wire_fee_object,
+                                            wire_method,
+                                            a));
+      }
+      GNUNET_free (wire_method);
+
+    }
+  }
+  wire_reply = json_pack (
+    "{s:O, s:O, s:o}",
+    "accounts", wire_accounts_array,
+    "fees", wire_fee_object,
+    "master_public_key",
+    GNUNET_JSON_from_data_auto (&TEH_master_public_key));
+  GNUNET_assert (NULL != wire_reply);
+  {
+    struct WireStateHandle *wsh;
+
+    wsh = GNUNET_new (struct WireStateHandle);
+    wsh->wire_reply = wire_reply;
+    wsh->wire_generation = wg;
+    return wsh;
+  }
+}
+
+
+/**
+ * Something changed in the database. Rebuild the wire replies.  This function
+ * should be called if the exchange learns about a new signature from our
+ * master key.
+ *
+ * (We do not do so immediately, but merely signal to all threads that they
+ * need to rebuild their wire state upon the next call to
+ * #wire_get_state()).
+ */
+void
+TEH_wire_update_state ()
+{
+  __sync_fetch_and_add (&key_generation,
+                        1);
+}
+
+
+/**
+ * Return the current key state for this thread.  Possibly
+ * re-builds the key state if we have reason to believe
+ * that something changed.
+ *
+ * @return NULL on error
+ */
+struct WireStateHandle *
+get_wire_state (void)
+{
+  struct WireStateHandle *old_wsh;
+  struct WireStateHandle *wsh;
+
+  old_wsh = pthread_getspecific (wire_state);
+  if ( (NULL == old_wsh) ||
+       (old_wsh->key_generation < key_generation) )
+  {
+    wsh = build_wire_state ();
+    if (NULL == wsh)
+      return NULL;
+    if (0 != pthread_setspecific (wire_state,
+                                  wsh))
+    {
+      GNUNET_break (0);
+      destroy_wire_state (wsh);
+      return NULL;
+    }
+    if (NULL != old_wsh)
+      destroy_key_state (old_wsh,
+                         false);
+    return wsh;
+  }
+  return old_wsh;
+}
+
+
+/**
+ * Handle a "/wire" request.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param args array of additional options (must be empty for this function)
+ * @return MHD result code
+  */
+MHD_RESULT
+TEH_handler_wire (const struct TEH_RequestHandler *rh,
+                  struct MHD_Connection *connection,
+                  const char *const args[])
+{
+  struct WireStateHandle *wsh;
+
+  (void) rh;
+  (void) args;
+  wsh = get_wire_state ();
+  if (NULL == wsh)
+    TALER_MHD_reply_error (connection,
+                           MHD_HTTP_INTERNAL_SERVER_ERROR,
+                           TALER_EC_WTF,
+                           NULL);
+  return TALER_MHD_reply_json (connection,
+                               json_incref (wsh->wire_reply),
+                               MHD_HTTP_OK);
+}
+
+
+/* end of taler-exchange-httpd_wire.c */
diff --git a/src/exchangedb/plugin_exchangedb_postgres.c 
b/src/exchangedb/plugin_exchangedb_postgres.c
index 2fcb0d01..24ae5b2e 100644
--- a/src/exchangedb/plugin_exchangedb_postgres.c
+++ b/src/exchangedb/plugin_exchangedb_postgres.c
@@ -1519,6 +1519,27 @@ postgres_get_session (void *cls)
                               " ,last_change=$3"
                               " WHERE payto_uri=$1",
                               3),
+      /* used in #postgres_update_wire() */
+      GNUNET_PQ_make_prepare ("get_wire_accounts",
+                              "SELECT"
+                              " payto_uri"
+                              ",master_sig"
+                              " FROM wire_accounts"
+                              " WHERE is_active",
+                              0),
+      /* used in #postgres_update_wire() */
+      GNUNET_PQ_make_prepare ("get_wire_fees",
+                              "SELECT"
+                              " wire_fee_val"
+                              ",wire_fee_frac"
+                              ",closing_fee_val"
+                              ",closing_fee_frac"
+                              ",start_date"
+                              ",end_date"
+                              ",master_sig"
+                              " FROM wire_fee"
+                              " WHERE wire_method=$1",
+                              1),
       /* used in #postgres_insert_signkey_revocation() */
       GNUNET_PQ_make_prepare ("insert_signkey_revocation",
                               "INSERT INTO signkey_revocations "
@@ -8211,6 +8232,240 @@ postgres_update_wire (void *cls,
 }
 
 
+/**
+ * Closure for #get_wire_accounts_cb().
+ */
+struct GetWireAccountsContext
+{
+  /**
+   * Function to call per result.
+   */
+  TALER_EXCHANGEDB_WireAccountCallback cb;
+
+  /**
+   * Closure for @e cb.
+   */
+  void *cb_cls;
+
+  /**
+   * Flag set to #GNUNET_OK as long as everything is fine.
+   */
+  int status;
+
+};
+
+
+/**
+ * Invoke the callback for each result.
+ *
+ * @param cls a `struct MissingWireContext *`
+ * @param result SQL result
+ * @param num_results number of rows in @a result
+ */
+static void
+get_wire_accounts_cb (void *cls,
+                      PGresult *result,
+                      unsigned int num_results)
+{
+  struct GetWireAccountsContext *ctx = cls;
+
+  for (unsigned int i = 0; i < num_results; i++)
+  {
+    char *payto_uri;
+    struct TALER_MasterSignatureP master_sig;
+    struct GNUNET_PQ_ResultSpec rs[] = {
+      GNUNET_PQ_result_spec_string ("payto_uri",
+                                    &payto_uri),
+      GNUNET_PQ_result_spec_auto_from_type ("master_sig",
+                                            &master_sig),
+      GNUNET_PQ_result_spec_end
+    };
+
+    if (GNUNET_OK !=
+        GNUNET_PQ_extract_result (result,
+                                  rs,
+                                  i))
+    {
+      GNUNET_break (0);
+      ctx->status = GNUNET_SYSERR;
+      return;
+    }
+    ctx->cb (ctx->cb_cls,
+             payto_uri,
+             &master_sig);
+    GNUNET_PQ_cleanup_result (rs);
+  }
+}
+
+
+/**
+ * Obtain information about the enabled wire accounts of the exchange.
+ *
+ * @param cls closure
+ * @param cb function to call on each account
+ * @param cb_cls closure for @a cb
+ * @return transaction status code
+ */
+static enum GNUNET_DB_QueryStatus
+postgres_get_wire_accounts (void *cls,
+                            TALER_EXCHANGEDB_WireAccountCallback cb,
+                            void *cb_cls)
+{
+  struct PostgresClosure *pg = cls;
+  struct GetWireAccountsContext ctx = {
+    .cb = cb,
+    .cb_cls = cb_cls,
+    .status = GNUNET_OK
+  };
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_end
+  };
+  enum GNUNET_DB_QueryStatus qs;
+  struct TALER_EXCHANGEDB_Session *session;
+
+  session = postgres_get_session (pg);
+  if (NULL == session)
+    return GNUNET_DB_STATUS_HARD_ERROR;
+  qs = GNUNET_PQ_eval_prepared_multi_select (session->conn,
+                                             "get_wire_accounts",
+                                             params,
+                                             &get_wire_accounts_cb,
+                                             &ctx);
+  if (GNUNET_OK != ctx.status)
+    return GNUNET_DB_STATUS_HARD_ERROR;
+  return qs;
+
+}
+
+
+/**
+ * Closure for #get_wire_fees_cb().
+ */
+struct GetWireFeesContext
+{
+  /**
+   * Function to call per result.
+   */
+  TALER_EXCHANGEDB_WireFeeCallback cb;
+
+  /**
+   * Closure for @e cb.
+   */
+  void *cb_cls;
+
+  /**
+   * Plugin context.
+   */
+  struct PostgresClosure *pg;
+
+  /**
+   * Flag set to #GNUNET_OK as long as everything is fine.
+   */
+  int status;
+
+};
+
+
+/**
+ * Invoke the callback for each result.
+ *
+ * @param cls a `struct MissingWireContext *`
+ * @param result SQL result
+ * @param num_results number of rows in @a result
+ */
+static void
+get_wire_fees_cb (void *cls,
+                  PGresult *result,
+                  unsigned int num_results)
+{
+  struct GetWireFeesContext *ctx = cls;
+  struct PostgresClosure *pg = ctx->pg;
+
+  for (unsigned int i = 0; i < num_results; i++)
+  {
+    struct TALER_MasterSignatureP master_sig;
+    struct TALER_Amount wire_fee;
+    struct TALER_Amount closing_fee;
+    struct GNUNET_TIME_Absolute start_date;
+    struct GNUNET_TIME_Absolute end_date;
+    struct GNUNET_PQ_ResultSpec rs[] = {
+      TALER_PQ_RESULT_SPEC_AMOUNT ("wire_fee",
+                                   &wire_fee),
+      TALER_PQ_RESULT_SPEC_AMOUNT ("closing_fee",
+                                   &closing_fee),
+      TALER_PQ_result_spec_absolute_time ("start_date",
+                                          &start_date),
+      TALER_PQ_result_spec_absolute_time ("end_date",
+                                          &end_date),
+      GNUNET_PQ_result_spec_auto_from_type ("master_sig",
+                                            &master_sig),
+      GNUNET_PQ_result_spec_end
+    };
+
+    if (GNUNET_OK !=
+        GNUNET_PQ_extract_result (result,
+                                  rs,
+                                  i))
+    {
+      GNUNET_break (0);
+      ctx->status = GNUNET_SYSERR;
+      return;
+    }
+    ctx->cb (ctx->cb_cls,
+             &wire_fee,
+             &closing_fee,
+             start_date,
+             end_date,
+             &master_sig);
+    GNUNET_PQ_cleanup_result (rs);
+  }
+}
+
+
+/**
+ * Obtain information about the fee structure of the exchange for
+ * a given @a wire_method
+ *
+ * @param cls closure
+ * @param wire_method which wire method to obtain fees for
+ * @param cb function to call on each account
+ * @param cb_cls closure for @a cb
+ * @return transaction status code
+ */
+static enum GNUNET_DB_QueryStatus
+postgres_get_wire_fees (void *cls,
+                        const char *wire_method,
+                        TALER_EXCHANGEDB_WireFeeCallback cb,
+                        void *cb_cls)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_string (wire_method),
+    GNUNET_PQ_query_param_end
+  };
+  struct GetWireFeesContext ctx = {
+    .cb = cb,
+    .cb_cls = cb_cls,
+    .pg = pg,
+    .status = GNUNET_OK
+  };
+  enum GNUNET_DB_QueryStatus qs;
+  struct TALER_EXCHANGEDB_Session *session;
+
+  session = postgres_get_session (pg);
+  if (NULL == session)
+    return GNUNET_DB_STATUS_HARD_ERROR;
+  qs = GNUNET_PQ_eval_prepared_multi_select (session->conn,
+                                             "get_wire_fees",
+                                             params,
+                                             &get_wire_fees_cb,
+                                             &ctx);
+  if (GNUNET_OK != ctx.status)
+    return GNUNET_DB_STATUS_HARD_ERROR;
+  return qs;
+}
+
+
 /**
  * Store information about a revoked online signing key.
  *
@@ -8810,6 +9065,10 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
     = &postgres_insert_wire;
   plugin->update_wire
     = &postgres_update_wire;
+  plugin->get_wire_accounts
+    = &postgres_get_wire_accounts;
+  plugin->get_wire_fees
+    = &postgres_get_wire_fees;
   plugin->insert_signkey_revocation
     = &postgres_insert_signkey_revocation;
   plugin->lookup_future_denomination_key
diff --git a/src/include/taler_exchangedb_plugin.h 
b/src/include/taler_exchangedb_plugin.h
index 57254787..65c31726 100644
--- a/src/include/taler_exchangedb_plugin.h
+++ b/src/include/taler_exchangedb_plugin.h
@@ -1427,6 +1427,42 @@ typedef int
   struct GNUNET_TIME_Absolute execution_date);
 
 
+/**
+ * Provide information about a wire account.
+ *
+ * @param cls closure
+ * @param payto_uri the exchange bank account URI
+ * @param master_sig master key signature affirming that this is a bank
+ *                   account of the exchange (of purpose 
#TALER_SIGNATURE_MASTER_WIRE_DETAILS)
+ */
+typedef void
+(*TALER_EXCHANGEDB_WireAccountCallback)(
+  void *cls,
+  const char *payto_uri,
+  const struct TALER_MasterSignatureP *master_sig);
+
+
+/**
+ * Provide information about wire fees.
+ *
+ * @param cls closure
+ * @param wire_fee the wire fee we charge
+ * @param closing_fee the closing fee we charge
+ * @param start_date from when are these fees valid (start date)
+ * @param end_date until when are these fees valid (end date, exclusive)
+ * @param master_sig master key signature affirming that this is the corrrect
+ *                   fee (of purpose #TALER_SIGNATURE_MASTER_WIRE_FEES)
+ */
+typedef void
+(*TALER_EXCHANGEDB_WireFeeCallback)(
+  void *cls,
+  const struct TALER_Amount *wire_fee,
+  const struct TALER_Amount *closing_fee,
+  struct GNUNET_TIME_Absolute start_date,
+  struct GNUNET_TIME_Absolute end_date,
+  const struct TALER_MasterSignatureP *master_sig);
+
+
 /**
  * Function called with details about withdraw operations.
  *
@@ -3254,6 +3290,37 @@ struct TALER_EXCHANGEDB_Plugin
                  bool enabled);
 
 
+  /**
+   * Obtain information about the enabled wire accounts of the exchange.
+   *
+   * @param cls closure
+   * @param cb function to call on each account
+   * @param cb_cls closure for @a cb
+   * @return transaction status code
+   */
+  enum GNUNET_DB_QueryStatus
+  (*get_wire_accounts)(void *cls,
+                       TALER_EXCHANGEDB_WireAccountCallback cb,
+                       void *cb_cls);
+
+
+  /**
+   * Obtain information about the fee structure of the exchange for
+   * a given @a wire_method
+   *
+   * @param cls closure
+   * @param wire_method which wire method to obtain fees for
+   * @param cb function to call on each account
+   * @param cb_cls closure for @a cb
+   * @return transaction status code
+   */
+  enum GNUNET_DB_QueryStatus
+  (*get_wire_fees)(void *cls,
+                   const char *wire_method,
+                   TALER_EXCHANGEDB_WireFeeCallback cb,
+                   void *cb_cls);
+
+
   /**
    * Store information about a revoked online signing key.
    *

-- 
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]