gnunet-svn
[Top][All Lists]
Advanced

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

[taler-exchange] branch master updated: simplify refund processing, add


From: gnunet
Subject: [taler-exchange] branch master updated: simplify refund processing, add additional checks for matching currency
Date: Mon, 16 Mar 2020 20:37:22 +0100

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

grothoff pushed a commit to branch master
in repository exchange.

The following commit(s) were added to refs/heads/master by this push:
     new cd83daae simplify refund processing, add additional checks for 
matching currency
cd83daae is described below

commit cd83daaeae915e0c1b6170cb11f40aa1cfbfece4
Author: Christian Grothoff <address@hidden>
AuthorDate: Mon Mar 16 20:22:30 2020 +0100

    simplify refund processing, add additional checks for matching currency
---
 src/exchange/taler-exchange-httpd_deposit.c  |  14 +-
 src/exchange/taler-exchange-httpd_refund.c   | 259 +++++++++++++--------------
 src/exchange/taler-exchange-httpd_withdraw.c | 222 +++++++++++++----------
 src/include/taler_error_codes.h              |  24 ++-
 4 files changed, 281 insertions(+), 238 deletions(-)

diff --git a/src/exchange/taler-exchange-httpd_deposit.c 
b/src/exchange/taler-exchange-httpd_deposit.c
index 4008ed27..039ca9f9 100644
--- a/src/exchange/taler-exchange-httpd_deposit.c
+++ b/src/exchange/taler-exchange-httpd_deposit.c
@@ -417,8 +417,8 @@ TEH_handler_deposit (struct MHD_Connection *connection,
                                                   &hc);
     if (NULL == dki)
     {
-      TEH_KS_release (key_state);
       TALER_LOG_WARNING ("Unknown denomination key in /deposit request\n");
+      TEH_KS_release (key_state);
       GNUNET_JSON_parse_free (spec);
       return TALER_MHD_reply_with_error (connection,
                                          hc,
@@ -427,6 +427,18 @@ TEH_handler_deposit (struct MHD_Connection *connection,
     }
     TALER_amount_ntoh (&deposit.deposit_fee,
                        &dki->issue.properties.fee_deposit);
+    if (GNUNET_YES !=
+        TALER_amount_cmp_currency (&deposit.amount_with_fee,
+                                   &deposit.deposit_fee) )
+    {
+      GNUNET_break_op (0);
+      TEH_KS_release (key_state);
+      GNUNET_JSON_parse_free (spec);
+      return TALER_MHD_reply_with_error (connection,
+                                         MHD_HTTP_BAD_REQUEST,
+                                         TALER_EC_DEPOSIT_CURRENCY_MISSMATCH,
+                                         "contribution");
+    }
     /* check coin signature */
     if (GNUNET_YES !=
         TALER_test_coin_valid (&deposit.coin,
diff --git a/src/exchange/taler-exchange-httpd_refund.c 
b/src/exchange/taler-exchange-httpd_refund.c
index d564a361..e590703a 100644
--- a/src/exchange/taler-exchange-httpd_refund.c
+++ b/src/exchange/taler-exchange-httpd_refund.c
@@ -15,7 +15,7 @@
 */
 /**
  * @file taler-exchange-httpd_refund.c
- * @brief Handle /refund requests; parses the POST and JSON and
+ * @brief Handle refund requests; parses the POST and JSON and
  *        verifies the coin signature before handing things off
  *        to the database.
  * @author Florian Dold
@@ -48,16 +48,17 @@ reply_refund_success (struct MHD_Connection *connection,
                       const struct TALER_CoinSpendPublicKeyP *coin_pub,
                       const struct TALER_EXCHANGEDB_RefundListEntry *refund)
 {
-  struct TALER_RefundConfirmationPS rc;
   struct TALER_ExchangePublicKeyP pub;
   struct TALER_ExchangeSignatureP sig;
+  struct TALER_RefundConfirmationPS rc = {
+    .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_REFUND),
+    .purpose.size = htonl (sizeof (rc)),
+    .h_contract_terms = refund->h_contract_terms,
+    .coin_pub = *coin_pub,
+    .merchant = refund->merchant_pub,
+    .rtransaction_id = GNUNET_htonll (refund->rtransaction_id)
+  };
 
-  rc.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_REFUND);
-  rc.purpose.size = htonl (sizeof (struct TALER_RefundConfirmationPS));
-  rc.h_contract_terms = refund->h_contract_terms;
-  rc.coin_pub = *coin_pub;
-  rc.merchant = refund->merchant_pub;
-  rc.rtransaction_id = GNUNET_htonll (refund->rtransaction_id);
   TALER_amount_hton (&rc.refund_amount,
                      &refund->refund_amount);
   TALER_amount_hton (&rc.refund_fee,
@@ -70,7 +71,7 @@ reply_refund_success (struct MHD_Connection *connection,
     return TALER_MHD_reply_with_error (connection,
                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
                                        TALER_EC_EXCHANGE_BAD_CONFIGURATION,
-                                       "no keys");
+                                       "no online signing key");
   }
   return TALER_MHD_reply_json_pack (connection,
                                     MHD_HTTP_OK,
@@ -81,51 +82,6 @@ reply_refund_success (struct MHD_Connection *connection,
 }
 
 
-/**
- * Generate refund conflict failure message. Returns the
- * transaction list @a tl with the details about the conflict.
- *
- * @param connection connection to the client
- * @param coin_pub public key this is about
- * @param tl transaction list showing the conflict
- * @return MHD result code
- */
-static int
-reply_refund_conflict (struct MHD_Connection *connection,
-                       const struct TALER_CoinSpendPublicKeyP *coin_pub,
-                       const struct TALER_EXCHANGEDB_TransactionList *tl)
-{
-  return TALER_MHD_reply_json_pack (connection,
-                                    MHD_HTTP_CONFLICT,
-                                    "{s:s, s:I, s:o}",
-                                    "hint", "conflicting refund",
-                                    "code",
-                                    (json_int_t) TALER_EC_REFUND_CONFLICT,
-                                    "history",
-                                    TEH_RESPONSE_compile_transaction_history (
-                                      coin_pub,
-                                      tl));
-}
-
-
-/**
- * Closure for the transaction.
- */
-struct TALER_EXCHANGEDB_RefundContext
-{
-  /**
-   * Information about the refund.
-   */
-  const struct TALER_EXCHANGEDB_Refund *refund;
-
-  /**
-   * Expected refund fee by the denomination of the coin.
-   */
-  struct TALER_Amount expect_fee;
-
-};
-
-
 /**
  * Execute a "/refund" transaction.  Returns a confirmation that the
  * refund was successful, or a failure if we are not aware of a
@@ -150,18 +106,14 @@ refund_transaction (void *cls,
                     struct TALER_EXCHANGEDB_Session *session,
                     int *mhd_ret)
 {
-  struct TALER_EXCHANGEDB_RefundContext *rc = cls;
-  const struct TALER_EXCHANGEDB_Refund *refund = rc->refund;
+  const struct TALER_EXCHANGEDB_Refund *refund = cls;
   struct TALER_EXCHANGEDB_TransactionList *tl;
   const struct TALER_EXCHANGEDB_DepositListEntry *dep;
   const struct TALER_EXCHANGEDB_RefundListEntry *ref;
   enum GNUNET_DB_QueryStatus qs;
   int deposit_found;
   int refund_found;
-  int fee_cmp;
 
-  dep = NULL;
-  ref = NULL;
   tl = NULL;
   qs = TEH_plugin->get_coin_transactions (TEH_plugin->cls,
                                           session,
@@ -177,6 +129,8 @@ refund_transaction (void *cls,
                                              "database transaction failure");
     return qs;
   }
+  dep = NULL;
+  ref = NULL;
   deposit_found = GNUNET_NO;
   refund_found = GNUNET_NO;
   for (struct TALER_EXCHANGEDB_TransactionList *tlp = tl;
@@ -267,9 +221,15 @@ refund_transaction (void *cls,
   /* handle if conflicting refund found */
   if (GNUNET_SYSERR == refund_found)
   {
-    *mhd_ret = reply_refund_conflict (connection,
-                                      &refund->coin.coin_pub,
-                                      tl);
+    *mhd_ret = TALER_MHD_reply_json_pack (
+      connection,
+      MHD_HTTP_CONFLICT,
+      "{s:s, s:I, s:o}",
+      "hint", "conflicting refund",
+      "code", (json_int_t) TALER_EC_REFUND_CONFLICT,
+      "history", TEH_RESPONSE_compile_transaction_history (
+        &refund->coin.coin_pub,
+        tl));
     TEH_plugin->free_coin_transaction_list (TEH_plugin->cls,
                                             tl);
     return GNUNET_DB_STATUS_HARD_ERROR;
@@ -321,7 +281,7 @@ refund_transaction (void *cls,
     *mhd_ret = TALER_MHD_reply_with_error (connection,
                                            MHD_HTTP_INTERNAL_SERVER_ERROR,
                                            TALER_EC_REFUND_DB_INCONSISTENT,
-                                           "database inconsistent");
+                                           "database inconsistent (deposit 
data became inaccessible during transaction)");
     return qs;
   }
   if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
@@ -352,24 +312,6 @@ refund_transaction (void *cls,
                                            "refund requested exceeds original 
value");
     return GNUNET_DB_STATUS_HARD_ERROR;
   }
-  /* Check refund fee matches fee of denomination key! */
-  fee_cmp = TALER_amount_cmp (&refund->details.refund_fee,
-                              &rc->expect_fee);
-  if (-1 == fee_cmp)
-  {
-    TEH_plugin->free_coin_transaction_list (TEH_plugin->cls,
-                                            tl);
-    *mhd_ret = TALER_MHD_reply_with_error (connection,
-                                           MHD_HTTP_BAD_REQUEST,
-                                           TALER_EC_REFUND_FEE_TOO_LOW,
-                                           "refund_fee");
-    return GNUNET_DB_STATUS_HARD_ERROR;
-  }
-  if (1 == fee_cmp)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                "Refund fee proposed by merchant is higher than necessary.\n");
-  }
   TEH_plugin->free_coin_transaction_list (TEH_plugin->cls,
                                           tl);
 
@@ -405,50 +347,35 @@ static int
 verify_and_execute_refund (struct MHD_Connection *connection,
                            const struct TALER_EXCHANGEDB_Refund *refund)
 {
-  struct TALER_EXCHANGEDB_RefundContext rc;
-  struct TALER_RefundRequestPS rr;
   struct GNUNET_HashCode denom_hash;
+  struct TALER_Amount expect_fee;
 
-  if (GNUNET_YES !=
-      TALER_amount_cmp_currency (&refund->details.refund_amount,
-                                 &refund->details.refund_fee) )
   {
-    GNUNET_break_op (0);
-    return TALER_MHD_reply_with_error (connection,
-                                       MHD_HTTP_BAD_REQUEST,
-                                       TALER_EC_REFUND_FEE_CURRENCY_MISSMATCH,
-                                       "refund_fee");
-  }
-  if (-1 == TALER_amount_cmp (&refund->details.refund_amount,
-                              &refund->details.refund_fee) )
-  {
-    GNUNET_break_op (0);
-    return TALER_MHD_reply_with_error (connection,
-                                       MHD_HTTP_BAD_REQUEST,
-                                       TALER_EC_REFUND_FEE_ABOVE_AMOUNT,
-                                       "refund_amount");
-  }
-  rr.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_REFUND);
-  rr.purpose.size = htonl (sizeof (struct TALER_RefundRequestPS));
-  rr.h_contract_terms = refund->details.h_contract_terms;
-  rr.coin_pub = refund->coin.coin_pub;
-  rr.merchant = refund->details.merchant_pub;
-  rr.rtransaction_id = GNUNET_htonll (refund->details.rtransaction_id);
-  TALER_amount_hton (&rr.refund_amount,
-                     &refund->details.refund_amount);
-  TALER_amount_hton (&rr.refund_fee,
-                     &refund->details.refund_fee);
-  if (GNUNET_OK !=
-      GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MERCHANT_REFUND,
-                                  &rr.purpose,
-                                  &refund->details.merchant_sig.eddsa_sig,
-                                  &refund->details.merchant_pub.eddsa_pub))
-  {
-    TALER_LOG_WARNING ("Invalid signature on /refund request\n");
-    return TALER_MHD_reply_with_error (connection,
-                                       MHD_HTTP_FORBIDDEN,
-                                       
TALER_EC_REFUND_MERCHANT_SIGNATURE_INVALID,
-                                       "merchant_sig");
+    struct TALER_RefundRequestPS rr = {
+      .purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_REFUND),
+      .purpose.size = htonl (sizeof (rr)),
+      .h_contract_terms = refund->details.h_contract_terms,
+      .coin_pub = refund->coin.coin_pub,
+      .merchant = refund->details.merchant_pub,
+      .rtransaction_id = GNUNET_htonll (refund->details.rtransaction_id)
+    };
+
+    TALER_amount_hton (&rr.refund_amount,
+                       &refund->details.refund_amount);
+    TALER_amount_hton (&rr.refund_fee,
+                       &refund->details.refund_fee);
+    if (GNUNET_OK !=
+        GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MERCHANT_REFUND,
+                                    &rr.purpose,
+                                    &refund->details.merchant_sig.eddsa_sig,
+                                    &refund->details.merchant_pub.eddsa_pub))
+    {
+      TALER_LOG_WARNING ("Invalid signature on refund request\n");
+      return TALER_MHD_reply_with_error (connection,
+                                         MHD_HTTP_FORBIDDEN,
+                                         
TALER_EC_REFUND_MERCHANT_SIGNATURE_INVALID,
+                                         "merchant_sig");
+    }
   }
 
   /* Fetch the coin's denomination (hash) */
