gnunet-svn
[Top][All Lists]
Advanced

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

[GNUnet-SVN] [taler-exchange] 01/02: fixing #5010 for /refresh/reveal


From: gnunet
Subject: [GNUnet-SVN] [taler-exchange] 01/02: fixing #5010 for /refresh/reveal
Date: Tue, 20 Jun 2017 23:20:55 +0200

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

grothoff pushed a commit to branch master
in repository exchange.

commit 053096475fdb1d6d81aa87bce36f1aceb6264038
Author: Christian Grothoff <address@hidden>
AuthorDate: Tue Jun 20 22:30:15 2017 +0200

    fixing #5010 for /refresh/reveal
---
 src/exchange/taler-exchange-httpd_refresh_melt.c   |  22 +-
 src/exchange/taler-exchange-httpd_refresh_reveal.c | 674 ++++++++++-----------
 src/exchangedb/plugin_exchangedb_postgres.c        | 333 ++++------
 src/exchangedb/test_exchangedb.c                   |  45 +-
 src/include/taler_exchangedb_plugin.h              |  33 +-
 5 files changed, 451 insertions(+), 656 deletions(-)

diff --git a/src/exchange/taler-exchange-httpd_refresh_melt.c 
b/src/exchange/taler-exchange-httpd_refresh_melt.c
index 1c4e5e8..1b7e679 100644
--- a/src/exchange/taler-exchange-httpd_refresh_melt.c
+++ b/src/exchange/taler-exchange-httpd_refresh_melt.c
@@ -500,7 +500,6 @@ handle_refresh_melt_binary (struct MHD_Connection 
*connection,
                             struct TALER_EXCHANGEDB_RefreshCommitCoin *const* 
commit_coin,
                             const struct TALER_TransferPublicKeyP 
*transfer_pubs)
 {
-  unsigned int i;
   struct TEH_KS_StateHandle *key_state;
   struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dk;
   struct TALER_EXCHANGEDB_DenominationKeyInformationP *dki;
@@ -519,7 +518,7 @@ handle_refresh_melt_binary (struct MHD_Connection 
*connection,
                  TALER_amount_get_zero (TEH_exchange_currency_string,
                                         &total_cost));
   key_state = TEH_KS_acquire ();
-  for (i=0;i<num_new_denoms;i++)
+  for (unsigned int i=0;i<num_new_denoms;i++)
   {
     dk = TEH_KS_denomination_key_lookup (key_state,
                                          &denom_pubs[i],
@@ -754,14 +753,11 @@ free_commit_coins (struct 
TALER_EXCHANGEDB_RefreshCommitCoin **commit_coin,
                    unsigned int kappa,
                    unsigned int num_new_coins)
 {
-  unsigned int i;
-  unsigned int j;
-
-  for (i=0;i<kappa;i++)
+  for (unsigned int i=0;i<kappa;i++)
   {
     if (NULL == commit_coin[i])
       break;
-    for (j=0;j<num_new_coins;j++)
+    for (unsigned int j=0;j<num_new_coins;j++)
       GNUNET_free_non_null (commit_coin[i][j].coin_ev);
     GNUNET_free (commit_coin[i]);
   }
@@ -790,8 +786,6 @@ handle_refresh_melt_json (struct MHD_Connection *connection,
                           const json_t *coin_evs)
 {
   int res;
-  unsigned int i;
-  unsigned int j;
   struct TALER_DenominationPublicKey *denom_pubs;
   unsigned int num_newcoins;
   struct TEH_DB_MeltDetails coin_melt_details;
@@ -804,7 +798,7 @@ handle_refresh_melt_json (struct MHD_Connection *connection,
      (except for the signatures on the coins). */
   hash_context = GNUNET_CRYPTO_hash_context_start ();
 
-  for (i = 0; i < TALER_CNC_KAPPA; i++)
+  for (unsigned int i = 0; i < TALER_CNC_KAPPA; i++)
   {
     struct GNUNET_JSON_Specification trans_spec[] = {
       GNUNET_JSON_spec_fixed_auto (NULL, &transfer_pub[i]),
@@ -830,7 +824,7 @@ handle_refresh_melt_json (struct MHD_Connection *connection,
   num_newcoins = json_array_size (new_denoms);
   denom_pubs = GNUNET_new_array (num_newcoins,
                                  struct TALER_DenominationPublicKey);
-  for (i=0;i<num_newcoins;i++)
+  for (unsigned int i=0;i<num_newcoins;i++)
   {
     char *buf;
     size_t buf_size;
@@ -885,11 +879,11 @@ handle_refresh_melt_json (struct MHD_Connection 
*connection,
   memset (commit_coin,
           0,
           sizeof (commit_coin));
-  for (i = 0; i < TALER_CNC_KAPPA; i++)
+  for (unsigned int i = 0; i < TALER_CNC_KAPPA; i++)
   {
     commit_coin[i] = GNUNET_new_array (num_newcoins,
                                        struct 
TALER_EXCHANGEDB_RefreshCommitCoin);
-    for (j = 0; j < num_newcoins; j++)
+    for (unsigned int j = 0; j < num_newcoins; j++)
     {
       struct TALER_EXCHANGEDB_RefreshCommitCoin *rcc = &commit_coin[i][j];
       struct GNUNET_JSON_Specification coin_spec[] = {
@@ -950,7 +944,7 @@ handle_refresh_melt_json (struct MHD_Connection *connection,
  cleanup_denoms:
   if (NULL != denom_pubs)
   {
-    for (j=0;j<num_newcoins;j++)
+    for (unsigned int j=0;j<num_newcoins;j++)
       if (NULL != denom_pubs[j].rsa_public_key)
         GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j].rsa_public_key);
     GNUNET_free (denom_pubs);
diff --git a/src/exchange/taler-exchange-httpd_refresh_reveal.c 
b/src/exchange/taler-exchange-httpd_refresh_reveal.c
index 05422a8..cfb2b68 100644
--- a/src/exchange/taler-exchange-httpd_refresh_reveal.c
+++ b/src/exchange/taler-exchange-httpd_refresh_reveal.c
@@ -32,95 +32,6 @@
 
 
 /**
- * How often should we retry a transaction before giving up
- * (for transactions resulting in serialization/dead locks only).
- */
-#define MAX_TRANSACTION_COMMIT_RETRIES 3
-
-/**
- * Code to begin a transaction, must be inline as we define a block
- * that ends with #COMMIT_TRANSACTION() within which we perform a number
- * of retries.  Note that this code may call "return" internally, so
- * it must be called within a function where any cleanup will be done
- * by the caller. Furthermore, the function's return value must
- * match that of a #TEH_RESPONSE_reply_internal_db_error() status code.
- *
- * @param session session handle
- * @param connection connection handle
- */
-#define START_TRANSACTION(session,connection)                 \
-{ /* start new scope, will be ended by COMMIT_TRANSACTION() */\
-  unsigned int transaction_retries = 0;                       \
-  enum GNUNET_DB_QueryStatus transaction_commit_result;       \
-transaction_start_label: /* we will use goto for retries */   \
-  if (GNUNET_OK !=                                            \
-      TEH_plugin->start (TEH_plugin->cls,                     \
-                         session))                            \
-  {                                                           \
-    GNUNET_break (0);                                         \
-    return TEH_RESPONSE_reply_internal_db_error (connection, \
-                                                TALER_EC_DB_START_FAILED);     
     \
-  }
-
-/**
- * Code to conclude a transaction, dual to #START_TRANSACTION().  Note
- * that this code may call "return" internally, so it must be called
- * within a function where any cleanup will be done by the caller.
- * Furthermore, the function's return value must match that of a
- * #TEH_RESPONSE_reply_internal_db_error() status code.
- *
- * @param session session handle
- * @param connection connection handle
- */
-#define COMMIT_TRANSACTION(session,connection)                             \
-  transaction_commit_result =                                              \
-    TEH_plugin->commit (TEH_plugin->cls,                                   \
-                        session);                                          \
-  if (GNUNET_DB_STATUS_HARD_ERROR == transaction_commit_result)            \
-  {                                                                        \
-    TALER_LOG_WARNING ("Transaction commit failed in %s\n", __FUNCTION__); \
-    return TEH_RESPONSE_reply_commit_error (connection, \
-                                           TALER_EC_DB_COMMIT_FAILED_HARD); \
-  }                                                       \
-  if (GNUNET_DB_STATUS_SOFT_ERROR == transaction_commit_result)            \
-  {                                                                        \
-    TALER_LOG_WARNING ("Transaction commit failed in %s\n", __FUNCTION__); \
-    if (transaction_retries++ <= MAX_TRANSACTION_COMMIT_RETRIES)           \
-      goto transaction_start_label;                                        \
-    TALER_LOG_WARNING ("Transaction commit failed %u times in %s\n",       \
-                       transaction_retries,                                \
-                       __FUNCTION__);                                      \
-    return TEH_RESPONSE_reply_commit_error (connection, \
-                                           
TALER_EC_DB_COMMIT_FAILED_ON_RETRY);                                \
-  }                                                                        \
-} /* end of scope opened by BEGIN_TRANSACTION */
-
-
-/**
- * Code to include to retry a transaction, must only be used in between
- * #START_TRANSACTION and #COMMIT_TRANSACTION.
- *
- * @param session session handle
- * @param connection connection handle
- */
-#define RETRY_TRANSACTION(session,connection)                                  
  \
-  do {                                                                         
  \
-    TEH_plugin->rollback (TEH_plugin->cls,                                     
  \
-                          session);                                            
  \
-    if (transaction_retries++ <= MAX_TRANSACTION_COMMIT_RETRIES)               
  \
-      goto transaction_start_label;                                            
  \
-    TALER_LOG_WARNING ("Transaction commit failed %u times in %s\n",           
  \
-                       transaction_retries,                                    
  \
-                       __FUNCTION__);                                          
  \
-    return TEH_RESPONSE_reply_commit_error (connection,                        
  \
-                                           
TALER_EC_DB_COMMIT_FAILED_ON_RETRY); \
-  } while (0)
-
-
-
-
-
-/**
  * Send a response for "/refresh/reveal".
  *
  * @param connection the connection to send the response to
@@ -133,14 +44,15 @@ reply_refresh_reveal_success (struct MHD_Connection 
*connection,
                              unsigned int num_newcoins,
                              const struct TALER_DenominationSignature *sigs)
 {
-  int newcoin_index;
   json_t *root;
   json_t *obj;
   json_t *list;
   int ret;
 
   list = json_array ();
-  for (newcoin_index = 0; newcoin_index < num_newcoins; newcoin_index++)
+  for (unsigned int newcoin_index = 0;
+       newcoin_index < num_newcoins;
+       newcoin_index++)
   {
     obj = json_object ();
     json_object_set_new (obj,
@@ -182,11 +94,10 @@ reply_refresh_reveal_missmatch (struct MHD_Connection 
*connection,
 {
   json_t *info_new;
   json_t *info_commit_k;
-  unsigned int i;
 
   info_new = json_array ();
   info_commit_k = json_array ();
-  for (i=0;i<session->num_newcoins;i++)
+  for (unsigned int i=0;i<session->num_newcoins;i++)
   {
     const struct TALER_EXCHANGEDB_RefreshCommitCoin *cc;
     json_t *cc_json;
@@ -220,7 +131,6 @@ reply_refresh_reveal_missmatch (struct MHD_Connection 
*connection,
 }
 
 
-
 /**
  * Check if the given @a transfer_privs correspond to an honest
  * commitment for the given session.
@@ -253,14 +163,13 @@ check_commitment (struct MHD_Connection *connection,
                   struct GNUNET_HashContext *hash_context)
 {
   struct TALER_TransferSecretP transfer_secret;
-  unsigned int j;
 
   TALER_link_reveal_transfer_secret (transfer_priv,
                                      &melt->coin.coin_pub,
                                      &transfer_secret);
 
   /* Check that the commitments for all new coins were correct */
-  for (j = 0; j < num_newcoins; j++)
+  for (unsigned int j = 0; j < num_newcoins; j++)
   {
     struct TALER_FreshCoinP fc;
     struct TALER_CoinSpendPublicKeyP coin_pub;
@@ -301,6 +210,58 @@ check_commitment (struct MHD_Connection *connection,
 
 
 /**
+ * State for a /refresh/reveal operation.
+ */
+struct RevealContext
+{
+
+  /**
+   * Hash of the refresh session.
+   */
+  const struct GNUNET_HashCode *session_hash;
+
+  /**
+   * Database session used to execute the transaction.
+   */
+  struct TALER_EXCHANGEDB_Session *session;
+
+  /**
+   * Session state from the database.
+   */
+  struct TALER_EXCHANGEDB_RefreshSession refresh_session;
+
+  /**
+   * Array of denomination public keys used for the refresh.
+   */
+  struct TALER_DenominationPublicKey *denom_pubs;
+
+  /**
+   * Envelopes with the signatures to be returned.
+   */
+  struct TALER_DenominationSignature *ev_sigs;
+
+  /**
+   * Commitment data from the DB giving data about original
+   * commitments, in particular the blinded envelopes (for
+   * index gamma).
+   */
+  struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coins;
+
+  /**
+   * Transfer public key associated with the gamma value
+   * selected by the exchange.
+   */
+  struct TALER_TransferPublicKeyP gamma_tp;
+
+  /**
+   * Transfer private keys revealed to us.
+   */
+  struct TALER_TransferPrivateKeyP transfer_privs[TALER_CNC_KAPPA - 1];
+
+};
+
+
+/**
  * Exchange a coin as part of a refresh operation.  Obtains the
  * envelope from the database and performs the signing operation.
  *
@@ -311,19 +272,21 @@ check_commitment (struct MHD_Connection *connection,
  * @param denom_pub denomination key for the coin to create
  * @param commit_coin the coin that was committed
  * @param coin_off number of the coin
- * @return NULL on error, otherwise signature over the coin
+ * @param[out] ev_sig set to signature over the coin upon success
+ * @return database transaction status
  */
-static struct TALER_DenominationSignature
+static enum GNUNET_DB_QueryStatus
 refresh_exchange_coin (struct MHD_Connection *connection,
                        struct TALER_EXCHANGEDB_Session *session,
                        const struct GNUNET_HashCode *session_hash,
                        struct TEH_KS_StateHandle *key_state,
                        const struct TALER_DenominationPublicKey *denom_pub,
                        const struct TALER_EXCHANGEDB_RefreshCommitCoin 
*commit_coin,
-                       unsigned int coin_off)
+                       unsigned int coin_off,
+                      struct TALER_DenominationSignature *ev_sig)
 {
   struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki;
-  struct TALER_DenominationSignature ev_sig;
+  enum GNUNET_DB_QueryStatus qs;
 
   dki = TEH_KS_denomination_key_lookup (key_state,
                                         denom_pub,
@@ -331,105 +294,91 @@ refresh_exchange_coin (struct MHD_Connection *connection,
   if (NULL == dki)
   {
     GNUNET_break (0);
-    ev_sig.rsa_signature = NULL;
-    return ev_sig;
+    ev_sig->rsa_signature = NULL;
+    return GNUNET_DB_STATUS_HARD_ERROR;
   }
-  if (GNUNET_OK ==
-      TEH_plugin->get_refresh_out (TEH_plugin->cls,
-                                   session,
-                                   session_hash,
-                                   coin_off,
-                                   &ev_sig))
+  qs = TEH_plugin->get_refresh_out (TEH_plugin->cls,
+                                   session,
+                                   session_hash,
+                                   coin_off,
+                                   ev_sig);
+  if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
                 "Returning cached reply for /refresh/reveal signature\n");
-    return ev_sig;
+    return qs;
   }
+  if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs)
+    return qs;
 
-  ev_sig.rsa_signature
+  ev_sig->rsa_signature
     = GNUNET_CRYPTO_rsa_sign_blinded (dki->denom_priv.rsa_private_key,
                                       commit_coin->coin_ev,
                                       commit_coin->coin_ev_size);
-  if (NULL == ev_sig.rsa_signature)
+  if (NULL == ev_sig->rsa_signature)
   {
     GNUNET_break (0);
-    return ev_sig;
+    return GNUNET_DB_STATUS_HARD_ERROR;
   }
-  if (GNUNET_SYSERR ==
-      TEH_plugin->insert_refresh_out (TEH_plugin->cls,
-                                      session,
-                                      session_hash,
-                                      coin_off,
-                                      &ev_sig))
+  qs = TEH_plugin->insert_refresh_out (TEH_plugin->cls,
+                                      session,
+                                      session_hash,
+                                      coin_off,
+                                      ev_sig);
+  if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
   {
-    GNUNET_break (0);
-    GNUNET_CRYPTO_rsa_signature_free (ev_sig.rsa_signature);
-    ev_sig.rsa_signature = NULL;
+    GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
+    if (NULL != ev_sig->rsa_signature)
+    {
+      GNUNET_CRYPTO_rsa_signature_free (ev_sig->rsa_signature);
+      ev_sig->rsa_signature = NULL;
+    }
   }
-
-  return ev_sig;
+  return qs;
 }
 
 
 /**
- * The client request was well-formed, now execute the DB transaction
- * of a "/refresh/reveal" operation.  We use the @a ev_sigs and
- * @a commit_coins to clean up resources after this function returns
- * as we might experience retries of the database transaction.
+ * Cleanup state of the transaction stored in @a rc.
  *
- * @param connection the MHD connection to handle
- * @param session database session
- * @param session_hash hash identifying the refresh session
- * @param refresh_session information about the refresh operation we are doing
- * @param denom_pubs array of "num_newcoins" denomination keys for the new 
coins
- * @param[out] ev_sigs where to store generated signatures for the new coins,
- *                     array of length "num_newcoins", memory released by the
- *                     caller
- * @param[out] commit_coins array of length "num_newcoins" to be used for
- *                     information about the new coins from the commitment.
- * @return MHD result code
+ * @param rc context to clean up
  */
-static int
-execute_refresh_reveal_transaction (struct MHD_Connection *connection,
-                                    struct TALER_EXCHANGEDB_Session *session,
-                                    const struct GNUNET_HashCode *session_hash,
-                                    const struct 
TALER_EXCHANGEDB_RefreshSession *refresh_session,
-                                    const struct TALER_DenominationPublicKey 
*denom_pubs,
-                                    struct TALER_DenominationSignature 
*ev_sigs,
-                                    struct TALER_EXCHANGEDB_RefreshCommitCoin 
*commit_coins)
+static void
+cleanup_rc (struct RevealContext *rc)
 {
-  unsigned int j;
-  struct TEH_KS_StateHandle *key_state;
-  int ret;
-
-  START_TRANSACTION (session, connection);
-  key_state = TEH_KS_acquire ();
-  for (j=0;j<refresh_session->num_newcoins;j++)
+  if (NULL != rc->denom_pubs)
   {
-    if (NULL == ev_sigs[j].rsa_signature) /* could be non-NULL during retries 
*/
-      ev_sigs[j] = refresh_exchange_coin (connection,
-                                          session,
-                                          session_hash,
-                                          key_state,
-                                          &denom_pubs[j],
-                                          &commit_coins[j],
-                                          j);
-    if (NULL == ev_sigs[j].rsa_signature)
-    {
-      TEH_plugin->rollback (TEH_plugin->cls,
-                            session);
-      ret = TEH_RESPONSE_reply_internal_db_error (connection,
-                                                 
TALER_EC_REFRESH_REVEAL_SIGNING_ERROR);
-      goto cleanup;
-    }
+    for (unsigned int i=0;i<rc->refresh_session.num_newcoins;i++)
+      if (NULL != rc->denom_pubs[i].rsa_public_key)
+       GNUNET_CRYPTO_rsa_public_key_free (rc->denom_pubs[i].rsa_public_key);
+    GNUNET_free (rc->denom_pubs);
+    rc->denom_pubs = NULL;
+  }
+  if (NULL != rc->commit_coins)
+  {
+    for (unsigned int j=0;j<rc->refresh_session.num_newcoins;j++)
+      GNUNET_free_non_null (rc->commit_coins[j].coin_ev);
+    GNUNET_free (rc->commit_coins);
+    rc->commit_coins = NULL;
+  }
+  if (NULL != rc->ev_sigs)
+  {
+    for (unsigned int j=0;j<rc->refresh_session.num_newcoins;j++)
+      if (NULL != rc->ev_sigs[j].rsa_signature)
+       GNUNET_CRYPTO_rsa_signature_free (rc->ev_sigs[j].rsa_signature);
+    GNUNET_free (rc->ev_sigs);
+    rc->ev_sigs = NULL;
+  }
+  if (NULL != rc->refresh_session.melt.coin.denom_sig.rsa_signature)
+  {
+    GNUNET_CRYPTO_rsa_signature_free 
(rc->refresh_session.melt.coin.denom_sig.rsa_signature);
+    rc->refresh_session.melt.coin.denom_sig.rsa_signature = NULL;
+  }
+  if (NULL != rc->refresh_session.melt.coin.denom_pub.rsa_public_key)
+  {
+    GNUNET_CRYPTO_rsa_public_key_free 
(rc->refresh_session.melt.coin.denom_pub.rsa_public_key);
+    rc->refresh_session.melt.coin.denom_pub.rsa_public_key = NULL;
   }
-  COMMIT_TRANSACTION (session, connection);
-  ret = reply_refresh_reveal_success (connection,
-                                     refresh_session->num_newcoins,
-                                     ev_sigs);
- cleanup:
-  TEH_KS_release (key_state);
-  return ret;
 }
 
 
@@ -440,94 +389,98 @@ execute_refresh_reveal_transaction (struct MHD_Connection 
*connection,
  * and if so, return the signed coins for corresponding to the set of
  * coins that was not chosen.
  *
- * @param connection the MHD connection to handle
- * @param session_hash hash identifying the refresh session
- * @param transfer_privs array with the revealed transfer keys,
- *                      length must be #TALER_CNC_KAPPA - 1
- * @return MHD result code
+ * 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 of type `struct RevealContext`
+ * @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
  */
-static int
-execute_refresh_reveal (struct MHD_Connection *connection,
-                       const struct GNUNET_HashCode *session_hash,
-                       struct TALER_TransferPrivateKeyP *transfer_privs)
+static enum GNUNET_DB_QueryStatus
+refresh_reveal_transaction (void *cls,
+                           struct MHD_Connection *connection,
+                           struct TALER_EXCHANGEDB_Session *session,
+                           int *mhd_ret)
 {
-  int res;
-  struct TALER_EXCHANGEDB_Session *session;
-  struct TALER_EXCHANGEDB_RefreshSession refresh_session;
-  struct TALER_DenominationPublicKey *denom_pubs;
-  struct TALER_DenominationSignature *ev_sigs;
-  struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coins;
-  unsigned int i;
-  unsigned int j;
+  struct RevealContext *rc = cls;
   unsigned int off;
   struct GNUNET_HashContext *hash_context;
   struct GNUNET_HashCode sh_check;
-  int ret;
-  struct TALER_TransferPublicKeyP gamma_tp;
-
-  if (NULL == (session = TEH_plugin->get_session (TEH_plugin->cls)))
+  enum GNUNET_DB_QueryStatus qs;
+
+  rc->session = session;
+  qs = TEH_plugin->get_refresh_session (TEH_plugin->cls,
+                                       session,
+                                       rc->session_hash,
+                                       &rc->refresh_session);
+  if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
+  {
+    *mhd_ret = TEH_RESPONSE_reply_arg_invalid (connection,
+                                              
TALER_EC_REFRESH_REVEAL_SESSION_UNKNOWN,
+                                              "session_hash");
+    return GNUNET_DB_STATUS_HARD_ERROR;
+  }
+  if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+    return qs;
+  if ( (GNUNET_DB_STATUS_HARD_ERROR == qs) ||
+       (rc->refresh_session.noreveal_index >= TALER_CNC_KAPPA) )
   {
     GNUNET_break (0);
-    return TEH_RESPONSE_reply_internal_db_error (connection,
-                                                TALER_EC_DB_SETUP_FAILED);
+    cleanup_rc (rc);
+    *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection,
+                                                    
TALER_EC_REFRESH_REVEAL_DB_FETCH_SESSION_ERROR);
+    return GNUNET_DB_STATUS_HARD_ERROR;
   }
-
-  res = TEH_plugin->get_refresh_session (TEH_plugin->cls,
-                                         session,
-                                         session_hash,
-                                         &refresh_session);
-  if (GNUNET_NO == res)
-    return TEH_RESPONSE_reply_arg_invalid (connection,
-                                          
TALER_EC_REFRESH_REVEAL_SESSION_UNKNOWN,
-                                           "session_hash");
-  if ( (GNUNET_SYSERR == res) ||
-       (refresh_session.noreveal_index >= TALER_CNC_KAPPA) )
-    return TEH_RESPONSE_reply_internal_db_error (connection,
-                                                
TALER_EC_REFRESH_REVEAL_DB_FETCH_SESSION_ERROR);
-  denom_pubs = GNUNET_new_array (refresh_session.num_newcoins,
-                                 struct TALER_DenominationPublicKey);
-  if (GNUNET_OK !=
-      TEH_plugin->get_refresh_order (TEH_plugin->cls,
-                                     session,
-                                     session_hash,
-                                     refresh_session.num_newcoins,
-                                     denom_pubs))
+  rc->denom_pubs = GNUNET_new_array (rc->refresh_session.num_newcoins,
+                                    struct TALER_DenominationPublicKey);
+  qs = TEH_plugin->get_refresh_order (TEH_plugin->cls,
+                                     session,
+                                     rc->session_hash,
+                                     rc->refresh_session.num_newcoins,
+                                     rc->denom_pubs);
+  if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
   {
+    cleanup_rc (rc);
+    if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+      return qs;
     GNUNET_break (0);
-    GNUNET_free (denom_pubs);
-    GNUNET_CRYPTO_rsa_signature_free 
(refresh_session.melt.coin.denom_sig.rsa_signature);
-    GNUNET_CRYPTO_rsa_public_key_free 
(refresh_session.melt.coin.denom_pub.rsa_public_key);
-    return (MHD_YES == TEH_RESPONSE_reply_internal_db_error (connection,
-                                                            
TALER_EC_REFRESH_REVEAL_DB_FETCH_ORDER_ERROR))
-        ? GNUNET_NO : GNUNET_SYSERR;
+    *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection,
+                                                    
TALER_EC_REFRESH_REVEAL_DB_FETCH_ORDER_ERROR);
+    return GNUNET_DB_STATUS_HARD_ERROR;
   }
 
   hash_context = GNUNET_CRYPTO_hash_context_start ();
   /* first, iterate over transfer public keys for hash_context */
   off = 0;
-  for (i=0;i<TALER_CNC_KAPPA;i++)
+  for (unsigned int i=0;i<TALER_CNC_KAPPA;i++)
   {
-    if (i == refresh_session.noreveal_index)
+    if (i == rc->refresh_session.noreveal_index)
     {
       off = 1;
       /* obtain gamma_tp from db */
-      if (GNUNET_OK !=
-          TEH_plugin->get_refresh_transfer_public_key (TEH_plugin->cls,
-                                                       session,
-                                                       session_hash,
-                                                       &gamma_tp))
+      qs = TEH_plugin->get_refresh_transfer_public_key (TEH_plugin->cls,
+                                                       session,
+                                                       rc->session_hash,
+                                                       &rc->gamma_tp);
+      if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
       {
-        GNUNET_break (0);
-        GNUNET_free (denom_pubs);
-        GNUNET_CRYPTO_rsa_signature_free 
(refresh_session.melt.coin.denom_sig.rsa_signature);
-        GNUNET_CRYPTO_rsa_public_key_free 
(refresh_session.melt.coin.denom_pub.rsa_public_key);
         GNUNET_CRYPTO_hash_context_abort (hash_context);
-        return (MHD_YES == TEH_RESPONSE_reply_internal_db_error (connection,
-                                                                
TALER_EC_REFRESH_REVEAL_DB_FETCH_TRANSFER_ERROR))
-          ? GNUNET_NO : GNUNET_SYSERR;
+       cleanup_rc (rc);
+       if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+         return qs;
+        GNUNET_break (0);
+        *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection,
+                                                        
TALER_EC_REFRESH_REVEAL_DB_FETCH_TRANSFER_ERROR);
+       return GNUNET_DB_STATUS_HARD_ERROR;
       }
       GNUNET_CRYPTO_hash_context_read (hash_context,
-                                       &gamma_tp,
+                                       &rc->gamma_tp,
                                        sizeof (struct 
TALER_TransferPublicKeyP));
     }
     else
@@ -535,7 +488,7 @@ execute_refresh_reveal (struct MHD_Connection *connection,
       /* compute tp from private key */
       struct TALER_TransferPublicKeyP tp;
 
-      GNUNET_CRYPTO_ecdhe_key_get_public (&transfer_privs[i - off].ecdhe_priv,
+      GNUNET_CRYPTO_ecdhe_key_get_public (&rc->transfer_privs[i - 
off].ecdhe_priv,
                                           &tp.ecdhe_pub);
       GNUNET_CRYPTO_hash_context_read (hash_context,
                                        &tp,
@@ -545,38 +498,17 @@ execute_refresh_reveal (struct MHD_Connection *connection,
 
   /* next, add all of the hashes from the denomination keys to the
      hash_context */
+  for (unsigned int i=0;i<rc->refresh_session.num_newcoins;i++)
   {
-    struct TALER_DenominationPublicKey 
denom_pubs[refresh_session.num_newcoins];
-
-    if (GNUNET_OK !=
-        TEH_plugin->get_refresh_order (TEH_plugin->cls,
-                                       session,
-                                       session_hash,
-                                       refresh_session.num_newcoins,
-                                       denom_pubs))
-    {
-      GNUNET_break (0);
-      GNUNET_free (denom_pubs);
-      GNUNET_CRYPTO_rsa_signature_free 
(refresh_session.melt.coin.denom_sig.rsa_signature);
-      GNUNET_CRYPTO_rsa_public_key_free 
(refresh_session.melt.coin.denom_pub.rsa_public_key);
-      GNUNET_CRYPTO_hash_context_abort (hash_context);
-      return (MHD_YES == TEH_RESPONSE_reply_internal_db_error (connection,
-                                                              
TALER_EC_REFRESH_REVEAL_DB_FETCH_ORDER_ERROR))
-        ? GNUNET_NO : GNUNET_SYSERR;
-    }
-    for (i=0;i<refresh_session.num_newcoins;i++)
-    {
-      char *buf;
-      size_t buf_size;
+    char *buf;
+    size_t buf_size;
 
-      buf_size = GNUNET_CRYPTO_rsa_public_key_encode 
(denom_pubs[i].rsa_public_key,
-                                                      &buf);
-      GNUNET_CRYPTO_hash_context_read (hash_context,
-                                       buf,
-                                       buf_size);
-      GNUNET_free (buf);
-      GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[i].rsa_public_key);
-    }
+    buf_size = GNUNET_CRYPTO_rsa_public_key_encode 
(rc->denom_pubs[i].rsa_public_key,
+                                                   &buf);
+    GNUNET_CRYPTO_hash_context_read (hash_context,
+                                    buf,
+                                    buf_size);
+    GNUNET_free (buf);
   }
 
   /* next, add public key of coin and amount being refreshed */
@@ -584,71 +516,67 @@ execute_refresh_reveal (struct MHD_Connection *connection,
     struct TALER_AmountNBO melt_amountn;
 
     GNUNET_CRYPTO_hash_context_read (hash_context,
-                                     &refresh_session.melt.coin.coin_pub,
+                                     &rc->refresh_session.melt.coin.coin_pub,
                                      sizeof (struct 
TALER_CoinSpendPublicKeyP));
     TALER_amount_hton (&melt_amountn,
-                       &refresh_session.melt.amount_with_fee);
+                       &rc->refresh_session.melt.amount_with_fee);
     GNUNET_CRYPTO_hash_context_read (hash_context,
                                      &melt_amountn,
                                      sizeof (struct TALER_AmountNBO));
   }
 
-  commit_coins = GNUNET_new_array (refresh_session.num_newcoins,
-                                   struct TALER_EXCHANGEDB_RefreshCommitCoin);
+  rc->commit_coins = GNUNET_new_array (rc->refresh_session.num_newcoins,
+                                      struct 
TALER_EXCHANGEDB_RefreshCommitCoin);
   off = 0;
-  for (i=0;i<TALER_CNC_KAPPA;i++)
+  for (unsigned int i=0;i<TALER_CNC_KAPPA;i++)
   {
-    if (i == refresh_session.noreveal_index)
+    int res;
+    
+    if (i == rc->refresh_session.noreveal_index)
     {
       off = 1;
       /* obtain commit_coins for the selected gamma value from DB */
-      if (GNUNET_OK !=
-          TEH_plugin->get_refresh_commit_coins (TEH_plugin->cls,
-                                                session,
-                                                session_hash,
-                                                refresh_session.num_newcoins,
-                                                commit_coins))
-      {
-        GNUNET_break (0);
-        GNUNET_free (denom_pubs);
-        GNUNET_CRYPTO_rsa_signature_free 
(refresh_session.melt.coin.denom_sig.rsa_signature);
-        GNUNET_CRYPTO_rsa_public_key_free 
(refresh_session.melt.coin.denom_pub.rsa_public_key);
+      qs = TEH_plugin->get_refresh_commit_coins (TEH_plugin->cls,
+                                                session,
+                                                rc->session_hash,
+                                                
rc->refresh_session.num_newcoins,
+                                                rc->commit_coins);
+      if (0 >= qs)
+      {        
+       cleanup_rc (rc);
         GNUNET_CRYPTO_hash_context_abort (hash_context);
-        return TEH_RESPONSE_reply_internal_db_error (connection,
-                                                    
TALER_EC_REFRESH_REVEAL_DB_FETCH_COMMIT_ERROR);
+       if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+         return qs;
+        GNUNET_break (0);
+        *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection,
+                                                        
TALER_EC_REFRESH_REVEAL_DB_FETCH_COMMIT_ERROR);
+       return GNUNET_DB_STATUS_HARD_ERROR;
       }
       /* add envelopes to hash_context */
-      for (j=0;j<refresh_session.num_newcoins;j++)
+      for (unsigned int j=0;j<rc->refresh_session.num_newcoins;j++)
       {
         GNUNET_CRYPTO_hash_context_read (hash_context,
-                                         commit_coins[j].coin_ev,
-                                         commit_coins[j].coin_ev_size);
+                                         rc->commit_coins[j].coin_ev,
+                                         rc->commit_coins[j].coin_ev_size);
       }
       continue;
     }
     if (GNUNET_OK !=
         (res = check_commitment (connection,
                                  session,
-                                 session_hash,
+                                 rc->session_hash,
                                  i,
-                                 &transfer_privs[i - off],
-                                 &refresh_session.melt,
-                                 refresh_session.num_newcoins,
-                                 denom_pubs,
+                                 &rc->transfer_privs[i - off],
+                                 &rc->refresh_session.melt,
+                                 rc->refresh_session.num_newcoins,
+                                 rc->denom_pubs,
                                  hash_context)))
     {
       GNUNET_break_op (0);
-      for (j=0;j<refresh_session.num_newcoins;j++)
-      {
-        GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j].rsa_public_key);
-        GNUNET_free (commit_coins[j].coin_ev);
-      }
-      GNUNET_free (commit_coins);
-      GNUNET_free (denom_pubs);
-      GNUNET_CRYPTO_rsa_signature_free 
(refresh_session.melt.coin.denom_sig.rsa_signature);
-      GNUNET_CRYPTO_rsa_public_key_free 
(refresh_session.melt.coin.denom_pub.rsa_public_key);
+      cleanup_rc (rc);
       GNUNET_CRYPTO_hash_context_abort (hash_context);
-      return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
+      *mhd_ret = (GNUNET_NO == res) ? MHD_YES : MHD_NO;
+      return GNUNET_DB_STATUS_HARD_ERROR;
     }
   }
 
@@ -656,56 +584,53 @@ execute_refresh_reveal (struct MHD_Connection *connection,
   GNUNET_CRYPTO_hash_context_finish (hash_context,
                                      &sh_check);
   if (0 != memcmp (&sh_check,
-                   session_hash,
+                   rc->session_hash,
                    sizeof (struct GNUNET_HashCode)))
   {
     GNUNET_break_op (0);
-    ret = reply_refresh_reveal_missmatch (connection,
-                                         &refresh_session,
-                                         commit_coins,
-                                         denom_pubs,
-                                         &gamma_tp);
-    for (j=0;j<refresh_session.num_newcoins;j++)
+    *mhd_ret = reply_refresh_reveal_missmatch (connection,
+                                              &rc->refresh_session,
+                                              rc->commit_coins,
+                                              rc->denom_pubs,
+                                              &rc->gamma_tp);
+    cleanup_rc (rc);
+    return GNUNET_DB_STATUS_HARD_ERROR;
+  }
+  
+  /* Client request OK, sign coins */
+  rc->ev_sigs = GNUNET_new_array (rc->refresh_session.num_newcoins,
+                                 struct TALER_DenominationSignature);
+  {
+    struct TEH_KS_StateHandle *key_state;
+
+    key_state = TEH_KS_acquire ();
+    for (unsigned int j=0;j<rc->refresh_session.num_newcoins;j++)
     {
-      GNUNET_free (commit_coins[j].coin_ev);
-      GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j].rsa_public_key);
+      qs = refresh_exchange_coin (connection,
+                                 session,
+                                 rc->session_hash,
+                                 key_state,
+                                 &rc->denom_pubs[j],
+                                 &rc->commit_coins[j],
+                                 j,
+                                 &rc->ev_sigs[j]);
+      if ( (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) ||
+          (NULL == rc->ev_sigs[j].rsa_signature) )
+      {
+       *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection,
+                                                        
TALER_EC_REFRESH_REVEAL_SIGNING_ERROR);
+       qs = GNUNET_DB_STATUS_HARD_ERROR;
+       break;
+      }
     }
-    GNUNET_free (commit_coins);
-    GNUNET_free (denom_pubs);
-    GNUNET_CRYPTO_rsa_signature_free 
(refresh_session.melt.coin.denom_sig.rsa_signature);
-    GNUNET_CRYPTO_rsa_public_key_free 
(refresh_session.melt.coin.denom_pub.rsa_public_key);
-
-    return ret;
+    TEH_KS_release (key_state);
   }
-
-  /* Client request OK, start transaction */
-  ev_sigs = GNUNET_new_array (refresh_session.num_newcoins,
-                              struct TALER_DenominationSignature);
-
-  /* FIXME: might need to store revealed transfer private keys for
-     the auditor for later; should pass them as arguments here! #4792*/
-  res = execute_refresh_reveal_transaction (connection,
-                                            session,
-                                            session_hash,
-                                            &refresh_session,
-                                            denom_pubs,
-                                            ev_sigs,
-                                            commit_coins);
-  for (i=0;i<refresh_session.num_newcoins;i++)
+  if (0 >= qs)
   {
-    if (NULL != ev_sigs[i].rsa_signature)
-      GNUNET_CRYPTO_rsa_signature_free (ev_sigs[i].rsa_signature);
-    GNUNET_free (commit_coins[i].coin_ev);
+    cleanup_rc (rc);
+    return qs;
   }
-  for (j=0;j<refresh_session.num_newcoins;j++)
-    if (NULL != denom_pubs[j].rsa_public_key)
-      GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j].rsa_public_key);
-  GNUNET_CRYPTO_rsa_signature_free 
(refresh_session.melt.coin.denom_sig.rsa_signature);
-  GNUNET_CRYPTO_rsa_public_key_free 
(refresh_session.melt.coin.denom_pub.rsa_public_key);
-  GNUNET_free (ev_sigs);
-  GNUNET_free (denom_pubs);
-  GNUNET_free (commit_coins);
-  return res;
+  return qs;
 }
 
 
@@ -726,37 +651,47 @@ handle_refresh_reveal_json (struct MHD_Connection 
*connection,
                             const struct GNUNET_HashCode *session_hash,
                             const json_t *tp_json)
 {
-  struct TALER_TransferPrivateKeyP transfer_privs[TALER_CNC_KAPPA - 1];
-  unsigned int i;
-  int res;
+  struct RevealContext rc;
+  int mhd_ret;
 
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "reveal request for session %s\n",
               GNUNET_h2s (session_hash));
-
-  res = GNUNET_OK;
-  for (i = 0; i < TALER_CNC_KAPPA - 1; i++)
+  memset (&rc,
+         0,
+         sizeof (rc));
+  rc.session_hash = session_hash;
+  for (unsigned int i = 0; i < TALER_CNC_KAPPA - 1; i++)
   {
     struct GNUNET_JSON_Specification tp_spec[] = {
-      GNUNET_JSON_spec_fixed_auto (NULL, &transfer_privs[i]),
+      GNUNET_JSON_spec_fixed_auto (NULL, &rc.transfer_privs[i]),
       GNUNET_JSON_spec_end ()
     };
+    int res;
 
-    if (GNUNET_OK != res)
-      break;
     res = TEH_PARSE_json_array (connection,
                                 tp_json,
                                 tp_spec,
-                                i, -1);
+                                i,
+                               -1);
     GNUNET_break_op (GNUNET_OK == res);
+    if (GNUNET_OK != res)
+      return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
   }
-  if (GNUNET_OK != res)
-    res = (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
-  else
-    res = execute_refresh_reveal (connection,
-                                 session_hash,
-                                 transfer_privs);
-  return res;
+  if (GNUNET_OK !=
+      TEH_DB_run_transaction (connection,
+                             &mhd_ret,
+                             &refresh_reveal_transaction,
+                             &rc))
+  {
+    cleanup_rc (&rc);
+    return mhd_ret;
+  }
+  mhd_ret = reply_refresh_reveal_success (connection,
+                                         rc.refresh_session.num_newcoins,
+                                         rc.ev_sigs);
+  cleanup_rc (&rc);
+  return mhd_ret;
 }
 
 
@@ -800,7 +735,8 @@ TEH_REFRESH_handler_refresh_reveal (struct 
TEH_RequestHandler *rh,
                              &root);
   if (GNUNET_SYSERR == res)
     return MHD_NO;
-  if ( (GNUNET_NO == res) || (NULL == root) )
+  if ( (GNUNET_NO == res) ||
+       (NULL == root) )
     return MHD_YES;
 
   res = TEH_PARSE_json_data (connection,
diff --git a/src/exchangedb/plugin_exchangedb_postgres.c 
b/src/exchangedb/plugin_exchangedb_postgres.c
index b11eec1..592751f 100644
--- a/src/exchangedb/plugin_exchangedb_postgres.c
+++ b/src/exchangedb/plugin_exchangedb_postgres.c
@@ -3099,6 +3099,7 @@ postgres_iterate_matching_deposits (void *cls,
  *           if upon succesfullying retrieving the record data info @a
  *           coin_info
  */
+// FIXME: #5010
 static int
 get_known_coin (void *cls,
                 struct TALER_EXCHANGEDB_Session *session,
@@ -3284,88 +3285,55 @@ postgres_insert_refund (void *cls,
  * @param cls the `struct PostgresClosure` with the plugin-specific state
  * @param session database handle to use
  * @param session_hash hash over the melt to use to locate the session
- * @param[out] refresh_session where to store the result, can be NULL
- *             to just check if the session exists
- * @return #GNUNET_YES on success,
- *         #GNUNET_NO if not found,
- *         #GNUNET_SYSERR on DB failure
+ * @param[out] refresh_session where to store the result
+ * @return transaction status
  */
-static int
+static enum GNUNET_DB_QueryStatus
 postgres_get_refresh_session (void *cls,
                               struct TALER_EXCHANGEDB_Session *session,
                               const struct GNUNET_HashCode *session_hash,
                               struct TALER_EXCHANGEDB_RefreshSession 
*refresh_session)
 {
-  PGresult *result;
   struct GNUNET_PQ_QueryParam params[] = {
     GNUNET_PQ_query_param_auto_from_type (session_hash),
     GNUNET_PQ_query_param_end
   };
+  struct GNUNET_PQ_ResultSpec rs[] = {
+    GNUNET_PQ_result_spec_uint16 ("num_newcoins",
+                                 &refresh_session->num_newcoins),
+    GNUNET_PQ_result_spec_uint16 ("noreveal_index",
+                                 &refresh_session->noreveal_index),
+    GNUNET_PQ_result_spec_auto_from_type ("old_coin_pub",
+                                         &refresh_session->melt.coin.coin_pub),
+    GNUNET_PQ_result_spec_auto_from_type ("old_coin_sig",
+                                         &refresh_session->melt.coin_sig),
+    TALER_PQ_result_spec_amount ("amount_with_fee",
+                                &refresh_session->melt.amount_with_fee),
+    TALER_PQ_result_spec_amount ("fee_refresh",
+                                &refresh_session->melt.melt_fee),
+    GNUNET_PQ_result_spec_end
+  };
+  enum GNUNET_DB_QueryStatus qs;
 
-  result = GNUNET_PQ_exec_prepared (session->conn,
-                                    "get_refresh_session",
-                                    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;
-  }
-  GNUNET_assert (1 == PQntuples (result));
-  if (NULL == refresh_session)
-  {
-    /* We're done if the caller is only interested in whether the
-     * session exists or not */
-    PQclear (result);
-    return GNUNET_YES;
-  }
   memset (refresh_session,
           0,
           sizeof (struct TALER_EXCHANGEDB_RefreshSession));
-  {
-    struct GNUNET_PQ_ResultSpec rs[] = {
-      GNUNET_PQ_result_spec_uint16 ("num_newcoins",
-                                    &refresh_session->num_newcoins),
-      GNUNET_PQ_result_spec_uint16 ("noreveal_index",
-                                    &refresh_session->noreveal_index),
-      GNUNET_PQ_result_spec_auto_from_type ("old_coin_pub",
-                                            
&refresh_session->melt.coin.coin_pub),
-      GNUNET_PQ_result_spec_auto_from_type ("old_coin_sig",
-                                            &refresh_session->melt.coin_sig),
-      TALER_PQ_result_spec_amount ("amount_with_fee",
-                                   &refresh_session->melt.amount_with_fee),
-      TALER_PQ_result_spec_amount ("fee_refresh",
-                                   &refresh_session->melt.melt_fee),
-      GNUNET_PQ_result_spec_end
-    };
-
-    if (GNUNET_OK !=
-        GNUNET_PQ_extract_result (result,
-                                  rs,
-                                  0))
-    {
-      GNUNET_break (0);
-      PQclear (result);
-      return GNUNET_SYSERR;
-    }
-  }
-  PQclear (result);
-  if (GNUNET_OK !=
-      get_known_coin (cls,
-                      session,
-                      &refresh_session->melt.coin.coin_pub,
-                      &refresh_session->melt.coin))
+  qs = GNUNET_PQ_eval_prepared_singleton_select (session->conn,
+                                                "get_refresh_session",
+                                                params,
+                                                rs);
+  if ( (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs) &&
+       (GNUNET_OK !=
+       get_known_coin (cls,
+                       session,
+                       &refresh_session->melt.coin.coin_pub,
+                       &refresh_session->melt.coin)) )
   {
     GNUNET_break (0);
-    return GNUNET_SYSERR;
+    return GNUNET_DB_STATUS_HARD_ERROR;
   }
   refresh_session->melt.session_hash = *session_hash;
-  return GNUNET_YES;
+  return qs;
 }
 
 
@@ -3501,69 +3469,49 @@ free_dpk_result (struct TALER_DenominationPublicKey 
*denom_pubs,
  * @param session_hash hash to identify refresh session
  * @param num_newcoins size of the array of the @a denom_pubs array
  * @param denom_pubs where to store the deomination keys
- * @return #GNUNET_OK on success
- *         #GNUNET_SYSERR on internal error
+ * @return transaction status
  */
-static int
+static enum GNUNET_DB_QueryStatus
 postgres_get_refresh_order (void *cls,
                             struct TALER_EXCHANGEDB_Session *session,
                             const struct GNUNET_HashCode *session_hash,
                             uint16_t num_newcoins,
                             struct TALER_DenominationPublicKey *denom_pubs)
-{
-  unsigned int i;
-
-  for (i=0;i<(unsigned int) num_newcoins;i++)
+{ 
+  for (unsigned i=0;i<(unsigned int) num_newcoins;i++)
   {
     uint16_t newcoin_off = (uint16_t) i;
-    PGresult *result;
-
-    {
-      struct GNUNET_PQ_QueryParam params[] = {
-        GNUNET_PQ_query_param_auto_from_type (session_hash),
-        GNUNET_PQ_query_param_uint16 (&newcoin_off),
-        GNUNET_PQ_query_param_end
-      };
-
-      result = GNUNET_PQ_exec_prepared (session->conn,
-                                       "get_refresh_order",
-                                       params);
-    }
-    if (PGRES_TUPLES_OK != PQresultStatus (result))
-    {
-      BREAK_DB_ERR (result, session->conn);
-      PQclear (result);
-      free_dpk_result (denom_pubs, i);
-      return GNUNET_SYSERR;
-    }
-    if (0 == PQntuples (result))
+    enum GNUNET_DB_QueryStatus qs;
+    struct GNUNET_PQ_QueryParam params[] = {
+      GNUNET_PQ_query_param_auto_from_type (session_hash),
+      GNUNET_PQ_query_param_uint16 (&newcoin_off),
+      GNUNET_PQ_query_param_end
+    };
+    struct GNUNET_PQ_ResultSpec rs[] = {
+      GNUNET_PQ_result_spec_rsa_public_key ("denom_pub",
+                                           &denom_pubs[i].rsa_public_key),
+      GNUNET_PQ_result_spec_end
+    };
+    
+    qs = GNUNET_PQ_eval_prepared_singleton_select (session->conn,
+                                                  "get_refresh_order",
+                                                  params,
+                                                  rs);
+    switch (qs)
     {
-      PQclear (result);
-      /* FIXME: may want to distinguish between different error cases! */
+    case GNUNET_DB_STATUS_HARD_ERROR:
+    case GNUNET_DB_STATUS_SOFT_ERROR:
+    case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
       free_dpk_result (denom_pubs, i);
-      return GNUNET_SYSERR;
-    }
-    GNUNET_assert (1 == PQntuples (result));
-    {
-      struct GNUNET_PQ_ResultSpec rs[] = {
-        GNUNET_PQ_result_spec_rsa_public_key ("denom_pub",
-                                             &denom_pubs[i].rsa_public_key),
-        GNUNET_PQ_result_spec_end
-      };
-      if (GNUNET_OK !=
-          GNUNET_PQ_extract_result (result,
-                                    rs,
-                                    0))
-      {
-        PQclear (result);
-        GNUNET_break (0);
-        free_dpk_result (denom_pubs, i);
-        return GNUNET_SYSERR;
-      }
-      PQclear (result);
+      return qs;
+    case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+      break;
+    default:
+      GNUNET_break (0);
+      break;
     }
   }
-  return GNUNET_OK;
+  return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
 }
 
 
@@ -3639,11 +3587,9 @@ postgres_free_refresh_commit_coins (void *cls,
  * @param session_hash hash to identify refresh session
  * @param num_newcoins size of the @a commit_coins array
  * @param[out] commit_coins array of coin commitments to return
- * @return #GNUNET_OK on success
- *         #GNUNET_NO if not found
- *         #GNUNET_SYSERR on error
+ * @return transaction status
  */
-static int
+static enum GNUNET_DB_QueryStatus
 postgres_get_refresh_commit_coins (void *cls,
                                    struct TALER_EXCHANGEDB_Session *session,
                                    const struct GNUNET_HashCode *session_hash,
@@ -3660,53 +3606,29 @@ postgres_get_refresh_commit_coins (void *cls,
     };
     void *c_buf;
     size_t c_buf_size;
-    PGresult *result;
+    struct GNUNET_PQ_ResultSpec rs[] = {
+      GNUNET_PQ_result_spec_variable_size ("coin_ev",
+                                          &c_buf,
+                                          &c_buf_size),
+      GNUNET_PQ_result_spec_end
+    };
+    enum GNUNET_DB_QueryStatus qs;
 
-    result = GNUNET_PQ_exec_prepared (session->conn,
-                                     "get_refresh_commit_coin",
-                                     params);
-    if (PGRES_TUPLES_OK != PQresultStatus (result))
-    {
-      BREAK_DB_ERR (result, session->conn);
-      PQclear (result);
-      postgres_free_refresh_commit_coins (cls,
-                                          i,
-                                          commit_coins);
-      return GNUNET_SYSERR;
-    }
-    if (0 == PQntuples (result))
+    qs = GNUNET_PQ_eval_prepared_singleton_select (session->conn,
+                                                  "get_refresh_commit_coin",
+                                                  params,
+                                                  rs);
+    if (0 >= qs)
     {
-      PQclear (result);
       postgres_free_refresh_commit_coins (cls,
                                           i,
                                           commit_coins);
-      return GNUNET_NO;
-    }
-    {
-      struct GNUNET_PQ_ResultSpec rs[] = {
-        GNUNET_PQ_result_spec_variable_size ("coin_ev",
-                                            &c_buf,
-                                            &c_buf_size),
-        GNUNET_PQ_result_spec_end
-      };
-
-      if (GNUNET_YES !=
-          GNUNET_PQ_extract_result (result,
-                                    rs,
-                                    0))
-      {
-        PQclear (result);
-        postgres_free_refresh_commit_coins (cls,
-                                            i,
-                                            commit_coins);
-        return GNUNET_SYSERR;
-      }
+      return qs;
     }
-    PQclear (result);
     commit_coins[i].coin_ev = c_buf;
     commit_coins[i].coin_ev_size = c_buf_size;
   }
-  return GNUNET_YES;
+  return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
 }
 
 
@@ -3748,11 +3670,9 @@ postgres_insert_refresh_transfer_public_key (void *cls,
  * @param session database connection to use
  * @param session_hash hash to identify refresh session
  * @param[out] tp information to return
- * @return #GNUNET_SYSERR on internal error,
- *         #GNUNET_NO if commitment was not found
- *         #GNUNET_OK on success
+ * @return transaction status
  */
-static int
+static enum GNUNET_DB_QueryStatus
 postgres_get_refresh_transfer_public_key (void *cls,
                                           struct TALER_EXCHANGEDB_Session 
*session,
                                           const struct GNUNET_HashCode 
*session_hash,
@@ -3762,40 +3682,16 @@ postgres_get_refresh_transfer_public_key (void *cls,
     GNUNET_PQ_query_param_auto_from_type (session_hash),
     GNUNET_PQ_query_param_end
   };
-  PGresult *result;
-
-  result = GNUNET_PQ_exec_prepared (session->conn,
-                                    "get_refresh_transfer_public_key",
-                                    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 GNUNET_PQ_ResultSpec rs[] = {
-      GNUNET_PQ_result_spec_auto_from_type ("transfer_pub",
-                                            tp),
-      GNUNET_PQ_result_spec_end
-    };
-
-    if (GNUNET_YES !=
-        GNUNET_PQ_extract_result (result,
-                                  rs,
-                                  0))
-    {
-      PQclear (result);
-      return GNUNET_SYSERR;
-    }
-  }
-  PQclear (result);
-  return GNUNET_OK;
+  struct GNUNET_PQ_ResultSpec rs[] = {
+    GNUNET_PQ_result_spec_auto_from_type ("transfer_pub",
+                                         tp),
+    GNUNET_PQ_result_spec_end
+  };
+  
+  return GNUNET_PQ_eval_prepared_singleton_select (session->conn,
+                                                  
"get_refresh_transfer_public_key",
+                                                  params,
+                                                  rs);
 }
 
 
@@ -3809,17 +3705,15 @@ postgres_get_refresh_transfer_public_key (void *cls,
  * @param session_hash hash to identify refresh session
  * @param newcoin_index coin index
  * @param ev_sig coin signature
- * @return #GNUNET_OK on success, #GNUNET_NO if we have no such result
- *         #GNUNET_SYSERR on error
+ * @return transaction result status
  */
-static int
+static enum GNUNET_DB_QueryStatus
 postgres_get_refresh_out (void *cls,
                           struct TALER_EXCHANGEDB_Session *session,
                           const struct GNUNET_HashCode *session_hash,
                           uint16_t newcoin_index,
                           struct TALER_DenominationSignature *ev_sig)
 {
-  PGresult *result;
   struct GNUNET_PQ_QueryParam params[] = {
     GNUNET_PQ_query_param_auto_from_type (session_hash),
     GNUNET_PQ_query_param_uint16 (&newcoin_index),
@@ -3831,31 +3725,10 @@ postgres_get_refresh_out (void *cls,
     GNUNET_PQ_result_spec_end
   };
 
-  result = GNUNET_PQ_exec_prepared (session->conn,
-                                    "get_refresh_out",
-                                    params);
-  if (PGRES_TUPLES_OK != PQresultStatus (result))
-  {
-    BREAK_DB_ERR (result, session->conn);
-    PQclear (result);
-    return GNUNET_SYSERR;
-  }
-  if (1 != PQntuples (result))
-  {
-    PQclear (result);
-    return GNUNET_NO;
-  }
-  if (GNUNET_OK !=
-      GNUNET_PQ_extract_result (result,
-                                rs,
-                                0))
-  {
-    PQclear (result);
-    GNUNET_break (0);
-    return GNUNET_SYSERR;
-  }
-  PQclear (result);
-  return GNUNET_OK;
+  return GNUNET_PQ_eval_prepared_singleton_select (session->conn,
+                                                  "get_refresh_out",
+                                                  params,
+                                                  rs);
 }
 
 
@@ -3870,11 +3743,9 @@ postgres_get_refresh_out (void *cls,
  * @param session_hash hash to identify refresh session
  * @param newcoin_index coin index
  * @param ev_sig coin signature
- * @return #GNUNET_OK on success
- *         #GNUNET_NO on transient error
- *         #GNUNET_SYSERR on error
+ * @return transaction result status
  */
-static int
+static enum GNUNET_DB_QueryStatus
 postgres_insert_refresh_out (void *cls,
                              struct TALER_EXCHANGEDB_Session *session,
                              const struct GNUNET_HashCode *session_hash,
@@ -3888,9 +3759,9 @@ postgres_insert_refresh_out (void *cls,
     GNUNET_PQ_query_param_end
   };
 
-  return execute_prepared_non_select (session,
-                                      "insert_refresh_out",
-                                      params);
+  return GNUNET_PQ_eval_prepared_non_select (session->conn,
+                                            "insert_refresh_out",
+                                            params);
 }
 
 
diff --git a/src/exchangedb/test_exchangedb.c b/src/exchangedb/test_exchangedb.c
index df730a0..673d514 100644
--- a/src/exchangedb/test_exchangedb.c
+++ b/src/exchangedb/test_exchangedb.c
@@ -357,7 +357,7 @@ test_refresh_commit_coins (struct TALER_EXCHANGEDB_Session 
*session,
                                                commit_coins));
   ret_commit_coins = GNUNET_new_array (MELT_NEW_COINS,
                                        struct 
TALER_EXCHANGEDB_RefreshCommitCoin);
-  FAILIF (GNUNET_OK !=
+  FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
           plugin->get_refresh_commit_coins (plugin->cls,
                                             session,
                                             session_hash,
@@ -410,7 +410,7 @@ test_refresh_commit_links (struct TALER_EXCHANGEDB_Session 
*session,
   unsigned int i;
 
   ret = GNUNET_SYSERR;
-  FAILIF (GNUNET_NO !=
+  FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
           plugin->get_refresh_transfer_public_key (plugin->cls,
                                                    session,
                                                    session_hash,
@@ -422,7 +422,7 @@ test_refresh_commit_links (struct TALER_EXCHANGEDB_Session 
*session,
                                                       session,
                                                       session_hash,
                                                       
&rctp[MELT_NOREVEAL_INDEX]));
-  FAILIF (GNUNET_OK !=
+  FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
           plugin->get_refresh_transfer_public_key (plugin->cls,
                                                    session,
                                                    session_hash,
@@ -572,21 +572,24 @@ test_melting (struct TALER_EXCHANGEDB_Session *session)
     meltp->melt_fee = fee_refresh;
   }
 
-  FAILIF (GNUNET_OK != plugin->create_refresh_session (plugin->cls,
-                                                       session,
-                                                       &session_hash,
-                                                       &refresh_session));
-  FAILIF (GNUNET_OK != plugin->get_refresh_session (plugin->cls,
-                                                    session,
-                                                    &session_hash,
-                                                    &ret_refresh_session));
+  FAILIF (GNUNET_OK !=
+         plugin->create_refresh_session (plugin->cls,
+                                         session,
+                                         &session_hash,
+                                         &refresh_session));
+  FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
+         plugin->get_refresh_session (plugin->cls,
+                                      session,
+                                      &session_hash,
+                                      &ret_refresh_session));
 
   auditor_row_cnt = 0;
-  FAILIF (GNUNET_OK != plugin->select_refreshs_above_serial_id (plugin->cls,
-                                                                session,
-                                                               0,
-                                                               
&audit_refresh_session_cb,
-                                                               NULL));
+  FAILIF (GNUNET_OK !=
+         plugin->select_refreshs_above_serial_id (plugin->cls,
+                                                  session,
+                                                  0,
+                                                  &audit_refresh_session_cb,
+                                                  NULL));
   FAILIF (1 != auditor_row_cnt);
   FAILIF (ret_refresh_session.num_newcoins != refresh_session.num_newcoins);
   FAILIF (ret_refresh_session.noreveal_index != 
refresh_session.noreveal_index);
@@ -633,7 +636,7 @@ test_melting (struct TALER_EXCHANGEDB_Session *session)
                                          &fee_refund);
     new_denom_pubs[cnt] = new_dkp[cnt]->pub;
   }
-  FAILIF (GNUNET_OK !=
+  FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
           plugin->insert_refresh_order (plugin->cls,
                                         session,
                                         &session_hash,
@@ -641,7 +644,7 @@ test_melting (struct TALER_EXCHANGEDB_Session *session)
                                         new_denom_pubs));
   ret_denom_pubs = GNUNET_new_array (MELT_NEW_COINS,
                                      struct TALER_DenominationPublicKey);
-  FAILIF (GNUNET_OK !=
+  FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
           plugin->get_refresh_order (plugin->cls,
                                      session,
                                      &session_hash,
@@ -672,19 +675,19 @@ test_melting (struct TALER_EXCHANGEDB_Session *session)
       = GNUNET_CRYPTO_rsa_sign_fdh (new_dkp[cnt]->priv.rsa_private_key,
                                     &hc);
     GNUNET_assert (NULL != ev_sigs[cnt].rsa_signature);
-    FAILIF (GNUNET_NO !=
+    FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
             plugin->get_refresh_out (plugin->cls,
                                      session,
                                      &session_hash,
                                      cnt,
                                      &test_sig));
-    FAILIF (GNUNET_OK !=
+    FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
             plugin->insert_refresh_out (plugin->cls,
                                         session,
                                         &session_hash,
                                         cnt,
                                         &ev_sigs[cnt]));
-    FAILIF (GNUNET_OK !=
+    FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
             plugin->get_refresh_out (plugin->cls,
                                      session,
                                      &session_hash,
diff --git a/src/include/taler_exchangedb_plugin.h 
b/src/include/taler_exchangedb_plugin.h
index 0406c8d..9fe0874 100644
--- a/src/include/taler_exchangedb_plugin.h
+++ b/src/include/taler_exchangedb_plugin.h
@@ -1441,11 +1441,9 @@ struct TALER_EXCHANGEDB_Plugin
    * @param session database handle to use
    * @param session_hash hash over the melt to use for the lookup
    * @param[out] refresh_session where to store the result
-   * @return #GNUNET_YES on success,
-   *         #GNUNET_NO if not found,
-   *         #GNUNET_SYSERR on DB failure
+   * @return transaction status
    */
-  int
+  enum GNUNET_DB_QueryStatus
   (*get_refresh_session) (void *cls,
                           struct TALER_EXCHANGEDB_Session *session,
                           const struct GNUNET_HashCode *session_hash,
@@ -1500,10 +1498,9 @@ struct TALER_EXCHANGEDB_Plugin
    * @param session_hash hash to identify refresh session
    * @param num_newcoins size of the @a denom_pubs array
    * @param[out] denom_pubs where to write @a num_newcoins denomination keys
-   * @return #GNUNET_OK on success
-   *         #GNUNET_SYSERR on internal error
+   * @return transaction status
    */
-  int
+  enum GNUNET_DB_QueryStatus
   (*get_refresh_order) (void *cls,
                         struct TALER_EXCHANGEDB_Session *session,
                         const struct GNUNET_HashCode *session_hash,
@@ -1541,11 +1538,9 @@ struct TALER_EXCHANGEDB_Plugin
    * @param session_hash hash to identify refresh session
    * @param num_coins size of the @a commit_coins array
    * @param[out] commit_coins array of coin commitments to return
-   * @return #GNUNET_OK on success
-   *         #GNUNET_NO if not found
-   *         #GNUNET_SYSERR on error
+   * @return transaction status
    */
-  int
+  enum GNUNET_DB_QueryStatus
   (*get_refresh_commit_coins) (void *cls,
                                struct TALER_EXCHANGEDB_Session *session,
                                const struct GNUNET_HashCode *session_hash,
@@ -1591,11 +1586,9 @@ struct TALER_EXCHANGEDB_Plugin
    * @param session database connection to use
    * @param session_hash hash to identify refresh session
    * @param[out] tp information to return
-   * @return #GNUNET_SYSERR on internal error,
-   *         #GNUNET_NO if commitment was not found
-   *         #GNUNET_OK on success
+   * @return transaction status
    */
-  int
+  enum GNUNET_DB_QueryStatus
   (*get_refresh_transfer_public_key) (void *cls,
                                       struct TALER_EXCHANGEDB_Session *session,
                                       const struct GNUNET_HashCode 
*session_hash,
@@ -1612,10 +1605,9 @@ struct TALER_EXCHANGEDB_Plugin
    * @param session_hash hash to identify refresh session
    * @param newcoin_index coin index
    * @param[out] ev_sig coin signature
-   * @return #GNUNET_OK on success, #GNUNET_NO if we have no such entry,
-   *         #GNUNET_SYSERR on error
+   * @return transaction result status
    */
-  int
+  enum GNUNET_DB_QueryStatus
   (*get_refresh_out) (void *cls,
                       struct TALER_EXCHANGEDB_Session *session,
                       const struct GNUNET_HashCode *session_hash,
@@ -1634,10 +1626,9 @@ struct TALER_EXCHANGEDB_Plugin
    * @param session_hash hash to identify refresh session
    * @param newcoin_index coin index
    * @param ev_sig coin signature
-   * @return #GNUNET_OK on success
-   *         #GNUNET_SYSERR on error
+   * @return transaction result status
    */
-  int
+  enum GNUNET_DB_QueryStatus
   (*insert_refresh_out) (void *cls,
                          struct TALER_EXCHANGEDB_Session *session,
                          const struct GNUNET_HashCode *session_hash,

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



reply via email to

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