gnunet-svn
[Top][All Lists]
Advanced

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

[taler-merchant] 05/06: more work on multicurrency support: use checks e


From: gnunet
Subject: [taler-merchant] 05/06: more work on multicurrency support: use checks everywhere...
Date: Fri, 13 Oct 2023 21:17:00 +0200

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

grothoff pushed a commit to branch master
in repository merchant.

commit 0f3490dc022620c7e42b86426e14198a04c2e17f
Author: Christian Grothoff <grothoff@gnunet.org>
AuthorDate: Fri Oct 13 20:51:04 2023 +0200

    more work on multicurrency support: use checks everywhere...
---
 src/backend/taler-merchant-httpd_get-orders-ID.c   | 135 +++++++++++++----
 src/backend/taler-merchant-httpd_helper.c          |   8 +-
 .../taler-merchant-httpd_post-orders-ID-pay.c      | 159 +++++++++++++++------
 .../taler-merchant-httpd_post-using-templates.c    |  23 ++-
 .../taler-merchant-httpd_private-get-orders-ID.c   |  96 +++++++++++--
 .../taler-merchant-httpd_private-get-orders.c      |  11 +-
 .../taler-merchant-httpd_private-post-orders.c     |  18 ++-
 .../taler-merchant-httpd_private-post-templates.c  |   2 +-
 src/backenddb/pg_increase_refund.c                 |   9 +-
 9 files changed, 363 insertions(+), 98 deletions(-)

diff --git a/src/backend/taler-merchant-httpd_get-orders-ID.c 
b/src/backend/taler-merchant-httpd_get-orders-ID.c
index 9c60f7a9..af5513d9 100644
--- a/src/backend/taler-merchant-httpd_get-orders-ID.c
+++ b/src/backend/taler-merchant-httpd_get-orders-ID.c
@@ -119,6 +119,22 @@ struct GetOrderData
    */
   json_t *contract_terms;
 
+  /**
+   * Merchant base URL from @e contract_terms.
+   */
+  const char *merchant_base_url;
+
+  /**
+   * Public reorder URL from @e contract_terms.
+   * Could be NULL if contract does not have one.
+   */
+  const char *public_reorder_url;
+
+  /**
+   * Total amount in contract.
+   */
+  struct TALER_Amount contract_total;
+
   /**
    * Total refunds granted for this payment. Only initialized
    * if @e refunded is set to true.
@@ -180,6 +196,16 @@ struct GetOrderData
    */
   bool generate_html;
 
+  /**
+   * Did we parse the contract terms?
+   */
+  bool contract_parsed;
+
+  /**
+   * Set to true if the refunds found in the DB have
+   * a different currency then the main contract.
+   */
+  bool bad_refund_currency_in_db;
 };
 
 
@@ -316,6 +342,9 @@ suspend_god (struct GetOrderData *god)
     json_decref (god->contract_terms);
     god->fulfillment_url = NULL;
     god->contract_terms = NULL;
+    god->contract_parsed = false;
+    god->merchant_base_url = NULL;
+    god->public_reorder_url = NULL;
   }
   GNUNET_assert (! god->suspended);
   god->suspended = GNUNET_YES;
@@ -712,6 +741,16 @@ process_refunds_cb (void *cls,
               TALER_B2S (coin_pub),
               reason);
   god->refund_pending |= pending;
+  if ( (GNUNET_OK !=
+        TALER_amount_cmp_currency (&god->refund_taken,
+                                   refund_amount)) ||
+       (GNUNET_OK !=
+        TALER_amount_cmp_currency (&god->refund_amount,
+                                   refund_amount)) )
+  {
+    god->bad_refund_currency_in_db = true;
+    return;
+  }
   if (! pending)
   {
     GNUNET_assert (0 <=
@@ -767,7 +806,6 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh,
   bool contract_match = false;
   bool token_match = false;
   bool contract_available = false;
-  const char *merchant_base_url;
 
   (void) rh;
   if (NULL == god)
@@ -945,10 +983,9 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh,
   if (NULL != god->contract_terms)
   {
     contract_available = true;
-
-    if (GNUNET_YES == GNUNET_is_zero (&god->h_contract_terms))
+    if (GNUNET_YES ==
+        GNUNET_is_zero (&god->h_contract_terms))
     {
-
       if (GNUNET_OK !=
           TALER_JSON_contract_hash (god->contract_terms,
                                     &god->h_contract_terms))
@@ -959,11 +996,9 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh,
                                            
TALER_EC_GENERIC_FAILED_COMPUTE_JSON_HASH,
                                            "contract terms");
       }
-
     }
     else
     {
-
       struct TALER_PrivateContractHashP h;
 
       if (GNUNET_OK !=
@@ -988,9 +1023,7 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh,
           TALER_EC_MERCHANT_GENERIC_CONTRACT_HASH_DOES_NOT_MATCH_ORDER,
           NULL);
       }
-
     }
