gnunet-svn
[Top][All Lists]
Advanced

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

[GNUnet-SVN] [taler-exchange] 04/08: refactoring /deposit towards new tr


From: gnunet
Subject: [GNUnet-SVN] [taler-exchange] 04/08: refactoring /deposit towards new transaction style (#5010)
Date: Mon, 19 Jun 2017 00:18:21 +0200

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

grothoff pushed a commit to branch master
in repository exchange.

commit 2ec1b055a0f574e3837f2fbbb38098db4eb65f6f
Author: Christian Grothoff <address@hidden>
AuthorDate: Sun Jun 18 21:47:05 2017 +0200

    refactoring /deposit towards new transaction style (#5010)
---
 src/exchange/taler-exchange-httpd_db.c             | 249 ++++++++-------------
 src/exchange/taler-exchange-httpd_db.h             |  61 ++++-
 src/exchange/taler-exchange-httpd_deposit.c        | 215 +++++++++++++++++-
 src/exchange/taler-exchange-httpd_responses.c      |  54 -----
 src/exchange/taler-exchange-httpd_responses.h      |  29 ---
 src/exchangedb/perf_taler_exchangedb_interpreter.c |   4 +-
 src/exchangedb/plugin_exchangedb_postgres.c        | 129 +++++------
 src/exchangedb/test_exchangedb.c                   |   8 +-
 src/include/taler_exchangedb_plugin.h              |  14 +-
 9 files changed, 422 insertions(+), 341 deletions(-)

diff --git a/src/exchange/taler-exchange-httpd_db.c 
b/src/exchange/taler-exchange-httpd_db.c
index abbb6c3..2cdf61d 100644
--- a/src/exchange/taler-exchange-httpd_db.c
+++ b/src/exchange/taler-exchange-httpd_db.c
@@ -113,19 +113,92 @@ transaction_start_label: /* we will use goto for retries 
*/   \
 
 
 /**
+ * Run a database transaction for @a connection.
+ * Starts a transaction and calls @a cb.  Upon success,
+ * attempts to commit the transaction.  Upon soft failures,
+ * retries @a cb a few times.  Upon hard or persistent soft
+ * errors, generates an error message for @a connection.
+ * 
+ * @param connection MHD connection to run @a cb for
+ * @param[out] set to MHD response code, if transaction failed
+ * @param cb callback implementing transaction logic
+ * @param cb_cls closure for @a cb, must be read-only!
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
+ */
+int
+TEH_DB_run_transaction (struct MHD_Connection *connection,
+                       int *mhd_ret,
+                       TEH_DB_TransactionCallback cb,
+                       void *cb_cls)
+{
+  struct TALER_EXCHANGEDB_Session *session;
+
+  *mhd_ret = -1; /* invalid value */
+  if (NULL == (session = TEH_plugin->get_session (TEH_plugin->cls)))
+  {
+    GNUNET_break (0);
+    *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection,
+                                                    TALER_EC_DB_SETUP_FAILED);
+    return GNUNET_SYSERR;
+  }
+  for (unsigned int retries = 0;retries < MAX_TRANSACTION_COMMIT_RETRIES; 
retries++)
+  {
+    enum GNUNET_DB_QueryStatus qs;
+
+    if (GNUNET_OK !=                                            
+       TEH_plugin->start (TEH_plugin->cls,                     
+                          session))                            
+    {                                      
+      GNUNET_break (0);                                         
+      *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection, 
+                                                      
TALER_EC_DB_START_FAILED);
+      return GNUNET_SYSERR;
+    }
+    qs = cb (cb_cls,
+            connection,
+            session,
+            mhd_ret);
+    if (0 > qs)
+      TEH_plugin->rollback (TEH_plugin->cls,
+                           session);      
+    if (GNUNET_DB_STATUS_HARD_ERROR == qs)
+      return GNUNET_SYSERR;
+    if (0 <= qs)
+      qs = TEH_plugin->commit (TEH_plugin->cls,
+                              session);                              
+    if (GNUNET_DB_STATUS_HARD_ERROR == qs)
+    {
+      *mhd_ret = TEH_RESPONSE_reply_commit_error (connection,
+                                                 
TALER_EC_DB_COMMIT_FAILED_HARD);
+      return GNUNET_SYSERR;
+    }
+    /* make sure callback did not violate invariants! */
+    GNUNET_assert (-1 == *mhd_ret);
+    if (0 <= qs)
+      return GNUNET_OK;
+  }
+  TALER_LOG_WARNING ("Transaction commit failed %u times\n",
+                    MAX_TRANSACTION_COMMIT_RETRIES);
+  *mhd_ret = TEH_RESPONSE_reply_commit_error (connection,
+                                             
TALER_EC_DB_COMMIT_FAILED_ON_RETRY);
+  return GNUNET_SYSERR;
+}
+
+
+/**
  * Calculate the total value of all transactions performed.
  * Stores @a off plus the cost of all transactions in @a tl
  * in @a ret.
  *
  * @param tl transaction list to process
  * @param off offset to use as the starting value
- * @param ret where the resulting total is to be stored
+ * @param[out] ret where the resulting total is to be stored
  * @return #GNUNET_OK on success, #GNUNET_SYSERR on errors
  */
