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 reserve history API


From: gnunet
Subject: [taler-exchange] branch master updated: work on reserve history API
Date: Tue, 19 Sep 2023 13:11:30 +0200

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 2f7f8253 work on reserve history API
2f7f8253 is described below

commit 2f7f82536d53cf015f46782c1a81280849fef935
Author: Christian Grothoff <christian@grothoff.org>
AuthorDate: Tue Sep 19 13:11:26 2023 +0200

    work on reserve history API
---
 src/exchange/taler-exchange-httpd_coins_get.c      |  10 +-
 src/exchange/taler-exchange-httpd_common_kyc.c     |   3 +-
 .../taler-exchange-httpd_reserves_history.c        | 303 +++++++++++----------
 src/exchangedb/pg_get_reserve_history.c            |  13 +-
 src/exchangedb/pg_get_reserve_history.h            |  12 +-
 src/exchangedb/test_exchangedb.c                   |   3 +
 src/include/taler_exchange_service.h               |  14 +-
 src/include/taler_exchangedb_plugin.h              |  12 +-
 8 files changed, 208 insertions(+), 162 deletions(-)

diff --git a/src/exchange/taler-exchange-httpd_coins_get.c 
b/src/exchange/taler-exchange-httpd_coins_get.c
index 7553bf19..e7b54337 100644
--- a/src/exchange/taler-exchange-httpd_coins_get.c
+++ b/src/exchange/taler-exchange-httpd_coins_get.c
@@ -30,7 +30,7 @@
 
 
 /**
- * Add the headers we want to set for every /keys response.
+ * Add the headers we want to set for every response.
  *
  * @param cls the key state to use
  * @param[in,out] response the response to modify
@@ -44,7 +44,7 @@ add_response_headers (void *cls,
   GNUNET_break (MHD_YES ==
                 MHD_add_response_header (response,
                                          MHD_HTTP_HEADER_CACHE_CONTROL,
-                                         "no-cache, public"));
+                                         "no-cache"));
 }
 
 
@@ -540,7 +540,7 @@ TEH_handler_coins_get (struct TEH_RequestContext *rc,
 {
   struct TALER_EXCHANGEDB_TransactionList *tl = NULL;
   uint64_t start_off = 0;
-  uint64_t etag_in = 0;
+  uint64_t etag_in;
   uint64_t etag_out;
   char etagp[24];
   struct MHD_Response *resp;
@@ -591,6 +591,7 @@ TEH_handler_coins_get (struct TEH_RequestContext *rc,
         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                     "Client send malformed `If-None-Match' header `%s'\n",
                     etags);
+        etag_in = start_off;
       }
       else
       {
@@ -622,7 +623,6 @@ TEH_handler_coins_get (struct TEH_RequestContext *rc,
                                          TALER_EC_GENERIC_DB_FETCH_FAILED,
                                          "get_coin_history");
     case GNUNET_DB_STATUS_SOFT_ERROR:
-      GNUNET_break (0); /* single-shot query should never have soft-errors */
       return TALER_MHD_reply_with_error (rc->connection,
                                          MHD_HTTP_INTERNAL_SERVER_ERROR,
                                          TALER_EC_GENERIC_DB_SOFT_FAILURE,
@@ -680,6 +680,8 @@ TEH_handler_coins_get (struct TEH_RequestContext *rc,
                                     history));
     http_status = MHD_HTTP_OK;
   }
