gnunet-svn
[Top][All Lists]
Advanced

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

[GNUnet-SVN] [taler-merchant] branch master updated: implement #4935 (wi


From: gnunet
Subject: [GNUnet-SVN] [taler-merchant] branch master updated: implement #4935 (wire fee support)
Date: Mon, 06 Mar 2017 18:20:13 +0100

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

grothoff pushed a commit to branch master
in repository merchant.

The following commit(s) were added to refs/heads/master by this push:
     new a4f578b  implement #4935 (wire fee support)
a4f578b is described below

commit a4f578ba3da614a41fd4c31017f702b2db7d90dc
Author: Christian Grothoff <address@hidden>
AuthorDate: Mon Mar 6 18:21:45 2017 +0100

    implement #4935 (wire fee support)
---
 ChangeLog                                    |   5 +
 doc/manual.texi                              |   4 +-
 src/backend/merchant.conf                    |  10 ++
 src/backend/taler-merchant-httpd.c           |  81 ++++++++++++++++-
 src/backend/taler-merchant-httpd.h           |  16 ++++
 src/backend/taler-merchant-httpd_exchanges.c | 129 +++++++++++++++++++-------
 src/backend/taler-merchant-httpd_pay.c       | 131 ++++++++++++++++++---------
 src/backend/taler-merchant-httpd_proposal.c  |  51 +++++++++--
 src/lib/test_merchant_api.conf               |   1 +
 9 files changed, 338 insertions(+), 90 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 6ea0738..8ff267c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+Mon Mar  6 17:57:51 CET 2017