-static int
-calculate_transaction_list_totals (struct TALER_EXCHANGEDB_TransactionList *tl,
-                                   const struct TALER_Amount *off,
-                                   struct TALER_Amount *ret)
+int
+TEH_DB_calculate_transaction_list_totals (struct 
TALER_EXCHANGEDB_TransactionList *tl,
+                                         const struct TALER_Amount *off,
+                                         struct TALER_Amount *ret)
 {
   struct TALER_Amount spent = *off;
   struct TALER_EXCHANGEDB_TransactionList *pos;
@@ -207,146 +280,6 @@ calculate_transaction_list_totals (struct 
TALER_EXCHANGEDB_TransactionList *tl,
 
 
 /**
- * Execute a deposit.  The validity of the coin and signature
- * have already been checked.  The database must now check that
- * the coin is not (double or over) spent, and execute the
- * transaction (record details, generate success or failure response).
- *
- * @param connection the MHD connection to handle
- * @param deposit information about the deposit
- * @return MHD result code
- */
-int
-TEH_DB_execute_deposit (struct MHD_Connection *connection,
-                        const struct TALER_EXCHANGEDB_Deposit *deposit)
-{
-  struct TALER_EXCHANGEDB_Session *session;
-  struct TALER_EXCHANGEDB_TransactionList *tl;
-  struct TALER_Amount spent;
-  struct TALER_Amount value;
-  struct TALER_Amount amount_without_fee;
-  struct TEH_KS_StateHandle *mks;
-  struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki;
-  int ret;
-  enum GNUNET_DB_QueryStatus qs;
-  unsigned int retries = 0;
-
-  if (NULL == (session = TEH_plugin->get_session (TEH_plugin->cls)))
-  {
-    GNUNET_break (0);
-    return TEH_RESPONSE_reply_internal_db_error (connection,
-                                                TALER_EC_DB_SETUP_FAILED);
-  }
- again:
-  if (GNUNET_YES ==
-      TEH_plugin->have_deposit (TEH_plugin->cls,
-                                session,
-                                deposit))
-  {
-    GNUNET_assert (GNUNET_OK ==
-                   TALER_amount_subtract (&amount_without_fee,
-                                          &deposit->amount_with_fee,
-                                          &deposit->deposit_fee));
-    return TEH_RESPONSE_reply_deposit_success (connection,
-                                               &deposit->coin.coin_pub,
-                                               &deposit->h_wire,
-                                               &deposit->h_contract_terms,
-                                               deposit->timestamp,
-                                               deposit->refund_deadline,
-                                               &deposit->merchant_pub,
-                                               &amount_without_fee);
-  }
-
-  /* FIXME: move the 'mks'-logic outside of _db.c? */
-  mks = TEH_KS_acquire ();
-  dki = TEH_KS_denomination_key_lookup (mks,
-                                        &deposit->coin.denom_pub,
-                                       TEH_KS_DKU_DEPOSIT);
-  if (NULL == dki)
-  {
-    TEH_KS_release (mks);
-    return TEH_RESPONSE_reply_internal_db_error (connection,
-                                                 
TALER_EC_DEPOSIT_DB_DENOMINATION_KEY_UNKNOWN);
-  }
-  TALER_amount_ntoh (&value,
-                     &dki->issue.properties.value);
-  TEH_KS_release (mks);
-
-  START_TRANSACTION (session, connection);
-
-  /* fee for THIS transaction */
-  spent = deposit->amount_with_fee;
-  /* add cost of all previous transactions */
-  tl = TEH_plugin->get_coin_transactions (TEH_plugin->cls,
-                                          session,
-                                          &deposit->coin.coin_pub);
-  if (GNUNET_OK !=
-      calculate_transaction_list_totals (tl,
-                                         &spent,
-                                         &spent))
-  {
-    TEH_plugin->rollback (TEH_plugin->cls,
-                          session);
-    TEH_plugin->free_coin_transaction_list (TEH_plugin->cls,
-                                            tl);
-    return TEH_RESPONSE_reply_internal_db_error (connection,
-                                                
TALER_EC_DEPOSIT_HISTORY_DB_ERROR);
-  }
-  /* Check that cost of all transactions is smaller than
-     the value of the coin. */
-  if (0 < TALER_amount_cmp (&spent,
-                            &value))
-  {
-    TEH_plugin->rollback (TEH_plugin->cls,
-                          session);
-    ret = TEH_RESPONSE_reply_coin_insufficient_funds (connection,
-                                                      
TALER_EC_DEPOSIT_INSUFFICIENT_FUNDS,
-                                                      tl);
-    TEH_plugin->free_coin_transaction_list (TEH_plugin->cls,
-                                            tl);
-    return ret;
-  }
-  TEH_plugin->free_coin_transaction_list (TEH_plugin->cls,
-                                          tl);
-  qs = TEH_plugin->insert_deposit (TEH_plugin->cls,
-                                  session,
-                                  deposit);
-  if (GNUNET_DB_STATUS_HARD_ERROR == qs)
-  {
-    TALER_LOG_WARNING ("Failed to store /deposit information in database\n");
-    TEH_plugin->rollback (TEH_plugin->cls,
-                          session);
-    return TEH_RESPONSE_reply_internal_db_error (connection,
-                                                
TALER_EC_DEPOSIT_STORE_DB_ERROR);
-  }
-  if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
-  {
-    retries++;
-    TEH_plugin->rollback (TEH_plugin->cls,
-                          session);
-    if (retries > 5)
-      return TEH_RESPONSE_reply_internal_db_error (connection,
-                                                  
TALER_EC_DEPOSIT_STORE_DB_ERROR);
-    goto again;
-  }
-
-  COMMIT_TRANSACTION(session, connection);
-  GNUNET_assert (GNUNET_SYSERR !=
-                 TALER_amount_subtract (&amount_without_fee,
-                                        &deposit->amount_with_fee,
-                                        &deposit->deposit_fee));
-  return TEH_RESPONSE_reply_deposit_success (connection,
-                                             &deposit->coin.coin_pub,
-                                             &deposit->h_wire,
-                                             &deposit->h_contract_terms,
-                                             deposit->timestamp,
-                                             deposit->refund_deadline,
-                                             &deposit->merchant_pub,
-                                             &amount_without_fee);
-}
-
-
-/**
  * Execute a "/refund".  Returns a confirmation that the refund
  * was successful, or a failure if we are not aware of a matching
  * /deposit or if it is too late to do the refund.
@@ -367,6 +300,7 @@ TEH_DB_execute_refund (struct MHD_Connection *connection,
   struct TEH_KS_StateHandle *mks;
   struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki;
   struct TALER_Amount expect_fee;
+  enum GNUNET_DB_QueryStatus qs;
   int ret;
   int deposit_found;
   int refund_found;
@@ -595,10 +529,10 @@ TEH_DB_execute_refund (struct MHD_Connection *connection,
                                           tl);
 
   /* Finally, store new refund data */
-  if (GNUNET_OK !=
-      TEH_plugin->insert_refund (TEH_plugin->cls,
-                                 session,
-                                 refund))
+  qs = TEH_plugin->insert_refund (TEH_plugin->cls,
+                                 session,
+                                 refund);
+  if (GNUNET_DB_STATUS_HARD_ERROR == qs)
   {
     TALER_LOG_WARNING ("Failed to store /refund information in database\n");
     TEH_plugin->rollback (TEH_plugin->cls,
@@ -606,6 +540,11 @@ TEH_DB_execute_refund (struct MHD_Connection *connection,
     return TEH_RESPONSE_reply_internal_db_error (connection,
                                                 
TALER_EC_REFUND_STORE_DB_ERROR);
   }
+  if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+  {
+    /* FIXME: #5010: retry! */
+  }
+  
   COMMIT_TRANSACTION (session, connection);
 
   return TEH_RESPONSE_reply_refund_success (connection,
@@ -1043,9 +982,9 @@ refresh_check_melt (struct MHD_Connection *connection,
                                           session,
                                           &coin_details->coin_info.coin_pub);
   if (GNUNET_OK !=
-      calculate_transaction_list_totals (tl,
-                                         &spent,
-                                         &spent))
+      TEH_DB_calculate_transaction_list_totals (tl,
+                                               &spent,
+                                               &spent))
   {
     GNUNET_break (0);
     TEH_plugin->free_coin_transaction_list (TEH_plugin->cls,
@@ -2403,9 +2342,9 @@ TEH_DB_execute_payback (struct MHD_Connection *connection,
   TALER_amount_get_zero (value->currency,
                          &spent);
   if (GNUNET_OK !=
-      calculate_transaction_list_totals (tl,
-                                         &spent,
-                                         &spent))
+      TEH_DB_calculate_transaction_list_totals (tl,
+                                               &spent,
+                                               &spent))
   {
     GNUNET_break (0);
     TEH_plugin->rollback (TEH_plugin->cls,
diff --git a/src/exchange/taler-exchange-httpd_db.h 
b/src/exchange/taler-exchange-httpd_db.h
index 55faafa..6d0b7e3 100644
--- a/src/exchange/taler-exchange-httpd_db.h
+++ b/src/exchange/taler-exchange-httpd_db.h
@@ -24,20 +24,63 @@
 #include <microhttpd.h>
 #include "taler_exchangedb_plugin.h"
 
+/**
+ * Function implementing a database transaction.  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 closure
+ * @param connection MHD request which triggered the transaction
+ * @param session database session to use
+ * @param[out] mhd_ret set to MHD response status for @a connection,
+ *             if transaction failed (!)
+ * @return transaction status
+ */
+typedef enum GNUNET_DB_QueryStatus
+(*TEH_DB_TransactionCallback)(void *cls,
+                             struct MHD_Connection *connection,
+                             struct TALER_EXCHANGEDB_Session *session,
+                             int *mhd_ret);
+
 
 /**
- * Execute a "/deposit".  The validity of the coin and signature
- * have already been checked.  The database must now check that
- * the coin is not (double or over) spent, and execute the
- * transaction (record details, generate success or failure response).
+ * Run a database transaction for @a connection.
+ * Starts a transaction and calls @a cb.  Upon success,
+ * attempts to commit the transaction.  Upon soft failures,
+ * retries @a cb a few times.  Upon hard or persistent soft
+ * errors, generates an error message for @a connection.
+ * 
+ * @param connection MHD connection to run @a cb for
+ * @param[out] set to MHD response code, if transaction failed
+ * @param cb callback implementing transaction logic
+ * @param cb_cls closure for @a cb, must be read-only!
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
+ */
+int
+TEH_DB_run_transaction (struct MHD_Connection *connection,
+                       int *mhd_ret,
+                       TEH_DB_TransactionCallback cb,
+                       void *cb_cls);
+
+
+/**
+ * Calculate the total value of all transactions performed.
+ * Stores @a off plus the cost of all transactions in @a tl
+ * in @a ret.
  *
- * @param connection the MHD connection to handle
- * @param deposit information about the deposit
- * @return MHD result code
+ * @param tl transaction list to process
+ * @param off offset to use as the starting value
+ * @param[out] ret where the resulting total is to be stored
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on errors
  */
+// FIXME: maybe move to another module?
 int
-TEH_DB_execute_deposit (struct MHD_Connection *connection,
-                        const struct TALER_EXCHANGEDB_Deposit *deposit);
+TEH_DB_calculate_transaction_list_totals (struct 
TALER_EXCHANGEDB_TransactionList *tl,
+                                         const struct TALER_Amount *off,
+                                         struct TALER_Amount *ret);
 
 
 /**
diff --git a/src/exchange/taler-exchange-httpd_deposit.c 
b/src/exchange/taler-exchange-httpd_deposit.c
index 85504d8..d732edb 100644
--- a/src/exchange/taler-exchange-httpd_deposit.c
+++ b/src/exchange/taler-exchange-httpd_deposit.c
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  Copyright (C) 2014, 2015, 2016 Inria and GNUnet e.V.
+  Copyright (C) 2014-2017 Inria and GNUnet e.V.
 
   TALER is free software; you can redistribute it and/or modify it under the
   terms of the GNU Affero General Public License as published by the Free 
Software
@@ -37,6 +37,174 @@
 
 
 /**
+ * Send confirmation of deposit success to client.  This function
+ * will create a signed message affirming the given information
+ * and return it to the client.  By this, the exchange affirms that
+ * the coin had sufficient (residual) value for the specified
+ * transaction and that it will execute the requested deposit
+ * operation with the given wiring details.
+ *
+ * @param connection connection to the client
+ * @param coin_pub public key of the coin
+ * @param h_wire hash of wire details
+ * @param h_contract_terms hash of contract details
+ * @param timestamp client's timestamp
+ * @param refund_deadline until when this deposit be refunded
+ * @param merchant merchant public key
+ * @param amount_without_fee fraction of coin value to deposit, without the fee
+ * @return MHD result code
+ */
+static int
+reply_deposit_success (struct MHD_Connection *connection,
+                      const struct TALER_CoinSpendPublicKeyP *coin_pub,
+                      const struct GNUNET_HashCode *h_wire,
+                      const struct GNUNET_HashCode *h_contract_terms,
+                      struct GNUNET_TIME_Absolute timestamp,
+                      struct GNUNET_TIME_Absolute refund_deadline,
+                      const struct TALER_MerchantPublicKeyP *merchant,
+                      const struct TALER_Amount *amount_without_fee)
+{
+  struct TALER_DepositConfirmationPS dc;
+  struct TALER_ExchangePublicKeyP pub;
+  struct TALER_ExchangeSignatureP sig;
+
+  dc.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_DEPOSIT);
+  dc.purpose.size = htonl (sizeof (struct TALER_DepositConfirmationPS));
+  dc.h_contract_terms = *h_contract_terms;
+  dc.h_wire = *h_wire;
+  dc.timestamp = GNUNET_TIME_absolute_hton (timestamp);
+  dc.refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline);
+  TALER_amount_hton (&dc.amount_without_fee,
+                     amount_without_fee);
+  dc.coin_pub = *coin_pub;
+  dc.merchant = *merchant;
+  TEH_KS_sign (&dc.purpose,
+               &pub,
+               &sig);
+  return TEH_RESPONSE_reply_json_pack (connection,
+                                       MHD_HTTP_OK,
+                                       "{s:s, s:o, s:o}",
+                                       "status", "DEPOSIT_OK",
+                                       "sig", GNUNET_JSON_from_data_auto 
(&sig),
+                                       "pub", GNUNET_JSON_from_data_auto 
(&pub));
+}
+
+
+/**
+ * Closure for #deposit_transaction.
+ */
+struct DepositContext
+{
+  /**
+   * Information about the deposit request.
+   */
+  const struct TALER_EXCHANGEDB_Deposit *deposit;
+
+  /**
+   * Value of the coin.
+   */
+  struct TALER_Amount value;
+  
+};
+
+
+/**
+ * Execute database transaction for /deposit.  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 DepositContext`
+ * @param connection MHD request context
+ * @param session database session and transaction to use
+ * @param[out] mhd_ret set to MHD status on error
+ * @return transaction status
+ */
+static enum GNUNET_DB_QueryStatus
+deposit_transaction (void *cls,
+                    struct MHD_Connection *connection,
+                    struct TALER_EXCHANGEDB_Session *session,
+                    int *mhd_ret)
+{
+  struct DepositContext *dc = cls;
+  const struct TALER_EXCHANGEDB_Deposit *deposit = dc->deposit;
+  struct TALER_EXCHANGEDB_TransactionList *tl;
+  struct TALER_Amount spent;
+  enum GNUNET_DB_QueryStatus qs;
+  
+  qs = TEH_plugin->have_deposit (TEH_plugin->cls,
+                                session,
+                                deposit);
+  if (qs < 0)
+    return qs;
+  if (1 == qs)
+  {
+    struct TALER_Amount amount_without_fee;
+
+    GNUNET_assert (GNUNET_OK ==
+                   TALER_amount_subtract (&amount_without_fee,
+                                          &deposit->amount_with_fee,
+                                          &deposit->deposit_fee));
+    *mhd_ret = reply_deposit_success (connection,
+                                     &deposit->coin.coin_pub,
+                                     &deposit->h_wire,
+                                     &deposit->h_contract_terms,
+                                     deposit->timestamp,
+                                     deposit->refund_deadline,
+                                     &deposit->merchant_pub,
+                                     &amount_without_fee);
+    /* Treat as 'hard' DB error as we want to rollback and
+       never try again. */
+    return GNUNET_DB_STATUS_HARD_ERROR;
+  }
+
+  /* Start with fee for THIS transaction */
+  spent = deposit->amount_with_fee;
+  /* add cost of all previous transactions */
+  tl = TEH_plugin->get_coin_transactions (TEH_plugin->cls,
+                                          session,
+                                          &deposit->coin.coin_pub);
+  if (GNUNET_OK !=
+      TEH_DB_calculate_transaction_list_totals (tl,
+                                               &spent,
+                                               &spent))
+  {
+    TEH_plugin->free_coin_transaction_list (TEH_plugin->cls,
+                                            tl);
+    *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection,
+                                                    
TALER_EC_DEPOSIT_HISTORY_DB_ERROR);
+    return GNUNET_DB_STATUS_HARD_ERROR;
+  }
+  /* Check that cost of all transactions is smaller than
+     the value of the coin. */
+  if (0 < TALER_amount_cmp (&spent,
+                            &dc->value))
+  {
+    *mhd_ret = TEH_RESPONSE_reply_coin_insufficient_funds (connection,
+                                                          
TALER_EC_DEPOSIT_INSUFFICIENT_FUNDS,
+                                                          tl);
+    TEH_plugin->free_coin_transaction_list (TEH_plugin->cls,
+                                            tl);
+    return GNUNET_DB_STATUS_HARD_ERROR;
+  }
+  TEH_plugin->free_coin_transaction_list (TEH_plugin->cls,
+                                          tl);
+  qs = TEH_plugin->insert_deposit (TEH_plugin->cls,
+                                  session,
+                                  deposit);
+  if (GNUNET_DB_STATUS_HARD_ERROR == qs)
+  {
+    TALER_LOG_WARNING ("Failed to store /deposit information in database\n");
+    *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection,
+                                                    
TALER_EC_DEPOSIT_STORE_DB_ERROR);
+  }
+  return qs;
+}
+
+
+/**
  * We have parsed the JSON information about the deposit, do some
  * basic sanity checks (especially that the signature on the coin is
  * valid, and that this type of coin exists) and then execute the
@@ -51,7 +219,13 @@ verify_and_execute_deposit (struct MHD_Connection 
*connection,
                            const struct TALER_EXCHANGEDB_Deposit *deposit)
 {
   struct TALER_DepositRequestPS dr;
+  int mhd_ret;
+  struct TALER_Amount amount_without_fee;
+  struct DepositContext dc;
+  struct TEH_KS_StateHandle *mks;
+  struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki;
 
+  /* check signature */
   dr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT);
   dr.purpose.size = htonl (sizeof (struct TALER_DepositRequestPS));
   dr.h_contract_terms = deposit->h_contract_terms;
@@ -76,8 +250,43 @@ verify_and_execute_deposit (struct MHD_Connection 
*connection,
                                                  "coin_sig");
   }
 
-  return TEH_DB_execute_deposit (connection,
-                                 deposit);
+  /* check denomination */
+  mks = TEH_KS_acquire ();
+  dki = TEH_KS_denomination_key_lookup (mks,
+                                        &deposit->coin.denom_pub,
+                                       TEH_KS_DKU_DEPOSIT);
+  if (NULL == dki)
+  {
+    TEH_KS_release (mks);
+    return TEH_RESPONSE_reply_internal_db_error (connection,
+                                                
TALER_EC_DEPOSIT_DB_DENOMINATION_KEY_UNKNOWN);
+  }
+  TALER_amount_ntoh (&dc.value,
+                     &dki->issue.properties.value);
+  TEH_KS_release (mks);
+
+  /* execute transaction */
+  dc.deposit = deposit;
+  if (GNUNET_OK !=
+      TEH_DB_run_transaction (connection,
+                             &mhd_ret,
+                             &deposit_transaction,
+                             &dc))
+    return mhd_ret;
+
+  /* generate regular response */
+  GNUNET_assert (GNUNET_SYSERR !=
+                 TALER_amount_subtract (&amount_without_fee,
+                                        &deposit->amount_with_fee,
+                                        &deposit->deposit_fee));
+  return reply_deposit_success (connection,
+                               &deposit->coin.coin_pub,
+                               &deposit->h_wire,
+                               &deposit->h_contract_terms,
+                               deposit->timestamp,
+                               deposit->refund_deadline,
+                               &deposit->merchant_pub,
+                               &amount_without_fee);
 }
 
 
diff --git a/src/exchange/taler-exchange-httpd_responses.c 
b/src/exchange/taler-exchange-httpd_responses.c
index 01b5606..771b8ad 100644
--- a/src/exchange/taler-exchange-httpd_responses.c
+++ b/src/exchange/taler-exchange-httpd_responses.c
@@ -462,60 +462,6 @@ TEH_RESPONSE_reply_invalid_json (struct MHD_Connection 
*connection)
 
 
 /**
- * Send confirmation of deposit success to client.  This function
- * will create a signed message affirming the given information
- * and return it to the client.  By this, the exchange affirms that
- * the coin had sufficient (residual) value for the specified
- * transaction and that it will execute the requested deposit
- * operation with the given wiring details.
- *
- * @param connection connection to the client
- * @param coin_pub public key of the coin
- * @param h_wire hash of wire details
- * @param h_contract_terms hash of contract details
- * @param timestamp client's timestamp
- * @param refund_deadline until when this deposit be refunded
- * @param merchant merchant public key
- * @param amount_without_fee fraction of coin value to deposit, without the fee
- * @return MHD result code
- */
-int
-TEH_RESPONSE_reply_deposit_success (struct MHD_Connection *connection,
-                                    const struct TALER_CoinSpendPublicKeyP 
*coin_pub,
-                                    const struct GNUNET_HashCode *h_wire,
-                                    const struct GNUNET_HashCode 
*h_contract_terms,
-                                    struct GNUNET_TIME_Absolute timestamp,
-                                    struct GNUNET_TIME_Absolute 
refund_deadline,
-                                    const struct TALER_MerchantPublicKeyP 
*merchant,
-                                    const struct TALER_Amount 
*amount_without_fee)
-{
-  struct TALER_DepositConfirmationPS dc;
-  struct TALER_ExchangePublicKeyP pub;
-  struct TALER_ExchangeSignatureP sig;
-
-  dc.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_DEPOSIT);
-  dc.purpose.size = htonl (sizeof (struct TALER_DepositConfirmationPS));
-  dc.h_contract_terms = *h_contract_terms;
-  dc.h_wire = *h_wire;
-  dc.timestamp = GNUNET_TIME_absolute_hton (timestamp);
-  dc.refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline);
-  TALER_amount_hton (&dc.amount_without_fee,
-                     amount_without_fee);
-  dc.coin_pub = *coin_pub;
-  dc.merchant = *merchant;
-  TEH_KS_sign (&dc.purpose,
-               &pub,
-               &sig);
-  return TEH_RESPONSE_reply_json_pack (connection,
-                                       MHD_HTTP_OK,
-                                       "{s:s, s:o, s:o}",
-                                       "status", "DEPOSIT_OK",
-                                       "sig", GNUNET_JSON_from_data_auto 
(&sig),
-                                       "pub", GNUNET_JSON_from_data_auto 
(&pub));
-}
-
-
-/**
  * Compile the transaction history of a coin into a JSON object.
  *
  * @param tl transaction history to JSON-ify
diff --git a/src/exchange/taler-exchange-httpd_responses.h 
b/src/exchange/taler-exchange-httpd_responses.h
index 6a33b65..047bb4f 100644
--- a/src/exchange/taler-exchange-httpd_responses.h
+++ b/src/exchange/taler-exchange-httpd_responses.h
@@ -244,35 +244,6 @@ TEH_RESPONSE_reply_invalid_json (struct MHD_Connection 
*connectionx);
 
 
 /**
- * Send confirmation of deposit success to client. This function
- * will create a signed message affirming the given information
- * and return it to the client.  By this, the exchange affirms that
- * the coin had sufficient (residual) value for the specified
- * transaction and that it will execute the requested deposit
- * operation with the given wiring details.
- *
- * @param connection connection to the client
- * @param coin_pub public key of the coin
- * @param h_wire hash of wire details
- * @param h_contract_terms hash of proposal data
- * @param timestamp client's timestamp
- * @param refund_deadline until when this deposit be refunded
- * @param merchant merchant public key
- * @param amount_without_fee fraction of coin value to deposit (without fee)
- * @return MHD result code
- */
-int
-TEH_RESPONSE_reply_deposit_success (struct MHD_Connection *connection,
-                                    const struct TALER_CoinSpendPublicKeyP 
*coin_pub,
-                                    const struct GNUNET_HashCode *h_wire,
-                                    const struct GNUNET_HashCode 
*h_contract_terms,
-                                    struct GNUNET_TIME_Absolute timestamp,
-                                    struct GNUNET_TIME_Absolute 
refund_deadline,
-                                    const struct TALER_MerchantPublicKeyP 
*merchant,
-                                    const struct TALER_Amount 
*amount_without_fee);
-
-
-/**
  * Send proof that a request is invalid to client because of
  * insufficient funds.  This function will create a message with all
  * of the operations affecting the coin that demonstrate that the coin
diff --git a/src/exchangedb/perf_taler_exchangedb_interpreter.c 
b/src/exchangedb/perf_taler_exchangedb_interpreter.c
index e378fc9..054df58 100644
--- a/src/exchangedb/perf_taler_exchangedb_interpreter.c
+++ b/src/exchangedb/perf_taler_exchangedb_interpreter.c
@@ -1350,7 +1350,7 @@ interpret (struct PERF_TALER_EXCHANGEDB_interpreter_state 
*state)
       case PERF_TALER_EXCHANGEDB_CMD_GET_DEPOSIT:
         {
           unsigned int source_index;
-          int ret;
+          enum GNUNET_DB_QueryStatus ret;
           struct PERF_TALER_EXCHANGEDB_Data *data;
 
           source_index = 
state->cmd[state->i].details.get_deposit.index_deposit;
@@ -1358,7 +1358,7 @@ interpret (struct PERF_TALER_EXCHANGEDB_interpreter_state 
*state)
           ret = state->plugin->have_deposit (state->plugin->cls,
                                              state->session,
                                              data->data.deposit);
-          GNUNET_assert (GNUNET_SYSERR != ret);
+          GNUNET_assert (0 >= ret);
         }
         break;
 
diff --git a/src/exchangedb/plugin_exchangedb_postgres.c 
b/src/exchangedb/plugin_exchangedb_postgres.c
index d56afed..954fca3 100644
--- a/src/exchangedb/plugin_exchangedb_postgres.c
+++ b/src/exchangedb/plugin_exchangedb_postgres.c
@@ -2698,11 +2698,11 @@ postgres_get_reserve_history (void *cls,
  * @param cls the `struct PostgresClosure` with the plugin-specific state
  * @param session database connection
  * @param deposit deposit to search for
- * @return #GNUNET_YES if we know this operation,
- *         #GNUNET_NO if this exact deposit is unknown to us
- *         #GNUNET_SYSERR on DB error
+ * @return 1 if we know this operation,
+ *         0 if this exact deposit is unknown to us,
+ *         otherwise transaction error status
  */
