gnunet-svn
[Top][All Lists]
Advanced

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

[taler-merchant] 98/277: implement POST /transfers


From: gnunet
Subject: [taler-merchant] 98/277: implement POST /transfers
Date: Sun, 05 Jul 2020 20:50:11 +0200

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

grothoff pushed a commit to branch master
in repository merchant.

commit 4344f16b33bad868e8aea32f4921640950068332
Author: Christian Grothoff <christian@grothoff.org>
AuthorDate: Thu May 7 13:01:29 2020 +0200

    implement POST /transfers
---
 src/backend/taler-merchant-httpd.c                 |   4 +-
 .../taler-merchant-httpd_post-orders-ID-pay.c      |   2 +-
 .../taler-merchant-httpd_post-orders-ID-pay.h      |   2 +-
 .../taler-merchant-httpd_private-post-transfers.c  | 822 ++++++++++-----------
 .../taler-merchant-httpd_private-post-transfers.h  |   8 +
 5 files changed, 388 insertions(+), 450 deletions(-)

diff --git a/src/backend/taler-merchant-httpd.c 
b/src/backend/taler-merchant-httpd.c
index 131699e..c5dbacd 100644
--- a/src/backend/taler-merchant-httpd.c
+++ b/src/backend/taler-merchant-httpd.c
@@ -422,8 +422,10 @@ do_shutdown (void *cls)
 
   (void) cls;
   TMH_force_get_orders_resume ();
-#if 0
+  TMH_force_ac_resume ();
   TMH_force_pc_resume ();
+  TMH_force_post_transfers_resume ();
+#if 0
   TMH_force_trh_resume ();
   TMH_force_refund_resume ();
   TMH_force_tip_pickup_resume ();
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 5962eb5..d76965d 100644
--- a/src/backend/taler-merchant-httpd_post-orders-ID-pay.c
+++ b/src/backend/taler-merchant-httpd_post-orders-ID-pay.c
@@ -386,7 +386,7 @@ abort_deposit (struct PayContext *pc)
  * to shut down MHD.
  */
 void
-MH_force_pc_resume ()
+TMH_force_pc_resume ()
 {
   for (struct PayContext *pc = pc_head;
        NULL != pc;
diff --git a/src/backend/taler-merchant-httpd_post-orders-ID-pay.h 
b/src/backend/taler-merchant-httpd_post-orders-ID-pay.h
index 0256494..dff46de 100644
--- a/src/backend/taler-merchant-httpd_post-orders-ID-pay.h
+++ b/src/backend/taler-merchant-httpd_post-orders-ID-pay.h
@@ -30,7 +30,7 @@
  * to shut down MHD.
  */
 void
-MH_force_pc_resume (void);
+TMH_force_pc_resume (void);
 
 
 /**
diff --git a/src/backend/taler-merchant-httpd_private-post-transfers.c 
b/src/backend/taler-merchant-httpd_private-post-transfers.c
index 6071800..d78746c 100644
--- a/src/backend/taler-merchant-httpd_private-post-transfers.c
+++ b/src/backend/taler-merchant-httpd_private-post-transfers.c
@@ -31,8 +31,9 @@
 /**
  * How long to wait before giving up processing with the exchange?
  */
-#define TRACK_TIMEOUT (GNUNET_TIME_relative_multiply 
(GNUNET_TIME_UNIT_SECONDS, \
-                                                      30))
+#define TRANSFER_TIMEOUT (GNUNET_TIME_relative_multiply ( \
+                            GNUNET_TIME_UNIT_SECONDS, \
+                            30))
 
 /**
  * How often do we retry the simple INSERT database transaction?
@@ -42,18 +43,18 @@
 /**
  * Context used for handing POST /private/transfers requests.
  */