+       Add support for wire fee calculations to /pay handling (#4935),
+       and adding setting "max_wire_fee" and "wire_fee_amortization"
+       in contract from defaults. -CG
+
 Mon Mar  6 00:59:25 CET 2017
        Implement BIND_TO option to allow binding backend to a particular
        IP address (#4752).  Enabling use of dual-stack by default. -CG
diff --git a/doc/manual.texi b/doc/manual.texi
index b97fe4e..af2dc37 100644
--- a/doc/manual.texi
+++ b/doc/manual.texi
@@ -507,14 +507,14 @@ Which currency the Web shop deals in, i.e. ``EUR'' or 
``USD'', is specified usin
 @cindex currency
 @cindex KUDOS
 @example
-[merchant]/currency
+[taler]/currency
 @end example
 
 For testing purposes, the currency MUST match ``KUDOS'' so that tests will work
 with the Taler demonstration exchange at 
@url{https://exchange.demo.taler.net/}:
 
 @example
-$ taler-config -s merchant -o currency -V KUDOS
+$ taler-config -s taler -o currency -V KUDOS
 @end example
 
 @item Database
diff --git a/src/backend/merchant.conf b/src/backend/merchant.conf
index 3723af0..5511787 100644
--- a/src/backend/merchant.conf
+++ b/src/backend/merchant.conf
@@ -24,6 +24,16 @@ UNIXPATH = ${TALER_RUNTIME_DIR}/merchant.http
 UNIXPATH_MODE = 660
 
 
+# Maximum wire fee to permit by default.  You most certainly want to
+# adjust at least the currency.
+# DEFAULT_MAX_WIRE_FEE = "KUDOS:0.10"
+
+# Which fraction of an exessivly high wire fee is the customer expected
+# to cover?  Must be a positive integer representing the expected
+# average number of transactions aggregated by exchanges.  1 is
+# always safe (financially speaking).
+DEFAULT_WIRE_FEE_AMORTIZATION = 1
+
 # Where does the backend store the merchant's private key?
 KEYFILE = ${TALER_DATA_HOME}/merchant/merchant.priv
 
diff --git a/src/backend/taler-merchant-httpd.c 
b/src/backend/taler-merchant-httpd.c
index b400416..f3faa30 100644
--- a/src/backend/taler-merchant-httpd.c
+++ b/src/backend/taler-merchant-httpd.c
@@ -73,6 +73,17 @@ static long long unsigned port;
 struct GNUNET_TIME_Relative wire_transfer_delay;
 
 /**
+ * Default maximum wire fee to assume, unless stated differently in the 
proposal
+ * already.
+ */
+struct TALER_Amount default_max_wire_fee;
+
+/**
+ * Default factor for wire fee amortization.
+ */
+unsigned long long default_wire_fee_amortization;
+
+/**
  * Should a "Connection: close" header be added to each HTTP response?
  */
 int TMH_merchant_connection_close;
@@ -275,6 +286,10 @@ do_shutdown (void *cls)
     GNUNET_SCHEDULER_cancel (mhd_task);
     mhd_task = NULL;
   }
+  /* FIXME: MHD API requires us to resume all suspended
+     connections before we do this, but /pay currently
+     suspends connections without giving us a way to
+     enumerate / resume them... */
   if (NULL != mhd)
   {
     MHD_stop_daemon (mhd);
@@ -446,13 +461,15 @@ instances_iterator_cb (void *cls,
   /* used as hashmap keys */
   struct GNUNET_HashCode h_pk;
   struct GNUNET_HashCode h_id;
+  json_t *type;
   char *emsg;
 
   iic = cls;
   substr = strstr (section, "merchant-instance-");
 
-  if ((NULL == substr)
-      || (NULL != strstr (section, "merchant-instance-wireformat-")))
+  if ( (NULL == substr) ||
+       (NULL != strstr (section,
+                        "merchant-instance-wireformat-")) )
     return;
 
   if (substr != section)
@@ -509,11 +526,19 @@ instances_iterator_cb (void *cls,
   GNUNET_asprintf (&instance_wiresection,
                    "merchant-instance-wireformat-%s",
                    mi->id);
-
   mi->j_wire = iic->plugin->get_wire_details (iic->plugin->cls,
                                               iic->config,
                                               instance_wiresection);
   GNUNET_free (instance_wiresection);
+  if ( (NULL == (type = json_object_get (mi->j_wire,
+                                         "type"))) ||
+       (! json_is_string (type)) )
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Malformed wireformat: lacks type\n");
+    iic->ret |= GNUNET_SYSERR;
+  }
+  mi->wire_method = json_string_value (type);
 
   if (TALER_EC_NONE !=
       iic->plugin->wire_validate (iic->plugin->cls,
@@ -521,7 +546,6 @@ instances_iterator_cb (void *cls,
                                   NULL,
                                   &emsg))
   {
-
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                 "Malformed wireformat: %s\n",
                 emsg);
@@ -762,6 +786,55 @@ run (void *cls,
     GNUNET_SCHEDULER_shutdown ();
     return;
   }
+
+  if (GNUNET_OK !=
+      TALER_config_get_denom (config,
+                              "merchant",
+                              "DEFAULT_MAX_WIRE_FEE",
+                              &default_max_wire_fee))
+  {
+    char *currency;
+
+    if (GNUNET_OK !=
+        GNUNET_CONFIGURATION_get_value_string (config,
+                                               "taler",
+                                               "CURRENCY",
+                                               &currency))
+    {
+      GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+                                 "taler",
+                                 "CURRENCY");
+      GNUNET_SCHEDULER_shutdown ();
+      return;
+    }
+    if (GNUNET_OK !=
+        TALER_amount_get_zero (currency,
+                               &default_max_wire_fee))
+    {
+      GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+                                 "taler",
+                                 "CURRENCY",
+                                 "Specified value not legal for a Taler 
currency");
+      GNUNET_SCHEDULER_shutdown ();
+      GNUNET_free (currency);
+      return;
+    }
+    GNUNET_free (currency);
+  }
+
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_number (config,
+                                             "merchant",
+                                             "DEFAULT_WIRE_FEE_AMORTIZATION",
+                                             &default_wire_fee_amortization))
+  {
+    GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+                               "merchant",
+                               "DEFAULT_WIRE_FEE_AMORTIZATION");
+    GNUNET_SCHEDULER_shutdown ();
+    return;
+  }
+
   wireformat = NULL;
   if (GNUNET_OK !=
       GNUNET_CONFIGURATION_get_value_string (config,
diff --git a/src/backend/taler-merchant-httpd.h 
b/src/backend/taler-merchant-httpd.h
index ee4a3b2..0526ad2 100644
--- a/src/backend/taler-merchant-httpd.h
+++ b/src/backend/taler-merchant-httpd.h
@@ -95,6 +95,11 @@ struct MerchantInstance
      once we implement #4939 */
 
   /**
+   * Which wire method is @e j_wire using?
+   */
+  const char *wire_method;
+
+  /**
    * Wire details for this instance
    */
   struct json_t *j_wire;
@@ -220,6 +225,17 @@ struct TM_HandlerContext
 extern json_t *j_wire;
 
 /**
+ * Default maximum wire fee to assume, unless stated differently in the 
proposal
+ * already.
+ */
+extern struct TALER_Amount default_max_wire_fee;
+
+/**
+ * Default factor for wire fee amortization.
+ */
+extern unsigned long long default_wire_fee_amortization;
+
+/**
  * Hash of our wire format details as given in #j_wire.
  */
 extern struct GNUNET_HashCode h_wire;
diff --git a/src/backend/taler-merchant-httpd_exchanges.c 
b/src/backend/taler-merchant-httpd_exchanges.c
index c7e88c7..daf5550 100644
--- a/src/backend/taler-merchant-httpd_exchanges.c
+++ b/src/backend/taler-merchant-httpd_exchanges.c
@@ -354,6 +354,40 @@ process_wire_fees (void *cls,
 
 
 /**
+ * Obtain applicable fees for @a exchange and @a wire_method.
+ *
+ * @param exchange the exchange to query
+ * @param now current time
+ * @param wire_method the wire method we want the fees for
+ * @return NULL if we do not have fees for this method yet
+ */
+static struct TALER_EXCHANGE_WireAggregateFees *
+get_wire_fees (struct Exchange *exchange,
+               struct GNUNET_TIME_Absolute now,
+               const char *wire_method)
+{
+  for (struct FeesByWireMethod *fbw = exchange->wire_fees_head;
+       NULL != fbw;
+       fbw = fbw->next)
+    if (0 == strcasecmp (fbw->wire_method,
+                         wire_method) )
+    {
+      struct TALER_EXCHANGE_WireAggregateFees *af;
+
+      /* Advance through list up to current time */
+      while ( (NULL != (af = fbw->af)) &&
+              (now.abs_value_us >= af->end_date.abs_value_us) )
+      {
+        fbw->af = af->next;
+        GNUNET_free (af);
+      }
+      return af;
+    }
+  return NULL;
+}
+
+
+/**
  * Check if we have any remaining pending requests for the
  * given @a exchange, and if we have the required data, call
  * the callback.
@@ -378,26 +412,12 @@ process_find_operations (struct Exchange *exchange)
     fn = fo->next;
     if (NULL != fo->wire_method)
     {
-      struct FeesByWireMethod *fbw;
       struct TALER_EXCHANGE_WireAggregateFees *af;
 
       /* Find fee structure for our wire method */
-      for (fbw = exchange->wire_fees_head; NULL != fbw; fbw = fbw->next)
-        if (0 == strcasecmp (fbw->wire_method,
-                             fo->wire_method) )
-          break;
-      if (NULL == fbw)
-      {
-        need_wire = GNUNET_YES;
-        continue;
-      }
-      /* Advance through list up to current time */
-      while ( (NULL != (af = fbw->af)) &&
-              (now.abs_value_us >= af->end_date.abs_value_us) )
-      {
-        fbw->af = af->next;
-        GNUNET_free (af);
-      }
+      af = get_wire_fees (exchange,
+                          now,
+                          fo->wire_method);
       if (NULL == af)
       {
         need_wire = GNUNET_YES;
@@ -479,18 +499,40 @@ handle_wire_data (void *cls,
     return;
   }
   if (GNUNET_OK !=
-      TALER_EXCHANGE_wire_get_fees (&exchange->master_pub,
+      TALER_EXCHANGE_wire_get_fees (&TALER_EXCHANGE_get_keys 
(exchange->conn)->master_pub,
                                     obj,
                                     &process_wire_fees,
                                     exchange))
   {
+    /* Report hard failure to all callbacks! */
+    struct TMH_EXCHANGES_FindOperation *fo;
+
     GNUNET_break_op (0);
+    while (NULL != (fo = exchange->fo_head))
+    {
+      GNUNET_CONTAINER_DLL_remove (exchange->fo_head,
+                                   exchange->fo_tail,
+                                   fo);
+      /* TODO: report more precise error, this ultimately generates
+         "exchange not supported" instead of "exchange violated
+         protocol"; we should ideally generate a reply with
+         a specific TALER_EC-code, boxing 'obj' within it. */
+      fo->fc (fo->fc_cls,
+              NULL,
+              NULL,
+              GNUNET_NO);
+      GNUNET_free_non_null (fo->wire_method);
+      GNUNET_free (fo);
+    }
     return;
   }
   if (GNUNET_YES ==
       process_find_operations (exchange))
   {
     /* need to run /wire again, with some delay */
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "Do not have sufficient wire data. Will re-request /wire in 1 
minute\n");
+
     GNUNET_assert (NULL == exchange->wire_task);
     exchange->wire_task = GNUNET_SCHEDULER_add_delayed 
(GNUNET_TIME_UNIT_MINUTES,
                                                         &wire_task_cb,
@@ -574,7 +616,8 @@ keys_mgmt_cb (void *cls,
     delay = RELOAD_DELAY;
   else
     delay = GNUNET_TIME_absolute_get_remaining (expire);
-  exchange->retry_delay = GNUNET_TIME_UNIT_ZERO;
+  exchange->retry_delay
+    = GNUNET_TIME_UNIT_ZERO;
   exchange->retry_task
     = GNUNET_SCHEDULER_add_delayed (delay,
                                     &retry_exchange,
@@ -583,6 +626,8 @@ keys_mgmt_cb (void *cls,
   if (GNUNET_YES ==
       process_find_operations (exchange))
   {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Got key data, but do not have current wire data. Will request 
/wire now\n");
     GNUNET_assert (NULL == exchange->wire_request);
     GNUNET_assert (NULL == exchange->wire_task);
     exchange->wire_request = TALER_EXCHANGE_wire (exchange->conn,
@@ -603,18 +648,19 @@ return_result (void *cls)
   struct TMH_EXCHANGES_FindOperation *fo = cls;
   struct Exchange *exchange = fo->my_exchange;
 
-  fo->at = NULL;
-  GNUNET_CONTAINER_DLL_remove (exchange->fo_head,
-                               exchange->fo_tail,
-                               fo);
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Returning result for exchange %s, trusted=%d\n",
-              exchange->uri, exchange->trusted);
-  fo->fc (fo->fc_cls,
-          (GNUNET_SYSERR == exchange->pending) ? NULL : exchange->conn,
-          NULL, /* FIXME: pass fees! */
-          exchange->trusted);
-  GNUNET_free (fo);
+  if ( (GNUNET_YES ==
+        process_find_operations (exchange)) &&
+       (NULL == exchange->wire_request) &&
+       (GNUNET_NO == exchange->pending) &&
+       (NULL != exchange->wire_task) )
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "Do not have current wire data. Will re-request /wire in 1 
minute\n");
+    exchange->wire_task
+      = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
+                                      &wire_task_cb,
+                                      exchange);
+  }
 }
 
 
@@ -689,7 +735,11 @@ TMH_EXCHANGES_find_exchange (const char *chosen_exchange,
                                exchange->fo_tail,
                                fo);
 
-  if (GNUNET_YES != exchange->pending)
+  if ( (GNUNET_YES != exchange->pending) &&
+       ( (NULL == fo->wire_method) ||
+         (NULL != get_wire_fees (exchange,
+                                 GNUNET_TIME_absolute_get (),
+                                 fo->wire_method)) ) )
   {
     /* We are not currently waiting for a reply, immediately
        return result */
@@ -702,9 +752,22 @@ TMH_EXCHANGES_find_exchange (const char *chosen_exchange,
   if ( (NULL == exchange->conn) &&
        (GNUNET_YES == exchange->pending) )
   {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Do not have current key data. Will request /keys now\n");
     exchange->retry_task = GNUNET_SCHEDULER_add_now (&retry_exchange,
                                                      exchange);
   }
+  else if ( (GNUNET_NO == exchange->pending) &&
+            (NULL == exchange->wire_task) &&
+            (NULL == exchange->wire_request) )
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Do not have current wire data. Will re-request /wire now\n");
+    exchange->wire_task = GNUNET_SCHEDULER_add_now (&wire_task_cb,
+                                                    exchange);
+  }
+
+
   return fo;
 }
 
@@ -723,7 +786,7 @@ TMH_EXCHANGES_find_exchange_cancel (struct 
TMH_EXCHANGES_FindOperation *fo)
   {
     GNUNET_SCHEDULER_cancel (fo->at);
     fo->at = NULL;
-  }
+   }
   GNUNET_CONTAINER_DLL_remove (exchange->fo_head,
                                exchange->fo_tail,
                                fo);
diff --git a/src/backend/taler-merchant-httpd_pay.c 
b/src/backend/taler-merchant-httpd_pay.c
index 54d8efa..c3203ef 100644
--- a/src/backend/taler-merchant-httpd_pay.c
+++ b/src/backend/taler-merchant-httpd_pay.c
@@ -315,28 +315,6 @@ resume_pay_with_response (struct PayContext *pc,
 
 
 /**
- * Convert denomination key to its base32 representation
- *
- * @param dk denomination key to convert
- * @return 0-terminated base32 encoding of @a dk, to be deallocated
- */
-static char *
-denomination_to_string_alloc (struct TALER_DenominationPublicKey *dk)
-{
-  char *buf;
-  char *buf2;
-  size_t buf_size;
-
-  buf_size = GNUNET_CRYPTO_rsa_public_key_encode (dk->rsa_public_key,
-                                                  &buf);
-  buf2 = GNUNET_STRINGS_data_to_string_alloc (buf,
-                                              buf_size);
-  GNUNET_free (buf);
-  return buf2;
-}
-
-
-/**
  * Abort all pending /deposit operations.
  *
  * @param pc pay context to abort
@@ -572,6 +550,8 @@ process_pay_with_exchange (void *cls,
   struct PayContext *pc = cls;
   struct TALER_Amount acc_fee;
   struct TALER_Amount acc_amount;
+  struct TALER_Amount wire_fee_delta;
+  struct TALER_Amount wire_fee_customer_contribution;
   const struct TALER_EXCHANGE_Keys *keys;
   unsigned int i;
 
@@ -609,8 +589,6 @@ process_pay_with_exchange (void *cls,
                                                         &dc->denom);
     if (NULL == denom_details)
     {
-      char *denom_enc;
-
       GNUNET_break_op (0);
       resume_pay_with_response (pc,
                                 MHD_HTTP_BAD_REQUEST,
@@ -619,11 +597,6 @@ process_pay_with_exchange (void *cls,
                                                             "code", 
TALER_EC_PAY_DENOMINATION_KEY_NOT_FOUND,
                                                              "denom_pub", 
GNUNET_JSON_from_rsa_public_key (dc->denom.rsa_public_key),
                                                              "exchange_keys", 
TALER_EXCHANGE_get_keys_raw (mh)));
-      denom_enc = denomination_to_string_alloc (&dc->denom);
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                  "unknown denom to exchange: %s\n",
-                  denom_enc);
-      GNUNET_free (denom_enc);
       return;
     }
     if (GNUNET_OK !=
@@ -631,8 +604,6 @@ process_pay_with_exchange (void *cls,
                                denom_details,
                                exchange_trusted))
     {
-      char *denom_enc;
-
       GNUNET_break_op (0);
       resume_pay_with_response (pc,
                                 MHD_HTTP_BAD_REQUEST,
@@ -640,11 +611,6 @@ process_pay_with_exchange (void *cls,
                                                              "error", "invalid 
denomination",
                                                             "code", 
(json_int_t) TALER_EC_PAY_DENOMINATION_KEY_AUDITOR_FAILURE,
                                                              "denom_pub", 
GNUNET_JSON_from_rsa_public_key (dc->denom.rsa_public_key)));
-      denom_enc = denomination_to_string_alloc (&dc->denom);
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                  "Client offered invalid denomination: %s\n",
-                  denom_enc);
-      GNUNET_free (denom_enc);
       return;
     }
     dc->deposit_fee = denom_details->fee_deposit;
@@ -690,6 +656,38 @@ process_pay_with_exchange (void *cls,
     }
   }
 
+  /* Now compare exchange wire fee compared to what we are willing to pay */
+  if (GNUNET_YES !=
+      TALER_amount_cmp_currency (wire_fee,
+                                 &pc->max_wire_fee))
+  {
+    GNUNET_break (0);
+    resume_pay_with_response (pc,
+                              MHD_HTTP_INTERNAL_SERVER_ERROR,
+                              TMH_RESPONSE_make_internal_error 
(TALER_EC_PAY_WIRE_FEE_CURRENCY_MISSMATCH,
+                                                                "wire_fee"));
+    return;
+  }
+
+  if (GNUNET_OK ==
+      TALER_amount_subtract (&wire_fee_delta,
+                             wire_fee,
+                             &pc->max_wire_fee))
+  {
+    /* Actual wire fee is indeed higher than our maximum, compute
+       how much the customer is expected to cover! */
+    TALER_amount_divide (&wire_fee_customer_contribution,
+                         &wire_fee_delta,
+                         pc->wire_fee_amortization);
+  }
+  else
+  {
+    GNUNET_assert (GNUNET_OK ==
+                   TALER_amount_get_zero (wire_fee->currency,
+                                          &wire_fee_customer_contribution));
+
+  }
+
   /* Now check that the customer paid enough for the full contract */
   if (-1 == TALER_amount_cmp (&pc->max_fee,
                               &acc_fee))
@@ -716,6 +714,12 @@ process_pay_with_exchange (void *cls,
                                                                  "overflow"));
       return;
     }
+    /* add wire fee contribution to the total */
+    if (GNUNET_OK ==
+        TALER_amount_add (&total_needed,
+                          &total_needed,
+                          &wire_fee_customer_contribution))
+
     /* check if total payment sufficies */
     if (-1 == TALER_amount_cmp (&acc_amount,
                                 &total_needed))
@@ -730,7 +734,40 @@ process_pay_with_exchange (void *cls,
   }
   else
   {
-    /* fees are acceptable, we cover them all; let's check the amount */
+    struct TALER_Amount deposit_fee_savings;
+
+    /* Compute how much the customer saved by not going to the
+       limit on the deposit fees, as this amount is counted against
+       what we expect him to cover for the wire fees */
+    GNUNET_assert (GNUNET_SYSERR !=
+                   TALER_amount_subtract (&deposit_fee_savings,
+                                          &pc->max_fee,
+                                          &acc_fee));
+    /* See how much of wire fee contribution is covered by fee_savings */
+    if (-1 == TALER_amount_cmp (&deposit_fee_savings,
+                                &wire_fee_customer_contribution))
+    {
+      /* wire_fee_customer_contribution > deposit_fee_savings */
+      GNUNET_assert (GNUNET_SYSERR !=
+                     TALER_amount_subtract (&wire_fee_customer_contribution,
+                                            &wire_fee_customer_contribution,
+                                            &deposit_fee_savings));
+      /* subtract remaining wire fees from total contribution */
+      if (GNUNET_SYSERR ==
+          TALER_amount_subtract (&acc_amount,
+                                 &acc_amount,
+                                 &wire_fee_customer_contribution))
+      {
+        GNUNET_break_op (0);
+        resume_pay_with_response (pc,
+                                  MHD_HTTP_METHOD_NOT_ACCEPTABLE,
+                                  TMH_RESPONSE_make_external_error 
(TALER_EC_PAY_PAYMENT_INSUFFICIENT_DUE_TO_FEES,
+                                                                    
"insufficient funds (including excessive exchange fees to be covered by 
customer)"));
+        return;
+      }
+    }
+
+    /* fees are acceptable, merchant covers them all; let's check the amount */
     if (-1 == TALER_amount_cmp (&acc_amount,
                                 &pc->amount))
     {
@@ -746,8 +783,6 @@ process_pay_with_exchange (void *cls,
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Exchange and fee structure OK. Initiating deposit operation for 
coins\n");
 
-
-
   /* Initiate /deposit operation for all coins */
   for (i=0;i<pc->coins_cnt;i++)
   {
@@ -1072,7 +1107,7 @@ parse_pay (struct MHD_Connection *connection,
   /* NOTE: In the future, iterate over all wire hashes
      available to a given instance here! (#4939) */
   if (0 != memcmp (&pc->h_wire,
-                   &mi->h_wire,
+                   &pc->mi->h_wire,
                    sizeof (struct GNUNET_HashCode)))
   {
     GNUNET_break (0);
@@ -1104,6 +1139,13 @@ parse_pay (struct MHD_Connection *connection,
                                             &pc->max_wire_fee));
     }
   }
+  else
+  {
+    /* default is we cover no fee */
+    GNUNET_assert (GNUNET_OK ==
+                   TALER_amount_get_zero (pc->max_fee.currency,
+                                          &pc->max_wire_fee));
+  }
   if (NULL != json_object_get (pc->proposal_data,
                                "wire_fee_amortization"))
   {
@@ -1124,6 +1166,10 @@ parse_pay (struct MHD_Connection *connection,
       pc->wire_fee_amortization = 1;
     }
   }
+  else
+  {
+    pc->wire_fee_amortization = 1;
+  }
 
   pc->coins_cnt = json_array_size (coins);
   if (0 == pc->coins_cnt)
@@ -1287,7 +1333,7 @@ handler_pay_json (struct MHD_Connection *connection,
 
   /* Find the responsible exchange, this may take a while... */
   pc->fo = TMH_EXCHANGES_find_exchange (pc->chosen_exchange,
-                                        NULL, /* FIXME: wire method! */
+                                        pc->mi->wire_method,
                                         &process_pay_with_exchange,
                                         pc);
 
@@ -1378,7 +1424,8 @@ MH_handler_pay (struct TMH_RequestHandler *rh,
     GNUNET_break (0);
     return TMH_RESPONSE_reply_invalid_json (connection);
   }
-  if ((GNUNET_NO == res) || (NULL == root))
+  if ( (GNUNET_NO == res) ||
+       (NULL == root) )
     return MHD_YES; /* the POST's body has to be further fetched */
 
   res = handler_pay_json (connection,
diff --git a/src/backend/taler-merchant-httpd_proposal.c 
b/src/backend/taler-merchant-httpd_proposal.c
index 09b221e..0d96a1f 100644
--- a/src/backend/taler-merchant-httpd_proposal.c
+++ b/src/backend/taler-merchant-httpd_proposal.c
@@ -170,35 +170,67 @@ proposal_put (struct MHD_Connection *connection,
     time (&timer);
     tm_info = localtime (&timer);
 
-    off = strftime (buf, sizeof (buf), "%H:%M:%S", tm_info);
+    off = strftime (buf,
+                    sizeof (buf),
+                    "%H:%M:%S",
+                    tm_info);
     snprintf (buf + off, sizeof (buf) - off,
               "-%llX",
-              (long long unsigned) GNUNET_CRYPTO_random_u64 
(GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX));
-    json_object_set (order, "order_id", json_string (buf));
+              (long long unsigned) GNUNET_CRYPTO_random_u64 
(GNUNET_CRYPTO_QUALITY_WEAK,
+                                                             UINT64_MAX));
+    json_object_set (order,
+                     "order_id",
+                     json_string (buf));
   }
 
-  if (NULL == json_string_value (json_object_get (order, "timestamp")))
+  if (NULL == json_object_get (order,
+                               "timestamp"))
   {
     struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
+
     (void) GNUNET_TIME_round_abs (&now);
-    json_object_set (order, "timestamp", GNUNET_JSON_from_time_abs (now));
+    json_object_set (order,
+                     "timestamp",
+                     GNUNET_JSON_from_time_abs (now));
   }
 
-  if (NULL == json_string_value (json_object_get (order, "refund_deadline")))
+  if (NULL == json_object_get (order,
+                               "refund_deadline"))
   {
     struct GNUNET_TIME_Absolute zero = { 0 };
-    json_object_set (order, "refund_deadline", GNUNET_JSON_from_time_abs 
(zero));
+
+    json_object_set (order,
+                     "refund_deadline",
+                     GNUNET_JSON_from_time_abs (zero));
   }
 
-  if (NULL == json_string_value (json_object_get (order, "pay_deadline")))
+  if (NULL == json_object_get (order,
+                               "pay_deadline"))
   {
     struct GNUNET_TIME_Absolute t;
+
     /* FIXME: read the delay for pay_deadline from config */
-    t = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), 
GNUNET_TIME_UNIT_HOURS);
+    t = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_HOURS);
     (void) GNUNET_TIME_round_abs (&t);
     json_object_set (order, "pay_deadline", GNUNET_JSON_from_time_abs (t));
   }
 
+  if (NULL == json_object_get (order,
+                               "max_wire_fee"))
+  {
+    json_object_set (order,
+                     "max_wire_fee",
+                     TALER_JSON_from_amount (&default_max_wire_fee));
+  }
+
+  if (NULL == json_object_get (order,
+                               "wire_fee_amortization"))
+  {
+    json_object_set (order,
+                     "wire_fee_amortization",
+                     json_integer ((json_int_t) 
default_wire_fee_amortization));
+  }
+
   /* extract fields we need to sign separately */
   res = TMH_PARSE_json_data (connection, order, spec);
   if (GNUNET_NO == res)
@@ -348,6 +380,7 @@ MH_handler_proposal_put (struct TMH_RequestHandler *rh,
   return res;
 }
 
+
 /**
  * Manage a GET /proposal request. Query the db and returns the
  * proposal's data related to the transaction id given as the URL's
diff --git a/src/lib/test_merchant_api.conf b/src/lib/test_merchant_api.conf
index dc580e2..8a9b80c 100644
--- a/src/lib/test_merchant_api.conf
+++ b/src/lib/test_merchant_api.conf
@@ -36,6 +36,7 @@ WIREFORMAT = test
 # section like X-wireformat and merchant-instance-X
 INSTANCES = tor default
 
+
 [exchange-wire-test]
 # Enable 'test' for testing of the actual coin operations.
 ENABLE = YES

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



reply via email to

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