-static int
+static enum GNUNET_DB_QueryStatus
 postgres_have_deposit (void *cls,
                        struct TALER_EXCHANGEDB_Session *session,
                        const struct TALER_EXCHANGEDB_Deposit *deposit)
@@ -2713,75 +2713,52 @@ postgres_have_deposit (void *cls,
     GNUNET_PQ_query_param_auto_from_type (&deposit->merchant_pub),
     GNUNET_PQ_query_param_end
   };
-  PGresult *result;
-
-  result = GNUNET_PQ_exec_prepared (session->conn,
-                                   "get_deposit",
-                                   params);
-  if (PGRES_TUPLES_OK !=
-      PQresultStatus (result))
-  {
-    BREAK_DB_ERR (result, session->conn);
-    PQclear (result);
-    return GNUNET_SYSERR;
-  }
-  if (0 == PQntuples (result))
-  {
-    PQclear (result);
-    return GNUNET_NO;
-  }
+  struct TALER_EXCHANGEDB_Deposit deposit2;
+  struct GNUNET_PQ_ResultSpec rs[] = {
+    TALER_PQ_result_spec_amount ("amount_with_fee",
+                                &deposit2.amount_with_fee),
+    GNUNET_PQ_result_spec_absolute_time ("timestamp",
+                                        &deposit2.timestamp),
+    GNUNET_PQ_result_spec_absolute_time ("refund_deadline",
+                                        &deposit2.refund_deadline),
+    GNUNET_PQ_result_spec_absolute_time ("wire_deadline",
+                                        &deposit2.wire_deadline),
+    GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms",
+                                         &deposit2.h_contract_terms),
+    GNUNET_PQ_result_spec_auto_from_type ("h_wire",
+                                         &deposit2.h_wire),
+    GNUNET_PQ_result_spec_end
+  };
+  enum GNUNET_DB_QueryStatus qs;
 