+  add_response_headers (NULL,
+                        resp);
   GNUNET_break (MHD_YES ==
                 MHD_add_response_header (resp,
                                          MHD_HTTP_HEADER_ETAG,
diff --git a/src/exchange/taler-exchange-httpd_common_kyc.c 
b/src/exchange/taler-exchange-httpd_common_kyc.c
index dfd9b710..5d4b4c11 100644
--- a/src/exchange/taler-exchange-httpd_common_kyc.c
+++ b/src/exchange/taler-exchange-httpd_common_kyc.c
@@ -23,6 +23,7 @@
 #include "taler-exchange-httpd_common_kyc.h"
 #include "taler_attributes.h"
 #include "taler_error_codes.h"
+#include "taler_kyclogic_lib.h"
 #include "taler_exchangedb_plugin.h"
 #include <gnunet/gnunet_common.h>
 
@@ -167,7 +168,7 @@ kyc_aml_finished (void *cls,
     &kyc_prox,
     kat->provider_section,
     num_checks,
-    provided_checks,
+    (const char **) provided_checks,
     birthday,
     GNUNET_TIME_timestamp_get (),
     kat->provider_user_id,
diff --git a/src/exchange/taler-exchange-httpd_reserves_history.c 
b/src/exchange/taler-exchange-httpd_reserves_history.c
index a73b5ab6..056d4b0e 100644
--- a/src/exchange/taler-exchange-httpd_reserves_history.c
+++ b/src/exchange/taler-exchange-httpd_reserves_history.c
@@ -29,40 +29,6 @@
 #include "taler-exchange-httpd_reserves_history.h"
 #include "taler-exchange-httpd_responses.h"
 
-/**
- * How far do we allow a client's time to be off when
- * checking the request timestamp?
- */
-#define TIMESTAMP_TOLERANCE \
-  GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
-
-
-/**
- * Closure for #reserve_history_transaction.
- */
-struct ReserveHistoryContext
-{
-  /**
-   * Public key of the reserve the inquiry is about.
-   */
-  const struct TALER_ReservePublicKeyP *reserve_pub;
-
-  /**
-   * History of the reserve, set in the callback.
-   */
-  struct TALER_EXCHANGEDB_ReserveHistory *rh;
-
-  /**
-   * Requested startin offset for the reserve history.
-   */
-  uint64_t start_off;
-
-  /**
-   * Current reserve balance.
-   */
-  struct TALER_Amount balance;
-};
-
 
 /**
  * Compile the history of a reserve into a JSON object.
@@ -95,7 +61,6 @@ compile_reserve_history (
               GNUNET_JSON_PACK (
                 GNUNET_JSON_pack_string ("type",
                                          "CREDIT"),
-                // FIXME: offset missing! (here and in all other cases!)
                 GNUNET_JSON_pack_timestamp ("timestamp",
                                             bank->execution_date),
                 GNUNET_JSON_pack_string ("sender_account_url",
@@ -364,74 +329,21 @@ compile_reserve_history (
 
 
 /**
- * Send reserve history to client.
+ * Add the headers we want to set for every /keys response.
  *
- * @param connection connection to the client
- * @param rhc reserve history to return
- * @return MHD result code
+ * @param cls the key state to use
+ * @param[in,out] response the response to modify
  */
-static MHD_RESULT
-reply_reserve_history_success (struct MHD_Connection *connection,
-                               const struct ReserveHistoryContext *rhc)
+static void
+add_response_headers (void *cls,
+                      struct MHD_Response *response)
 {
-  const struct TALER_EXCHANGEDB_ReserveHistory *rh = rhc->rh;
-  json_t *json_history;
-
-  json_history = compile_reserve_history (rh);
-  if (NULL == json_history)
-    return TALER_MHD_reply_with_error (connection,
-                                       MHD_HTTP_INTERNAL_SERVER_ERROR,
-                                       
TALER_EC_GENERIC_JSON_ALLOCATION_FAILURE,
-                                       NULL);
-  return TALER_MHD_REPLY_JSON_PACK (
-    connection,
-    MHD_HTTP_OK,
-    TALER_JSON_pack_amount ("balance",
-                            &rhc->balance),
-    GNUNET_JSON_pack_array_steal ("history",
-                                  json_history));
-}
-
-
-/**
- * Function implementing /reserves/ HISTORY transaction.
- * Execute a /reserves/ HISTORY.  Given the public key of a reserve,
- * return the associated transaction history.  Runs the
- * transaction logic; IF it returns a non-error code, the transaction
- * logic MUST NOT queue a MHD response.  IF it returns an hard error,
- * the transaction logic MUST queue a MHD response and set @a mhd_ret.
- * IF it returns the soft error code, the function MAY be called again
- * to retry and MUST not queue a MHD response.
- *
- * @param cls a `struct ReserveHistoryContext *`
- * @param connection MHD request which triggered the transaction
- * @param[out] mhd_ret set to MHD response history for @a connection,
- *             if transaction failed (!); unused
- * @return transaction history
- */
-static enum GNUNET_DB_QueryStatus
-reserve_history_transaction (void *cls,
-                             struct MHD_Connection *connection,
-                             MHD_RESULT *mhd_ret)
-{
-  struct ReserveHistoryContext *rsc = cls;
-  enum GNUNET_DB_QueryStatus qs;
-
-  qs = TEH_plugin->get_reserve_history (TEH_plugin->cls,
-                                        rsc->reserve_pub,
-                                        rsc->start_off,
-                                        &rsc->balance,
-                                        &rsc->rh);
-  if (GNUNET_DB_STATUS_HARD_ERROR == qs)
-  {
-    GNUNET_break (0);
-    *mhd_ret
-      = TALER_MHD_reply_with_error (connection,
-                                    MHD_HTTP_INTERNAL_SERVER_ERROR,
-                                    TALER_EC_GENERIC_DB_FETCH_FAILED,
-                                    "get_reserve_history");
-  }
-  return qs;
+  (void) cls;
+  TALER_MHD_add_global_headers (response);
+  GNUNET_break (MHD_YES ==
+                MHD_add_response_header (response,
+                                         MHD_HTTP_HEADER_CACHE_CONTROL,
+                                         "no-cache"));
 }
 
 
@@ -440,56 +352,165 @@ TEH_handler_reserves_history (
   struct TEH_RequestContext *rc,
   const struct TALER_ReservePublicKeyP *reserve_pub)
 {
-  struct ReserveHistoryContext rsc = {
-    .reserve_pub = reserve_pub
-  };
-  MHD_RESULT mhd_ret;
-  struct TALER_ReserveSignatureP reserve_sig;
-  bool required = true;
-
-  TALER_MHD_parse_request_header_auto (rc->connection,
-                                       TALER_RESERVE_HISTORY_SIGNATURE_HEADER,
-                                       &reserve_sig,
-                                       required);
+  struct TALER_EXCHANGEDB_ReserveHistory *rh = NULL;
+  uint64_t start_off = 0;
+  struct TALER_Amount balance;
+  uint64_t etag_in;
+  uint64_t etag_out;
+  char etagp[24];
+  struct MHD_Response *resp;
+  unsigned int http_status;
+
   TALER_MHD_parse_request_number (rc->connection,
                                   "start",
-                                  &rsc.start_off);
-  rsc.reserve_pub = reserve_pub;
+                                  &start_off);
+  {
+    struct TALER_ReserveSignatureP reserve_sig;
+    bool required = true;
+
+    TALER_MHD_parse_request_header_auto (rc->connection,
+                                         
TALER_RESERVE_HISTORY_SIGNATURE_HEADER,
+                                         &reserve_sig,
+                                         required);
+
+    if (GNUNET_OK !=
+        TALER_wallet_reserve_history_verify (start_off,
+                                             reserve_pub,
+                                             &reserve_sig))
+    {
+      GNUNET_break_op (0);
+      return TALER_MHD_reply_with_error (rc->connection,
+                                         MHD_HTTP_FORBIDDEN,
+                                         
TALER_EC_EXCHANGE_RESERVE_HISTORY_BAD_SIGNATURE,
+                                         NULL);
+    }
+  }
+
+  /* Get etag */
+  {
+    const char *etags;
+
+    etags = MHD_lookup_connection_value (rc->connection,
+                                         MHD_HEADER_KIND,
+                                         MHD_HTTP_HEADER_IF_NONE_MATCH);
+    if (NULL != etags)
+    {
+      char dummy;
+      unsigned long long ev;
+
+      if (1 != sscanf (etags,
+                       "\"%llu\"%c",
+                       &ev,
+                       &dummy))
+      {
+        GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                    "Client send malformed `If-None-Match' header `%s'\n",
+                    etags);
+        etag_in = 0;
+      }
+      else
+      {
+        etag_in = (uint64_t) ev;
+      }
+    }
+    else
+    {
+      etag_in = start_off;
+    }
+  }
+
+  {
+    enum GNUNET_DB_QueryStatus qs;
+
+    qs = TEH_plugin->get_reserve_history (TEH_plugin->cls,
+                                          reserve_pub,
+                                          start_off,
+                                          etag_in,
+                                          &etag_out,
+                                          &balance,
+                                          &rh);
+    switch (qs)
+    {
+    case GNUNET_DB_STATUS_HARD_ERROR:
+      GNUNET_break (0);
+      return TALER_MHD_reply_with_error (rc->connection,
+                                         MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                         TALER_EC_GENERIC_DB_FETCH_FAILED,
+                                         "get_reserve_history");
+    case GNUNET_DB_STATUS_SOFT_ERROR:
+      return TALER_MHD_reply_with_error (rc->connection,
+                                         MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                         TALER_EC_GENERIC_DB_SOFT_FAILURE,
+                                         "get_reserve_history");
+    case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+      return TALER_MHD_reply_with_error (rc->connection,
+                                         MHD_HTTP_NOT_FOUND,
+                                         
TALER_EC_EXCHANGE_GENERIC_RESERVE_UNKNOWN,
+                                         NULL);
+    case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+      /* Handled below */
+      break;
+    }
+  }
 
-  if (GNUNET_OK !=
-      TALER_wallet_reserve_history_verify (rsc.start_off,
-                                           reserve_pub,
-                                           &reserve_sig))
+  GNUNET_snprintf (etagp,
+                   sizeof (etagp),
+                   "\"%llu\"",
+                   (unsigned long long) etag_out);
+  if (etag_in == etag_out)
+  {
+    return TEH_RESPONSE_reply_not_modified (rc->connection,
+                                            etagp,
+                                            &add_response_headers,
+                                            NULL);
+  }
+  if (NULL == rh)
   {
-    GNUNET_break_op (0);
-    return TALER_MHD_reply_with_error (rc->connection,
-                                       MHD_HTTP_FORBIDDEN,
-                                       
TALER_EC_EXCHANGE_RESERVE_HISTORY_BAD_SIGNATURE,
-                                       NULL);
+    /* 204: empty history */
+    resp = MHD_create_response_from_buffer (0,
+                                            "",
+                                            MHD_RESPMEM_PERSISTENT);
+    http_status = MHD_HTTP_NO_CONTENT;
   }
-  rsc.rh = NULL;
-  if (GNUNET_OK !=
-      TEH_DB_run_transaction (rc->connection,
-                              "get reserve history",
-                              TEH_MT_REQUEST_OTHER,
-                              &mhd_ret,
-                              &reserve_history_transaction,
-                              &rsc))
+  else
   {
-    return mhd_ret;
+    json_t *history;
+
+    http_status = MHD_HTTP_OK;
+    history = compile_reserve_history (rh);
+    TEH_plugin->free_reserve_history (TEH_plugin->cls,
+                                      rh);
+    rh = NULL;
+    if (NULL == history)
+    {
+      GNUNET_break (0);
+      return TALER_MHD_reply_with_error (rc->connection,
+                                         MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                         
TALER_EC_GENERIC_JSON_ALLOCATION_FAILURE,
+                                         NULL);
+    }
+    resp = TALER_MHD_MAKE_JSON_PACK (
+      TALER_JSON_pack_amount ("balance",
+                              &balance),
+      GNUNET_JSON_pack_array_steal ("history",
+                                    history));
   }
-  if (NULL == rsc.rh)
+  add_response_headers (NULL,
+                        resp);
+  GNUNET_break (MHD_YES ==
+                MHD_add_response_header (resp,
+                                         MHD_HTTP_HEADER_ETAG,
+                                         etagp));
   {
-    return TALER_MHD_reply_with_error (rc->connection,
-                                       MHD_HTTP_NOT_FOUND,
-                                       
TALER_EC_EXCHANGE_GENERIC_RESERVE_UNKNOWN,
-                                       NULL);
+    MHD_RESULT ret;
+
+    ret = MHD_queue_response (rc->connection,
+                              http_status,
+                              resp);
+    GNUNET_break (MHD_YES == ret);
+    MHD_destroy_response (resp);
+    return ret;
   }
-  mhd_ret = reply_reserve_history_success (rc->connection,
-                                           &rsc);
-  TEH_plugin->free_reserve_history (TEH_plugin->cls,
-                                    rsc.rh);
-  return mhd_ret;
 }
 
 
diff --git a/src/exchangedb/pg_get_reserve_history.c 
b/src/exchangedb/pg_get_reserve_history.c
index ba1db2a1..9c7ff39d 100644
--- a/src/exchangedb/pg_get_reserve_history.c
+++ b/src/exchangedb/pg_get_reserve_history.c
@@ -540,11 +540,14 @@ add_close_requests (void *cls,
 
 
 enum GNUNET_DB_QueryStatus
-TEH_PG_get_reserve_history (void *cls,
-                            const struct TALER_ReservePublicKeyP *reserve_pub,
-                            uint64_t start_off,
-                            struct TALER_Amount *balance,
-                            struct TALER_EXCHANGEDB_ReserveHistory **rhp)
+TEH_PG_get_reserve_history (
+  void *cls,
+  const struct TALER_ReservePublicKeyP *reserve_pub,
+  uint64_t start_off,
+  uint64_t etag_in,
+  uint64_t *etag_out,
+  struct TALER_Amount *balance,
+  struct TALER_EXCHANGEDB_ReserveHistory **rhp)
 {
   struct PostgresClosure *pg = cls;
   struct ReserveHistoryContext rhc;
diff --git a/src/exchangedb/pg_get_reserve_history.h 
b/src/exchangedb/pg_get_reserve_history.h
index ca6740c6..15765f12 100644
--- a/src/exchangedb/pg_get_reserve_history.h
+++ b/src/exchangedb/pg_get_reserve_history.h
@@ -27,12 +27,18 @@
 
 
 /**
- * Get all of the transaction history associated with the specified
- * reserve.
+ * Compile a list of (historic) transactions performed with the given reserve
+ * (withdraw, incoming wire, open, close operations).  Should return 0 if the 
@a
+ * reserve_pub is unknown, otherwise determine @a etag_out and if it is past @a
+ * etag_in return the history after @a start_off. @a etag_out should be set
+ * to the last row ID of the given @a reserve_pub in the reserve history table.
  *
  * @param cls the `struct PostgresClosure` with the plugin-specific state
  * @param reserve_pub public key of the reserve
  * @param start_off maximum starting offset in history to exclude from 
returning
+ * @param etag_in up to this offset the client already has a response, do not
+ *                   return anything unless @a etag_out will be larger
+ * @param[out] etag_out set to the latest history offset known for this @a 
coin_pub
  * @param[out] balance set to the reserve balance
  * @param[out] rhp set to known transaction history (NULL if reserve is 
unknown)
  * @return transaction status
@@ -42,6 +48,8 @@ TEH_PG_get_reserve_history (
   void *cls,
   const struct TALER_ReservePublicKeyP *reserve_pub,
   uint64_t start_off,
+  uint64_t etag_in,
+  uint64_t *etag_out,
   struct TALER_Amount *balance,
   struct TALER_EXCHANGEDB_ReserveHistory **rhp);
 
diff --git a/src/exchangedb/test_exchangedb.c b/src/exchangedb/test_exchangedb.c
index f2df1f38..50ce1e04 100644
--- a/src/exchangedb/test_exchangedb.c
+++ b/src/exchangedb/test_exchangedb.c
@@ -1863,10 +1863,13 @@ run (void *cls)
   /* check reserve history */
   {
     struct TALER_Amount balance;
+    uint64_t etag_out;
 
     qs = plugin->get_reserve_history (plugin->cls,
                                       &reserve_pub,
                                       0,
+                                      0,
+                                      &etag_out,
                                       &balance,
                                       &rh);
   }
diff --git a/src/include/taler_exchange_service.h 
b/src/include/taler_exchange_service.h
index f973cfb0..c344a93a 100644
--- a/src/include/taler_exchange_service.h
+++ b/src/include/taler_exchange_service.h
@@ -1648,13 +1648,6 @@ struct TALER_EXCHANGE_ReserveHistoryEntry
    */
   struct TALER_Amount amount;
 
-  /**
-   * Index of this entry in the reserve history.
-   * Useful to filter requests by starting offset.
-   * Offsets are not necessarily contiguous.
-   */
-  uint64_t entry_off;
-
   /**
    * Details depending on @e type.
    */
@@ -2063,6 +2056,13 @@ struct TALER_EXCHANGE_ReserveHistory
        */
       struct TALER_Amount total_out;
 
+      /**
+       * Current etag / last entry in the history.
+       * Useful to filter requests by starting offset.
+       * Offsets are not necessarily contiguous.
+       */
+      uint64_t etag;
+
       /**
        * Reserve history.
        */
diff --git a/src/include/taler_exchangedb_plugin.h 
b/src/include/taler_exchangedb_plugin.h
index fc11a292..484b1155 100644
--- a/src/include/taler_exchangedb_plugin.h
+++ b/src/include/taler_exchangedb_plugin.h
@@ -4221,12 +4221,18 @@ struct TALER_EXCHANGEDB_Plugin
 
 
   /**
-   * Get all of the transaction history associated with the specified
-   * reserve.
+   * Compile a list of (historic) transactions performed with the given reserve
+   * (withdraw, incoming wire, open, close operations).  Should return 0 if 
the @a
+   * reserve_pub is unknown, otherwise determine @a etag_out and if it is past 
@a
+   * etag_in return the history after @a start_off. @a etag_out should be set
+   * to the last row ID of the given @a reserve_pub in the reserve history 
table.
    *
    * @param cls the @e cls of this struct with the plugin-specific state
    * @param reserve_pub public key of the reserve
    * @param start_off maximum starting offset in history to exclude from 
returning
+   * @param etag_in up to this offset the client already has a response, do not
+   *                   return anything unless @a etag_out will be larger
+   * @param[out] etag_out set to the latest history offset known for this @a 
coin_pub
    * @param[out] balance set to the reserve balance
    * @param[out] rhp set to known transaction history (NULL if reserve is 
unknown)
    * @return transaction status
@@ -4235,6 +4241,8 @@ struct TALER_EXCHANGEDB_Plugin
   (*get_reserve_history)(void *cls,
                          const struct TALER_ReservePublicKeyP *reserve_pub,
                          uint64_t start_off,
+                         uint64_t etag_in,
+                         uint64_t *etag_out,
                          struct TALER_Amount *balance,
                          struct TALER_EXCHANGEDB_ReserveHistory **rhp);
 

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