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: first refactoring f


From: gnunet
Subject: [GNUnet-SVN] [taler-merchant] branch master updated: first refactoring for #5158: allow multiple exchange URLs to be in database per /pay operation, plus other minor clean ups
Date: Tue, 26 Dec 2017 10:15:31 +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 b7c3585  first refactoring for #5158: allow multiple exchange URLs to 
be in database per /pay operation, plus other minor clean ups
b7c3585 is described below

commit b7c3585b77bd3f04f03568e72a2642ea43143d80
Author: Christian Grothoff <address@hidden>
AuthorDate: Tue Dec 26 10:15:15 2017 +0100

    first refactoring for #5158: allow multiple exchange URLs to be in database 
per /pay operation, plus other minor clean ups
---
 src/backend/taler-merchant-httpd.c                 |  27 ++-
 src/backend/taler-merchant-httpd_pay.c             | 131 ++++------
 .../taler-merchant-httpd_track-transaction.c       | 266 +++++++++++++--------
 src/backend/taler-merchant-httpd_track-transfer.c  |   2 +
 src/backenddb/plugin_merchantdb_postgres.c         | 137 ++++++-----
 src/backenddb/test_merchantdb.c                    | 103 ++++----
 src/include/taler_merchant_service.h               |   4 +
 src/include/taler_merchantdb_plugin.h              |  36 +--
 8 files changed, 371 insertions(+), 335 deletions(-)

diff --git a/src/backend/taler-merchant-httpd.c 
b/src/backend/taler-merchant-httpd.c
index c9b66a4..ff23f6f 100644
--- a/src/backend/taler-merchant-httpd.c
+++ b/src/backend/taler-merchant-httpd.c
@@ -404,6 +404,12 @@ prepare_daemon (void);
 
 
 /**
+ * Set if we should immediately #MHD_run again.
+ */
+static int triggered;
+
+
+/**
  * Call MHD to process pending requests and then go back
  * and schedule the next run.
  *
@@ -413,7 +419,10 @@ static void
 run_daemon (void *cls)
 {
   mhd_task = NULL;
-  GNUNET_assert (MHD_YES == MHD_run (mhd));
+  do {
+    triggered = 0;
+    GNUNET_assert (MHD_YES == MHD_run (mhd));
+  } while (0 != triggered);
   mhd_task = prepare_daemon ();
 }
 
@@ -427,8 +436,16 @@ run_daemon (void *cls)
 void
 TMH_trigger_daemon ()
 {
-  GNUNET_SCHEDULER_cancel (mhd_task);
-  run_daemon (NULL);
+  if (NULL != mhd_task)
+  {
+    GNUNET_SCHEDULER_cancel (mhd_task);
+    mhd_task = NULL;
+    run_daemon (NULL);
+  }
+  else
+  {
+    triggered = 1;
+  }
 }
 
 
@@ -802,6 +819,7 @@ iterate_instances (const struct GNUNET_CONFIGURATION_Handle 
*config,
   return GNUNET_SYSERR;
 }
 
+
 /**
  * Main function that will be run by the scheduler.
  *
@@ -1217,7 +1235,8 @@ run (void *cls,
  * @return 0 ok, 1 on error
  */
 int