+  qs = GNUNET_PQ_eval_prepared_singleton_select (session->conn,
+                                                "get_deposit",
+                                                params,
+                                                rs);
+  if (0 >= qs)
+    return qs;
   /* Now we check that the other information in @a deposit
      also matches, and if not report inconsistencies. */
-  {
-    struct TALER_EXCHANGEDB_Deposit deposit2;
-    struct GNUNET_PQ_ResultSpec rs[] = {
-      TALER_PQ_result_spec_amount ("amount_with_fee",
-                                   &deposit2.amount_with_fee),
-      GNUNET_PQ_result_spec_absolute_time ("timestamp",
-                                          &deposit2.timestamp),
-      GNUNET_PQ_result_spec_absolute_time ("refund_deadline",
-                                          &deposit2.refund_deadline),
-      GNUNET_PQ_result_spec_absolute_time ("wire_deadline",
-                                          &deposit2.wire_deadline),
-      GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms",
-                                           &deposit2.h_contract_terms),
-      GNUNET_PQ_result_spec_auto_from_type ("h_wire",
-                                           &deposit2.h_wire),
-      GNUNET_PQ_result_spec_end
-    };
-    if (GNUNET_OK !=
-        GNUNET_PQ_extract_result (result,
-                                  rs,
-                                  0))
-    {
-      GNUNET_break (0);
-      PQclear (result);
-      return GNUNET_SYSERR;
-    }
-    if ( (0 != TALER_amount_cmp (&deposit->amount_with_fee,
-                                 &deposit2.amount_with_fee)) ||
-         (deposit->timestamp.abs_value_us !=
-          deposit2.timestamp.abs_value_us) ||
-         (deposit->refund_deadline.abs_value_us !=
-          deposit2.refund_deadline.abs_value_us) ||
-         (0 != memcmp (&deposit->h_contract_terms,
-                       &deposit2.h_contract_terms,
-                       sizeof (struct GNUNET_HashCode))) ||
-         (0 != memcmp (&deposit->h_wire,
-                       &deposit2.h_wire,
-                       sizeof (struct GNUNET_HashCode))) )
-    {
-      /* Inconsistencies detected! Does not match!  (We might want to
-         expand the API with a 'get_deposit' function to return the
-         original transaction details to be used for an error message
-         in the future!) #3838 */
-      PQclear (result);
-      return GNUNET_NO;
-    }
-  }
-  PQclear (result);
-  return GNUNET_YES;
+  if ( (0 != TALER_amount_cmp (&deposit->amount_with_fee,
+                              &deposit2.amount_with_fee)) ||
+       (deposit->timestamp.abs_value_us !=
+       deposit2.timestamp.abs_value_us) ||
+       (deposit->refund_deadline.abs_value_us !=
+       deposit2.refund_deadline.abs_value_us) ||
+       (0 != memcmp (&deposit->h_contract_terms,
+                    &deposit2.h_contract_terms,
+                    sizeof (struct GNUNET_HashCode))) ||
+       (0 != memcmp (&deposit->h_wire,
+                    &deposit2.h_wire,
+                    sizeof (struct GNUNET_HashCode))) )
+  {
+    /* Inconsistencies detected! Does not match!  (We might want to
+       expand the API with a 'get_deposit' function to return the
+       original transaction details to be used for an error message
+       in the future!) #3838 */
+    return 0; /* Counts as if the transaction was not there */
+  }
+  return 1;
 }
 
 