-struct TrackTransferContext
+struct PostTransfersContext
 {
 
   /**
    * Kept in a DLL.
    */
-  struct TrackTransferContext *next;
+  struct PostTransfersContext *next;
 
   /**
    * Kept in a DLL.
    */
-  struct TrackTransferContext *prev;
+  struct PostTransfersContext *prev;
 
   /**
    * Argument for the /wire/transfers request.
@@ -112,7 +113,6 @@ struct TrackTransferContext
    */
   struct GNUNET_SCHEDULER_Task *timeout_task;
 
-
   /**
    * Pointer to the detail that we are currently
    * checking in #check_transfer().
@@ -141,285 +141,116 @@ struct TrackTransferContext
 /**
  * Head of list of suspended requests.
  */
-static struct TrackTransferContext *ttc_head;
+static struct PostTransfersContext *ptc_head;
 
 /**
  * Tail of list of suspended requests.
  */
-static struct TrackTransferContext *ttc_tail;
-
-
-/**
- * Represents an entry in the table used to sum up
- * individual deposits for each h_contract_terms/order_id
- * (as the exchange gives us per coin, and we return
- * per order).  FIXME: decide whether we do this HERE
- * or in the DB! (SUM()...)
- */
-struct Entry
-{
-
-  /**
-   * Order of the entry. FIXME: to be used!?
-   */
-  char *order_id;
-
-  /**
-   * Sum accumulator for deposited value.
-   */
-  struct TALER_Amount deposit_value;
-
-  /**
-   * Sum accumulator for deposit fee.
-   */
-  struct TALER_Amount deposit_fee;
-
-};
-
-
-/**
- * Free the @a ttc.
- *
- * @param ttc data to free
- */
-static void
-free_transfer_track_context (struct TrackTransferContext *ttc)
-{
-  if (NULL != ttc->fo)
-  {
-    TMH_EXCHANGES_find_exchange_cancel (ttc->fo);
-    ttc->fo = NULL;
-  }
-  if (NULL != ttc->timeout_task)
-  {
-    GNUNET_SCHEDULER_cancel (ttc->timeout_task);
-    ttc->timeout_task = NULL;
-  }
-  if (NULL != ttc->wdh)
-  {
-    TALER_EXCHANGE_transfers_get_cancel (ttc->wdh);
-    ttc->wdh = NULL;
-  }
-  GNUNET_free (ttc);
-}
-
-
-/**
- * Callback that frees all the elements in the hashmap
- *
- * @param cls closure, NULL
- * @param key current key
- * @param value a `struct Entry`
- * @return #GNUNET_YES if the iteration should continue,
- *         #GNUNET_NO otherwise.
- */
-static int
-hashmap_free (void *cls,
-              const struct GNUNET_HashCode *key,
-              void *value)
-{
-  struct TALER_Entry *entry = value;
-
-  (void) cls;
-  (void) key;
-  GNUNET_free (entry);
-  return GNUNET_YES;
-}
+static struct PostTransfersContext *ptc_tail;
 
 
 /**
- * Builds JSON response containing the summed-up amounts
- * from individual deposits.
- *
- * @param cls a `json_t *` array to append additional entries to
- * @param key map's current key
- * @param map's current value
- * @return #GNUNET_YES if iteration is to be continued,
- *         #GNUNET_NO otherwise.
+ * We are shutting down, force resume of all POST /transfers requests.
  */
-static int
-build_deposits_response (void *cls,
-                         const struct GNUNET_HashCode *key,
-                         void *value)
+void
+TMH_force_post_transfers_resume ()
 {
-  json_t *deposits_response;
-  struct Entry *entry = value;
-  json_t *element;
-
-  element = json_pack ("{s:s, s:o, s:o}",
-                       "order_id", entry->order_id,
-                       "deposit_value", TALER_JSON_from_amount (
-                         &entry->deposit_value),
-                       "deposit_fee", TALER_JSON_from_amount (
-                         &entry->deposit_fee));
-  GNUNET_assert (NULL != element);
-  GNUNET_assert (0 ==
-                 json_array_append_new (deposits_response,
-                                        element));
-  return GNUNET_YES;
-}
+  struct PostTransfersContext *ptc;
 
-
-/**
- * Transform /track/transfer result as gotten from the exchange
- * and transforms it in a format liked by the backoffice Web interface.
- *
- * @param result response from exchange's /track/transfer
- * @result pointer to new JSON, or NULL upon errors.
- */
-static json_t *
-transform_response (const json_t *result,
-                    struct TrackTransferContext *ttc)
-{
-  json_t *deposits;
-  json_t *value;
-  json_t *result_mod = NULL;
-  size_t index;
-  const char *key;
-  struct GNUNET_HashCode h_key;
-  struct GNUNET_CONTAINER_MultiHashMap *map;
-  struct TALER_Amount iter_value;
-  struct TALER_Amount iter_fee;
-  struct Entry *current_entry;
-  struct GNUNET_JSON_Specification spec[] = {
-    TALER_JSON_spec_amount ("deposit_value", &iter_value),
-    TALER_JSON_spec_amount ("deposit_fee", &iter_fee),
-    GNUNET_JSON_spec_string ("h_contract_terms", &key),
-    GNUNET_JSON_spec_end ()
-  };
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Transforming /track/transfer response.\n");
-  map = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
-  deposits = json_object_get (result,
-                              "deposits");
-
-  json_array_foreach (deposits, index, value)
+  while (NULL != (ptc = ptc_head))
   {
-    if (GNUNET_OK !=
-        GNUNET_JSON_parse (value,
-                           spec,
-                           NULL,
-                           NULL))
-    {
-      GNUNET_break_op (0);
-      return NULL;
-    }
-    GNUNET_CRYPTO_hash_from_string (key,
-                                    &h_key);
-
-    if (NULL != (current_entry =
-                   GNUNET_CONTAINER_multihashmap_get (map,
-                                                      &h_key)))
+    GNUNET_CONTAINER_DLL_remove (ptc_head,
+                                 ptc_tail,
+                                 ptc);
+    MHD_resume_connection (ptc->connection);
+    if (NULL != ptc->timeout_task)
     {
-      /* The map already knows this h_contract_terms*/
-      if ( (0 >
-            TALER_amount_add (&current_entry->deposit_value,
-                              &current_entry->deposit_value,
-                              &iter_value)) ||
-           (0 >
-            TALER_amount_add (&current_entry->deposit_fee,
-                              &current_entry->deposit_fee,
-                              &iter_fee)) )
-      {
-        GNUNET_JSON_parse_free (spec);
-        goto cleanup;
-      }
+      GNUNET_SCHEDULER_cancel (ptc->timeout_task);
+      ptc->timeout_task = NULL;
     }
-    else
-    {
-      /* First time in the map for this h_contract_terms*/
-      current_entry = GNUNET_new (struct Entry);
-      current_entry->deposit_value = iter_value;
-      current_entry->deposit_fee = iter_fee;
-      current_entry->order_id = "FIXME";
-
-      if (GNUNET_SYSERR ==
-          GNUNET_CONTAINER_multihashmap_put (map,
-                                             &h_key,
-                                             current_entry,
-                                             
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
-      {
-        GNUNET_JSON_parse_free (spec);
-        goto cleanup;
-      }
-    }
-    GNUNET_JSON_parse_free (spec);
   }
-
-  {
-    json_t *deposits_response;
-
-    deposits_response = json_array ();
-    GNUNET_assert (NULL != deposits_response);
-    if (GNUNET_SYSERR ==
-        GNUNET_CONTAINER_multihashmap_iterate (map,
-                                               &build_deposits_response,
-                                               deposits_response))
-    {
-      json_decref (deposits_response);
-      goto cleanup;
-    }
-
-    result_mod = json_copy ((struct json_t *) result);
-    json_object_del (result_mod,
-                     "deposits");
-    json_object_set_new (result_mod,
-                         "deposits_sums",
-                         deposits_response);
-  }
-cleanup:
-  GNUNET_CONTAINER_multihashmap_iterate (map,
-                                         &hashmap_free,
-                                         NULL);
-  GNUNET_CONTAINER_multihashmap_destroy (map);
-  return result_mod;
 }
 
 
 /**
  * Resume the given /track/transfer operation and send the given response.
- * Stores the response in the @a ttc and signals MHD to resume
+ * Stores the response in the @a ptc and signals MHD to resume
  * the connection.  Also ensures MHD runs immediately.
  *
- * @param ttc transfer tracking context
+ * @param ptc transfer tracking context
  * @param response_code response code to use
  * @param response response data to send back
  */
 static void
-resume_track_transfer_with_response (struct TrackTransferContext *ttc,
-                                     unsigned int response_code,
-                                     struct MHD_Response *response)
+resume_transfer_with_response (struct PostTransfersContext *ptc,
+                               unsigned int response_code,
+                               struct MHD_Response *response)
 {
-  ttc->response_code = response_code;
-  ttc->response = response;
+  ptc->response_code = response_code;
+  ptc->response = response;
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Resuming POST /transfers handling as exchange interaction is 
done (%u)\n",
               response_code);
-  if (NULL != ttc->timeout_task)
+  if (NULL != ptc->timeout_task)
   {
-    GNUNET_SCHEDULER_cancel (ttc->timeout_task);
-    ttc->timeout_task = NULL;
+    GNUNET_SCHEDULER_cancel (ptc->timeout_task);
+    ptc->timeout_task = NULL;
   }
-  GNUNET_CONTAINER_DLL_remove (ttc_head,
-                               ttc_tail,
-                               ttc);
-  MHD_resume_connection (ttc->connection);
-  TMH_trigger_daemon (); /* we resumed, kick MHD */
+  GNUNET_CONTAINER_DLL_remove (ptc_head,
+                               ptc_tail,
+                               ptc);
+  MHD_resume_connection (ptc->connection);
+  TMH_trigger_daemon ();   /* we resumed, kick MHD */
 }
 
 
 /**
- * Custom cleanup routine for a `struct TrackTransferContext`.
+ * Resume the given POST /transfers operation with an error.
  *
- * @param cls the `struct TrackTransferContext` to clean up.
+ * @param ptc transfer tracking context
+ * @param response_code response code to use
+ * @param ec error code to use
+ * @param hint hint text to provide
  */
 static void
-track_transfer_cleanup (void *cls)
+resume_transfer_with_error (struct PostTransfersContext *ptc,
+                            unsigned int response_code,
+                            enum TALER_ErrorCode ec,
+                            const char *hint)
 {
-  struct TrackTransferContext *ttc = cls;
+  resume_transfer_with_response (ptc,
+                                 response_code,
+                                 TALER_MHD_make_error (ec,
+                                                       hint));
+}
+
 
-  free_transfer_track_context (ttc);
+/**
+ * Custom cleanup routine for a `struct PostTransfersContext`.
+ *
+ * @param cls the `struct PostTransfersContext` to clean up.
+ */
+static void
+transfer_cleanup (void *cls)
+{
+  struct PostTransfersContext *ptc = cls;
+
+  if (NULL != ptc->fo)
+  {
+    TMH_EXCHANGES_find_exchange_cancel (ptc->fo);
+    ptc->fo = NULL;
+  }
+  if (NULL != ptc->timeout_task)
+  {
+    GNUNET_SCHEDULER_cancel (ptc->timeout_task);
+    ptc->timeout_task = NULL;
+  }
+  if (NULL != ptc->wdh)
+  {
+    TALER_EXCHANGE_transfers_get_cancel (ptc->wdh);
+    ptc->wdh = NULL;
+  }
+  GNUNET_free (ptc);
 }
 
 
@@ -428,7 +259,7 @@ track_transfer_cleanup (void *cls)
  * was paid back by _this_ wire transfer matches what _we_ (the merchant)
  * knew about this coin.
  *
- * @param cls closure with our `struct TrackTransferContext *`
+ * @param cls closure with our `struct PostTransfersContext *`
  * @param transaction_id of the contract
  * @param coin_pub public key of the coin
  * @param exchange_url URL of the exchange that issued @a coin_pub
@@ -448,11 +279,11 @@ check_transfer (void *cls,
                 const struct TALER_Amount *wire_fee,
                 const json_t *exchange_proof)
 {
-  struct TrackTransferContext *ttc = cls;
-  const struct TALER_TrackTransferDetails *ttd = ttc->current_detail;
+  struct PostTransfersContext *ptc = cls;
+  const struct TALER_TrackTransferDetails *ttd = ptc->current_detail;
 
-  if (GNUNET_SYSERR == ttc->check_transfer_result)
-    return; /* already had a serious issue; odd that we're called more than 
once as well... */
+  if (GNUNET_SYSERR == ptc->check_transfer_result)
+    return;   /* already had a serious issue; odd that we're called more than 
once as well... */
   if ( (0 != TALER_amount_cmp (amount_with_fee,
                                &ttd->coin_value)) ||
        (0 != TALER_amount_cmp (deposit_fee,
@@ -461,15 +292,15 @@ check_transfer (void *cls,
     /* Disagreement between the exchange and us about how much this
        coin is worth! */
     GNUNET_break_op (0);
-    ttc->check_transfer_result = GNUNET_SYSERR;
+    ptc->check_transfer_result = GNUNET_SYSERR;
     /* Build the `TrackTransferConflictDetails` */
-    ttc->response
+    ptc->response
       = TALER_MHD_make_json_pack (
           "{s:I, s:s, s:o, s:I, s:o, s:s, s:o, s:o}",
-          "code", (json_int_t) TALER_EC_TRACK_TRANSFER_CONFLICTING_REPORTS,
+          "code", (json_int_t) TALER_EC_POST_TRANSFERS_CONFLICTING_REPORTS,
           "hint", "disagreement about deposit valuation",
           "exchange_deposit_proof", exchange_proof,
-          "conflict_offset", (json_int_t) ttc->current_offset,
+          "conflict_offset", (json_int_t) ptc->current_offset,
           "coin_pub", GNUNET_JSON_from_data_auto (coin_pub),
           "h_contract_terms", GNUNET_JSON_from_data_auto (
             &ttd->h_contract_terms),
@@ -477,7 +308,7 @@ check_transfer (void *cls,
           "deposit_fee", TALER_JSON_from_amount (deposit_fee));
     return;
   }
-  ttc->check_transfer_result = GNUNET_OK;
+  ptc->check_transfer_result = GNUNET_OK;
 }
 
 
@@ -490,7 +321,7 @@ check_transfer (void *cls,
  * if we have proof that the fee is bogus, we respond with
  * the proof to the client and return #GNUNET_SYSERR.
  *
- * @param ttc context of the transfer to respond to
+ * @param ptc context of the transfer to respond to
  * @param json response from the exchange
  * @param execution_time time of the wire transfer
  * @param wire_fee fee claimed by the exchange
@@ -498,7 +329,7 @@ check_transfer (void *cls,
  *   missbehavior from the exchange to the client
  */
 static int
-check_wire_fee (struct TrackTransferContext *ttc,
+check_wire_fee (struct PostTransfersContext *ptc,
                 const json_t *json,
                 struct GNUNET_TIME_Absolute execution_time,
                 const struct TALER_Amount *wire_fee)
@@ -511,10 +342,10 @@ check_wire_fee (struct TrackTransferContext *ttc,
   enum GNUNET_DB_QueryStatus qs;
   char *wire_method;
 
-  wire_method = TALER_payto_get_method (ttc->payto_uri);
+  wire_method = TALER_payto_get_method (ptc->payto_uri);
   TMH_db->preflight (TMH_db->cls);
   qs = TMH_db->lookup_wire_fee (TMH_db->cls,
-                                &ttc->master_pub,
+                                &ptc->master_pub,
                                 wire_method,
                                 execution_time,
                                 &expected_fee,
@@ -526,7 +357,7 @@ check_wire_fee (struct TrackTransferContext *ttc,
   {
     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                 "Failed to find wire fee for `%s' and method `%s' at %s in DB, 
accepting blindly that the fee is %s\n",
-                TALER_B2S (&ttc->master_pub),
+                TALER_B2S (&ptc->master_pub),
                 wire_method,
                 GNUNET_STRINGS_absolute_time_to_string (execution_time),
                 TALER_amount2s (wire_fee));
@@ -537,15 +368,15 @@ check_wire_fee (struct TrackTransferContext *ttc,
                              wire_fee))
   {
     GNUNET_free (wire_method);
-    return GNUNET_OK; /* expected_fee >= wire_fee */
+    return GNUNET_OK;   /* expected_fee >= wire_fee */
   }
   /* Wire fee check failed, export proof to client */
-  resume_track_transfer_with_response (
-    ttc,
+  resume_transfer_with_response (
+    ptc,
     MHD_HTTP_FAILED_DEPENDENCY,
     TALER_MHD_make_json_pack (
       "{s:I, s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:O}",
-      "code", (json_int_t) TALER_EC_TRACK_TRANSFER_JSON_BAD_WIRE_FEE,
+      "code", (json_int_t) TALER_EC_POST_TRANSFERS_JSON_BAD_WIRE_FEE,
       "wire_fee", TALER_JSON_from_amount (wire_fee),
       "execution_time", GNUNET_JSON_from_time_abs (execution_time),
       "expected_wire_fee", TALER_JSON_from_amount (&expected_fee),
@@ -553,7 +384,7 @@ check_wire_fee (struct TrackTransferContext *ttc,
       "start_date", GNUNET_JSON_from_time_abs (start_date),
       "end_date", GNUNET_JSON_from_time_abs (end_date),
       "master_sig", GNUNET_JSON_from_data_auto (&master_sig),
-      "master_pub", GNUNET_JSON_from_data_auto (&ttc->master_pub),
+      "master_pub", GNUNET_JSON_from_data_auto (&ptc->master_pub),
       "json", json));
   GNUNET_free (wire_method);
   return GNUNET_SYSERR;
@@ -573,54 +404,30 @@ wire_transfer_cb (void *cls,
                   const struct TALER_EXCHANGE_HttpResponse *hr,
                   const struct TALER_EXCHANGE_TransferData *td)
 {
-  struct TrackTransferContext *ttc = cls;
-  const char *instance_id = ttc->hc->instance->settings.id;
+  struct PostTransfersContext *ptc = cls;
+  const char *instance_id = ptc->hc->instance->settings.id;
   enum GNUNET_DB_QueryStatus qs;
 
-  ttc->wdh = NULL;
+  ptc->wdh = NULL;
   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
               "Got response code %u from exchange for GET /transfers/$WTID\n",
               hr->http_status);
   if (MHD_HTTP_OK != hr->http_status)
   {
-    resume_track_transfer_with_response (
-      ttc,
+    resume_transfer_with_response (
+      ptc,
       MHD_HTTP_FAILED_DEPENDENCY,
       TALER_MHD_make_json_pack (
         "{s:I, s:I, s:I, s:O}",
-        "code", (json_int_t) TALER_EC_TRACK_TRANSFER_EXCHANGE_ERROR,
+        "code", (json_int_t) TALER_EC_POST_TRANSFERS_EXCHANGE_ERROR,
         "exchange_code", (json_int_t) hr->ec,
         "exchange_http_status", (json_int_t) hr->http_status,
         "exchange_reply", hr->reply));
     return;
   }
-  TMH_db->preflight (TMH_db->cls);
-  qs = TMH_db->insert_transfer_details (TMH_db->cls,
-                                        instance_id,
-                                        ttc->exchange_url,
-                                        ttc->payto_uri,
-                                        &ttc->wtid,
-                                        td);
-  if (0 > qs)
-  {
-    /* Special report if retries insufficient */
-    GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
-    /* Always report on hard error as well to enable diagnostics */
-    GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
-    resume_track_transfer_with_response (
-      ttc,
-      MHD_HTTP_INTERNAL_SERVER_ERROR,
-      TALER_MHD_make_json_pack (
-        "{s:I, s:s}",
-        "code",
-        (json_int_t) TALER_EC_TRACK_TRANSFER_DB_STORE_TRANSFER_ERROR,
-        "details",
-        "failed to store response from exchange to local database"));
-    return;
-  }
 
   if (GNUNET_SYSERR ==
-      check_wire_fee (ttc,
+      check_wire_fee (ptc,
                       hr->reply,
                       td->execution_time,
                       &td->wire_fee))
@@ -638,17 +445,17 @@ wire_transfer_cb (void *cls,
   {
     const struct TALER_TrackTransferDetails *ttd = &td->details[i];
 
-    ttc->current_offset = i;
-    ttc->current_detail = ttd;
+    ptc->current_offset = i;
+    ptc->current_detail = ttd;
     /* Set the coin as "never seen" before. */
-    ttc->check_transfer_result = GNUNET_NO;
+    ptc->check_transfer_result = GNUNET_NO;
     TMH_db->preflight (TMH_db->cls);
     qs = TMH_db->lookup_deposits_by_contract_and_coin (TMH_db->cls,
                                                        instance_id,
                                                        &ttd->h_contract_terms,
                                                        &ttd->coin_pub,
                                                        &check_transfer,
-                                                       ttc);
+                                                       ptc);
     if (0 > qs)
     {
       /* single, read-only SQL statements should never cause
@@ -656,15 +463,11 @@ wire_transfer_cb (void *cls,
       GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
       /* Always report on hard error as well to enable diagnostics */
       GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
-      resume_track_transfer_with_response (
-        ttc,
+      resume_transfer_with_error (
+        ptc,
         MHD_HTTP_INTERNAL_SERVER_ERROR,
-        TALER_MHD_make_json_pack ("{s:I, s:s}",
-                                  "code",
-                                  (json_int_t)
-                                  
TALER_EC_TRACK_TRANSFER_DB_FETCH_DEPOSIT_ERROR,
-                                  "details",
-                                  "failed to obtain deposit data from local 
database"));
+        TALER_EC_POST_TRANSFERS_DB_FETCH_DEPOSIT_ERROR,
+        "failed to obtain deposit data from local database");
       return;
     }
     if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
@@ -674,110 +477,138 @@ wire_transfer_cb (void *cls,
          Well, let's say thanks and accept the money! */
       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                   "Failed to find payment data in DB\n");
-      ttc->check_transfer_result = GNUNET_OK;
+      ptc->check_transfer_result = GNUNET_OK;
     }
-    if (GNUNET_NO == ttc->check_transfer_result)
+    if (GNUNET_NO == ptc->check_transfer_result)
     {
       /* Internal error: how can we have called #check_transfer()
          but still have no result? */
       GNUNET_break (0);
-      resume_track_transfer_with_response (
-        ttc,
-        MHD_HTTP_INTERNAL_SERVER_ERROR,
-        TALER_MHD_make_json_pack ("{s:I, s:s, s:I, s:s}",
-                                  "code",
-                                  (json_int_t)
-                                  
TALER_EC_TRACK_TRANSFER_DB_INTERNAL_LOGIC_ERROR,
-                                  "details", "internal logic error",
-                                  "line", (json_int_t) __LINE__,
-                                  "file", __FILE__));
+      resume_transfer_with_error (ptc,
+                                  MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                  
TALER_EC_POST_TRANSFERS_DB_INTERNAL_LOGIC_ERROR,
+                                  "internal logic error");
       return;
     }
-    if (GNUNET_SYSERR == ttc->check_transfer_result)
+    if (GNUNET_SYSERR == ptc->check_transfer_result)
     {
       /* #check_transfer() failed, report conflict! */
       GNUNET_break_op (0);
-      GNUNET_assert (NULL != ttc->response);
-      resume_track_transfer_with_response (
-        ttc,
-        MHD_HTTP_FAILED_DEPENDENCY,
-        ttc->response);
-      ttc->response = NULL;
+      GNUNET_assert (NULL != ptc->response);
+      resume_transfer_with_response (ptc,
+                                     MHD_HTTP_FAILED_DEPENDENCY,
+                                     ptc->response);
+      ptc->response = NULL;
       return;
     }
-    /* Response is consistent with the /deposit we made,
-       remember it for future reference */
-    for (unsigned int r = 0; r<MAX_RETRIES; r++)
+  }
+
+  /* Response is consistent with the /deposit we made,
+     remember it for future reference */
+  for (unsigned int r = 0; r<MAX_RETRIES; r++)
+  {
+    TMH_db->preflight (TMH_db->cls);
+    if (GNUNET_OK !=
+        TMH_db->start (TMH_db->cls,
+                       "insert transaction details"))
+    {
+      GNUNET_break (0);
+      resume_transfer_with_error (ptc,
+                                  MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                  
TALER_EC_POST_TRANSFERS_DB_STORE_TRANSFER_ERROR,
+                                  "could not start transaction");
+      return;
+    }
+    for (unsigned int i = 0; i < td->details_length; i++)
     {
       const struct TALER_TrackTransferDetails *ttd = &td->details[i];
 
-      TMH_db->preflight (TMH_db->cls);
       qs = TMH_db->store_coin_to_transfer (TMH_db->cls,
                                            &ttd->h_contract_terms,
                                            &ttd->coin_pub,
-                                           &ttc->wtid);
-      if (GNUNET_DB_STATUS_SOFT_ERROR != qs)
-        break;
+                                           &ptc->wtid);
+      if (0 > qs)
+        goto retry;
     }
+
+    /* Ok, exchange answer is acceptable, store it */
+    qs = TMH_db->insert_transfer_details (TMH_db->cls,
+                                          instance_id,
+                                          ptc->exchange_url,
+                                          ptc->payto_uri,
+                                          &ptc->wtid,
+                                          td);
     if (0 > qs)
+      goto retry;
+    qs = TMH_db->commit (TMH_db->cls);
+retry:
+    if (GNUNET_DB_STATUS_HARD_ERROR == qs)
     {
-      /* Special report if retries insufficient */
-      GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
+      TMH_db->rollback (TMH_db->cls);
       /* Always report on hard error as well to enable diagnostics */
       GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
-      resume_track_transfer_with_response (
-        ttc,
+      resume_transfer_with_error (
+        ptc,
         MHD_HTTP_INTERNAL_SERVER_ERROR,
-        TALER_MHD_make_json_pack ("{s:I, s:s}",
-                                  "code",
-                                  (json_int_t)
-                                  TALER_EC_TRACK_TRANSFER_DB_STORE_COIN_ERROR,
-                                  "details",
-                                  "failed to store response from exchange to 
local database"));
+        TALER_EC_POST_TRANSFERS_DB_STORE_TRANSFER_ERROR,
+        "failed to commit transaction to local database");
       return;
     }
+    if (0 <= qs)
+      break; /* success! */
+  }
+  if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+  {
+    TMH_db->rollback (TMH_db->cls);
+    /* Always report on hard error as well to enable diagnostics */
+    GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
+    resume_transfer_with_error (
+      ptc,
+      MHD_HTTP_INTERNAL_SERVER_ERROR,
+      TALER_EC_POST_TRANSFERS_DB_STORE_TRANSFER_ERROR,
+      "repeated serialization failures trying to commit transaction to local 
database");
+    return;
   }
 
   /* resume processing, main function will build the response */
-  resume_track_transfer_with_response (ttc,
-                                       0,
-                                       NULL);
+  resume_transfer_with_response (ptc,
+                                 0,
+                                 NULL);
 }
 
 
 /**
  * Function called with the result of our exchange lookup.
  *
- * @param cls the `struct TrackTransferContext`
+ * @param cls the `struct PostTransfersContext`
  * @param hr HTTP response details
  * @param eh NULL if exchange was not found to be acceptable
  * @param wire_fee NULL (we did not specify a wire method)
  * @param exchange_trusted #GNUNET_YES if this exchange is trusted by config
  */
 static void
-process_track_transfer_with_exchange (
-  void *cls,
-  const struct TALER_EXCHANGE_HttpResponse *hr,
-  struct TALER_EXCHANGE_Handle *eh,
-  const struct TALER_Amount *wire_fee,
-  int exchange_trusted)
+process_transfer_with_exchange (void *cls,
+                                const struct TALER_EXCHANGE_HttpResponse *hr,
+                                struct TALER_EXCHANGE_Handle *eh,
+                                const struct TALER_Amount *wire_fee,
+                                int exchange_trusted)
 {
-  struct TrackTransferContext *ttc = cls;
+  struct PostTransfersContext *ptc = cls;
 
-  ttc->fo = NULL;
+  ptc->fo = NULL;
   if (MHD_HTTP_OK != hr->http_status)
   {
     /* The request failed somehow */
     GNUNET_break_op (0);
-    resume_track_transfer_with_response (
-      ttc,
+    resume_transfer_with_response (
+      ptc,
       MHD_HTTP_FAILED_DEPENDENCY,
       TALER_MHD_make_json_pack (
         (NULL != hr->reply)
         ? "{s:s, s:I, s:I, s:I, s:O}"
         : "{s:s, s:I, s:I, s:I}",
         "hint", "failed to obtain meta-data from exchange",
-        "code", (json_int_t) TALER_EC_TRACK_TRANSFER_EXCHANGE_KEYS_FAILURE,
+        "code", (json_int_t) TALER_EC_POST_TRANSFERS_EXCHANGE_KEYS_FAILURE,
         "exchange_http_status", (json_int_t) hr->http_status,
         "exchange_code", (json_int_t) hr->ec,
         "exchange_reply", hr->reply));
@@ -792,39 +623,62 @@ process_track_transfer_with_exchange (
     if (NULL == keys)
     {
       GNUNET_break (0);
-      resume_track_transfer_with_response (
-        ttc,
-        MHD_HTTP_INTERNAL_SERVER_ERROR,
-        TALER_MHD_make_error (
-          TALER_EC_TRACK_TRANSFER_EXCHANGE_KEYS_FAILURE,
-          "failed to get keys"));
+      resume_transfer_with_error (ptc,
+                                  MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                  
TALER_EC_POST_TRANSFERS_EXCHANGE_KEYS_FAILURE,
+                                  "failed to get keys");
       return;
     }
-    ttc->master_pub = keys->master_pub;
+    ptc->master_pub = keys->master_pub;
   }
 
-  ttc->wdh = TALER_EXCHANGE_transfers_get (eh,
-                                           &ttc->wtid,
+  ptc->wdh = TALER_EXCHANGE_transfers_get (eh,
+                                           &ptc->wtid,
                                            &wire_transfer_cb,
-                                           ttc);
-  if (NULL == ttc->wdh)
+                                           ptc);
+  if (NULL == ptc->wdh)
   {
     GNUNET_break (0);
-    resume_track_transfer_with_response (
-      ttc,
-      MHD_HTTP_INTERNAL_SERVER_ERROR,
-      TALER_MHD_make_error (
-        TALER_EC_TRACK_TRANSFER_REQUEST_ERROR,
-        "failed to run GET /transfers/ on exchange"));
+    resume_transfer_with_error (ptc,
+                                MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                TALER_EC_POST_TRANSFERS_REQUEST_ERROR,
+                                "failed to run GET /transfers/ on exchange");
   }
 }
 
 
+/**
+ * Represents an entry in the table used to sum up
+ * individual deposits for each h_contract_terms/order_id
+ * (as the exchange gives us per coin, and we return
+ * per order).
+ */
+struct Entry
+{
+
+  /**
+   * Order of the entry.
+   */
+  char *order_id;
+
+  /**
+   * Sum accumulator for deposited value.
+   */
+  struct TALER_Amount deposit_value;
+
+  /**
+   * Sum accumulator for deposit fee.
+   */
+  struct TALER_Amount deposit_fee;
+
+};
+
+
 /**
  * Function called with information about a wire transfer identifier.
  * Generate a response array based on the given information.
  *
- * @param cls closure, a `json_t` array to update
+ * @param cls closure, a hashmap to update
  * @param order_id the order to which the deposits belong
  * @param deposit_value the amount deposited under @a order_id
  * @param deposit_fee the fee charged for @a deposit_value
@@ -834,17 +688,79 @@ transfer_details_cb (void *cls,
                      const char *order_id,
                      const struct TALER_Amount *deposit_value,
                      const struct TALER_Amount *deposit_fee)
+{
+  struct GNUNET_CONTAINER_MultiHashMap *map = cls;
+  struct Entry *current_entry;
+  struct GNUNET_HashCode h_key;
+
+  GNUNET_CRYPTO_hash_from_string (order_id,
+                                  &h_key);
+  current_entry = GNUNET_CONTAINER_multihashmap_get (map,
+                                                     &h_key);
+  if (NULL != current_entry)
+  {
+    /* The map already knows this order, do aggregation */
+    GNUNET_assert ( (0 <=
+                     TALER_amount_add (&current_entry->deposit_value,
+                                       &current_entry->deposit_value,
+                                       deposit_value)) &&
+                    (0 <=
+                     TALER_amount_add (&current_entry->deposit_fee,
+                                       &current_entry->deposit_fee,
+                                       deposit_fee)) );
+  }
+  else
+  {
+    /* First time in the map for this h_contract_terms*/
+    current_entry = GNUNET_new (struct Entry);
+    current_entry->deposit_value = *deposit_value;
+    current_entry->deposit_fee = *deposit_fee;
+    current_entry->order_id = GNUNET_strdup (order_id);
+    GNUNET_assert (GNUNET_SYSERR !=
+                   GNUNET_CONTAINER_multihashmap_put (map,
+                                                      &h_key,
+                                                      current_entry,
+                                                      
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+  }
+}
+
+
+/**
+ * Callback that frees all the elements in the hashmap, and @a cls
+ * is non-NULL, appends them as JSON to the array
+ *
+ * @param cls closure, NULL or a `json_t *` array
+ * @param key current key
+ * @param value a `struct Entry`
+ * @return #GNUNET_YES if the iteration should continue,
+ *         #GNUNET_NO otherwise.
+ */
+static int
+hashmap_free (void *cls,
+              const struct GNUNET_HashCode *key,
+              void *value)
 {
   json_t *ja = cls;
+  struct Entry *entry = value;
 
-  GNUNET_assert (
-    0 ==
-    json_array_append_new (
-      ja,
-      json_pack ("{s:s,s:o,s:o}",
-                 "order_id", order_id,
-                 "deposit_value", TALER_JSON_from_amount (deposit_value),
-                 "deposit_fee", TALER_JSON_from_amount (deposit_fee))));
+  (void) key;
+  if (NULL != ja)
+  {
+    GNUNET_assert (
+      0 ==
+      json_array_append_new (
+        ja,
+        json_pack ("{s:s,s:o,s:o}",
+                   "order_id",
+                   entry->order_id,
+                   "deposit_value",
+                   TALER_JSON_from_amount (&entry->deposit_value),
+                   "deposit_fee",
+                   TALER_JSON_from_amount (&entry->deposit_fee))));
+  }
+  GNUNET_free (entry->order_id);
+  GNUNET_free (entry);
+  return GNUNET_YES;
 }
 
 
@@ -854,28 +770,27 @@ transfer_details_cb (void *cls,
  * @param cls closure
  */
 static void
-handle_track_transfer_timeout (void *cls)
+handle_transfer_timeout (void *cls)
 {
-  struct TrackTransferContext *ttc = cls;
+  struct PostTransfersContext *ptc = cls;
 
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Resuming POST /private/transfers with error after timeout\n");
-  ttc->timeout_task = NULL;
-  if (NULL != ttc->fo)
+  ptc->timeout_task = NULL;
+  if (NULL != ptc->fo)
   {
-    TMH_EXCHANGES_find_exchange_cancel (ttc->fo);
-    ttc->fo = NULL;
+    TMH_EXCHANGES_find_exchange_cancel (ptc->fo);
+    ptc->fo = NULL;
   }
-  if (NULL != ttc->wdh)
+  if (NULL != ptc->wdh)
   {
-    TALER_EXCHANGE_transfers_get_cancel (ttc->wdh);
-    ttc->wdh = NULL;
+    TALER_EXCHANGE_transfers_get_cancel (ptc->wdh);
+    ptc->wdh = NULL;
   }
-  resume_track_transfer_with_response (ttc,
-                                       MHD_HTTP_SERVICE_UNAVAILABLE,
-                                       TALER_MHD_make_error (
-                                         
TALER_EC_TRACK_TRANSFER_EXCHANGE_TIMEOUT,
-                                         "exchange not reachable"));
+  resume_transfer_with_error (ptc,
+                              MHD_HTTP_SERVICE_UNAVAILABLE,
+                              TALER_EC_POST_TRANSFERS_EXCHANGE_TIMEOUT,
+                              "exchange not reachable");
 }
 
 
@@ -894,43 +809,44 @@ TMH_private_post_transfers (const struct 
TMH_RequestHandler *rh,
                             struct MHD_Connection *connection,
                             struct TMH_HandlerContext *hc)
 {
-  struct TrackTransferContext *ttc = hc->ctx;
+  struct PostTransfersContext *ptc = hc->ctx;
   enum GNUNET_DB_QueryStatus qs;
 
-  if (NULL == ttc)
+  if (NULL == ptc)
   {
-    ttc = GNUNET_new (struct TrackTransferContext);
-    ttc->connection = connection;
-    hc->ctx = ttc;
-    hc->cc = &track_transfer_cleanup;
+    ptc = GNUNET_new (struct PostTransfersContext);
+    ptc->connection = connection;
+    hc->ctx = ptc;
+    hc->cc = &transfer_cleanup;
   }
 
-  if (0 != ttc->response_code)
+  if (0 != ptc->response_code)
   {
     MHD_RESULT ret;
 
     /* We are *done* processing the request, just queue the response (!) */
-    if (UINT_MAX == ttc->response_code)
+    if (UINT_MAX == ptc->response_code)
     {
       GNUNET_break (0);
       return MHD_NO; /* hard error */
     }
     ret = MHD_queue_response (connection,
-                              ttc->response_code,
-                              ttc->response);
-    if (NULL != ttc->response)
+                              ptc->response_code,
+                              ptc->response);
+    if (NULL != ptc->response)
     {
-      MHD_destroy_response (ttc->response);
-      ttc->response = NULL;
+      MHD_destroy_response (ptc->response);
+      ptc->response = NULL;
     }
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                 "Queueing response (%u) for POST /private/transfers (%s).\n",
-                (unsigned int) ttc->response_code,
+                (unsigned int) ptc->response_code,
                 ret ? "OK" : "FAILED");
     return ret;
   }
-  if ( (NULL != ttc->fo) ||
-       (NULL != ttc->wdh) )
+
+  if ( (NULL != ptc->fo) ||
+       (NULL != ptc->wdh) )
   {
     /* likely old MHD version */
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -938,16 +854,18 @@ TMH_private_post_transfers (const struct 
TMH_RequestHandler *rh,
     return MHD_YES; /* still work in progress */
   }
 
+  if (NULL == ptc->exchange_url)
   {
+    /* First request, parse it! */
     struct GNUNET_JSON_Specification spec[] = {
       GNUNET_JSON_spec_string ("exchange",
-                               &ttc->exchange_url),
+                               &ptc->exchange_url),
       GNUNET_JSON_spec_string ("payto_uri",
-                               &ttc->payto_uri),
+                               &ptc->payto_uri),
       TALER_JSON_spec_amount ("amount",
-                              &ttc->amount),
+                              &ptc->amount),
       GNUNET_JSON_spec_fixed_auto ("wtid",
-                                   &ttc->wtid),
+                                   &ptc->wtid),
       GNUNET_JSON_spec_end ()
     };
 
@@ -964,40 +882,51 @@ TMH_private_post_transfers (const struct 
TMH_RequestHandler *rh,
     }
   }
 
-  /* Check if reply is already in database! */
+  /* Check if transfer data is in database! */
   {
-    json_t *deposit_sums;
+    struct GNUNET_CONTAINER_MultiHashMap *map;
     struct GNUNET_TIME_Absolute execution_time;
     struct TALER_Amount total_amount;
     struct TALER_Amount wire_fee;
 
-    deposit_sums = json_array ();
-    GNUNET_assert (NULL != deposit_sums);
     TMH_db->preflight (TMH_db->cls);
+    map = GNUNET_CONTAINER_multihashmap_create (16,
+                                                GNUNET_NO);
     qs = TMH_db->lookup_transfer_details (TMH_db->cls,
                                           hc->instance->settings.id,
-                                          ttc->exchange_url,
-                                          ttc->payto_uri,
-                                          &ttc->wtid,
+                                          ptc->exchange_url,
+                                          ptc->payto_uri,
+                                          &ptc->wtid,
                                           &total_amount,
                                           &wire_fee,
                                           execution_time,
                                           &transfer_details_cb,
-                                          deposit_sums);
+                                          map);
     if (0 > qs)
     {
       /* Simple select queries should not cause serialization issues */
       GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
       /* Always report on hard error as well to enable diagnostics */
       GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
-      json_decref (deposit_sums);
+      GNUNET_CONTAINER_multihashmap_iterate (map,
+                                             &hashmap_free,
+                                             NULL);
+      GNUNET_CONTAINER_multihashmap_destroy (map);
       return TALER_MHD_reply_with_error (connection,
                                          MHD_HTTP_INTERNAL_SERVER_ERROR,
                                          
TALER_EC_POST_TRANSFERS_DB_LOOKUP_ERROR,
-                                         "Fail to query database about 
proofs");
+                                         "Failed to query database about 
transfer details");
     }
     if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs)
     {
+      json_t *deposit_sums;
+
+      deposit_sums = json_array ();
+      GNUNET_assert (NULL != deposit_sums);
+      GNUNET_CONTAINER_multihashmap_iterate (map,
+                                             &hashmap_free,
+                                             deposit_sums);
+      GNUNET_CONTAINER_multihashmap_destroy (map);
       return TALER_MHD_reply_json_pack (
         connection,
         MHD_HTTP_OK,
@@ -1007,17 +936,16 @@ TMH_private_post_transfers (const struct 
TMH_RequestHandler *rh,
         "execution_time", GNUNET_JSON_from_time_abs (execution_time),
         "deposit_sums", deposit_sums);
     }
-    json_decref (deposit_sums);
   }
 
   /* reply not in database, ensure the POST is in the database, and
      start work to obtain the reply from the exchange */
   qs = TMH_db->insert_transfer (TMH_db->cls,
-                                ttc->hc->instance->settings.id,
-                                ttc->exchange_url,
-                                &ttc->wtid,
-                                &ttc->amount,
-                                ttc->payto_uri,
+                                ptc->hc->instance->settings.id,
+                                ptc->exchange_url,
+                                &ptc->wtid,
+                                &ptc->amount,
+                                ptc->payto_uri,
                                 true /* confirmed! */);
   if (0 > qs)
   {
@@ -1038,8 +966,8 @@ TMH_private_post_transfers (const struct 
TMH_RequestHandler *rh,
        the INSERT failed because we did not find the account based on
        the given payto-URI and the instance. */
     qs = TMH_db->lookup_account (TMH_db->cls,
-                                 ttc->hc->instance->settings.id,
-                                 ttc->payto_uri,
+                                 ptc->hc->instance->settings.id,
+                                 ptc->payto_uri,
                                  &account_serial);
     if (0 >= qs)
       return TALER_MHD_reply_with_error (connection,
@@ -1051,18 +979,18 @@ TMH_private_post_transfers (const struct 
TMH_RequestHandler *rh,
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Suspending POST /private/transfers handling while working with 
exchange\n");
   MHD_suspend_connection (connection);
-  GNUNET_CONTAINER_DLL_insert (ttc_head,
-                               ttc_tail,
-                               ttc);
-  ttc->fo = TMH_EXCHANGES_find_exchange (ttc->exchange_url,
+  GNUNET_CONTAINER_DLL_insert (ptc_head,
+                               ptc_tail,
+                               ptc);
+  ptc->fo = TMH_EXCHANGES_find_exchange (ptc->exchange_url,
                                          NULL,
                                          GNUNET_NO,
-                                         &process_track_transfer_with_exchange,
-                                         ttc);
-  ttc->timeout_task
-    = GNUNET_SCHEDULER_add_delayed (TRACK_TIMEOUT,
-                                    &handle_track_transfer_timeout,
-                                    ttc);
+                                         &process_transfer_with_exchange,
+                                         ptc);
+  ptc->timeout_task
+    = GNUNET_SCHEDULER_add_delayed (TRANSFER_TIMEOUT,
+                                    &handle_transfer_timeout,
+                                    ptc);
   return MHD_YES;
 }
 
diff --git a/src/backend/taler-merchant-httpd_private-post-transfers.h 
b/src/backend/taler-merchant-httpd_private-post-transfers.h
index 2c548f7..676b27d 100644
--- a/src/backend/taler-merchant-httpd_private-post-transfers.h
+++ b/src/backend/taler-merchant-httpd_private-post-transfers.h
@@ -24,6 +24,14 @@
 #include <microhttpd.h>
 #include "taler-merchant-httpd.h"
 
+
+/**
+ * We are shutting down, force resume of all POST /transfers requests.
+ */
+void
+TMH_force_post_transfers_resume (void);
+
+
 /**
  * Manages a POST /private/transfers call. It calls the GET /transfers/$WTID
  * offered by the exchange in order to obtain the set of transfers

-- 
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]