-
   }
 
   if (contract_available)
@@ -1040,21 +1073,46 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh,
   } /* end unclaimed order logic */
 
   GNUNET_assert (NULL != god->contract_terms);
-  merchant_base_url = json_string_value (json_object_get (god->contract_terms,
-                                                          
"merchant_base_url"));
-  if (NULL == merchant_base_url)
+  if (! god->contract_parsed)
   {
-    GNUNET_break (0);
-    return TALER_MHD_reply_with_error (connection,
-                                       MHD_HTTP_INTERNAL_SERVER_ERROR,
-                                       
TALER_EC_MERCHANT_GENERIC_DB_CONTRACT_CONTENT_INVALID,
-                                       order_id);
+    struct GNUNET_JSON_Specification espec[] = {
+      TALER_JSON_spec_amount_any ("amount",
+                                  &god->contract_total),
+      GNUNET_JSON_spec_string ("merchant_base_url",
+                               &god->merchant_base_url),
+      GNUNET_JSON_spec_mark_optional (
+        GNUNET_JSON_spec_string ("fulfillment_url",
+                                 &god->fulfillment_url),
+        NULL),
+      GNUNET_JSON_spec_mark_optional (
+        GNUNET_JSON_spec_string ("public_reorder_url",
+                                 &god->public_reorder_url),
+        NULL),
+      GNUNET_JSON_spec_end ()
+    };
+    enum GNUNET_GenericReturnValue res;
+    const char *ename;
+    unsigned int eline;
+
+    res = GNUNET_JSON_parse (god->contract_terms,
+                             espec,
+                             &ename,
+                             &eline);
+    if (GNUNET_OK != res)
+    {
+      GNUNET_break (0);
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  "Failed to parse contract %s in DB at field %s\n",
+                  order_id,
+                  ename);
+      return TALER_MHD_reply_with_error (connection,
+                                         MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                         
TALER_EC_MERCHANT_GENERIC_DB_CONTRACT_CONTENT_INVALID,
+                                         order_id);
+    }
+    god->contract_parsed = true;
   }
 
-  if (NULL == god->fulfillment_url)
-    god->fulfillment_url = json_string_value (json_object_get (
-                                                god->contract_terms,
-                                                "fulfillment_url"));
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Token match: %d, contract_available: %d, contract match: %d, 
claimed: %d\n",
               token_match,
@@ -1085,15 +1143,11 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh,
   if (! (token_match ||
          contract_match) )
   {
-    const char *public_reorder_url;
 
     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
                 "Neither claim token nor contract matched\n");
-    public_reorder_url = json_string_value (json_object_get (
-                                              god->contract_terms,
-                                              "public_reorder_url"));
     /* Client has no rights to this order */
-    if (NULL == public_reorder_url)
+    if (NULL == god->public_reorder_url)
     {
       /* We cannot give the client a new order, just fail */
       if (! GNUNET_is_zero (&god->h_contract_terms))
@@ -1135,7 +1189,7 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh,
       GNUNET_break (MHD_YES ==
                     MHD_add_response_header (reply,
                                              MHD_HTTP_HEADER_LOCATION,
-                                             public_reorder_url));
+                                             god->public_reorder_url));
       ret = MHD_queue_response (connection,
                                 MHD_HTTP_FOUND,
                                 reply);
@@ -1147,7 +1201,7 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh,
       connection,
       MHD_HTTP_ACCEPTED,
       GNUNET_JSON_pack_string ("public_reorder_url",
-                               public_reorder_url));
+                               god->public_reorder_url));
   }
 
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -1247,13 +1301,25 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh,
     }
   }
 