@@ -3267,11 +3244,9 @@ postgres_insert_deposit (void *cls,
  * @param cls the @e cls of this struct with the plugin-specific state
  * @param session connection to the database
  * @param refund refund information to store
- * @return #GNUNET_OK on success
- *         #GNUNET_NO on transient error
- *         #GNUNET_SYSERR on error
+ * @return query result status
  */
-static int
+static enum GNUNET_DB_QueryStatus
 postgres_insert_refund (void *cls,
                         struct TALER_EXCHANGEDB_Session *session,
                         const struct TALER_EXCHANGEDB_Refund *refund)
@@ -3289,9 +3264,9 @@ postgres_insert_refund (void *cls,
   GNUNET_assert (GNUNET_YES ==
                  TALER_amount_cmp_currency (&refund->refund_amount,
                                             &refund->refund_fee));
-  return execute_prepared_non_select (session,
-                                      "insert_refund",
-                                      params);
+  return GNUNET_PQ_eval_prepared_non_select (session->conn,
+                                            "insert_refund",
+                                            params);
 }
 
 
diff --git a/src/exchangedb/test_exchangedb.c b/src/exchangedb/test_exchangedb.c
index 319b4dc..ba47c2d 100644
--- a/src/exchangedb/test_exchangedb.c
+++ b/src/exchangedb/test_exchangedb.c
@@ -1772,7 +1772,7 @@ run (void *cls)
           plugin->insert_deposit (plugin->cls,
                                   session,
                                   &deposit));