@@ -503,23 +430,53 @@ verify_and_execute_refund (struct MHD_Connection 
*connection,
                                            ec,
                                            "denomination not found, but coin 
known");
       }
-      TALER_amount_ntoh (&rc.expect_fee,
+      TALER_amount_ntoh (&expect_fee,
                          &dki->issue.properties.fee_refund);
     }
     TEH_KS_release (key_state);
   }
 
+  /* Check refund fee matches fee of denomination key! */
+  if (GNUNET_YES !=
+      TALER_amount_cmp_currency (&expect_fee,
+                                 &refund->details.refund_fee) )
+  {
+    GNUNET_break_op (0);
+    return TALER_MHD_reply_with_error (connection,
+                                       MHD_HTTP_BAD_REQUEST,
+                                       TALER_EC_REFUND_FEE_CURRENCY_MISSMATCH,
+                                       "refund_fee");
+  }
+  {
+    int fee_cmp;
+
+    fee_cmp = TALER_amount_cmp (&refund->details.refund_fee,
+                                &expect_fee);
+    if (-1 == fee_cmp)
+    {
+      return TALER_MHD_reply_with_error (connection,
+                                         MHD_HTTP_BAD_REQUEST,
+                                         TALER_EC_REFUND_FEE_TOO_LOW,
+                                         "refund_fee");
+    }
+    if (1 == fee_cmp)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                  "Refund fee proposed by merchant is higher than 
necessary.\n");
+    }
+  }
+
+
   /* Finally run the actual transaction logic */
   {
     int mhd_ret;
 
-    rc.refund = refund;
     if (GNUNET_OK !=
         TEH_DB_run_transaction (connection,
                                 "run refund",
                                 &mhd_ret,
                                 &refund_transaction,
-                                &rc))
+                                (void *) refund))
     {
       return mhd_ret;
     }