-main (int argc, char *const *argv)
+main (int argc,
+      char *const *argv)
 {
   struct GNUNET_GETOPT_CommandLineOption options[] = {
 
diff --git a/src/backend/taler-merchant-httpd_pay.c 
b/src/backend/taler-merchant-httpd_pay.c
index ff8d59c..1315b9c 100644
--- a/src/backend/taler-merchant-httpd_pay.c
+++ b/src/backend/taler-merchant-httpd_pay.c
@@ -520,6 +520,7 @@ deposit_cb (void *cls,
                            &pc->h_contract_terms,
                            &pc->mi->pubkey,
                            &dc->coin_pub,
+                           pc->chosen_exchange,
                            &dc->amount_with_fee,
                            &dc->deposit_fee,
                            &dc->refund_fee,
@@ -642,52 +643,6 @@ pay_context_cleanup (struct TM_HandlerContext *hc)
 
 
 /**
- * Check if the existing transaction matches our transaction.
- * Update `transaction_exists` accordingly.
- *
- * @param cls closure with the `struct PayContext`
- * @param merchant_pub merchant's public key
- * @param exchange_uri URI of the exchange
- * @param h_contract_terms hashed proposal data
- * @param h_xwire hash of our wire details
- * @param timestamp time of the confirmation
- * @param refund refund deadline
- * @param total_amount total amount we receive for the contract after fees
- */
-static void
-check_transaction_exists (void *cls,
-                         const struct TALER_MerchantPublicKeyP *merchant_pub,
-                         const char *exchange_uri,
-                         const struct GNUNET_HashCode *h_contract_terms,
-                         const struct GNUNET_HashCode *h_xwire,
-                         struct GNUNET_TIME_Absolute timestamp,
-                         struct GNUNET_TIME_Absolute refund,
-                         const struct TALER_Amount *total_amount)
-{
-  struct PayContext *pc = cls;
-
-  if ( (0 == memcmp (h_contract_terms,
-                    &pc->h_contract_terms,
-                     sizeof (struct GNUNET_HashCode))) &&
-       (0 == memcmp (h_xwire,
-                    &pc->mi->h_wire,
-                    sizeof (struct GNUNET_HashCode))) &&
-       (timestamp.abs_value_us == pc->timestamp.abs_value_us) &&
-       (refund.abs_value_us == pc->refund_deadline.abs_value_us) &&
-       (0 == TALER_amount_cmp (total_amount,
-                              &pc->amount) ) )
-  {
-    pc->transaction_exists = GNUNET_YES;
-  }
-  else
-  {
-    GNUNET_break_op (0);
-    pc->transaction_exists = GNUNET_SYSERR;
-  }
-}
-
-
-/**
  * Function called with the result of our exchange lookup.
  *
  * @param cls the `struct PayContext`
@@ -953,40 +908,55 @@ process_pay_with_exchange (void *cls,
   }
 
   /* Check if transaction is already known, if not store it. */
-  /* FIXME: What if transaction exists, with a failed payment at
-     a different exchange? */
-  qs = db->find_transaction (db->cls,
-                            &pc->h_contract_terms,
-                            &pc->mi->pubkey,
-                            &check_transaction_exists,
-                            pc);
-  if (0 > qs)
   {
-    /* single, read-only SQL statements should never cause
-       serialization problems */
-    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);
-    /* FIXME: factor common logic of these calls into a function! */
-    resume_pay_with_response (pc,
-                              MHD_HTTP_INTERNAL_SERVER_ERROR,
-                              TMH_RESPONSE_make_json_pack ("{s:I, s:s}",
-                                                           "code", 
(json_int_t) TALER_EC_PAY_DB_FETCH_TRANSACTION_ERROR,
-                                                           "hint", "Merchant 
database error"));
-    return;
-  }
-  if (GNUNET_SYSERR == pc->transaction_exists)
-  {
-    GNUNET_break (0);
-    /* FIXME: factor common logic of these calls into a function! */
-    resume_pay_with_response (pc,
-                              MHD_HTTP_BAD_REQUEST,
-                              TMH_RESPONSE_make_json_pack ("{s:I, s:s}",
-                                                           "code", 
(json_int_t) TALER_EC_PAY_DB_TRANSACTION_ID_CONFLICT,
-                                                           "hint", 
"Transaction ID reused with different transaction details"));
-    return;
+    struct GNUNET_HashCode h_xwire;
+    struct GNUNET_TIME_Absolute xtimestamp;
+    struct GNUNET_TIME_Absolute xrefund;
+    struct TALER_Amount xtotal_amount;
+    
+    qs = db->find_transaction (db->cls,
+                              &pc->h_contract_terms,
+                              &pc->mi->pubkey,
+                              &h_xwire,
+                              &xtimestamp,
+                              &xrefund,
+                              &xtotal_amount);
+    if (0 > qs)
+    {
+      /* single, read-only SQL statements should never cause
+        serialization problems */
+      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);
+      /* FIXME: factor common logic of these calls into a function! */
+      resume_pay_with_response (pc,
+                               MHD_HTTP_INTERNAL_SERVER_ERROR,
+                               TMH_RESPONSE_make_json_pack ("{s:I, s:s}",
+                                                            "code", 
(json_int_t) TALER_EC_PAY_DB_FETCH_TRANSACTION_ERROR,
+                                                            "hint", "Merchant 
database error"));
+      return;
+    }
+    if ( (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == pc->transaction_exists) &&
+        ( (0 != memcmp (&h_xwire,
+                        &pc->mi->h_wire,
+                        sizeof (struct GNUNET_HashCode))) ||
+          (xtimestamp.abs_value_us != pc->timestamp.abs_value_us) ||
+          (xrefund.abs_value_us != pc->refund_deadline.abs_value_us) ||
+          (0 != TALER_amount_cmp (&xtotal_amount,
+                                  &pc->amount) ) ) )
+    {
+      GNUNET_break (0);
+      /* FIXME: factor common logic of these calls into a function! */
+      resume_pay_with_response (pc,
+                               MHD_HTTP_BAD_REQUEST,
+                               TMH_RESPONSE_make_json_pack ("{s:I, s:s}",
+                                                            "code", 
(json_int_t) TALER_EC_PAY_DB_TRANSACTION_ID_CONFLICT,
+                                                            "hint", 
"Transaction ID reused with different transaction details"));
+      return;
+    }
   }
-  if (GNUNET_NO == pc->transaction_exists)
+  
+  if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == pc->transaction_exists)
   {
     struct GNUNET_TIME_Absolute now;
     enum GNUNET_DB_QueryStatus qs_st;
@@ -1016,7 +986,6 @@ process_pay_with_exchange (void *cls,
     qs_st = db->store_transaction (db->cls,
                                    &pc->h_contract_terms,
                                    &pc->mi->pubkey,
-                                   pc->chosen_exchange,
                                    &pc->mi->h_wire,
                                    pc->timestamp,
                                    pc->refund_deadline,
@@ -1061,7 +1030,7 @@ process_pay_with_exchange (void *cls,
                                                              "hint", "Merchant 
database error: failed to store transaction"));
       return;
     }
-  } /* end of if (GNUNET_NO == pc->transaction_esists) */
+  } /* end of if (GNUNET_NO == pc->transaction_exists) */
 
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Found transaction data for proposal `%s' of merchant `%s', 
initiating deposits\n",
@@ -1147,6 +1116,7 @@ handle_pay_timeout (void *cls)
  * @param cls closure
  * @param h_contract_terms hashed proposal data
  * @param coin_pub public key of the coin
+ * @param exchange_url URL of the exchange that issued @a coin_pub
  * @param amount_with_fee amount the exchange will deposit for this coin
  * @param deposit_fee fee the exchange will charge for this coin
  * @param refund_fee fee the exchange will charge for refunding this coin
@@ -1156,6 +1126,7 @@ static void
 check_coin_paid (void *cls,
                  const struct GNUNET_HashCode *h_contract_terms,
                  const struct TALER_CoinSpendPublicKeyP *coin_pub,
+                const char *exchange_url,
                  const struct TALER_Amount *amount_with_fee,
                  const struct TALER_Amount *deposit_fee,
                  const struct TALER_Amount *refund_fee,
diff --git a/src/backend/taler-merchant-httpd_track-transaction.c 
b/src/backend/taler-merchant-httpd_track-transaction.c
index 7a4d0c0..c60daf6 100644
--- a/src/backend/taler-merchant-httpd_track-transaction.c
+++ b/src/backend/taler-merchant-httpd_track-transaction.c
@@ -33,6 +33,41 @@
 
 
 /**
+ * Information about a wire transfer for a /track/transaction response.
+ */
+struct TransactionWireTransfer
+{
+
+  /**
+   * Wire transfer identifier this struct is about.
+   */
+  struct TALER_WireTransferIdentifierRawP wtid;
+
+  /**
+   * When was this wire transfer executed?
+   */
+  struct GNUNET_TIME_Absolute execution_time;
+
+  /**
+   * Number of coins of the selected transaction that
+   * is covered by this wire transfer.
+   */
+  unsigned int num_coins;
+
+  /**
+   * Information about the coins of the selected transaction
+   * that are part of the wire transfer.
+   */
+  struct TALER_MERCHANT_CoinWireTransfer *coins;
+
+  /**
+   * URL of the exchange that executed the wire transfer.
+   */
+  char *exchange_url;
+};
+
+
+/**
  * Map containing all the known merchant instances
  */
 extern struct GNUNET_CONTAINER_MultiHashMap *by_id_map;
@@ -53,13 +88,11 @@ extern struct GNUNET_CONTAINER_MultiHashMap *by_id_map;
  *
  * @param num_transfers how many wire transfers make up the transaction
  * @param transfers data on each wire transfer
- * @param exchange_uri URI of the exchange that made the transfer
  * @return MHD response object
  */
 static struct MHD_Response *
 make_track_transaction_ok (unsigned int num_transfers,
-                          const struct TALER_MERCHANT_TransactionWireTransfer 
*transfers,
-                          const char *exchange_uri)
+                          const struct TransactionWireTransfer *transfers)
 {
   struct MHD_Response *ret;
   json_t *j_transfers;
@@ -68,7 +101,7 @@ make_track_transaction_ok (unsigned int num_transfers,
   j_transfers = json_array ();
   for (unsigned int i=0;i<num_transfers;i++)
   {
-    const struct TALER_MERCHANT_TransactionWireTransfer *transfer = 
&transfers[i];
+    const struct TransactionWireTransfer *transfer = &transfers[i];
 
     sum = transfer->coins[0].amount_with_fee;
     for (unsigned int j=1;j<transfer->num_coins;j++)
@@ -84,7 +117,7 @@ make_track_transaction_ok (unsigned int num_transfers,
     GNUNET_assert (0 ==
                    json_array_append_new (j_transfers,
                                           json_pack ("{s:s, s:o, s:o, s:o}",
-                                                     "exchange", exchange_uri,
+                                                     "exchange", 
transfer->exchange_url,
                                                      "wtid", 
GNUNET_JSON_from_data_auto (&transfer->wtid),
                                                      "execution_time", 
GNUNET_JSON_from_time_abs (transfer->execution_time),
                                                      "amount", 
TALER_JSON_from_amount (&sum))));
@@ -121,7 +154,7 @@ struct TrackCoinContext
   struct TrackCoinContext *prev;
 
   /**
-   * Our Context for a /track/transaction operation.
+   * Our context for a /track/transaction operation.
    */
   struct TrackTransactionContext *tctx;
 
@@ -131,6 +164,11 @@ struct TrackCoinContext
   struct TALER_CoinSpendPublicKeyP coin_pub;
 
   /**
+   * Exchange that was used for the transaction.
+   */
+  char *exchange_url;
+
+  /**
    * Handle for the request to resolve the WTID for this coin.
    */
   struct TALER_EXCHANGE_TrackTransactionHandle *dwh;
@@ -190,11 +228,6 @@ struct TrackTransactionContext
   struct TrackCoinContext *tcc_tail;
 
   /**
-   * Exchange that was used for the transaction.
-   */
-  char *exchange_uri;
-
-  /**
    * Task run on timeout.
    */
   struct GNUNET_SCHEDULER_Task *timeout_task;
@@ -212,6 +245,11 @@ struct TrackTransactionContext
   struct TALER_EXCHANGE_Handle *eh;
 
   /**
+   * URL of the exchange we currently have in @e eh.
+   */
+  const char *current_exchange;
+  
+  /**
    * Handle we use to resolve transactions for a given WTID.
    */
   struct TALER_EXCHANGE_TrackTransferHandle *wdh;
@@ -300,6 +338,11 @@ free_tctx (struct TrackTransactionContext *tctx)
       TALER_EXCHANGE_track_transaction_cancel (tcc->dwh);
       tcc->dwh = NULL;
     }
+    if (NULL != tcc->exchange_url)
+    {
+      GNUNET_free (tcc->exchange_url);
+      tcc->exchange_url = NULL;
+    }
     GNUNET_free (tcc);
   }
   if (NULL != tctx->wdh)
@@ -317,11 +360,6 @@ free_tctx (struct TrackTransactionContext *tctx)
     GNUNET_SCHEDULER_cancel (tctx->timeout_task);
     tctx->timeout_task = NULL;
   }
-  if (NULL != tctx->exchange_uri)
-  {
-    GNUNET_free (tctx->exchange_uri);
-    tctx->exchange_uri = NULL;
-  }
   GNUNET_free (tctx);
 }
 
@@ -435,7 +473,7 @@ wire_deposits_cb (void *cls,
   for (unsigned int i=0;i<MAX_RETRIES;i++)
   {
     qs = db->store_transfer_to_proof (db->cls,
-                                     tctx->exchange_uri,
+                                     tctx->current_exchange,
                                      &tctx->current_wtid,
                                      tctx->current_execution_time,
                                      exchange_pub,
@@ -587,8 +625,9 @@ wtid_cb (void *cls,
   tctx->current_wtid = *wtid;
   tctx->current_execution_time = execution_time;
   pcc.p_ret = NULL;
+  /* FIXME: change to avoid using callback! */
   qs = db->find_proof_by_wtid (db->cls,
-                              tctx->exchange_uri,
+                              tctx->current_exchange,
                               wtid,
                               &proof_cb,
                               &pcc);
@@ -630,35 +669,16 @@ wtid_cb (void *cls,
 
 
 /**
- * This function is called to trace the wire transfers for
- * all of the coins of the transaction of the @a tctx.  Once
- * we have traced all coins, we build the response.
+ * We have obtained all WTIDs, now prepare the response 
  *
- * @param tctx track context with established connection to exchange
+ * @param tctx handle for the operation 
  */
 static void
-trace_coins (struct TrackTransactionContext *tctx)
+generate_response (struct TrackTransactionContext *tctx)
 {
   struct TrackCoinContext *tcc;
   unsigned int num_wtid;
 
-  GNUNET_assert (NULL != tctx->eh);
-  for (tcc = tctx->tcc_head; NULL != tcc; tcc = tcc->next)
-    if (GNUNET_YES != tcc->have_wtid)
-      break;
-  if (NULL != tcc)
-  {
-    /* we are not done requesting WTIDs, do the next one */
-    tcc->dwh = TALER_EXCHANGE_track_transaction (tctx->eh,
-                                                 &tctx->mi->privkey,
-                                                 &tctx->h_wire,
-                                                 &tctx->h_contract_terms,
-                                                 &tcc->coin_pub,
-                                                 &wtid_cb,
-                                                 tcc);
-    return;
-  }
-  /* We have obtained all WTIDs, now prepare the response */
   num_wtid = 0;
   /* count how many disjoint wire transfer identifiers there are;
      note that there should only usually be one, so while this
@@ -687,7 +707,7 @@ trace_coins (struct TrackTransactionContext *tctx)
     /* on-stack allocation is fine, as the number of coins and the
        number of wire-transfers per-transaction is expected to be tiny. */
     struct MHD_Response *resp;
-    struct TALER_MERCHANT_TransactionWireTransfer wts[num_wtid];
+    struct TransactionWireTransfer wts[num_wtid];
     unsigned int wtid_off;
 
     wtid_off = 0;
@@ -710,10 +730,11 @@ trace_coins (struct TrackTransactionContext *tctx)
       if (GNUNET_NO == found)
       {
         unsigned int num_coins;
-        struct TALER_MERCHANT_TransactionWireTransfer *wt;
+        struct TransactionWireTransfer *wt;
 
         wt = &wts[wtid_off++];
         wt->wtid = tcc->wtid;
+       wt->exchange_url = tcc->exchange_url;
         wt->execution_time = tcc->execution_time;
         /* count number of coins with this wtid */
         num_coins = 0;
@@ -751,8 +772,7 @@ trace_coins (struct TrackTransactionContext *tctx)
     GNUNET_assert (wtid_off == num_wtid);
 
     resp = make_track_transaction_ok (num_wtid,
-                                     wts,
-                                     tctx->exchange_uri);
+                                     wts);
     for (wtid_off=0;wtid_off < num_wtid; wtid_off++)
       GNUNET_free (wts[wtid_off].coins);
     resume_track_transaction_with_response (tctx,
@@ -763,6 +783,59 @@ trace_coins (struct TrackTransactionContext *tctx)
 
 
 /**
+ * Find the exchange to trace the next coin(s).
+ *
+ * @param tctx operation context
+ */ 
+static void
+find_exchange (struct TrackTransactionContext *tctx);
+
+
+/**
+ * This function is called to trace the wire transfers for
+ * all of the coins of the transaction of the @a tctx.  Once
+ * we have traced all coins, we build the response.
+ *
+ * @param tctx track context with established connection to exchange
+ */
+static void
+trace_coins (struct TrackTransactionContext *tctx)
+{
+  struct TrackCoinContext *tcc;
+
+  GNUNET_assert (NULL != tctx->eh);
+  for (tcc = tctx->tcc_head; NULL != tcc; tcc = tcc->next)
+    if (GNUNET_YES != tcc->have_wtid)
+      break;
+  if (NULL != tcc)
+  {
+    if (0 != strcmp (tcc->exchange_url,
+                    tctx->current_exchange))
+    {
+      /* exchange changed, find matching one first! */
+      tctx->eh = NULL;
+      tctx->current_exchange = NULL;
+      find_exchange (tctx);
+      return;
+    }
+    /* we are not done requesting WTIDs from the current
+       exchange; do the next one */
+    tcc->dwh = TALER_EXCHANGE_track_transaction (tctx->eh,
+                                                 &tctx->mi->privkey,
+                                                 &tctx->h_wire,
+                                                 &tctx->h_contract_terms,
+                                                 &tcc->coin_pub,
+                                                 &wtid_cb,
+                                                 tcc);
+    return;
+  }
+  tctx->current_exchange = NULL;
+  tctx->eh = NULL;
+  generate_response (tctx);
+}
+
+
+/**
  * Function called with the result of our exchange lookup.
  *
  * @param cls the `struct TrackTransactionContext`
@@ -811,42 +884,6 @@ handle_track_transaction_timeout (void *cls)
 
 
 /**
- * Function called with information about a transaction.
- * Responsible to fill up the "context" for the whole
- * tracking operation.
- *
- * @param cls closure
- * @param transaction_id of the contract
- * @param merchant's public key
- * @param exchange_uri URI of the exchange
- * @param h_contract hash of the contract
- * @param h_wire hash of our wire details
- * @param timestamp time of the confirmation
- * @param refund refund deadline
- * @param total_amount total amount we receive for the contract after fees
- */
-static void
-transaction_cb (void *cls,
-               const struct TALER_MerchantPublicKeyP *merchant_pub,
-                const char *exchange_uri,
-                const struct GNUNET_HashCode *h_contract_terms,
-                const struct GNUNET_HashCode *h_wire,
-                struct GNUNET_TIME_Absolute timestamp,
-                struct GNUNET_TIME_Absolute refund,
-                const struct TALER_Amount *total_amount)
-{
-  struct TrackTransactionContext *tctx = cls;
-
-  tctx->h_contract_terms = *h_contract_terms;
-  tctx->exchange_uri = GNUNET_strdup (exchange_uri);
-  tctx->h_wire = *h_wire;
-  tctx->timestamp = timestamp;
-  tctx->refund_deadline = refund;
-  tctx->total_amount = *total_amount;
-}
-
-
-/**
  * Information about the wire transfer corresponding to
  * a deposit operation.  Note that it is in theory possible
  * that we have a @a transaction_id and @a coin_pub in the
@@ -865,7 +902,7 @@ transaction_cb (void *cls,
  */
 static void
 transfer_cb (void *cls,
-             const struct GNUNET_HashCode *h_contract_terms,
+            const struct GNUNET_HashCode *h_contract_terms,
              const struct TALER_CoinSpendPublicKeyP *coin_pub,
              const struct TALER_WireTransferIdentifierRawP *wtid,
              struct GNUNET_TIME_Absolute execution_time,
@@ -889,6 +926,7 @@ transfer_cb (void *cls,
  * @param cls closure
  * @param transaction_id of the contract
  * @param coin_pub public key of the coin
+ * @param exchange_url URL of exchange that issued @a coin_pub
  * @param amount_with_fee amount the exchange will deposit for this coin
  * @param deposit_fee fee the exchange will charge for this coin
  * @param refund_fee fee the exchange will charge for refunding this coin
@@ -898,6 +936,7 @@ static void
 coin_cb (void *cls,
          const struct GNUNET_HashCode *h_contract_terms,
          const struct TALER_CoinSpendPublicKeyP *coin_pub,
+        const char *exchange_url,
          const struct TALER_Amount *amount_with_fee,
          const struct TALER_Amount *deposit_fee,
          const struct TALER_Amount *refund_fee,
@@ -910,6 +949,7 @@ coin_cb (void *cls,
   tcc = GNUNET_new (struct TrackCoinContext);
   tcc->tctx = tctx;
   tcc->coin_pub = *coin_pub;
+  tcc->exchange_url = GNUNET_strdup (exchange_url);
 
   tcc->amount_with_fee = *amount_with_fee;
   tcc->deposit_fee = *deposit_fee;
@@ -929,6 +969,35 @@ coin_cb (void *cls,
 
 
 /**
+ * Find the exchange to trace the next coin(s).
+ *
+ * @param tctx operation context
+ */ 
+static void
+find_exchange (struct TrackTransactionContext *tctx)
+{
+  struct TrackCoinContext *tcc = tctx->tcc_head;
+
+  while ( (NULL != tcc) &&
+         (GNUNET_YES == tcc->have_wtid) )
+    tcc = tcc->next;
+  if (NULL != tcc)
+  {
+    tctx->current_exchange = tcc->exchange_url;
+    tctx->fo = TMH_EXCHANGES_find_exchange (tctx->current_exchange,
+                                           NULL,
+                                           
&process_track_transaction_with_exchange,
+                                           tctx);
+    
+  }
+  else
+  {
+    generate_response (tctx);
+  }
+}
+
+
+/**
  * Handle a "/track/transaction" request.
  *
  * @param rh context of the handler
@@ -951,7 +1020,6 @@ MH_handler_track_transaction (struct TMH_RequestHandler 
*rh,
   int ret;
   enum GNUNET_DB_QueryStatus qs;
   struct GNUNET_HashCode h_instance;
-  struct GNUNET_HashCode h_contract_terms;
   struct json_t *contract_terms;
 
   if (NULL == *connection_cls)
@@ -1042,7 +1110,7 @@ MH_handler_track_transaction (struct TMH_RequestHandler 
*rh,
                                         "Given order_id doesn't map to any 
proposal");
   if (GNUNET_OK !=
       TALER_JSON_hash (contract_terms,
-                       &h_contract_terms))
+                       &tctx->h_contract_terms))
   {
     json_decref (contract_terms);
     return TMH_RESPONSE_reply_internal_error (connection,
@@ -1053,14 +1121,15 @@ MH_handler_track_transaction (struct TMH_RequestHandler 
*rh,
 
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Trying to track h_contract_terms '%s'\n",
-              GNUNET_h2s (&h_contract_terms));
-
+              GNUNET_h2s (&tctx->h_contract_terms));
   qs = db->find_transaction (db->cls,
-                            &h_contract_terms,
+                            &tctx->h_contract_terms,
                             &tctx->mi->pubkey,
-                            &transaction_cb,
-                            tctx);
-  if (0 > qs)
+                            &tctx->h_wire,
+                            &tctx->timestamp,
+                            &tctx->refund_deadline,
+                            &tctx->total_amount);
+   if (0 > qs)
   {
     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
     return TMH_RESPONSE_reply_internal_error (connection,
@@ -1075,19 +1144,9 @@ MH_handler_track_transaction (struct TMH_RequestHandler 
*rh,
                                         
TALER_EC_TRACK_TRANSACTION_TRANSACTION_UNKNOWN,
                                          "h_contract_terms is unknown");
   }
-  if ( (0 != memcmp (&tctx->h_contract_terms,
-                     &h_contract_terms,
-                     sizeof (struct GNUNET_HashCode))) ||
-       (NULL == tctx->exchange_uri) )
-  {
-    GNUNET_break (0);
-    return TMH_RESPONSE_reply_internal_error (connection,
-                                             
TALER_EC_TRACK_TRANSACTION_DB_FETCH_TRANSACTION_ERROR,
-                                              "Database error: failed to 
obtain correct data from database");
-  }
   tctx->qs = GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
   qs = db->find_payments (db->cls,
-                         &h_contract_terms,
+                         &tctx->h_contract_terms,
                          &tctx->mi->pubkey,
                          &coin_cb,
                          tctx);
@@ -1111,16 +1170,13 @@ MH_handler_track_transaction (struct TMH_RequestHandler 
*rh,
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Suspending /track/transaction handling while working with the 
exchange\n");
   MHD_suspend_connection (connection);
-  tctx->fo = TMH_EXCHANGES_find_exchange (tctx->exchange_uri,
-                                          NULL,
-                                          
&process_track_transaction_with_exchange,
-                                          tctx);
-
   tctx->timeout_task
     = GNUNET_SCHEDULER_add_delayed (TRACK_TIMEOUT,
                                    &handle_track_transaction_timeout,
                                    tctx);
+  find_exchange (tctx);
   return MHD_YES;
 }
 
+
 /* end of taler-merchant-httpd_track-transaction.c */
diff --git a/src/backend/taler-merchant-httpd_track-transfer.c 
b/src/backend/taler-merchant-httpd_track-transfer.c
index f66457a..0e84b1d 100644
--- a/src/backend/taler-merchant-httpd_track-transfer.c
+++ b/src/backend/taler-merchant-httpd_track-transfer.c
@@ -433,6 +433,7 @@ track_transfer_cleanup (struct TM_HandlerContext *hc)
  * @param cls closure with our `struct TrackTransferContext *`
  * @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
  * @param amount_with_fee amount the exchange will transfer for this coin
  * @param deposit_fee fee the exchange will charge for this coin
  * @param refund_fee fee the exchange will charge for refunding this coin
@@ -442,6 +443,7 @@ static void
 check_transfer (void *cls,
                 const struct GNUNET_HashCode *h_contract_terms,
                 const struct TALER_CoinSpendPublicKeyP *coin_pub,
+               const char *exchange_url,
                 const struct TALER_Amount *amount_with_fee,
                 const struct TALER_Amount *deposit_fee,
                 const struct TALER_Amount *refund_fee,
diff --git a/src/backenddb/plugin_merchantdb_postgres.c 
b/src/backenddb/plugin_merchantdb_postgres.c
index cb1d9c6..e6e992e 100644
--- a/src/backenddb/plugin_merchantdb_postgres.c
+++ b/src/backenddb/plugin_merchantdb_postgres.c
@@ -107,10 +107,9 @@ postgres_initialize (void *cls)
                             ",PRIMARY KEY (order_id, merchant_pub)"
                            ",UNIQUE (h_contract_terms, merchant_pub)"
                             ");"),
-    /* Contracts that were paid via some exchange (or attempted to be paid???) 
*/
+    /* Contracts that were paid */
     GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS merchant_transactions 
("
                             " h_contract_terms BYTEA NOT NULL CHECK 
(LENGTH(h_contract_terms)=64)"
-                            ",exchange_uri VARCHAR NOT NULL"
                             ",merchant_pub BYTEA NOT NULL CHECK 
(LENGTH(merchant_pub)=32)"
                             ",h_wire BYTEA NOT NULL CHECK (LENGTH(h_wire)=64)"
                             ",timestamp INT8 NOT NULL"
@@ -126,6 +125,7 @@ postgres_initialize (void *cls)
                             " h_contract_terms BYTEA NOT NULL"
                             ",merchant_pub BYTEA NOT NULL CHECK 
(LENGTH(merchant_pub)=32)"
                             ",coin_pub BYTEA NOT NULL CHECK 
(LENGTH(coin_pub)=32)"
+                            ",exchange_url VARCHAR NOT NULL"
                             ",amount_with_fee_val INT8 NOT NULL"
                             ",amount_with_fee_frac INT4 NOT NULL"
                             ",amount_with_fee_curr VARCHAR(" 
TALER_CURRENCY_LEN_STR ") NOT NULL"
@@ -141,12 +141,12 @@ postgres_initialize (void *cls)
                             ",FOREIGN KEY (h_contract_terms, merchant_pub) 
REFERENCES merchant_transactions (h_contract_terms, merchant_pub)"
                             ");"),
     GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS merchant_proofs ("
-                            " exchange_uri VARCHAR NOT NULL"
+                            " exchange_url VARCHAR NOT NULL"
                             ",wtid BYTEA CHECK (LENGTH(wtid)=32)"
                             ",execution_time INT8 NOT NULL"
                             ",signkey_pub BYTEA NOT NULL CHECK 
(LENGTH(signkey_pub)=32)"
                             ",proof BYTEA NOT NULL"
-                            ",PRIMARY KEY (wtid, exchange_uri)"
+                            ",PRIMARY KEY (wtid, exchange_url)"
                             ");"),
     /* Note that h_contract_terms + coin_pub may actually be unknown to
        us, e.g. someone else deposits something for us at the exchange.
@@ -211,7 +211,7 @@ postgres_initialize (void *cls)
     GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS merchant_tips ("
                             " reserve_priv BYTEA NOT NULL CHECK 
(LENGTH(reserve_priv)=32)"
                             ",tip_id BYTEA NOT NULL CHECK (LENGTH(tip_id)=64)"
-                           ",exchange_uri VARCHAR NOT NULL"
+                           ",exchange_url VARCHAR NOT NULL"
                             ",justification VARCHAR NOT NULL"
                             ",timestamp INT8 NOT NULL"
                             ",amount_val INT8 NOT NULL" /* overall tip amount 
*/
@@ -237,7 +237,6 @@ postgres_initialize (void *cls)
     GNUNET_PQ_make_prepare ("insert_transaction",
                             "INSERT INTO merchant_transactions"
                             "(h_contract_terms"
-                            ",exchange_uri"
                             ",merchant_pub"
                             ",h_wire"
                             ",timestamp"
@@ -246,13 +245,14 @@ postgres_initialize (void *cls)
                             ",total_amount_frac"
                             ",total_amount_curr"
                             ") VALUES "
-                            "($1, $2, $3, $4, $5, $6, $7, $8, $9)",
-                            9),
+                            "($1, $2, $3, $4, $5, $6, $7, $8)",
+                            8),
     GNUNET_PQ_make_prepare ("insert_deposit",
                             "INSERT INTO merchant_deposits"
                             "(h_contract_terms"
                             ",merchant_pub"
                             ",coin_pub"
+                            ",exchange_url"
                             ",amount_with_fee_val"
                             ",amount_with_fee_frac"
                             ",amount_with_fee_curr"
@@ -264,8 +264,8 @@ postgres_initialize (void *cls)
                             ",refund_fee_curr"
                             ",signkey_pub"
                             ",exchange_proof) VALUES "
-                            "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, 
$12, $13, $14)",
-                            14),
+                            "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, 
$12, $13, $14, $15)",
+                            15),
     GNUNET_PQ_make_prepare ("insert_transfer",
                             "INSERT INTO merchant_transfers"
                             "(h_contract_terms"
@@ -290,7 +290,7 @@ postgres_initialize (void *cls)
                             10),
     GNUNET_PQ_make_prepare ("insert_proof",
                             "INSERT INTO merchant_proofs"
-                            "(exchange_uri"
+                            "(exchange_url"
                             ",wtid"
                             ",execution_time"
                             ",signkey_pub"
@@ -440,8 +440,7 @@ postgres_initialize (void *cls)
                             4),
     GNUNET_PQ_make_prepare ("find_transaction",
                             "SELECT"
-                            " exchange_uri"
-                            ",h_wire"
+                            " h_wire"
                             ",timestamp"
                             ",refund_deadline"
                             ",total_amount_val"
@@ -454,6 +453,7 @@ postgres_initialize (void *cls)
     GNUNET_PQ_make_prepare ("find_deposits",
                             "SELECT"
                             " coin_pub"
+                           ",exchange_url"
                             ",amount_with_fee_val"
                             ",amount_with_fee_frac"
                             ",amount_with_fee_curr"
@@ -479,6 +479,7 @@ postgres_initialize (void *cls)
                             ",refund_fee_val"
                             ",refund_fee_frac"
                             ",refund_fee_curr"
+                           ",exchange_url"
                             ",exchange_proof"
                             " FROM merchant_deposits"
                             " WHERE h_contract_terms=$1"
@@ -508,6 +509,7 @@ postgres_initialize (void *cls)
                             ",merchant_deposits.refund_fee_val"
                             ",merchant_deposits.refund_fee_frac"
                             ",merchant_deposits.refund_fee_curr"
+                            ",merchant_deposits.exchange_url"
                             ",merchant_deposits.exchange_proof"
                             " FROM merchant_transfers"
                             "   JOIN merchant_deposits"
@@ -521,7 +523,7 @@ postgres_initialize (void *cls)
                             " proof"
                             " FROM merchant_proofs"
                             " WHERE wtid=$1"
-                            "  AND exchange_uri=$2",
+                            "  AND exchange_url=$2",
                             2),
     GNUNET_PQ_make_prepare ("lookup_tip_reserve_balance",
                             "SELECT"
@@ -554,7 +556,7 @@ postgres_initialize (void *cls)
                             "INSERT INTO merchant_tips"
                             "(reserve_priv"
                             ",tip_id"
-                           ",exchange_uri"
+                           ",exchange_url"
                             ",justification"
                             ",timestamp"
                             ",amount_val"
@@ -586,7 +588,7 @@ postgres_initialize (void *cls)
                             2),
     GNUNET_PQ_make_prepare ("find_tip_by_id",
                             "SELECT"
-                            " exchange_uri"
+                            " exchange_url"
                             ",timestamp"
                             ",amount_val"
                             ",amount_frac"
@@ -907,7 +909,7 @@ postgres_mark_proposal_paid (void *cls,
  * @param h_contract_terms hashcode of the proposal data associated with the
  * transaction being stored
  * @param merchant_pub merchant's public key
- * @param exchange_uri URI of the exchange
+ * @param exchange_url URL of the exchange
  * @param h_wire hash of our wire details
  * @param timestamp time of the confirmation
  * @param refund refund deadline
@@ -918,7 +920,6 @@ static enum GNUNET_DB_QueryStatus
 postgres_store_transaction (void *cls,
                             const struct GNUNET_HashCode *h_contract_terms,
                            const struct TALER_MerchantPublicKeyP *merchant_pub,
-                            const char *exchange_uri,
                             const struct GNUNET_HashCode *h_wire,
                             struct GNUNET_TIME_Absolute timestamp,
                             struct GNUNET_TIME_Absolute refund,
@@ -927,7 +928,6 @@ postgres_store_transaction (void *cls,
   struct PostgresClosure *pg = cls;
   struct GNUNET_PQ_QueryParam params[] = {
     GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
-    GNUNET_PQ_query_param_string (exchange_uri),
     GNUNET_PQ_query_param_auto_from_type (merchant_pub),
     GNUNET_PQ_query_param_auto_from_type (h_wire),
     GNUNET_PQ_query_param_absolute_time (&timestamp),
@@ -966,6 +966,7 @@ postgres_store_deposit (void *cls,
                         const struct GNUNET_HashCode *h_contract_terms,
                         const struct TALER_MerchantPublicKeyP *merchant_pub,
                         const struct TALER_CoinSpendPublicKeyP *coin_pub,
+                       const char *exchange_url,
                         const struct TALER_Amount *amount_with_fee,
                         const struct TALER_Amount *deposit_fee,
                         const struct TALER_Amount *refund_fee,
@@ -977,6 +978,7 @@ postgres_store_deposit (void *cls,
     GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
     GNUNET_PQ_query_param_auto_from_type (merchant_pub),
     GNUNET_PQ_query_param_auto_from_type (coin_pub),
+    GNUNET_PQ_query_param_string (exchange_url),
     TALER_PQ_query_param_amount (amount_with_fee),
     TALER_PQ_query_param_amount (deposit_fee),
     TALER_PQ_query_param_amount (refund_fee),
@@ -1036,7 +1038,7 @@ postgres_store_coin_to_transfer (void *cls,
  * Insert wire transfer confirmation from the exchange into the database.
  *
  * @param cls closure
- * @param exchange_uri URI of the exchange
+ * @param exchange_url URL of the exchange
  * @param wtid identifier of the wire transfer
  * @param execution_time when was @a wtid executed
  * @param signkey_pub public key used by the exchange for @a exchange_proof
@@ -1045,7 +1047,7 @@ postgres_store_coin_to_transfer (void *cls,
  */
 static enum GNUNET_DB_QueryStatus
 postgres_store_transfer_to_proof (void *cls,
-                                  const char *exchange_uri,
+                                  const char *exchange_url,
                                   const struct 
TALER_WireTransferIdentifierRawP *wtid,
                                   struct GNUNET_TIME_Absolute execution_time,
                                   const struct TALER_ExchangePublicKeyP 
*signkey_pub,
@@ -1053,7 +1055,7 @@ postgres_store_transfer_to_proof (void *cls,
 {
   struct PostgresClosure *pg = cls;
   struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_string (exchange_uri),
+    GNUNET_PQ_query_param_string (exchange_url),
     GNUNET_PQ_query_param_auto_from_type (wtid),
     GNUNET_PQ_query_param_absolute_time (&execution_time),
     GNUNET_PQ_query_param_auto_from_type (signkey_pub),
@@ -1306,16 +1308,20 @@ postgres_find_contract_terms_by_date (void *cls,
  * @param cls our plugin handle
  * @param h_contract_terms value used to perform the lookup
  * @param merchant_pub merchant's public key
- * @param cb function to call with transaction data
- * @param cb_cls closure for @a cb
+ * @param[out] h_wire set to hash of wire details
+ * @param[out] timestamp set to timestamp
+ * @param[out] refund_deadline set to refund deadline
+ * @param[out] total_amount set to total amount
  * @return transaction status
  */
 static enum GNUNET_DB_QueryStatus
 postgres_find_transaction (void *cls,
                            const struct GNUNET_HashCode *h_contract_terms,
                           const struct TALER_MerchantPublicKeyP *merchant_pub,
-                           TALER_MERCHANTDB_TransactionCallback cb,
-                           void *cb_cls)
+                          struct GNUNET_HashCode *h_wire,
+                          struct GNUNET_TIME_Absolute *timestamp,
+                          struct GNUNET_TIME_Absolute *refund_deadline,
+                          struct TALER_Amount *total_amount)
 {
   struct PostgresClosure *pg = cls;
   struct GNUNET_PQ_QueryParam params[] = {
@@ -1323,25 +1329,17 @@ postgres_find_transaction (void *cls,
     GNUNET_PQ_query_param_auto_from_type (merchant_pub),
     GNUNET_PQ_query_param_end
   };
-  char *exchange_uri;
-  struct GNUNET_HashCode h_wire;
-  struct GNUNET_TIME_Absolute timestamp;
-  struct GNUNET_TIME_Absolute refund_deadline;
-  struct TALER_Amount total_amount;
   struct GNUNET_PQ_ResultSpec rs[] = {
-    GNUNET_PQ_result_spec_string ("exchange_uri",
-                                 &exchange_uri),
     GNUNET_PQ_result_spec_auto_from_type ("h_wire",
-                                         &h_wire),
+                                         h_wire),
     GNUNET_PQ_result_spec_absolute_time ("timestamp",
-                                        &timestamp),
+                                        timestamp),
     GNUNET_PQ_result_spec_absolute_time ("refund_deadline",
-                                        &refund_deadline),
+                                        refund_deadline),
     TALER_PQ_result_spec_amount ("total_amount",
-                                &total_amount),
+                                total_amount),
     GNUNET_PQ_result_spec_end
   };
-  enum GNUNET_DB_QueryStatus qs;
 
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Finding transaction for h_contract_terms '%s', merchant_pub: 
'%s'.\n",
@@ -1349,23 +1347,10 @@ postgres_find_transaction (void *cls,
               TALER_B2S (merchant_pub));
 
   check_connection (pg);
-  qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
-                                                "find_transaction",
-                                                params,
-                                                rs);
-  if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
-  {
-    cb (cb_cls,
-       merchant_pub,
-        exchange_uri,
-        h_contract_terms,
-        &h_wire,
-        timestamp,
-        refund_deadline,
-        &total_amount);
-    GNUNET_PQ_cleanup_result (rs);
-  }
-  return qs;
+  return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+                                                  "find_transaction",
+                                                  params,
+                                                  rs);
 }
 
 
@@ -1418,9 +1403,12 @@ find_payments_cb (void *cls,
     struct TALER_Amount deposit_fee;
     struct TALER_Amount refund_fee;
     json_t *exchange_proof;
+    char *exchange_url;
     struct GNUNET_PQ_ResultSpec rs[] = {
       GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
                                             &coin_pub),
+      GNUNET_PQ_result_spec_string ("exchange_url",
+                                   &exchange_url),
       TALER_PQ_result_spec_amount ("amount_with_fee",
                                    &amount_with_fee),
       TALER_PQ_result_spec_amount ("deposit_fee",
@@ -1445,6 +1433,7 @@ find_payments_cb (void *cls,
     fpc->cb (fpc->cb_cls,
             fpc->h_contract_terms,
             &coin_pub,
+            exchange_url,
             &amount_with_fee,
             &deposit_fee,
             &refund_fee,
@@ -1552,6 +1541,7 @@ find_payments_by_coin_cb (void *cls,
     struct TALER_Amount amount_with_fee;
     struct TALER_Amount deposit_fee;
     struct TALER_Amount refund_fee;
+    char *exchange_url;
     json_t *exchange_proof;
     struct GNUNET_PQ_ResultSpec rs[] = {
       TALER_PQ_result_spec_amount ("amount_with_fee",
@@ -1560,6 +1550,8 @@ find_payments_by_coin_cb (void *cls,
                                    &deposit_fee),
       TALER_PQ_result_spec_amount ("refund_fee",
                                    &refund_fee),
+      GNUNET_PQ_result_spec_string ("exchange_url",
+                                   &exchange_url),
       TALER_PQ_result_spec_json ("exchange_proof",
                                  &exchange_proof),
       GNUNET_PQ_result_spec_end
@@ -1578,6 +1570,7 @@ find_payments_by_coin_cb (void *cls,
     fpc->cb (fpc->cb_cls,
             fpc->h_contract_terms,
             fpc->coin_pub,
+            exchange_url,
             &amount_with_fee,
             &deposit_fee,
             &refund_fee,
@@ -1803,6 +1796,7 @@ find_deposits_cb (void *cls,
     struct TALER_Amount amount_with_fee;
     struct TALER_Amount deposit_fee;
     struct TALER_Amount refund_fee;
+    char *exchange_url;
     json_t *exchange_proof;
     struct GNUNET_PQ_ResultSpec rs[] = {
       GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms",
@@ -1815,6 +1809,8 @@ find_deposits_cb (void *cls,
                                    &deposit_fee),
       TALER_PQ_result_spec_amount ("refund_fee",
                                    &refund_fee),
+      GNUNET_PQ_result_spec_string ("exchange_url",
+                                   &exchange_url),
       TALER_PQ_result_spec_json ("exchange_proof",
                                  &exchange_proof),
       GNUNET_PQ_result_spec_end
@@ -1833,6 +1829,7 @@ find_deposits_cb (void *cls,
     fdc->cb (fdc->cb_cls,
             &h_contract_terms,
             &coin_pub,
+            exchange_url,
             &amount_with_fee,
             &deposit_fee,
             &refund_fee,
@@ -2566,7 +2563,7 @@ postgres_increase_refund_for_contract (void *cls,
  * Lookup proof information about a wire transfer.
  *
  * @param cls closure
- * @param exchange_uri from which exchange are we looking for proof
+ * @param exchange_url from which exchange are we looking for proof
  * @param wtid wire transfer identifier for the search
  * @param cb function to call with proof data
  * @param cb_cls closure for @a cb
@@ -2574,7 +2571,7 @@ postgres_increase_refund_for_contract (void *cls,
  */
 static enum GNUNET_DB_QueryStatus
 postgres_find_proof_by_wtid (void *cls,
-                             const char *exchange_uri,
+                             const char *exchange_url,
                              const struct TALER_WireTransferIdentifierRawP 
*wtid,
                              TALER_MERCHANTDB_ProofCallback cb,
                              void *cb_cls)
@@ -2582,7 +2579,7 @@ postgres_find_proof_by_wtid (void *cls,
   struct PostgresClosure *pg = cls;
   struct GNUNET_PQ_QueryParam params[] = {
     GNUNET_PQ_query_param_auto_from_type (wtid),
-    GNUNET_PQ_query_param_string (exchange_uri),
+    GNUNET_PQ_query_param_string (exchange_url),
     GNUNET_PQ_query_param_end
   };
   json_t *proof;
@@ -2781,7 +2778,7 @@ postgres_enable_tip_reserve (void *cls,
  * @param justification why was the tip approved
  * @param amount how high is the tip (with fees)
  * @param reserve_priv which reserve is debited
- * @param exchange_uri which exchange manages the tip
+ * @param exchange_url which exchange manages the tip
  * @param[out] expiration set to when the tip expires
  * @param[out] tip_id set to the unique ID for the tip
  * @return taler error code
@@ -2797,7 +2794,7 @@ postgres_authorize_tip (void *cls,
                         const char *justification,
                         const struct TALER_Amount *amount,
                         const struct TALER_ReservePrivateKeyP *reserve_priv,
-                       const char *exchange_uri,
+                       const char *exchange_url,
                         struct GNUNET_TIME_Absolute *expiration,
                         struct GNUNET_HashCode *tip_id)
 {
@@ -2888,7 +2885,7 @@ postgres_authorize_tip (void *cls,
     struct GNUNET_PQ_QueryParam params[] = {
       GNUNET_PQ_query_param_auto_from_type (reserve_priv),
       GNUNET_PQ_query_param_auto_from_type (tip_id),
-      GNUNET_PQ_query_param_string (exchange_uri),
+      GNUNET_PQ_query_param_string (exchange_url),
       GNUNET_PQ_query_param_string (justification),
       GNUNET_PQ_query_param_absolute_time (&now),
       TALER_PQ_query_param_amount (amount), /* overall amount */
@@ -2922,7 +2919,7 @@ postgres_authorize_tip (void *cls,
  *
  * @param cls closure, typically a connection to the d
  * @param tip_id the unique ID for the tip
- * @param[out] exchange_uri set to the URI of the exchange (unless NULL)
+ * @param[out] exchange_url set to the URL of the exchange (unless NULL)
  * @param[out] amount set to the authorized amount (unless NULL)
  * @param[out] timestamp set to the timestamp of the tip authorization (unless 
NULL)
  * @return transaction status, usually
@@ -2932,11 +2929,11 @@ postgres_authorize_tip (void *cls,
 static enum GNUNET_DB_QueryStatus
 postgres_lookup_tip_by_id (void *cls,
                            const struct GNUNET_HashCode *tip_id,
-                           char **exchange_uri,
+                           char **exchange_url,
                            struct TALER_Amount *amount,
                            struct GNUNET_TIME_Absolute *timestamp)
 {
-  char *res_exchange_uri;
+  char *res_exchange_url;
   struct TALER_Amount res_amount;
   struct GNUNET_TIME_Absolute res_timestamp;
 
@@ -2946,8 +2943,8 @@ postgres_lookup_tip_by_id (void *cls,
     GNUNET_PQ_query_param_end
   };
   struct GNUNET_PQ_ResultSpec rs[] = {
-    GNUNET_PQ_result_spec_string ("exchange_uri",
-                                 &res_exchange_uri),
+    GNUNET_PQ_result_spec_string ("exchange_url",
+                                 &res_exchange_url),
     GNUNET_PQ_result_spec_absolute_time ("timestamp",
                                          &res_timestamp),
     TALER_PQ_result_spec_amount ("amount",
@@ -2962,12 +2959,12 @@ postgres_lookup_tip_by_id (void *cls,
                                                 rs);
   if (0 >= qs)
   {
-    if (NULL != exchange_uri)
-      *exchange_uri = NULL;
+    if (NULL != exchange_url)
+      *exchange_url = NULL;
     return qs;
   }
-  if (NULL != exchange_uri)
-    *exchange_uri = strdup (res_exchange_uri);
+  if (NULL != exchange_url)
+    *exchange_url = strdup (res_exchange_url);
   if (NULL != amount)
     *amount = res_amount;
   if (NULL != timestamp)
diff --git a/src/backenddb/test_merchantdb.c b/src/backenddb/test_merchantdb.c
index 0bbea3f..cd37149 100644
--- a/src/backenddb/test_merchantdb.c
+++ b/src/backenddb/test_merchantdb.c
@@ -14,7 +14,7 @@
   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
 */
 /**
- * @file merchant/test_merchantdb_postgres.c
+ * @file merchant/test_merchantdb.c
  * @brief testcase for merchant's postgres db plugin
  * @author Marcello Stanisci
  * @author Christian Grothoff
@@ -44,11 +44,11 @@
 #define CURRENCY "EUR"
 
 /**
- * URI we use for the exchange in the database.
+ * URL we use for the exchange in the database.
  * Note that an exchange does not actually have
  * to run at this address.
  */
-#define EXCHANGE_URI "http://localhost:8888/";
+#define EXCHANGE_URL "http://localhost:8888/";
 
 /**
  * Global return value for the test.  Initially -1, set to 0 upon
@@ -190,47 +190,6 @@ static json_t *contract_terms_future;
 
 
 /**
- * Function called with information about a transaction.
- *
- * @param cls closure
- * @param transaction_id of the contract
- * @param merchant_pub public key of the merchant
- * @param exchange_uri URI of the exchange
- * @param h_wire hash of our wire details
- * @param timestamp time of the confirmation
- * @param refund_deadline refund deadline
- * @param total_amount total amount we receive for the contract after fees
- */
-static void
-transaction_cb (void *cls,
-               const struct TALER_MerchantPublicKeyP *amerchant_pub,
-                const char *aexchange_uri,
-                const struct GNUNET_HashCode *ah_contract_terms,
-                const struct GNUNET_HashCode *ah_wire,
-                struct GNUNET_TIME_Absolute atimestamp,
-                struct GNUNET_TIME_Absolute arefund_deadline,
-                const struct TALER_Amount *atotal_amount)
-{
-#define CHECK(a) do { if (! (a)) { GNUNET_break (0); result = 3; } } while (0)
-  CHECK (0 == memcmp (amerchant_pub,
-                      &merchant_pub,
-                     sizeof (struct TALER_MerchantPublicKeyP)));
-  CHECK (0 == memcmp (ah_contract_terms,
-                      &h_contract_terms,
-                      sizeof (struct GNUNET_HashCode)));
-  CHECK (0 == strcmp (aexchange_uri,
-                      EXCHANGE_URI));
-  CHECK (0 == memcmp (ah_wire,
-                      &h_wire,
-                      sizeof (struct GNUNET_HashCode)));
-  CHECK (atimestamp.abs_value_us == timestamp.abs_value_us);
-  CHECK (arefund_deadline.abs_value_us == refund_deadline.abs_value_us);
-  CHECK (0 == TALER_amount_cmp (atotal_amount,
-                                &amount_with_fee));
-}
-
-
-/**
  * Function called with information about a refund.
  *
  * @param cls closure
@@ -272,12 +231,16 @@ pd_cb (void *cls,
 }
 
 
+#define CHECK(a) do { if (! (a)) { GNUNET_break (0); result = 3; } } while (0)
+
+
 /**
  * Function called with information about a coin that was deposited.
  *
  * @param cls closure
  * @param transaction_id of the contract
- * @param coin_pub public key of the coin
+ * @param acoin_pub public key of the coin
+ * @param aexchange_url exchange associated with @a acoin_pub in DB
  * @param aamount_with_fee amount the exchange will deposit for this coin
  * @param adeposit_fee fee the exchange will charge for this coin
  * @param adeposit_fee fee the exchange will charge for refunding this coin
@@ -287,6 +250,7 @@ static void
 deposit_cb (void *cls,
             const struct GNUNET_HashCode *ah_contract_terms,
             const struct TALER_CoinSpendPublicKeyP *acoin_pub,
+           const char *aexchange_url,
             const struct TALER_Amount *aamount_with_fee,
             const struct TALER_Amount *adeposit_fee,
             const struct TALER_Amount *arefund_fee,
@@ -298,6 +262,8 @@ deposit_cb (void *cls,
   CHECK (0 == memcmp (acoin_pub,
                       &coin_pub,
                       sizeof (struct TALER_CoinSpendPublicKeyP)));
+  CHECK (0 == strcmp (aexchange_url,
+                      EXCHANGE_URL));
   CHECK (0 == TALER_amount_cmp (aamount_with_fee,
                                 &amount_with_fee));
   CHECK (0 == TALER_amount_cmp (adeposit_fee,
@@ -529,7 +495,7 @@ test_tipping ()
   struct TALER_Amount total;
   struct TALER_Amount amount;
   struct TALER_Amount inc;
-  char *uri;
+  char *url;
 
   RND_BLK (&tip_reserve_priv);
   if (TALER_EC_TIP_AUTHORIZE_RESERVE_NOT_ENABLED !=
@@ -641,20 +607,20 @@ test_tipping ()
   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
       plugin->lookup_tip_by_id (plugin->cls,
                                      &tip_id,
-                                     &uri,
+                                     &url,
                                       NULL, NULL))
   {
     GNUNET_break (0);
     return GNUNET_SYSERR;
   }
   if (0 != strcmp ("http://localhost:8081/";,
-                  uri))
+                  url))
   {
-    GNUNET_free (uri);
+    GNUNET_free (url);
     GNUNET_break (0);
     return GNUNET_SYSERR;
   }
-  GNUNET_free (uri);
+  GNUNET_free (url);
   if (TALER_EC_NONE !=
       plugin->authorize_tip (plugin->cls,
                              "testing tips more",
@@ -935,8 +901,7 @@ run (void *cls)
   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
           plugin->store_transaction (plugin->cls,
                                      &h_contract_terms,
-                                    &merchant_pub,
-                                     EXCHANGE_URI,
+                                    &merchant_pub,                             
       
                                      &h_wire,
                                      timestamp,
                                      refund_deadline,
@@ -946,6 +911,7 @@ run (void *cls)
                                  &h_contract_terms,
                                 &merchant_pub,
                                  &coin_pub,
+                                EXCHANGE_URL,
                                  &amount_with_fee,
                                  &deposit_fee,
                                  &refund_fee,
@@ -958,18 +924,35 @@ run (void *cls)
                                           &wtid));
   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
           plugin->store_transfer_to_proof (plugin->cls,
-                                           EXCHANGE_URI,
+                                           EXCHANGE_URL,
                                            &wtid,
                                            GNUNET_TIME_UNIT_ZERO_ABS,
                                            &signkey_pub,
                                            transfer_proof));
-  FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
-          plugin->find_transaction (plugin->cls,
-                                    &h_contract_terms,
-                                   &merchant_pub,
-                                    &transaction_cb,
-                                    NULL));
+  {
+    struct GNUNET_HashCode ah_wire;
+    struct GNUNET_TIME_Absolute atimestamp;
+    struct GNUNET_TIME_Absolute arefund_deadline;
+    struct TALER_Amount atotal_amount;
+
+    FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
+           plugin->find_transaction (plugin->cls,
+                                     &h_contract_terms,
+                                     &merchant_pub,
+                                     &ah_wire,
+                                     &atimestamp,
+                                     &arefund_deadline,
+                                     &atotal_amount));
+    FAILIF (0 != memcmp (&ah_wire,
+                        &h_wire,
+                        sizeof (struct GNUNET_HashCode)));
+    FAILIF (atimestamp.abs_value_us != timestamp.abs_value_us);
+    FAILIF (arefund_deadline.abs_value_us != refund_deadline.abs_value_us);
+    FAILIF (0 != TALER_amount_cmp (&atotal_amount,
+                                  &amount_with_fee));
+  }
 
+  
   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
           plugin->find_payments (plugin->cls,
                                  &h_contract_terms,
@@ -988,7 +971,7 @@ run (void *cls)
                                          NULL));
   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
           plugin->find_proof_by_wtid (plugin->cls,
-                                      EXCHANGE_URI,
+                                      EXCHANGE_URL,
                                       &wtid,
                                       &proof_cb,
                                       NULL));
diff --git a/src/include/taler_merchant_service.h 
b/src/include/taler_merchant_service.h
index a1ee0dd..e99024a 100644
--- a/src/include/taler_merchant_service.h
+++ b/src/include/taler_merchant_service.h
@@ -606,6 +606,10 @@ struct TALER_MERCHANT_TransactionWireTransfer
    */
   struct TALER_MERCHANT_CoinWireTransfer *coins;
 
+  /**
+   * URL of the exchange that executed the wire transfer.
+   */
+  char *exchange_url;
 };
 
 
diff --git a/src/include/taler_merchantdb_plugin.h 
b/src/include/taler_merchantdb_plugin.h
index b36a04e..6b83306 100644
--- a/src/include/taler_merchantdb_plugin.h
+++ b/src/include/taler_merchantdb_plugin.h
@@ -51,7 +51,6 @@ struct TALER_MERCHANTDB_Plugin;
  *
  * @param cls closure
  * @param merchant_pub merchant's public key
- * @param exchange_uri URI of the exchange
  * @param h_contract_terms proposal data's hashcode
  * @param h_wire hash of our wire details
  * @param timestamp time of the confirmation
@@ -61,7 +60,6 @@ struct TALER_MERCHANTDB_Plugin;
 typedef void
 (*TALER_MERCHANTDB_TransactionCallback)(void *cls,
                                        const struct TALER_MerchantPublicKeyP 
*merchant_pub,
-                                        const char *exchange_uri,
                                         const struct GNUNET_HashCode 
*h_contract_terms,
                                         const struct GNUNET_HashCode *h_wire,
                                         struct GNUNET_TIME_Absolute timestamp,
@@ -75,6 +73,7 @@ typedef void
  * @param cls closure
  * @param h_contract_terms proposal data's hashcode
  * @param coin_pub public key of the coin
+ * @param exchange_url URL of the exchange that issued the coin
  * @param amount_with_fee amount the exchange will deposit for this coin
  * @param deposit_fee fee the exchange will charge for this coin
  * @param refund_fee fee the exchange will charge for refunding this coin
@@ -85,6 +84,7 @@ typedef void
 (*TALER_MERCHANTDB_CoinDepositCallback)(void *cls,
                                         const struct GNUNET_HashCode 
*h_contract_terms,
                                         const struct TALER_CoinSpendPublicKeyP 
*coin_pub,
+                                       const char *exchange_url,
                                         const struct TALER_Amount 
*amount_with_fee,
                                         const struct TALER_Amount *deposit_fee,
                                         const struct TALER_Amount *refund_fee,
@@ -329,7 +329,6 @@ struct TALER_MERCHANTDB_Plugin
    * @param cls closure
    * @param h_contract_terms proposal data's hashcode
    * @param merchant_pub merchant's public key
-   * @param exchange_uri URI of the exchange
    * @param h_wire hash of our wire details
    * @param timestamp time of the confirmation
    * @param refund refund deadline
@@ -340,7 +339,6 @@ struct TALER_MERCHANTDB_Plugin
   (*store_transaction) (void *cls,
                         const struct GNUNET_HashCode *h_contract_terms,
                        const struct TALER_MerchantPublicKeyP *merchant_pub,
-                        const char *exchange_uri,
                         const struct GNUNET_HashCode *h_wire,
                         struct GNUNET_TIME_Absolute timestamp,
                         struct GNUNET_TIME_Absolute refund,
@@ -354,6 +352,7 @@ struct TALER_MERCHANTDB_Plugin
    * @param h_contract_terms proposal data's hashcode
    * @param merchant_pub merchant's public key
    * @param coin_pub public key of the coin
+   * @param exchange_url URL of the exchange that issued @a coin_pub
    * @param amount_with_fee amount the exchange will deposit for this coin
    * @param deposit_fee fee the exchange will charge for this coin
    * @param signkey_pub public key used by the exchange for @a exchange_proof
@@ -365,6 +364,7 @@ struct TALER_MERCHANTDB_Plugin
                     const struct GNUNET_HashCode *h_contract_terms,
                     const struct TALER_MerchantPublicKeyP *merchant_pub,
                     const struct TALER_CoinSpendPublicKeyP *coin_pub,
+                   const char *exchange_url,
                     const struct TALER_Amount *amount_with_fee,
                     const struct TALER_Amount *deposit_fee,
                     const struct TALER_Amount *refund_fee,
@@ -394,7 +394,7 @@ struct TALER_MERCHANTDB_Plugin
    * Insert wire transfer confirmation from the exchange into the database.
    *
    * @param cls closure
-   * @param exchange_uri from which exchange did we get the @a exchange_proof
+   * @param exchange_url from which exchange did we get the @a exchange_proof
    * @param wtid identifier of the wire transfer
    * @param execution_time when was @a wtid executed
    * @param signkey_pub public key used by the exchange for @a exchange_proof
@@ -403,7 +403,7 @@ struct TALER_MERCHANTDB_Plugin
    */
   enum GNUNET_DB_QueryStatus
   (*store_transfer_to_proof) (void *cls,
-                              const char *exchange_uri,
+                              const char *exchange_url,
                               const struct TALER_WireTransferIdentifierRawP 
*wtid,
                               struct GNUNET_TIME_Absolute execution_time,
                               const struct TALER_ExchangePublicKeyP 
*signkey_pub,
@@ -458,16 +458,20 @@ struct TALER_MERCHANTDB_Plugin
    * @param cls our plugin handle
    * @param h_contract_terms proposal data's hashcode
    * @param merchant_pub merchant's public key.
-   * @param cb function to call with transaction data
-   * @param cb_cls closure for @a cb
+   * @param[out] h_wire set to hash of wire details
+   * @param[out] timestamp set to timestamp
+   * @param[out] refund_deadline set to refund deadline
+   * @param[out] total_amount set to total amount
    * @return transaction status
    */
   enum GNUNET_DB_QueryStatus
   (*find_transaction) (void *cls,
                        const struct GNUNET_HashCode *h_contract_terms,
                       const struct TALER_MerchantPublicKeyP *merchant_pub,
-                       TALER_MERCHANTDB_TransactionCallback cb,
-                       void *cb_cls);
+                      struct GNUNET_HashCode *h_wire,
+                      struct GNUNET_TIME_Absolute *timestamp,
+                      struct GNUNET_TIME_Absolute *refund_deadline,
+                      struct TALER_Amount *total_amount);
 
 
   /**
@@ -550,7 +554,7 @@ struct TALER_MERCHANTDB_Plugin
    * Lookup proof information about a wire transfer.
    *
    * @param cls closure
-   * @param exchange_uri from which exchange are we looking for proof
+   * @param exchange_url from which exchange are we looking for proof
    * @param wtid wire transfer identifier for the search
    * @param cb function to call with proof data
    * @param cb_cls closure for @a cb
@@ -558,7 +562,7 @@ struct TALER_MERCHANTDB_Plugin
    */
   enum GNUNET_DB_QueryStatus
   (*find_proof_by_wtid) (void *cls,
-                         const char *exchange_uri,
+                         const char *exchange_url,
                          const struct TALER_WireTransferIdentifierRawP *wtid,
                          TALER_MERCHANTDB_ProofCallback cb,
                          void *cb_cls);
@@ -663,7 +667,7 @@ struct TALER_MERCHANTDB_Plugin
    * @param justification why was the tip approved
    * @param amount how high is the tip (with fees)
    * @param reserve_priv which reserve is debited
-   * @param exchange_uri which exchange manages the tip
+   * @param exchange_url which exchange manages the tip
    * @param[out] expiration set to when the tip expires
    * @param[out] tip_id set to the unique ID for the tip
    * @return transaction status,
@@ -679,7 +683,7 @@ struct TALER_MERCHANTDB_Plugin
                    const char *justification,
                    const struct TALER_Amount *amount,
                    const struct TALER_ReservePrivateKeyP *reserve_priv,
-                  const char *exchange_uri,
+                  const char *exchange_url,
                    struct GNUNET_TIME_Absolute *expiration,
                    struct GNUNET_HashCode *tip_id);
 
@@ -689,7 +693,7 @@ struct TALER_MERCHANTDB_Plugin
    *
    * @param cls closure, typically a connection to the d
    * @param tip_id the unique ID for the tip
-   * @param[out] exchange_uri set to the URI of the exchange (unless NULL)
+   * @param[out] exchange_url set to the URL of the exchange (unless NULL)
    * @param[out] amount set to the authorized amount (unless NULL)
    * @param[out] timestamp set to the timestamp of the tip authorization 
(unless NULL)
    * @return transaction status, usually
@@ -699,7 +703,7 @@ struct TALER_MERCHANTDB_Plugin
   enum GNUNET_DB_QueryStatus
   (*lookup_tip_by_id)(void *cls,
                       const struct GNUNET_HashCode *tip_id,
-                      char **exchange_uri,
+                      char **exchange_url,
                       struct TALER_Amount *amount,
                       struct GNUNET_TIME_Absolute *timestamp);
 

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



reply via email to

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