-  FAILIF (GNUNET_YES !=
+  FAILIF (1 !=
           plugin->have_deposit (plugin->cls,
                                 session,
                                 &deposit));
@@ -1839,13 +1839,13 @@ run (void *cls)
   result = 10;
   deposit2 = deposit;
   RND_BLK (&deposit2.merchant_pub); /* should fail if merchant is different */
-  FAILIF (GNUNET_NO !=
+  FAILIF (0 !=
           plugin->have_deposit (plugin->cls,
                                 session,
                                 &deposit2));
   deposit2.merchant_pub = deposit.merchant_pub;
   RND_BLK (&deposit2.coin.coin_pub); /* should fail if coin is different */
-  FAILIF (GNUNET_NO !=
+  FAILIF (0 !=
           plugin->have_deposit (plugin->cls,
                                 session,
                                 &deposit2));
@@ -1860,7 +1860,7 @@ run (void *cls)
   refund.rtransaction_id = GNUNET_CRYPTO_random_u64 
(GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
   refund.refund_amount = deposit.amount_with_fee;
   refund.refund_fee = fee_refund;
-  FAILIF (GNUNET_OK !=
+  FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
           plugin->insert_refund (plugin->cls,
                                  session,
                                  &refund));
diff --git a/src/include/taler_exchangedb_plugin.h 
b/src/include/taler_exchangedb_plugin.h
index b5eaeea..2cf553b 100644
--- a/src/include/taler_exchangedb_plugin.h
+++ b/src/include/taler_exchangedb_plugin.h
@@ -1293,11 +1293,11 @@ struct TALER_EXCHANGEDB_Plugin
    * @param cls the @e cls of this struct with the plugin-specific state
    * @param session database connection
    * @param deposit deposit to search for
-   * @return #GNUNET_YES if we know this operation,
-   *         #GNUNET_NO if this exact deposit is unknown to us,
-   *         #GNUNET_SYSERR on DB error
+   * @return 1 if we know this operation,
+   *         0 if this exact deposit is unknown to us,
+   *         otherwise transaction error status
    */
-  int
+  enum GNUNET_DB_QueryStatus
   (*have_deposit) (void *cls,
                    struct TALER_EXCHANGEDB_Session *session,
                    const struct TALER_EXCHANGEDB_Deposit *deposit);
@@ -1323,11 +1323,9 @@ struct TALER_EXCHANGEDB_Plugin
    * @param cls the @e cls of this struct with the plugin-specific state
    * @param session connection to the database
    * @param refund refund information to store
-   * @return #GNUNET_OK on success,
-   *         #GNUNET_NO on transient error
-   *         #GNUNET_SYSERR on error
+   * @return query result status
    */
-  int
+  enum GNUNET_DB_QueryStatus
   (*insert_refund) (void *cls,
                     struct TALER_EXCHANGEDB_Session *session,
                     const struct TALER_EXCHANGEDB_Refund *refund);

-- 
To stop receiving notification emails like this one, please contact
address@hidden



reply via email to

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