@@ -546,7 +503,6 @@ TEH_handler_refund (struct MHD_Connection *connection,
                     const struct TALER_CoinSpendPublicKeyP *coin_pub,
                     const json_t *root)
 {
-  int res;
   struct TALER_EXCHANGEDB_Refund refund;
   struct GNUNET_JSON_Specification spec[] = {
     TALER_JSON_spec_amount ("refund_amount", &refund.details.refund_amount),
@@ -561,17 +517,46 @@ TEH_handler_refund (struct MHD_Connection *connection,
   };
 
   refund.coin.coin_pub = *coin_pub;
-  res = TALER_MHD_parse_json_data (connection,
-                                   root,
-                                   spec);
-  if (GNUNET_SYSERR == res)
-    return MHD_NO; /* hard failure */
-  if (GNUNET_NO == res)
-    return MHD_YES; /* failure */
-  res = verify_and_execute_refund (connection,
-                                   &refund);
-  GNUNET_JSON_parse_free (spec);
-  return res;
+  {
+    int res;
+
+    res = TALER_MHD_parse_json_data (connection,
+                                     root,
+                                     spec);
+    if (GNUNET_SYSERR == res)
+      return MHD_NO; /* hard failure */
+    if (GNUNET_NO == res)
+      return MHD_YES; /* failure */
+  }
+  if (GNUNET_YES !=
+      TALER_amount_cmp_currency (&refund.details.refund_amount,
+                                 &refund.details.refund_fee) )
+  {
+    GNUNET_break_op (0);
+    GNUNET_JSON_parse_free (spec);
+    return TALER_MHD_reply_with_error (connection,
+                                       MHD_HTTP_BAD_REQUEST,
+                                       TALER_EC_REFUND_FEE_CURRENCY_MISSMATCH,
+                                       "refund_amount or refund_fee");
+  }
+  if (-1 == TALER_amount_cmp (&refund.details.refund_amount,
+                              &refund.details.refund_fee) )
+  {
+    GNUNET_break_op (0);
+    GNUNET_JSON_parse_free (spec);
+    return TALER_MHD_reply_with_error (connection,
+                                       MHD_HTTP_BAD_REQUEST,
+                                       TALER_EC_REFUND_FEE_ABOVE_AMOUNT,
+                                       "refund_amount");
+  }
+  {
+    int res;
+
+    res = verify_and_execute_refund (connection,
+                                     &refund);
+    GNUNET_JSON_parse_free (spec);
+    return res;
+  }
 }
 
 
diff --git a/src/exchange/taler-exchange-httpd_withdraw.c 
b/src/exchange/taler-exchange-httpd_withdraw.c
index 0a334ec4..4575a8ab 100644
--- a/src/exchange/taler-exchange-httpd_withdraw.c
+++ b/src/exchange/taler-exchange-httpd_withdraw.c
@@ -18,7 +18,7 @@
 */
 /**
  * @file taler-exchange-httpd_withdraw.c
- * @brief Handle /reserve/withdraw requests
+ * @brief Handle /reserves/$RESERVE_PUB/withdraw requests
  * @author Florian Dold
  * @author Benedikt Mueller
  * @author Christian Grothoff
@@ -42,7 +42,7 @@
 
 
 /**
- * Send reserve status information to client with the
+ * Send reserve history information to client with the
  * message that we have insufficient funds for the
  * requested withdraw operation.
  *
@@ -52,10 +52,10 @@
  * @return MHD result code
  */
 static int
-reply_reserve_withdraw_insufficient_funds (struct MHD_Connection *connection,
-                                           const struct TALER_Amount *ebalance,
-                                           const struct
-                                           TALER_EXCHANGEDB_ReserveHistory *rh)
+reply_withdraw_insufficient_funds (
+  struct MHD_Connection *connection,
+  const struct TALER_Amount *ebalance,
+  const struct TALER_EXCHANGEDB_ReserveHistory *rh)
 {
   json_t *json_history;
   struct TALER_Amount balance;
@@ -66,7 +66,7 @@ reply_reserve_withdraw_insufficient_funds (struct 
MHD_Connection *connection,
     return TALER_MHD_reply_with_error (connection,
                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
                                        
TALER_EC_WITHDRAW_HISTORY_DB_ERROR_INSUFFICIENT_FUNDS,
-                                       "balance calculation failure");
+                                       "reserve balance calculation failure");
   if (0 !=
       TALER_amount_cmp (&balance,
                         ebalance))
@@ -75,7 +75,7 @@ reply_reserve_withdraw_insufficient_funds (struct 
MHD_Connection *connection,
     json_decref (json_history);
     return TALER_MHD_reply_with_error (connection,
                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
-                                       
TALER_EC_WITHDRAW_HISTORY_RESERVE_BALANCE_CORRUPT,
+                                       
TALER_EC_WITHDRAW_RESERVE_BALANCE_CORRUPT,
                                        "internal balance inconsistency error");
   }
   return TALER_MHD_reply_json_pack (connection,
@@ -92,21 +92,25 @@ reply_reserve_withdraw_insufficient_funds (struct 
MHD_Connection *connection,
 
 
 /**
- * Send blinded coin information to client.
+ * Send blind signature to client.
  *
  * @param connection connection to the client
  * @param collectable blinded coin to return
  * @return MHD result code
  */
 static int
-reply_reserve_withdraw_success (struct MHD_Connection *connection,
-                                const struct
-                                TALER_EXCHANGEDB_CollectableBlindcoin *
-                                collectable)
+reply_withdraw_success (
+  struct MHD_Connection *connection,
+  const struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable)
 {
   json_t *sig_json;
 
   sig_json = GNUNET_JSON_from_rsa_signature (collectable->sig.rsa_signature);
+  if (NULL == sig_json)
+    return TALER_MHD_reply_with_error (connection,
+                                       MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                       TALER_EC_JSON_ALLOCATION_FAILURE,
+                                       "GNUNET_JSON_from_rsa_signature() 
failed");
   return TALER_MHD_reply_json_pack (connection,
                                     MHD_HTTP_OK,
                                     "{s:o}",
@@ -168,7 +172,7 @@ struct WithdrawContext
 
 
 /**
- * Function implementing /reserve/withdraw transaction.  Runs the
+ * Function implementing withdraw 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.
@@ -180,9 +184,9 @@ struct WithdrawContext
  * before entering the transaction, or because this function is run
  * twice (!) by #TEH_DB_run_transaction() and the first time created
  * the signature and then failed to commit.  Furthermore, we may get
- * a 2nd correct signature briefly if "get_withdraw_info" suceeds and
+ * a 2nd correct signature briefly if "get_withdraw_info" succeeds and
  * finds one in the DB.  To avoid signing twice, the function may
- * return a valid signature in "wc->collectable.sig" even if it failed.
+ * return a valid signature in "wc->collectable.sig" **even if it failed**.
  * The caller must thus free the signature in either case.
  *
  * @param cls a `struct WithdrawContext *`
@@ -201,7 +205,6 @@ withdraw_transaction (void *cls,
   struct WithdrawContext *wc = cls;
   struct TALER_EXCHANGEDB_Reserve r;
   enum GNUNET_DB_QueryStatus qs;
-  struct TALER_Amount fee_withdraw;
   struct TALER_DenominationSignature denom_sig;
 
 #if OPTIMISTIC_SIGN
@@ -227,18 +230,23 @@ withdraw_transaction (void *cls,
   }
 
   /* Don't sign again if we have already signed the coin */
-  if (1 == qs)
+  if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
   {
+    /* Toss out the optimistic signature, we got another one from the DB;
+       optimization trade-off loses in this case: we unnecessarily computed
+       a signature :-( */
 #if OPTIMISTIC_SIGN
     GNUNET_CRYPTO_rsa_signature_free (denom_sig.rsa_signature);
 #endif
     return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
   }
-  GNUNET_assert (0 == qs);
-  wc->collectable.sig = denom_sig;
+  /* We should never get more than one result, and we handled
+     the errors (negative case) above, so that leaves no results. */
+  GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs);
+  wc->collectable.sig = denom_sig; /* Note: might still be NULL if we didn't 
do OPTIMISTIC_SIGN */
 
   /* Check if balance is sufficient */
-  r.pub = wc->wsrd.reserve_pub;
+  r.pub = wc->wsrd.reserve_pub; /* other fields of 'r' initialized in 
reserves_get (if successful) */
   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
               "Trying to withdraw from reserve: %s\n",
               TALER_B2S (&r.pub));
@@ -265,20 +273,25 @@ withdraw_transaction (void *cls,
   if (0 < TALER_amount_cmp (&wc->amount_required,
                             &r.balance))
   {
-    char *amount_required;
-    char *r_balance;
     struct TALER_EXCHANGEDB_ReserveHistory *rh;
 
     /* The reserve does not have the required amount (actual
      * amount + withdraw fee) */
     GNUNET_break_op (0);
-    amount_required = TALER_amount_to_string (&wc->amount_required);
-    r_balance = TALER_amount_to_string (&r.balance);
-    TALER_LOG_WARNING ("Asked %s over a reserve worth %s\n",
-                       amount_required,
-                       r_balance);
-    GNUNET_free (amount_required);
-    GNUNET_free (r_balance);
+#if GNUNET_EXTRA_LOGGING
+    {
+      char *amount_required;
+      char *r_balance;
+
+      amount_required = TALER_amount_to_string (&wc->amount_required);
+      r_balance = TALER_amount_to_string (&r.balance);
+      TALER_LOG_WARNING ("Asked %s over a reserve worth %s\n",
+                         amount_required,
+                         r_balance);
+      GNUNET_free (amount_required);
+      GNUNET_free (r_balance);
+    }
+#endif
     qs = TEH_plugin->get_reserve_history (TEH_plugin->cls,
                                           session,
                                           &wc->wsrd.reserve_pub,
@@ -292,9 +305,9 @@ withdraw_transaction (void *cls,
                                                "failed to fetch reserve 
history");
       return GNUNET_DB_STATUS_HARD_ERROR;
     }
-    *mhd_ret = reply_reserve_withdraw_insufficient_funds (connection,
-                                                          &r.balance,
-                                                          rh);
+    *mhd_ret = reply_withdraw_insufficient_funds (connection,
+                                                  &r.balance,
+                                                  rh);
     TEH_plugin->free_reserve_history (TEH_plugin->cls,
                                       rh);
     return GNUNET_DB_STATUS_HARD_ERROR;
@@ -314,16 +327,15 @@ withdraw_transaction (void *cls,
       *mhd_ret = TALER_MHD_reply_with_error (connection,
                                              MHD_HTTP_INTERNAL_SERVER_ERROR,
                                              
TALER_EC_WITHDRAW_SIGNATURE_FAILED,
-                                             "Failed to create signature");
+                                             "Failed to create blind 
signature");
       return GNUNET_DB_STATUS_HARD_ERROR;
     }
   }
 #endif
-  TALER_amount_ntoh (&fee_withdraw,
-                     &wc->dki->issue.properties.fee_withdraw);
   wc->collectable.denom_pub_hash = wc->denom_pub_hash;
   wc->collectable.amount_with_fee = wc->amount_required;
-  wc->collectable.withdraw_fee = fee_withdraw;
+  TALER_amount_ntoh (&wc->collectable.withdraw_fee,
+                     &wc->dki->issue.properties.fee_withdraw);
   wc->collectable.reserve_pub = wc->wsrd.reserve_pub;
   wc->collectable.h_coin_envelope = wc->wsrd.h_coin_envelope;
   wc->collectable.reserve_sig = wc->signature;
@@ -366,12 +378,6 @@ TEH_handler_withdraw (const struct TEH_RequestHandler *rh,
                       const char *const args[2])
 {
   struct WithdrawContext wc;
-  int res;
-  int mhd_ret;
-  unsigned int hc;
-  enum TALER_ErrorCode ec;
-  struct TALER_Amount amount;
-  struct TALER_Amount fee_withdraw;
   struct GNUNET_JSON_Specification spec[] = {
     GNUNET_JSON_spec_varsize ("coin_ev",
                               (void **) &wc.blinded_msg,
@@ -397,11 +403,15 @@ TEH_handler_withdraw (const struct TEH_RequestHandler *rh,
                                        "reserve public key malformed");
   }
 
-  res = TALER_MHD_parse_json_data (connection,
-                                   root,
-                                   spec);
-  if (GNUNET_OK != res)
-    return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
+  {
+    int res;
+
+    res = TALER_MHD_parse_json_data (connection,
+                                     root,
+                                     spec);
+    if (GNUNET_OK != res)
+      return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
+  }
   wc.key_state = TEH_KS_acquire (GNUNET_TIME_absolute_get ());
   if (NULL == wc.key_state)
   {
@@ -412,41 +422,52 @@ TEH_handler_withdraw (const struct TEH_RequestHandler *rh,
                                        TALER_EC_EXCHANGE_BAD_CONFIGURATION,
                                        "no keys");
   }
-  wc.dki = TEH_KS_denomination_key_lookup_by_hash (wc.key_state,
-                                                   &wc.denom_pub_hash,
-                                                   TEH_KS_DKU_WITHDRAW,
-                                                   &ec,
-                                                   &hc);
-  if (NULL == wc.dki)
   {
-    GNUNET_JSON_parse_free (spec);
-    TEH_KS_release (wc.key_state);
-    return TALER_MHD_reply_with_error (connection,
-                                       hc,
-                                       ec,
-                                       "could not find denomination key");
+    unsigned int hc;
+    enum TALER_ErrorCode ec;
+
+    wc.dki = TEH_KS_denomination_key_lookup_by_hash (wc.key_state,
+                                                     &wc.denom_pub_hash,
+                                                     TEH_KS_DKU_WITHDRAW,
+                                                     &ec,
+                                                     &hc);
+    if (NULL == wc.dki)
+    {
+      GNUNET_JSON_parse_free (spec);
+      TEH_KS_release (wc.key_state);
+      return TALER_MHD_reply_with_error (connection,
+                                         hc,
+                                         ec,
+                                         "could not find denomination key");
+    }
   }
   GNUNET_assert (NULL != wc.dki->denom_priv.rsa_private_key);
-  TALER_amount_ntoh (&amount,
-                     &wc.dki->issue.properties.value);
-  TALER_amount_ntoh (&fee_withdraw,
-                     &wc.dki->issue.properties.fee_withdraw);
-  if (GNUNET_OK !=
-      TALER_amount_add (&wc.amount_required,
-                        &amount,
-                        &fee_withdraw))
   {
-    GNUNET_JSON_parse_free (spec);
-    TEH_KS_release (wc.key_state);
-    return TALER_MHD_reply_with_error (connection,
-                                       MHD_HTTP_INTERNAL_SERVER_ERROR,
-                                       TALER_EC_WITHDRAW_AMOUNT_FEE_OVERFLOW,
-                                       "amount overflow for value plus 
withdraw fee");
+    struct TALER_Amount amount;
+    struct TALER_Amount fee_withdraw;
+
+    TALER_amount_ntoh (&amount,
+                       &wc.dki->issue.properties.value);
+    TALER_amount_ntoh (&fee_withdraw,
+                       &wc.dki->issue.properties.fee_withdraw);
+    if (GNUNET_OK !=
+        TALER_amount_add (&wc.amount_required,
+                          &amount,
+                          &fee_withdraw))
+    {
+      GNUNET_JSON_parse_free (spec);
+      TEH_KS_release (wc.key_state);
+      return TALER_MHD_reply_with_error (connection,
+                                         MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                         TALER_EC_WITHDRAW_AMOUNT_FEE_OVERFLOW,
+                                         "amount overflow for value plus 
withdraw fee");
+    }
+    TALER_amount_hton (&wc.wsrd.amount_with_fee,
+                       &wc.amount_required);
+    TALER_amount_hton (&wc.wsrd.withdraw_fee,
+                       &fee_withdraw);
   }
-  TALER_amount_hton (&wc.wsrd.amount_with_fee,
-                     &wc.amount_required);
-  TALER_amount_hton (&wc.wsrd.withdraw_fee,
-                     &fee_withdraw);
+
   /* verify signature! */
   wc.wsrd.purpose.size
     = htonl (sizeof (struct TALER_WithdrawRequestPS));
@@ -491,28 +512,39 @@ TEH_handler_withdraw (const struct TEH_RequestHandler *rh,
   }
 #endif
 
-  if (GNUNET_OK !=
-      TEH_DB_run_transaction (connection,
-                              "run withdraw",
-                              &mhd_ret,
-                              &withdraw_transaction,
-                              &wc))
+  /* run transaction and sign (if not optimistically signed before) */
   {
-    TEH_KS_release (wc.key_state);
-    /* Even if #withdraw_transaction() failed, it may have created a signature
-       (or we might have done it optimistically above). */
-    if (NULL != wc.collectable.sig.rsa_signature)
-      GNUNET_CRYPTO_rsa_signature_free (wc.collectable.sig.rsa_signature);
-    GNUNET_JSON_parse_free (spec);
-    return mhd_ret;
+    int mhd_ret;
+
+    if (GNUNET_OK !=
+        TEH_DB_run_transaction (connection,
+                                "run withdraw",
+                                &mhd_ret,
+                                &withdraw_transaction,
+                                &wc))
+    {
+      TEH_KS_release (wc.key_state);
+      /* Even if #withdraw_transaction() failed, it may have created a 
signature
+         (or we might have done it optimistically above). */
+      if (NULL != wc.collectable.sig.rsa_signature)
+        GNUNET_CRYPTO_rsa_signature_free (wc.collectable.sig.rsa_signature);
+      GNUNET_JSON_parse_free (spec);
+      return mhd_ret;
+    }
   }
+
+  /* Clean up and send back final (positive) response */
   TEH_KS_release (wc.key_state);
   GNUNET_JSON_parse_free (spec);
 
-  mhd_ret = reply_reserve_withdraw_success (connection,
-                                            &wc.collectable);
-  GNUNET_CRYPTO_rsa_signature_free (wc.collectable.sig.rsa_signature);
-  return mhd_ret;
+  {
+    int ret;
+
+    ret = reply_withdraw_success (connection,
+                                  &wc.collectable);
+    GNUNET_CRYPTO_rsa_signature_free (wc.collectable.sig.rsa_signature);
+    return ret;
+  }
 }
 
 
diff --git a/src/include/taler_error_codes.h b/src/include/taler_error_codes.h
index e6bd7364..9a7c544b 100644
--- a/src/include/taler_error_codes.h
+++ b/src/include/taler_error_codes.h
@@ -382,11 +382,11 @@ enum TALER_ErrorCode
   TALER_EC_DENOMINATION_KEY_LOST = 1116,
 
   /**
-   * The exchange's database entry with the reserve balance summary
-   * is inconsistent with its own history of the reserve.
-   * Returned with an HTTP status of #MHD_HTTP_INTERNAL_SERVER_ERROR.
+   * The exchange's database entry with the reserve balance summary is
+   * inconsistent with its own history of the reserve. Returned with an
+   * HTTP status of #MHD_HTTP_INTERNAL_SERVER_ERROR.
    */
-  TALER_EC_WITHDRAW_HISTORY_RESERVE_BALANCE_CORRUPT = 1117,
+  TALER_EC_WITHDRAW_RESERVE_BALANCE_CORRUPT = 1117,
 
   /**
    * The exchange failed to obtain the transaction history of the given
@@ -528,6 +528,13 @@ enum TALER_ErrorCode
    */
   TALER_EC_DEPOSIT_INVALID_SIGNATURE_BY_EXCHANGE = 1221,
 
+  /**
+   * The currency specified for the deposit is different from the
+   * currency of the coin.  This response is provided with HTTP status
+   * code MHD_HTTP_PRECONDITION_FAILED.
+   */
+  TALER_EC_DEPOSIT_CURRENCY_MISSMATCH = 1222,
+
   /**
    * The respective coin did not have sufficient residual value for the
    * /refresh/melt operation.  The "history" in this response provdes
@@ -544,7 +551,7 @@ enum TALER_ErrorCode
    * "original_value".  This response is provided with HTTP status code
    * MHD_HTTP_CONFLICT.
    */
-  TALER_EC_TALER_EC_REFRESH_MELT_DENOMINATION_KEY_NOT_FOUND = 1301,
+  TALER_EC_REFRESH_MELT_DENOMINATION_KEY_NOT_FOUND = 1301,
 
   /**
    * The exchange had an internal error reconstructing the transaction
@@ -607,6 +614,13 @@ enum TALER_ErrorCode
    */
   TALER_EC_MELT_INVALID_SIGNATURE_BY_EXCHANGE = 1310,
 
+  /**
+   * The currency specified for the melt amount is different from the
+   * currency of the coin.  This response is provided with HTTP status
+   * code MHD_HTTP_PRECONDITION_FAILED.
+   */
+  TALER_EC_MELT_CURRENCY_MISSMATCH = 1311,
+
   /**
    * The exchange is unaware of the denomination key that was used to
    * sign the melted zombie coin.  This response is provided with HTTP

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



reply via email to

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