+  if ( (god->sc.awaiting_refund) &&
+       (GNUNET_OK !=
+        TALER_amount_cmp_currency (&god->contract_total,
+                                   &god->sc.refund_expected)) )
+  {
+    GNUNET_break (0);
+    return TALER_MHD_reply_with_error (connection,
+                                       MHD_HTTP_CONFLICT,
+                                       
TALER_EC_MERCHANT_GENERIC_CURRENCY_MISMATCH,
+                                       god->contract_total.currency);
+  }
+
   /* At this point, we know the contract was paid. Let's check for
      refunds. First, clear away refunds found from previous invocations. */
   GNUNET_assert (GNUNET_OK ==
-                 TALER_amount_set_zero (TMH_currency,
+                 TALER_amount_set_zero (god->contract_total.currency,
                                         &god->refund_amount));
   GNUNET_assert (GNUNET_OK ==
-                 TALER_amount_set_zero (TMH_currency,
+                 TALER_amount_set_zero (god->contract_total.currency,
                                         &god->refund_taken));
   qs = TMH_db->lookup_refunds_detailed (TMH_db->cls,
                                         hc->instance->settings.id,
@@ -1268,7 +1334,14 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh,
                                        TALER_EC_GENERIC_DB_FETCH_FAILED,
                                        "lookup_refunds_detailed");
   }
-
+  if (god->bad_refund_currency_in_db)
+  {
+    GNUNET_break (0);
+    return TALER_MHD_reply_with_error (connection,
+                                       MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                       TALER_EC_GENERIC_DB_FETCH_FAILED,
+                                       "currency mix-up between contract price 
and refunds in database");
+  }
   if ( ((god->sc.awaiting_refund) &&
         ( (! god->refunded) ||
           (1 != TALER_amount_cmp (&god->refund_amount,
@@ -1308,7 +1381,7 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh,
       char *uri;
 
       GNUNET_assert (NULL != god->contract_terms);
-      uri = make_taler_refund_uri (merchant_base_url,
+      uri = make_taler_refund_uri (god->merchant_base_url,
                                    order_id);
       if (NULL == uri)
       {
diff --git a/src/backend/taler-merchant-httpd_helper.c 
b/src/backend/taler-merchant-httpd_helper.c
index 53b4fe89..3e525245 100644
--- a/src/backend/taler-merchant-httpd_helper.c
+++ b/src/backend/taler-merchant-httpd_helper.c
@@ -413,6 +413,7 @@ bool
 TMH_template_contract_valid (const json_t *template_contract)
 {
   const char *summary;
+  const char *currency;
   struct TALER_Amount amount = { .value = 0};
   uint32_t minimum_age = 0;
   struct GNUNET_TIME_Relative pay_duration = { 0 };
@@ -421,9 +422,10 @@ TMH_template_contract_valid (const json_t 
*template_contract)
       GNUNET_JSON_spec_string ("summary",
                                &summary),
       NULL),
-    /* FIXME: #7951: may want to allow the template to only
-       fix the currency but not the amount; current approach
-       does not allow this! */
+    GNUNET_JSON_spec_mark_optional (
+      GNUNET_JSON_spec_string ("currency",
+                               &currency),
+      NULL),
     GNUNET_JSON_spec_mark_optional (
       TALER_JSON_spec_amount_any ("amount",
                                   &amount),
diff --git a/src/backend/taler-merchant-httpd_post-orders-ID-pay.c 
b/src/backend/taler-merchant-httpd_post-orders-ID-pay.c
index d17e98c8..9edc553c 100644
--- a/src/backend/taler-merchant-httpd_post-orders-ID-pay.c
+++ b/src/backend/taler-merchant-httpd_post-orders-ID-pay.c
@@ -399,6 +399,18 @@ struct PayContext
    */
   enum GNUNET_GenericReturnValue suspended;
 
+  /**
+   * Set to true if the deposit currency of a coin
+   * does not match the contract currency.
+   */
+  bool deposit_currency_mismatch;
+  
+  /**
+   * Set to true if the database contains a (bogus)
+   * refund for a different currency.
+   */
+  bool refund_currency_mismatch;
+  
 };
 
 
@@ -909,11 +921,13 @@ batch_deposit_transaction (const struct ExchangeGroup *eg,
 {
   const struct PayContext *pc = eg->pc;
   enum GNUNET_DB_QueryStatus qs;
-  struct TALER_Amount total_without_fees = { 0 };
+  struct TALER_Amount total_without_fees;
   uint64_t b_dep_serial;
   uint32_t off = 0;
-  bool found = false;
 
+  GNUNET_assert (GNUNET_OK ==
+                 TALER_amount_set_zero (pc->amount.currency,
+                                        &total_without_fees));
   for (unsigned int i = 0; i<pc->coins_cnt; i++)
   {
     struct DepositConfirmation *dc = &pc->dc[i];
@@ -925,25 +939,14 @@ batch_deposit_transaction (const struct ExchangeGroup *eg,
       continue;
     if (dc->found_in_db)
       continue;
-    /* FIXME: #7951 */
     GNUNET_assert (0 <=
                    TALER_amount_subtract (&amount_without_fees,
                                           &dc->cdd.amount,
                                           &dc->deposit_fee));
-    if (! found)
-    {
-      found = true;
-      total_without_fees = amount_without_fees;
-    }
-    else
-    {
-      /* FIXME: #7951 */
-      GNUNET_assert (
-        0 <=
-        TALER_amount_add (&total_without_fees,
-                          &total_without_fees,
-                          &amount_without_fees));
-    }
+    GNUNET_assert (0 <=
+                   TALER_amount_add (&total_without_fees,
+                                     &total_without_fees,
+                                     &amount_without_fees));
   }
   qs = TMH_db->insert_deposit_confirmation (
     TMH_db->cls,
@@ -960,13 +963,6 @@ batch_deposit_transaction (const struct ExchangeGroup *eg,
   if (qs <= 0)
     return qs; /* Entire batch already known or failure, we're done */
 
-  if (! found)
-  {
-    /* All coins already done, but the batch was not? Invariant violation! */
-    GNUNET_break (0);
-    return GNUNET_DB_STATUS_HARD_ERROR;
-  }
-
   for (unsigned int i = 0; i<pc->coins_cnt; i++)
   {
     struct DepositConfirmation *dc = &pc->dc[i];
@@ -1596,14 +1592,26 @@ check_coin_paid (void *cls,
          (0 !=
           strcmp (exchange_url,
                   dc->exchange_url)) ||
-         /* FIXME: #7951 */
+         (GNUNET_OK !=
+          TALER_amount_cmp_currency (amount_with_fee,
+                                     &dc->cdd.amount)) ||
          (0 != TALER_amount_cmp (amount_with_fee,
                                  &dc->cdd.amount)) )
       continue; /* does not match, skip */
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                 "Deposit of coin `%s' already in our DB.\n",
                 TALER_B2S (coin_pub));
-    /* FIXME: #7951 */
+    if ( (GNUNET_OK !=
+          TALER_amount_cmp_currency (&pc->total_paid,
+                                     amount_with_fee)) ||
+         (GNUNET_OK !=
+          TALER_amount_cmp_currency (&pc->total_fees_paid,
+                                     deposit_fee)) )
+    {
+      GNUNET_break_op (0);
+      pc->deposit_currency_mismatch = true;
+      break;
+    }
     GNUNET_assert (0 <=
                    TALER_amount_add (&pc->total_paid,
                                      &pc->total_paid,
@@ -1654,7 +1662,14 @@ check_coin_refunded (void *cls,
     if (0 != GNUNET_memcmp (coin_pub,
                             &dc->cdd.coin_pub))
       continue;
-    /* FIXME: #7951 */
+    if (GNUNET_OK !=
+        TALER_amount_cmp_currency (&pc->total_refunded,
+                                   refund_amount))
+    {
+      GNUNET_break (0);
+      pc->refund_currency_mismatch = true;
+      break;
+    }
     GNUNET_assert (0 <=
                    TALER_amount_add (&pc->total_refunded,
                                      &pc->total_refunded,
@@ -1681,15 +1696,12 @@ check_payment_sufficient (struct PayContext *pc)
   struct TALER_Amount total_needed;
 
   if (0 == pc->coins_cnt)
+    return TALER_amount_is_zero (&pc->amount);
+  GNUNET_assert (GNUNET_OK ==
+                 TALER_amount_set_zero (pc->amount.currency,
+                                        &total_wire_fee));
+  for (unsigned int i = 0; i < pc->num_exchanges; i++)
   {
-    return ((0 == pc->amount.value) &&
-            (0 == pc->amount.fraction));
-  }
-
-  total_wire_fee = pc->egs[0]->wire_fee;
-  for (unsigned int i = 1; i < pc->num_exchanges; i++)
-  {
-    /* FIXME: #7951 */
     if (GNUNET_OK !=
         TALER_amount_cmp_currency (&total_wire_fee,
                                    &pc->egs[i]->wire_fee))
@@ -1700,7 +1712,6 @@ check_payment_sufficient (struct PayContext *pc)
                              total_wire_fee.currency);
       return false;
     }
-    /* FIXME: #7951 */
     if (0 >
         TALER_amount_add (&total_wire_fee,
                           &total_wire_fee,
@@ -1714,19 +1725,34 @@ check_payment_sufficient (struct PayContext *pc)
     }
   }
 
-  acc_fee = pc->dc[0].deposit_fee;
-  acc_amount = pc->dc[0].cdd.amount;
-
   /**
    * This loops calculates what are the deposit fee / total
    * amount with fee / and wire fee, for all the coins.
    */
-  for (unsigned int i = 1; i<pc->coins_cnt; i++)
+  GNUNET_assert (GNUNET_OK ==
+                 TALER_amount_set_zero (pc->amount.currency,
+                                        &acc_fee));
+  GNUNET_assert (GNUNET_OK ==
+                 TALER_amount_set_zero (pc->amount.currency,
+                                        &acc_amount));
+  for (unsigned int i = 0; i<pc->coins_cnt; i++)
   {
     struct DepositConfirmation *dc = &pc->dc[i];
 
     GNUNET_assert (dc->found_in_db);
-    /* FIXME: #7951 */
+    if ( (GNUNET_OK !=
+          TALER_amount_cmp_currency (&acc_fee,
+                                     &dc->deposit_fee)) ||
+         (GNUNET_OK !=
+          TALER_amount_cmp_currency (&acc_amount,
+                                     &dc->cdd.amount)) )
+    {
+      GNUNET_break_op (0);
+      resume_pay_with_error (pc,
+                             TALER_EC_GENERIC_CURRENCY_MISMATCH,
+                             dc->deposit_fee.currency);
+      return false;
+    }
     if ( (0 >
           TALER_amount_add (&acc_fee,
                             &dc->deposit_fee,
@@ -1743,7 +1769,6 @@ check_payment_sufficient (struct PayContext *pc)
                              "Overflow adding up amounts");
       return false;
     }
-    /* FIXME: #7951 */
     if (1 ==
         TALER_amount_cmp (&dc->deposit_fee,
                           &dc->cdd.amount))
@@ -1786,9 +1811,7 @@ check_payment_sufficient (struct PayContext *pc)
     return false;
   }
 
-
   /* add wire fee to the total fees */
-  /* FIXME: #7951 */
   if (0 >
       TALER_amount_add (&acc_fee,
                         &acc_fee,
@@ -1800,7 +1823,6 @@ check_payment_sufficient (struct PayContext *pc)
                            "Overflow adding up amounts");
     return false;
   }
-  /* FIXME: #7951 */
   if (-1 == TALER_amount_cmp (&pc->max_fee,
                               &acc_fee))
   {
@@ -2045,6 +2067,14 @@ execute_pay_transaction (struct PayContext *pc)
                              "lookup deposits");
       return;
     }
+    if (pc->deposit_currency_mismatch)
+    {
+      GNUNET_break_op (0);
+      resume_pay_with_error (pc,
+                             TALER_EC_MERCHANT_GENERIC_CURRENCY_MISMATCH,
+                             pc->amount.currency);
+      return;
+    }
   }
 
 
@@ -2072,6 +2102,14 @@ execute_pay_transaction (struct PayContext *pc)
                              "lookup refunds");
       return;
     }
+    if (pc->refund_currency_mismatch)
+    {
+      TMH_db->rollback (TMH_db->cls);
+      resume_pay_with_error (pc,
+                             TALER_EC_GENERIC_DB_FETCH_FAILED,
+                             "refund currency in database does not match order 
currency");
+      return;
+    }
   }
 
   /* Check if there are coins that still need to be processed */
@@ -2299,7 +2337,6 @@ parse_pay (struct PayContext *pc)
         GNUNET_break_op (0);
         return res;
       }
-
       for (unsigned int j = 0; j<coins_index; j++)
       {
         if (0 ==
@@ -2657,6 +2694,36 @@ check_contract (struct PayContext *pc)
     }
   }
 
+  if (GNUNET_OK !=
+      TALER_amount_cmp_currency (&pc->max_fee,
+                                 &pc->amount))
+  {
+    GNUNET_break (0);
+    return TALER_MHD_reply_with_error (pc->connection,
+                                       MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                       TALER_EC_GENERIC_DB_FETCH_FAILED,
+                                       "'max_fee' in database does not match 
currency of contract price");
+  }
+
+  for (unsigned int i=0;i<pc->coins_cnt;i++)
+  {
+    struct DepositConfirmation *dc = &pc->dc[i];
+
+    if (GNUNET_OK !=
+        TALER_amount_cmp_currency (&dc->cdd.amount,
+                                   &pc->amount))
+    {
+      GNUNET_break_op (0);
+      return (MHD_YES ==
+              TALER_MHD_reply_with_error (pc->connection,
+                                          MHD_HTTP_CONFLICT,
+                                          
TALER_EC_MERCHANT_GENERIC_CURRENCY_MISMATCH,
+                                          pc->amount.currency))
+        ? GNUNET_NO
+        : GNUNET_SYSERR;
+    }
+  }
+
   if (GNUNET_TIME_timestamp_cmp (pc->wire_transfer_deadline,
                                  <,
                                  pc->refund_deadline))
diff --git a/src/backend/taler-merchant-httpd_post-using-templates.c 
b/src/backend/taler-merchant-httpd_post-using-templates.c
index 9be6e46b..cdaf917e 100644
--- a/src/backend/taler-merchant-httpd_post-using-templates.c
+++ b/src/backend/taler-merchant-httpd_post-using-templates.c
@@ -160,7 +160,8 @@ TMH_post_using_templates_ID (const struct 
TMH_RequestHandler *rh,
 
   {
     /* template */
-    const char *tsummary;
+    const char *tsummary = NULL;
+    const char *tcurrency = NULL;
     uint32_t min_age;
     struct GNUNET_TIME_Relative pay_duration;
     struct TALER_Amount tamount;
@@ -170,9 +171,10 @@ TMH_post_using_templates_ID (const struct 
TMH_RequestHandler *rh,
         GNUNET_JSON_spec_string ("summary",
                                  &tsummary),
         NULL),
-      /* FIXME: #7951: may want to allow the template to only
-         fix the currency but not the amount; current approach
-         does not allow this! */
+      GNUNET_JSON_spec_mark_optional (
+        GNUNET_JSON_spec_string ("currency",
+                                 &tcurrency),
+        NULL),
       GNUNET_JSON_spec_mark_optional (
         TALER_JSON_spec_amount_any ("amount",
                                     &tamount),
@@ -219,6 +221,19 @@ TMH_post_using_templates_ID (const struct 
TMH_RequestHandler *rh,
         NULL);
     }
 
+    if ( (! no_amount) &&
+         (NULL != tcurrency) &&
+         (0 != strcmp (tcurrency,
+                       amount.currency)) )
+    {
+      GNUNET_JSON_parse_free (spec);
+      return TALER_MHD_reply_with_error (
+        connection,
+        MHD_HTTP_CONFLICT,
+        TALER_EC_MERCHANT_GENERIC_CURRENCY_MISMATCH,
+        tcurrency);
+    }
+
     if (no_amount && no_tamount)
     {
       GNUNET_JSON_parse_free (spec);
diff --git a/src/backend/taler-merchant-httpd_private-get-orders-ID.c 
b/src/backend/taler-merchant-httpd_private-get-orders-ID.c
index 14e71762..98bf2ab8 100644
--- a/src/backend/taler-merchant-httpd_private-get-orders-ID.c
+++ b/src/backend/taler-merchant-httpd_private-get-orders-ID.c
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  (C) 2017-2022 Taler Systems SA
+  (C) 2017-2023 Taler Systems SA
 
   TALER is free software; you can redistribute it and/or modify it under the
   terms of the GNU General Public License as published by the Free Software
@@ -285,6 +285,19 @@ struct GetOrderRequestContext
    */
   bool transfer_status_requested;
 
+  /**
+   * Set to true if our database (incorrectly) has refunds
+   * in a different currency than the currency of the
+   * original payment for the order.
+   */
+  bool refund_currency_mismatch;
+
+  /**
+   * Set to true if our database (incorrectly) has deposits
+   * in a different currency than the currency of the
+   * original payment for the order.
+   */
+  bool deposit_currency_mismatch;
 };
 
 
@@ -484,6 +497,29 @@ deposit_get_cb (void *cls,
         return;
       }
       /* Compute total amount *wired* */
+      if ( (GNUNET_OK !=
+            TALER_amount_cmp_currency (
+              &gorc->deposits_total,
+              &dr->details.ok.coin_contribution)) ||
+           (GNUNET_OK !=
+            TALER_amount_cmp_currency (
+              &gorc->deposit_fees_total,
+              &tq->deposit_fee)) )
+      {
+        /* something very wrong in our database ... */
+        GNUNET_break (0);
+        gorc_report (gorc,
+                     TALER_EC_GENERIC_DB_FETCH_FAILED,
+                     &tq->coin_pub,
+                     NULL);
+        GNUNET_free (tq->exchange_url);
+        GNUNET_free (tq);
+        if (NULL == gorc->tq_head)
+          gorc_resume (gorc,
+                       0,
+                       TALER_EC_NONE);
+        return;
+      }
       if (0 >
           TALER_amount_add (&gorc->deposits_total,
                             &gorc->deposits_total,
@@ -775,12 +811,29 @@ process_refunds_cb (void *cls,
         GNUNET_memcmp (&tq->coin_pub,
                        coin_pub))
     {
+      if (GNUNET_OK !=
+          TALER_amount_cmp_currency (
+            &gorc->deposit_fees_total,
+            &tq->deposit_fee))
+      {
+        gorc->refund_currency_mismatch = true;
+        return;
+      }
+         
       GNUNET_assert (0 <=
                      TALER_amount_subtract (&gorc->deposit_fees_total,
                                             &gorc->deposit_fees_total,
                                             &tq->deposit_fee));
     }
   }
+  if (GNUNET_OK !=
+      TALER_amount_cmp_currency (
+        &gorc->refund_amount,
+        refund_amount))
+  {
+    gorc->refund_currency_mismatch = true;
+    return;
+  }
   GNUNET_assert (0 <=
                  TALER_amount_add (&gorc->refund_amount,
                                    &gorc->refund_amount,
@@ -817,6 +870,18 @@ process_transfer_details (
   json_t *wire_details = gorc->wire_details;
   struct TALER_Amount wired;
 
+  if ( (GNUNET_OK !=
+        TALER_amount_cmp_currency (&gorc->deposits_total,
+                                   deposit_value)) ||
+       (GNUNET_OK !=
+        TALER_amount_cmp_currency (&gorc->deposit_fees_total,
+                                   deposit_fee)) )
+  {
+    GNUNET_break (0);
+    gorc->deposit_currency_mismatch = true;
+    return;
+  }
+       
   /* Compute total amount *wired* */
   GNUNET_assert (0 <
                  TALER_amount_add (&gorc->deposits_total,
@@ -1233,12 +1298,11 @@ TMH_private_get_orders_ID (const struct 
TMH_RequestHandler *rh,
   {
     /* suspend connection, wait for exchange to check wire transfer status 
there */
     gorc->transfer_status_requested = false;   /* only try ONCE */
-    /* FIXME: #7951 */
     GNUNET_assert (GNUNET_OK ==
-                   TALER_amount_set_zero (TMH_currency,
+                   TALER_amount_set_zero (gorc->contract_amount.currency,
                                           &gorc->deposits_total));
     GNUNET_assert (GNUNET_OK ==
-                   TALER_amount_set_zero (TMH_currency,
+                   TALER_amount_set_zero (gorc->contract_amount.currency,
                                           &gorc->deposit_fees_total));
     TMH_db->lookup_deposits_by_order (TMH_db->cls,
                                       gorc->order_serial,
@@ -1316,9 +1380,8 @@ TMH_private_get_orders_ID (const struct 
TMH_RequestHandler *rh,
   GNUNET_assert (paid);
   /* Accumulate refunds, if any. */
   {
-    /* FIXME: #7951 */
     GNUNET_assert (GNUNET_OK ==
-                   TALER_amount_set_zero (TMH_currency,
+                   TALER_amount_set_zero (gorc->contract_amount.currency,
                                           &gorc->refund_amount));
     qs = TMH_db->lookup_refunds_detailed (TMH_db->cls,
                                           hc->instance->settings.id,
@@ -1334,18 +1397,25 @@ TMH_private_get_orders_ID (const struct 
TMH_RequestHandler *rh,
                                        TALER_EC_GENERIC_DB_FETCH_FAILED,
                                        "detailed refunds");
   }
+  if (gorc->refund_currency_mismatch)
+  {
+    GNUNET_break (0);
+    return TALER_MHD_reply_with_error (connection,
+                                       MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                       TALER_EC_GENERIC_DB_FETCH_FAILED,
+                                       "refunds in different currency than 
original order price");
+  }
 
   /* Generate final reply, including wire details if we have them */
   {
     MHD_RESULT ret;
     char *order_status_url;
 
-    /* FIXME: #7951 */
     GNUNET_assert (GNUNET_OK ==
-                   TALER_amount_set_zero (TMH_currency,
+                   TALER_amount_set_zero (gorc->contract_amount.currency,
                                           &gorc->deposits_total));
     GNUNET_assert (GNUNET_OK ==
-                   TALER_amount_set_zero (TMH_currency,
+                   TALER_amount_set_zero (gorc->contract_amount.currency,
                                           &gorc->deposit_fees_total));
     qs = TMH_db->lookup_transfer_details_by_order (TMH_db->cls,
                                                    gorc->order_serial,
@@ -1359,6 +1429,14 @@ TMH_private_get_orders_ID (const struct 
TMH_RequestHandler *rh,
                                          TALER_EC_GENERIC_DB_FETCH_FAILED,
                                          "transfer details");
     }
+    if (gorc->deposit_currency_mismatch)
+    {
+      GNUNET_break (0);
+      return TALER_MHD_reply_with_error (connection,
+                                         MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                         TALER_EC_GENERIC_DB_FETCH_FAILED,
+                                         "deposits in different currency than 
original order price");
+    }
 
     if (! wired)
     {
diff --git a/src/backend/taler-merchant-httpd_private-get-orders.c 
b/src/backend/taler-merchant-httpd_private-get-orders.c
index 3b8f8c34..0e0511cc 100644
--- a/src/backend/taler-merchant-httpd_private-get-orders.c
+++ b/src/backend/taler-merchant-httpd_private-get-orders.c
@@ -251,6 +251,16 @@ process_refunds_cb (void *cls,
 {
   struct TALER_Amount *total_refund_amount = cls;
 
+  if (GNUNET_OK !=
+      TALER_amount_cmp_currency (total_refund_amount,
+                                 refund_amount))
+  {
+    /* Database error, refunds in mixed currency in DB. Not OK! */
+    /* FIXME: we may want to return DB error to the client instead of just
+       ignoring the refund. */
+    GNUNET_break (0);
+    return;
+  }
   GNUNET_assert (0 <=
                  TALER_amount_add (total_refund_amount,
                                    total_refund_amount,
@@ -387,7 +397,6 @@ add_order (void *cls,
     {
       struct TALER_Amount refund_amount;
 
-      /* FIXME: #7951 */
       GNUNET_assert (GNUNET_OK ==
                      TALER_amount_set_zero (order_amount.currency,
                                             &refund_amount));
diff --git a/src/backend/taler-merchant-httpd_private-post-orders.c 
b/src/backend/taler-merchant-httpd_private-post-orders.c
index 09c709e9..7d9bc4f0 100644
--- a/src/backend/taler-merchant-httpd_private-post-orders.c
+++ b/src/backend/taler-merchant-httpd_private-post-orders.c
@@ -1238,6 +1238,7 @@ patch_order (struct OrderContext *oc)
    * mostly because in GNUnet relative times can't
    * be negative.  */
   struct GNUNET_TIME_Relative auto_refund;
+  bool no_fee;
   struct GNUNET_JSON_Specification spec[] = {
     GNUNET_JSON_spec_mark_optional (
       GNUNET_JSON_spec_string ("merchant_base_url",
@@ -1276,7 +1277,7 @@ patch_order (struct OrderContext *oc)
     GNUNET_JSON_spec_mark_optional (
       TALER_JSON_spec_amount_any ("max_fee",
                                   &oc->max_fee),
-      NULL),
+      &no_fee),
     GNUNET_JSON_spec_mark_optional (
       GNUNET_JSON_spec_timestamp ("delivery_date",
                                   &delivery_date),
@@ -1310,7 +1311,20 @@ patch_order (struct OrderContext *oc)
     reply_with_error (oc,
                       MHD_HTTP_BAD_REQUEST,
                       TALER_EC_GENERIC_CURRENCY_MISMATCH,
-                      NULL);
+                      "no trusted exchange for this currency");
+    return;
+  }
+  if ( (! no_fee) &&
+       (GNUNET_OK !=
+        TALER_amount_cmp_currency (&oc->brutto,
+                                   &oc->max_fee)) )
+  {
+    GNUNET_break_op (0);
+    GNUNET_JSON_parse_free (spec);
+    reply_with_error (oc,
+                      MHD_HTTP_BAD_REQUEST,
+                      TALER_EC_GENERIC_CURRENCY_MISMATCH,
+                      "different currencies used for 'max_fee' and 'amount' 
currency");
     return;
   }
 
diff --git a/src/backend/taler-merchant-httpd_private-post-templates.c 
b/src/backend/taler-merchant-httpd_private-post-templates.c
index 4a5d8133..a064769c 100644
--- a/src/backend/taler-merchant-httpd_private-post-templates.c
+++ b/src/backend/taler-merchant-httpd_private-post-templates.c
@@ -189,7 +189,7 @@ TMH_private_post_templates (const struct TMH_RequestHandler 
*rh,
     /* idempotency check: is etp == tp? */
     {
       bool eq;
-      
+
       eq = templates_equal (&tp,
                             &etp);
       TALER_MERCHANTDB_template_details_free (&etp);
diff --git a/src/backenddb/pg_increase_refund.c 
b/src/backenddb/pg_increase_refund.c
index 832a84eb..eef7adc6 100644
--- a/src/backenddb/pg_increase_refund.c
+++ b/src/backenddb/pg_increase_refund.c
@@ -91,7 +91,14 @@ process_refund_cb (void *cls,
       ictx->err = true;
       return;
     }
-    /* FIXME: #7951 */
+    if (GNUNET_OK !=
+        TALER_amount_cmp_currency (&ictx->refunded_amount,
+                                   &acc))
+    {
+      GNUNET_break (0);
+      ictx->err = true;
+      return;
+    }
     if (0 >
         TALER_amount_add (&ictx->refunded_amount,
                           &ictx->refunded_amount,

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

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