gnunet-svn
[Top][All Lists]
Advanced

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

[taler-merchant] branch master updated: implement #6173


From: gnunet
Subject: [taler-merchant] branch master updated: implement #6173
Date: Sun, 12 Apr 2020 20:47:01 +0200

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 c548a40  implement #6173
c548a40 is described below

commit c548a400ea1956d55c675e6a21fff46f6271455b
Author: Christian Grothoff <address@hidden>
AuthorDate: Sun Apr 12 20:46:18 2020 +0200

    implement #6173
---
 ChangeLog                                          |   4 +
 src/backend/taler-merchant-httpd_tip-pickup.c      | 204 ++++++++----
 src/include/taler_merchant_service.h               | 104 +++++-
 src/lib/Makefile.am                                |   1 +
 src/lib/merchant_api_tip_pickup.c                  | 359 ++++++++-------------
 ...api_tip_pickup.c => merchant_api_tip_pickup2.c} |  56 ++--
 src/lib/testing_api_cmd_tip_pickup.c               | 219 +++----------
 7 files changed, 437 insertions(+), 510 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 4a61c55..2ab8d28 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+Sun 12 Apr 2020 08:45:11 PM CEST
+    Changed /tip-pickup API to withdraw directly from the exchange
+    and return blind signatures, instead of having the wallet do it (#6173). 
-CG
+
 Fri 10 Apr 2020 09:01:22 PM CEST
     Changing refund API to have the merchant backend make the /refund
     request to the exchange instead of having the wallet do it (#5299). -CG
diff --git a/src/backend/taler-merchant-httpd_tip-pickup.c 
b/src/backend/taler-merchant-httpd_tip-pickup.c
index 34c50f0..51dd812 100644
--- a/src/backend/taler-merchant-httpd_tip-pickup.c
+++ b/src/backend/taler-merchant-httpd_tip-pickup.c
@@ -29,6 +29,12 @@
 #include "taler-merchant-httpd_tip-pickup.h"
 
 
+/**
+ * Information we keep per tip pickup request.
+ */
+struct PickupContext;
+
+
 /**
  * Details about a planchet that the customer wants to obtain
  * a withdrawal authorization.  This is the information that
@@ -39,10 +45,24 @@ struct PlanchetDetail
 {
 
   /**
-   * The complete withdraw request that we are building to sign.
-   * Built incrementally during the processing of the request.
+   * Hash of the denomination public key requested for this planchet.
+   */
+  struct GNUNET_HashCode h_denom_pub;
+
+  /**
+   * Pickup context this planchet belongs to.
+   */
+  struct PickupContext *pc;
+
+  /**
+   * Handle to withdraw operation with the exchange.
+   */
+  struct TALER_EXCHANGE_Withdraw2Handle *wh;
+
+  /**
+   * Blind signature to return, or NULL if not available.
    */
-  struct TALER_WithdrawRequestPS wr;
+  json_t *blind_sig;
 
   /**
    * Blinded coin (see GNUNET_CRYPTO_rsa_blind()).  Note: is malloc()'ed!
@@ -58,8 +78,7 @@ struct PlanchetDetail
 
 
 /**
- * Information we keep for individual calls
- * to requests that parse JSON, but keep no other state.
+ * Information we keep per tip pickup request.
  */
 struct PickupContext
 {
@@ -95,6 +114,11 @@ struct PickupContext
    */
   struct TMH_EXCHANGES_FindOperation *fo;
 
+  /**
+   * Handle to the exchange (set after exchange_found_cb()).
+   */
+  struct TALER_EXCHANGE_Handle *eh;
+
   /**
    * Array of planchets of length @e planchets_len.
    */
@@ -187,7 +211,20 @@ pickup_cleanup (struct TM_HandlerContext *hc)
   if (NULL != pc->planchets)
   {
     for (unsigned int i = 0; i<pc->planchets_len; i++)
-      GNUNET_free_non_null (pc->planchets[i].coin_ev);
+    {
+      struct PlanchetDetail *pd = &pc->planchets[i];
+      GNUNET_free_non_null (pd->coin_ev);
+      if (NULL != pd->wh)
+      {
+        TALER_EXCHANGE_withdraw2_cancel (pd->wh);
+        pd->wh = NULL;
+      }
+      if (NULL != pd->blind_sig)
+      {
+        json_decref (pd->blind_sig);
+        pd->blind_sig = NULL;
+      }
+    }
     GNUNET_free (pc->planchets);
     pc->planchets = NULL;
   }
@@ -203,7 +240,6 @@ pickup_cleanup (struct TM_HandlerContext *hc)
     MHD_destroy_response (pc->response);
     pc->response = NULL;
   }
-
   GNUNET_free (pc);
 }
 
@@ -216,6 +252,16 @@ pickup_cleanup (struct TM_HandlerContext *hc)
 static void
 resume_pc (struct PickupContext *pc)
 {
+  for (unsigned int i = 0; i<pc->planchets_len; i++)
+  {
+    struct PlanchetDetail *pd = &pc->planchets[i];
+
+    if (NULL != pd->wh)
+    {
+      TALER_EXCHANGE_withdraw2_cancel (pc->planchets[i].wh);
+      pc->planchets[i].wh = NULL;
+    }
+  }
   GNUNET_assert (GNUNET_YES == pc->suspended);
   GNUNET_CONTAINER_DLL_remove (pc_head,
                                pc_tail,
@@ -225,6 +271,68 @@ resume_pc (struct PickupContext *pc)
 }
 
 
+/**
+ * Function called with the result of our attempt to withdraw
+ * the coin for a tip.
+ *
+ * @param cls closure
+ * @param hr HTTP response data
+ * @param blind_sig blind signature over the coin, NULL on error
+ */
+static void
+withdraw_cb (void *cls,
+             const struct TALER_EXCHANGE_HttpResponse *hr,
+             const struct GNUNET_CRYPTO_RsaSignature *blind_sig)
+{
+  struct PlanchetDetail *pd = cls;
+  struct PickupContext *pc = pd->pc;
+  json_t *ja;
+
+  pd->wh = NULL;
+  if (NULL == blind_sig)
+  {
+    pc->response_code = MHD_HTTP_FAILED_DEPENDENCY;
+    pc->response = 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 withdraw coin from exchange",
+      "code", (json_int_t) TALER_EC_TIP_PICKUP_WITHDRAW_FAILED_AT_EXCHANGE,
+      "exchange_http_status", (json_int_t) hr->http_status,
+      "exchange_code", (json_int_t) hr->ec,
+      "exchange_reply", hr->reply);
+    resume_pc (pc);
+    return;
+  }
+  /* FIXME: persisit blind_sig in our database!?
+     (or at least _all_ of them once we have them all?) */
+  pd->blind_sig = GNUNET_JSON_from_rsa_signature (blind_sig);
+  GNUNET_assert (NULL != pd->blind_sig);
+  for (unsigned int i = 0; i<pc->planchets_len; i++)
+    if (NULL != pc->planchets[i].wh)
+      return;
+  /* All done, build final response */
+  ja = json_array ();
+  GNUNET_assert (NULL != ja);
+  for (unsigned int i = 0; i<pc->planchets_len; i++)
+  {
+    struct PlanchetDetail *pd = &pc->planchets[i];
+
+    GNUNET_assert (0 ==
+                   json_array_append_new (ja,
+                                          json_pack ("{s:o}",
+                                                     "blind_sig",
+                                                     pd->blind_sig)));
+    pd->blind_sig = NULL;
+  }
+  pc->response_code = MHD_HTTP_OK;
+  pc->response = TALER_MHD_make_json_pack ("{s:o}",
+                                           "blind_sigs",
+                                           ja);
+  resume_pc (pc);
+}
+
+
 /**
  * Prepare (and eventually execute) a pickup.  Computes
  * the "pickup ID" (by hashing the planchets and denomination keys),
@@ -237,9 +345,7 @@ static void
 run_pickup (struct PickupContext *pc)
 {
   struct TALER_ReservePrivateKeyP reserve_priv;
-  struct TALER_ReservePublicKeyP reserve_pub;
   enum TALER_ErrorCode ec;
-  json_t *sigs;
 
   db->preflight (db->cls);
   ec = db->pickup_tip_TR (db->cls,
@@ -271,50 +377,30 @@ run_pickup (struct PickupContext *pc)
     resume_pc (pc);
     return;
   }
-  sigs = json_array ();
-  if (NULL == sigs)
-  {
-    GNUNET_break (0);
-    pc->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
-    pc->response = TALER_MHD_make_error (TALER_EC_JSON_ALLOCATION_FAILURE,
-                                         "could not create JSON array");
-    resume_pc (pc);
-    return;
-  }
-  GNUNET_CRYPTO_eddsa_key_get_public (&reserve_priv.eddsa_priv,
-                                      &reserve_pub.eddsa_pub);
   for (unsigned int i = 0; i<pc->planchets_len; i++)
   {
     struct PlanchetDetail *pd = &pc->planchets[i];
-    struct TALER_ReserveSignatureP reserve_sig;
-
-    pd->wr.reserve_pub = reserve_pub;
-    GNUNET_CRYPTO_eddsa_sign (&reserve_priv.eddsa_priv,
-                              &pd->wr,
-                              &reserve_sig.eddsa_signature);
-    if (0 !=
-        json_array_append_new (sigs,
-                               json_pack ("{s:o}",
-                                          "reserve_sig",
-                                          GNUNET_JSON_from_data_auto (
-                                            &reserve_sig))))
+    struct TALER_PlanchetDetail pdx = {
+      .denom_pub_hash = pd->h_denom_pub,
+      .coin_ev = pd->coin_ev,
+      .coin_ev_size = pd->coin_ev_size,
+    };
+
+    pd->wh = TALER_EXCHANGE_withdraw2 (pc->eh,
+                                       &pdx,
+                                       &reserve_priv,
+                                       &withdraw_cb,
+                                       pd);
+    if (NULL == pd->wh)
     {
       GNUNET_break (0);
-      json_decref (sigs);
       pc->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
-      pc->response = TALER_MHD_make_error (TALER_EC_JSON_ALLOCATION_FAILURE,
-                                           "could not add element to JSON 
array");
+      pc->response = TALER_MHD_make_error (TALER_EC_TIP_PICKUP_WITHDRAW_FAILED,
+                                           "could not inititate withdrawal");
       resume_pc (pc);
       return;
     }
   }
-  pc->response_code = MHD_HTTP_OK;
-  pc->response = TALER_MHD_make_json_pack ("{s:o, s:o}",
-                                           "reserve_pub",
-                                           GNUNET_JSON_from_data_auto (
-                                             &reserve_pub),
-                                           "reserve_sigs", sigs);
-  resume_pc (pc);
 }
 
 
@@ -387,12 +473,11 @@ exchange_found_cb (void *cls,
     for (unsigned int i = 0; i<pc->planchets_len; i++)
     {
       struct PlanchetDetail *pd = &pc->planchets[i];
-      const struct TALER_EXCHANGE_DenomPublicKey *dk;
       struct TALER_Amount amount_with_fee;
+      const struct TALER_EXCHANGE_DenomPublicKey *dk;
 
       dk = TALER_EXCHANGE_get_denomination_key_by_hash (keys,
-                                                        &pd->wr.
-                                                        h_denomination_pub);
+                                                        &pd->h_denom_pub);
       if (NULL == dk)
       {
         pc->response_code = MHD_HTTP_NOT_FOUND;
@@ -408,7 +493,7 @@ exchange_found_cb (void *cls,
         return;
       }
       GNUNET_CRYPTO_hash_context_read (hc,
-                                       &pd->wr.h_denomination_pub,
+                                       &pd->h_denom_pub,
                                        sizeof (struct GNUNET_HashCode));
       GNUNET_CRYPTO_hash_context_read (hc,
                                        pd->coin_ev,
@@ -434,10 +519,6 @@ exchange_found_cb (void *cls,
           ae = GNUNET_YES;
         }
       }
-      TALER_amount_hton (&pd->wr.withdraw_fee,
-                         &dk->fee_withdraw);
-      TALER_amount_hton (&pd->wr.amount_with_fee,
-                         &amount_with_fee);
     }
     GNUNET_CRYPTO_hash_context_finish (hc,
                                        &pc->pickup_id);
@@ -455,6 +536,7 @@ exchange_found_cb (void *cls,
     resume_pc (pc);
     return;
   }
+  pc->eh = eh;
   pc->total = total;
   run_pickup (pc);
 }
@@ -545,32 +627,23 @@ prepare_pickup (struct PickupContext *pc)
  * @return #GNUNET_OK upon success, #GNUNET_NO if a response
  *    was generated, #GNUNET_SYSERR to drop the connection
  */
-static int
+static enum GNUNET_GenericReturnValue
 parse_planchet (struct MHD_Connection *connection,
                 const json_t *planchet,
                 struct PlanchetDetail *pd)
 {
-  int ret;
   struct GNUNET_JSON_Specification spec[] = {
     GNUNET_JSON_spec_fixed_auto ("denom_pub_hash",
-                                 &pd->wr.h_denomination_pub),
+                                 &pd->h_denom_pub),
     GNUNET_JSON_spec_varsize ("coin_ev",
                               (void **) &pd->coin_ev,
                               &pd->coin_ev_size),
     GNUNET_JSON_spec_end ()
   };
 
-  ret = TALER_MHD_parse_json_data (connection,
-                                   planchet,
-                                   spec);
-  if (GNUNET_OK != ret)
-    return ret;
-  pd->wr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW);
-  pd->wr.purpose.size = htonl (sizeof (struct TALER_WithdrawRequestPS));
-  GNUNET_CRYPTO_hash (pd->coin_ev,
-                      pd->coin_ev_size,
-                      &pd->wr.h_coin_envelope);
-  return ret;
+  return TALER_MHD_parse_json_data (connection,
+                                    planchet,
+                                    spec);
 }
 
 
@@ -674,6 +747,7 @@ MH_handler_tip_pickup (struct TMH_RequestHandler *rh,
                                     struct PlanchetDetail);
   for (unsigned int i = 0; i<pc->planchets_len; i++)
   {
+    pc->planchets[i].pc = pc;
     if (GNUNET_OK !=
         (res = parse_planchet (connection,
                                json_array_get (planchets,
diff --git a/src/include/taler_merchant_service.h 
b/src/include/taler_merchant_service.h
index 7298b8b..71b69f5 100644
--- a/src/include/taler_merchant_service.h
+++ b/src/include/taler_merchant_service.h
@@ -1156,24 +1156,38 @@ struct TALER_MERCHANT_TipPickupOperation;
 
 
 /**
- * Callback for a /tip-pickup request.  Returns the result of
- * the operation.
+ * Callback for a /tip-pickup request.  Returns the result of the operation.
  *
  * @param cls closure
  * @param hr HTTP response details
- * @param reserve_pub public key of the reserve that made the @a reserve_sigs, 
NULL on error
- * @param num_reserve_sigs length of the @a reserve_sigs array, 0 on error
- * @param reserve_sigs array of signatures authorizing withdrawals, NULL on 
error
+ * @param num_sigs length of the @a reserve_sigs array, 0 on error
+ * @param sigs array of signatures over the coins, NULL on error
  */
 typedef void
 (*TALER_MERCHANT_TipPickupCallback) (
   void *cls,
   const struct TALER_MERCHANT_HttpResponse *hr,
-  const struct TALER_ReservePublicKeyP *reserve_pub,
-  unsigned int num_reserve_sigs,
-  const struct TALER_ReserveSignatureP *reserve_sigs);
+  unsigned int num_sigs,
+  const struct TALER_DenominationSignature *sigs);
 
 
+/**
+ * Information per planchet.
+ */
+struct TALER_MERCHANT_PlanchetData
+{
+  /**
+   * Planchet secrets.
+   */
+  struct TALER_PlanchetSecretsP ps;
+
+  /**
+   * Denomination key desired.
+   */
+  const struct TALER_EXCHANGE_DenomPublicKey *pk;
+
+};
+
 /**
  * Issue a /tip-pickup request to the backend.  Informs the backend
  * that a customer wants to pick up a tip.
@@ -1181,8 +1195,8 @@ typedef void
  * @param ctx execution context
  * @param backend_url base URL of the merchant backend
  * @param tip_id unique identifier for the tip
- * @param num_planches number of planchets provided in @a planchets
- * @param planchets array of planchets to be signed into existence for the tip
+ * @param num_planches number of planchets provided in @a pds
+ * @param pds array of planchet secrets to be signed into existence for the tip
  * @param pickup_cb callback which will work the response gotten from the 
backend
  * @param pickup_cb_cls closure to pass to @a pickup_cb
  * @return handle for this operation, NULL upon errors
@@ -1192,7 +1206,7 @@ TALER_MERCHANT_tip_pickup (struct GNUNET_CURL_Context 
*ctx,
                            const char *backend_url,
                            const struct GNUNET_HashCode *tip_id,
                            unsigned int num_planchets,
-                           struct TALER_PlanchetDetail *planchets,
+                           const struct TALER_MERCHANT_PlanchetData *pds,
                            TALER_MERCHANT_TipPickupCallback pickup_cb,
                            void *pickup_cb_cls);
 
@@ -1206,6 +1220,74 @@ void
 TALER_MERCHANT_tip_pickup_cancel (struct TALER_MERCHANT_TipPickupOperation 
*tp);
 
 
+/**
+ * Handle for a low-level /tip-pickup operation (without unblinding).
+ */
+struct TALER_MERCHANT_TipPickup2Operation;
+
+/**
+ * A blind signature returned via tipping API.
+ */
+
+struct TALER_MERCHANT_BlindSignature
+{
+  /**
+   * We use RSA.
+   */
+  const struct GNUNET_CRYPTO_RsaSignature *blind_sig;
+};
+
+
+/**
+ * Callback for a /tip-pickup request.  Returns the result of the operation.
+ * Note that the client MUST still do the unblinding of the @a blind_sigs.
+ *
+ * @param cls closure
+ * @param hr HTTP response details
+ * @param num_blind_sigs length of the @a blind_sigs array, 0 on error
+ * @param blind_sigs array of blind signatures over the planchets, NULL on 
error
+ */
+typedef void
+(*TALER_MERCHANT_TipPickup2Callback) (
+  void *cls,
+  const struct TALER_MERCHANT_HttpResponse *hr,
+  unsigned int num_blind_sigs,
+  const struct TALER_MERCHANT_BlindSignature *blind_sigs);
+
+
+/**
+ * Issue a /tip-pickup request to the backend.  Informs the backend
+ * that a customer wants to pick up a tip.
+ *
+ * @param ctx execution context
+ * @param backend_url base URL of the merchant backend
+ * @param tip_id unique identifier for the tip
+ * @param num_planches number of planchets provided in @a planchets
+ * @param planchets array of planchets to be signed into existence for the tip
+ * @param pickup_cb callback which will work the response gotten from the 
backend
+ * @param pickup_cb_cls closure to pass to @a pickup_cb
+ * @return handle for this operation, NULL upon errors
+ */
+struct TALER_MERCHANT_TipPickup2Operation *
+TALER_MERCHANT_tip_pickup2 (struct GNUNET_CURL_Context *ctx,
+                            const char *backend_url,
+                            const struct GNUNET_HashCode *tip_id,
+                            unsigned int num_planchets,
+                            struct TALER_PlanchetDetail *planchets,
+                            TALER_MERCHANT_TipPickup2Callback pickup_cb,
+                            void *pickup_cb_cls);
+
+
+/**
+ * Cancel a pending /tip-pickup request.
+ *
+ * @param tp handle from the operation to cancel
+ */
+void
+TALER_MERCHANT_tip_pickup2_cancel (
+  struct TALER_MERCHANT_TipPickup2Operation *tp);
+
+
 /* ********************** /check-payment ************************* */
 
 
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
index 3d42777..1561f57 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -31,6 +31,7 @@ libtalermerchant_la_SOURCES = \
   merchant_api_refund_increase.c \
   merchant_api_tip_authorize.c \
   merchant_api_tip_pickup.c \
+  merchant_api_tip_pickup2.c \
   merchant_api_tip_query.c \
   merchant_api_track_transaction.c \
   merchant_api_track_transfer.c
diff --git a/src/lib/merchant_api_tip_pickup.c 
b/src/lib/merchant_api_tip_pickup.c
index f402209..6e48f16 100644
--- a/src/lib/merchant_api_tip_pickup.c
+++ b/src/lib/merchant_api_tip_pickup.c
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  Copyright (C) 2014-2017 Taler Systems SA
+  Copyright (C) 2014-2017, 2020 Taler Systems SA
 
   TALER is free software; you can redistribute it and/or modify it under the
   terms of the GNU Lesser General Public License as published by the Free 
Software
@@ -33,25 +33,32 @@
 
 
 /**
- * @brief A handle for tracking transactions.
+ * Data we keep per planchet.
  */
-struct TALER_MERCHANT_TipPickupOperation
+struct PlanchetData
 {
-
   /**
-   * The url for this request.
+   * Secrets of the planchet.
    */
-  char *url;
+  struct TALER_PlanchetSecretsP ps;
 
   /**
-   * Minor context that holds body and headers.
+   * Denomination key we are withdrawing.
    */
-  struct TALER_CURL_PostContext post_ctx;
+  struct TALER_EXCHANGE_DenomPublicKey pk;
 
   /**
-   * Handle for the request.
+   * Hash of the public key of the coin we are signing.
    */
-  struct GNUNET_CURL_Job *job;
+  struct GNUNET_HashCode c_hash;
+};
+
+
+/**
+ * Handle for a /tip-pickup operation.
+ */
+struct TALER_MERCHANT_TipPickupOperation
+{
 
   /**
    * Function to call with the result.
@@ -64,162 +71,99 @@ struct TALER_MERCHANT_TipPickupOperation
   void *cb_cls;
 
   /**
-   * Reference to the execution context.
+   * Handle for the actual (internal) withdraw operation.
    */
-  struct GNUNET_CURL_Context *ctx;
+  struct TALER_MERCHANT_TipPickup2Operation *tpo2;
 
   /**
-   * Expected number of planchets.
+   * Number of planchets/coins used for this operation.
    */
   unsigned int num_planchets;
+
+  /**
+   * Array of length @e num_planchets.
+   */
+  struct PlanchetData *planchets;
+
 };
 
 
 /**
- * We got a 200 response back from the exchange (or the merchant).
- * Now we need to parse the response and if it is well-formed,
- * call the callback (and set it to NULL afterwards).
+ * Callback for a /tip-pickup request.  Returns the result of the operation.
+ * Note that the client MUST still do the unblinding of the @a blind_sigs.
  *
- * @param tpo handle of the original authorization operation
- * @param json cryptographic proof returned by the exchange/merchant
- * @return #GNUNET_OK if response is valid
+ * @param cls closure, a `struct TALER_MERCHANT_TipPickupOperation *`
+ * @param hr HTTP response details
+ * @param num_blind_sigs length of the @a reserve_sigs array, 0 on error
+ * @param blind_sigs array of blind signatures over the planchets, NULL on 
error
  */
-static int
-check_ok (struct TALER_MERCHANT_TipPickupOperation *tpo,
-          const json_t *json)
+static void
+pickup_done_cb (void *cls,
+                const struct TALER_MERCHANT_HttpResponse *hr,
+                unsigned int num_blind_sigs,
+                const struct TALER_MERCHANT_BlindSignature *blind_sigs)
 {
-  struct TALER_ReservePublicKeyP reserve_pub;
-  json_t *ja;
-  unsigned int ja_len;
-  struct GNUNET_JSON_Specification spec[] = {
-    GNUNET_JSON_spec_fixed_auto ("reserve_pub", &reserve_pub),
-    GNUNET_JSON_spec_json ("reserve_sigs", &ja),
-    GNUNET_JSON_spec_end ()
-  };
-  struct TALER_MERCHANT_HttpResponse hr = {
-    .http_status = MHD_HTTP_OK,
-    .reply = json
-  };
+  struct TALER_MERCHANT_TipPickupOperation *tp = cls;
 
-  if (GNUNET_OK !=
-      GNUNET_JSON_parse (json,
-                         spec,
-                         NULL, NULL))
-  {
-    GNUNET_break_op (0);
-    return GNUNET_SYSERR;
-  }
-  ja_len = json_array_size (ja);
-  if (ja_len != tpo->num_planchets)
+  tp->tpo2 = NULL;
+  if (NULL == blind_sigs)
   {
-    GNUNET_break_op (0);
-    GNUNET_JSON_parse_free (spec);
-    return GNUNET_SYSERR;
+    tp->cb (tp->cb_cls,
+            hr,
+            0,
+            NULL);
+    TALER_MERCHANT_tip_pickup_cancel (tp);
+    return;
   }
   {
-    struct TALER_ReserveSignatureP reserve_sigs[ja_len];
-
-    for (unsigned int i = 0; i<ja_len; i++)
+    struct TALER_DenominationSignature sigs[num_blind_sigs];
+    int ok;
+
+    ok = GNUNET_OK;
+    memset (sigs,
+            0,
+            sizeof (sigs));
+    for (unsigned int i = 0; i<num_blind_sigs; i++)
     {
-      json_t *pj = json_array_get (ja, i);
-
-      struct GNUNET_JSON_Specification ispec[] = {
-        GNUNET_JSON_spec_fixed_auto ("reserve_sig", &reserve_sigs[i]),
-        GNUNET_JSON_spec_end ()
-      };
+      struct TALER_FreshCoin fc;
 
       if (GNUNET_OK !=
-          GNUNET_JSON_parse (pj,
-                             ispec,
-                             NULL, NULL))
+          TALER_planchet_to_coin (&tp->planchets[i].pk.key,
+                                  blind_sigs[i].blind_sig,
+                                  &tp->planchets[i].ps,
+                                  &tp->planchets[i].c_hash,
+                                  &fc))
       {
-        GNUNET_break_op (0);
-        GNUNET_JSON_parse_free (spec);
-        return GNUNET_SYSERR;
+        ok = GNUNET_SYSERR;
+        break;
       }
+      sigs[i] = fc.sig;
     }
-    tpo->cb (tpo->cb_cls,
-             &hr,
-             &reserve_pub,
-             ja_len,
-             reserve_sigs);
-    tpo->cb = NULL; /* do not call twice */
-  }
-  GNUNET_JSON_parse_free (spec);
-  return GNUNET_OK;
-}
-
-
-/**
- * Function called when we're done processing the
- * HTTP /track/transaction request.
- *
- * @param cls the `struct TALER_MERCHANT_TipPickupOperation`
- * @param response_code HTTP response code, 0 on error
- * @param json response body, NULL if not in JSON
- */
-static void
-handle_tip_pickup_finished (void *cls,
-                            long response_code,
-                            const void *response)
-{
-  struct TALER_MERCHANT_TipPickupOperation *tpo = cls;
-  const json_t *json = response;
-  struct TALER_MERCHANT_HttpResponse hr = {
-    .http_status = (unsigned int) response_code,
-    .reply = json
-  };
-
-  tpo->job = NULL;
-  switch (response_code)
-  {
-  case MHD_HTTP_OK:
-    if (GNUNET_OK != check_ok (tpo,
-                               json))
+    if (GNUNET_OK == ok)
     {
-      GNUNET_break_op (0);
-      hr.http_status = 0;
-      hr.ec = TALER_EC_INVALID_RESPONSE;
+      tp->cb (tp->cb_cls,
+              hr,
+              num_blind_sigs,
+              sigs);
     }
-    break;
-  case MHD_HTTP_INTERNAL_SERVER_ERROR:
-    /* Server had an internal issue; we should retry, but this API
-       leaves this to the application */
-    hr.ec = TALER_JSON_get_error_code (json);
-    hr.hint = TALER_JSON_get_error_hint (json);
-    break;
-  case MHD_HTTP_CONFLICT:
-    /* legal, can happen if we pickup a tip twice... */
-    hr.ec = TALER_JSON_get_error_code (json);
-    hr.hint = TALER_JSON_get_error_hint (json);
-    break;
-  case MHD_HTTP_NOT_FOUND:
-    /* legal, can happen if tip ID is unknown */
-    hr.ec = TALER_JSON_get_error_code (json);
-    hr.hint = TALER_JSON_get_error_hint (json);
-    break;
-  default:
-    /* unexpected response code */
-    GNUNET_break_op (0);
-    TALER_MERCHANT_parse_error_details_ (json,
-                                         response_code,
-                                         &hr);
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "Unexpected response code %u/%d\n",
-                (unsigned int) response_code,
-                (int) hr.ec);
-    break;
-  }
-  if (NULL != tpo->cb)
-  {
-    tpo->cb (tpo->cb_cls,
-             &hr,
-             NULL,
-             0,
-             NULL);
-    tpo->cb = NULL;
+    else
+    {
+      struct TALER_MERCHANT_HttpResponse hrx = {
+        .reply = hr->reply,
+        .http_status = 0,
+        .ec = TALER_EC_TIP_PICKUP_UNBLIND_FAILURE
+      };
+
+      tp->cb (tp->cb_cls,
+              &hrx,
+              0,
+              NULL);
+    }
+    for (unsigned int i = 0; i<num_blind_sigs; i++)
+      if (NULL != sigs[i].rsa_signature)
+        GNUNET_CRYPTO_rsa_signature_free (sigs[i].rsa_signature);
   }
-  TALER_MERCHANT_tip_pickup_cancel (tpo);
+  TALER_MERCHANT_tip_pickup_cancel (tp);
 }
 
 
@@ -230,8 +174,8 @@ handle_tip_pickup_finished (void *cls,
  * @param ctx execution context
  * @param backend_url base URL of the merchant backend
  * @param tip_id unique identifier for the tip
- * @param num_planches number of planchets provided in @a planchets
- * @param planchets array of planchets to be signed into existence for the tip
+ * @param num_planches number of planchets provided in @a pds
+ * @param pds array of planchet secrets to be signed into existence for the tip
  * @param pickup_cb callback which will work the response gotten from the 
backend
  * @param pickup_cb_cls closure to pass to @a pickup_cb
  * @return handle for this operation, NULL upon errors
@@ -241,122 +185,83 @@ TALER_MERCHANT_tip_pickup (struct GNUNET_CURL_Context 
*ctx,
                            const char *backend_url,
                            const struct GNUNET_HashCode *tip_id,
                            unsigned int num_planchets,
-                           struct TALER_PlanchetDetail *planchets,
+                           const struct TALER_MERCHANT_PlanchetData *pds,
                            TALER_MERCHANT_TipPickupCallback pickup_cb,
                            void *pickup_cb_cls)
 {
-  struct TALER_MERCHANT_TipPickupOperation *tpo;
-  CURL *eh;
-  json_t *pa;
-  json_t *tp_obj;
+  struct TALER_MERCHANT_TipPickupOperation *tp;
+  struct TALER_PlanchetDetail details[GNUNET_NZL (num_planchets)];
 
   if (0 == num_planchets)
   {
     GNUNET_break (0);
     return NULL;
   }
-  pa = json_array ();
+  tp = GNUNET_new (struct TALER_MERCHANT_TipPickupOperation);
+  GNUNET_array_grow (tp->planchets,
+                     tp->num_planchets,
+                     num_planchets);
   for (unsigned int i = 0; i<num_planchets; i++)
   {
-    const struct TALER_PlanchetDetail *planchet = &planchets[i];
-    json_t *p;
-
-    p = json_pack ("{"
-                   " s:o," /* denom_pub_hash */
-                   " s:o," /* coin_ev */
-                   "}",
-                   "denom_pub_hash", GNUNET_JSON_from_data_auto (
-                     &planchet->denom_pub_hash),
-                   "coin_ev", GNUNET_JSON_from_data (planchet->coin_ev,
-                                                     planchet->coin_ev_size));
-    if (NULL == p)
+    tp->planchets[i].ps = pds[i].ps;
+    if (GNUNET_OK !=
+        TALER_planchet_prepare (&pds[i].pk->key,
+                                &tp->planchets[i].ps,
+                                &tp->planchets[i].c_hash,
+                                &details[i]))
     {
       GNUNET_break (0);
-      json_decref (pa);
+      GNUNET_array_grow (tp->planchets,
+                         tp->num_planchets,
+                         0);
+      GNUNET_free (tp);
       return NULL;
     }
-    if (0 !=
-        json_array_append_new (pa,
-                               p))
-    {
-      GNUNET_break (0);
-      json_decref (pa);
-      return NULL;
-    }
-  }
-  tp_obj = json_pack ("{"
-                      " s:o," /* tip_id */
-                      " s:o," /* planchets */
-                      "}",
-                      "tip_id", GNUNET_JSON_from_data_auto (tip_id),
-                      "planchets", pa);
-  if (NULL == tp_obj)
-  {
-    GNUNET_break (0);
-    return NULL;
   }
-  tpo = GNUNET_new (struct TALER_MERCHANT_TipPickupOperation);
-  tpo->num_planchets = num_planchets;
-  tpo->ctx = ctx;
-  tpo->cb = pickup_cb;
-  tpo->cb_cls = pickup_cb_cls;
-
-  tpo->url = TALER_url_join (backend_url,
-                             "tip-pickup",
-                             NULL);
-  if (NULL == tpo->url)
+  for (unsigned int i = 0; i<num_planchets; i++)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "Could not construct request URL.\n");
-    json_decref (tp_obj);
-    GNUNET_free (tpo);
-    return NULL;
+    tp->planchets[i].pk = *pds[i].pk;
+    tp->planchets[i].pk.key.rsa_public_key
+      = GNUNET_CRYPTO_rsa_public_key_dup (pds[i].pk->key.rsa_public_key);
   }
-  eh = curl_easy_init ();
-  if (GNUNET_OK != TALER_curl_easy_post (&tpo->post_ctx,
-                                         eh,
-                                         tp_obj))
+  tp->cb = pickup_cb;
+  tp->cb_cls = pickup_cb_cls;
+  tp->tpo2 = TALER_MERCHANT_tip_pickup2 (ctx,
+                                         backend_url,
+                                         tip_id,
+                                         num_planchets,
+                                         details,
+                                         &pickup_done_cb,
+                                         tp);
+  if (NULL == tp->tpo2)
   {
     GNUNET_break (0);
-    json_decref (tp_obj);
-    GNUNET_free (tpo);
+    TALER_MERCHANT_tip_pickup_cancel (tp);
     return NULL;
   }
-  json_decref (tp_obj);
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Requesting URL '%s'\n",
-              tpo->url);
-
-  GNUNET_assert (CURLE_OK == curl_easy_setopt (eh,
-                                               CURLOPT_URL,
-                                               tpo->url));
-  tpo->job = GNUNET_CURL_job_add2 (ctx,
-                                   eh,
-                                   tpo->post_ctx.headers,
-                                   &handle_tip_pickup_finished,
-                                   tpo);
-  return tpo;
+  return tp;
 }
 
 
 /**
- * Cancel a /track/transaction request.  This function cannot be used
- * on a request handle if a response is already served for it.
+ * Cancel a pending /tip-pickup request
  *
- * @param tpo handle to the tracking operation being cancelled
+ * @param tp handle from the operation to cancel
  */
 void
-TALER_MERCHANT_tip_pickup_cancel (struct TALER_MERCHANT_TipPickupOperation 
*tpo)
+TALER_MERCHANT_tip_pickup_cancel (struct TALER_MERCHANT_TipPickupOperation *tp)
 {
-  if (NULL != tpo->job)
+  for (unsigned int i = 0; i<tp->num_planchets; i++)
+    GNUNET_CRYPTO_rsa_public_key_dup (tp->planchets[i].pk.key.rsa_public_key);
+  GNUNET_array_grow (tp->planchets,
+                     tp->num_planchets,
+                     0);
+  if (NULL != tp->tpo2)
   {
-    GNUNET_CURL_job_cancel (tpo->job);
-    tpo->job = NULL;
+    TALER_MERCHANT_tip_pickup2_cancel (tp->tpo2);
+    tp->tpo2 = NULL;
   }
-  TALER_curl_easy_post_finished (&tpo->post_ctx);
-  GNUNET_free (tpo->url);
-  GNUNET_free (tpo);
+  GNUNET_free (tp);
 }
 
 
diff --git a/src/lib/merchant_api_tip_pickup.c 
b/src/lib/merchant_api_tip_pickup2.c
similarity index 85%
copy from src/lib/merchant_api_tip_pickup.c
copy to src/lib/merchant_api_tip_pickup2.c
index f402209..751d126 100644
--- a/src/lib/merchant_api_tip_pickup.c
+++ b/src/lib/merchant_api_tip_pickup2.c
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  Copyright (C) 2014-2017 Taler Systems SA
+  Copyright (C) 2014-2017, 2020 Taler Systems SA
 
   TALER is free software; you can redistribute it and/or modify it under the
   terms of the GNU Lesser General Public License as published by the Free 
Software
@@ -15,7 +15,7 @@
   <http://www.gnu.org/licenses/>
 */
 /**
- * @file lib/merchant_api_tip_pickup.c
+ * @file lib/merchant_api_tip_pickup2.c
  * @brief Implementation of the /tip-pickup request of the merchant's HTTP API
  * @author Marcello Stanisci
  * @author Christian Grothoff
@@ -35,7 +35,7 @@
 /**
  * @brief A handle for tracking transactions.
  */
-struct TALER_MERCHANT_TipPickupOperation
+struct TALER_MERCHANT_TipPickup2Operation
 {
 
   /**
@@ -56,7 +56,7 @@ struct TALER_MERCHANT_TipPickupOperation
   /**
    * Function to call with the result.
    */
-  TALER_MERCHANT_TipPickupCallback cb;
+  TALER_MERCHANT_TipPickup2Callback cb;
 
   /**
    * Closure for @a cb.
@@ -85,15 +85,13 @@ struct TALER_MERCHANT_TipPickupOperation
  * @return #GNUNET_OK if response is valid
  */
 static int
-check_ok (struct TALER_MERCHANT_TipPickupOperation *tpo,
+check_ok (struct TALER_MERCHANT_TipPickup2Operation *tpo,
           const json_t *json)
 {
-  struct TALER_ReservePublicKeyP reserve_pub;
   json_t *ja;
   unsigned int ja_len;
   struct GNUNET_JSON_Specification spec[] = {
-    GNUNET_JSON_spec_fixed_auto ("reserve_pub", &reserve_pub),
-    GNUNET_JSON_spec_json ("reserve_sigs", &ja),
+    GNUNET_JSON_spec_json ("blind_sigs", &ja),
     GNUNET_JSON_spec_end ()
   };
   struct TALER_MERCHANT_HttpResponse hr = {
@@ -117,14 +115,14 @@ check_ok (struct TALER_MERCHANT_TipPickupOperation *tpo,
     return GNUNET_SYSERR;
   }
   {
-    struct TALER_ReserveSignatureP reserve_sigs[ja_len];
+    struct TALER_MERCHANT_BlindSignature mblind_sigs[ja_len];
+    struct GNUNET_CRYPTO_RsaSignature *blind_sigs[ja_len];
 
     for (unsigned int i = 0; i<ja_len; i++)
     {
       json_t *pj = json_array_get (ja, i);
-
       struct GNUNET_JSON_Specification ispec[] = {
-        GNUNET_JSON_spec_fixed_auto ("reserve_sig", &reserve_sigs[i]),
+        GNUNET_JSON_spec_rsa_signature ("blind_sig", &blind_sigs[i]),
         GNUNET_JSON_spec_end ()
       };
 
@@ -137,12 +135,14 @@ check_ok (struct TALER_MERCHANT_TipPickupOperation *tpo,
         GNUNET_JSON_parse_free (spec);
         return GNUNET_SYSERR;
       }
+      mblind_sigs[i].blind_sig = blind_sigs[i];
     }
     tpo->cb (tpo->cb_cls,
              &hr,
-             &reserve_pub,
              ja_len,
-             reserve_sigs);
+             mblind_sigs);
+    for (unsigned int i = 0; i<ja_len; i++)
+      GNUNET_CRYPTO_rsa_signature_free (blind_sigs[i]);
     tpo->cb = NULL; /* do not call twice */
   }
   GNUNET_JSON_parse_free (spec);
@@ -163,7 +163,7 @@ handle_tip_pickup_finished (void *cls,
                             long response_code,
                             const void *response)
 {
-  struct TALER_MERCHANT_TipPickupOperation *tpo = cls;
+  struct TALER_MERCHANT_TipPickup2Operation *tpo = cls;
   const json_t *json = response;
   struct TALER_MERCHANT_HttpResponse hr = {
     .http_status = (unsigned int) response_code,
@@ -214,12 +214,11 @@ handle_tip_pickup_finished (void *cls,
   {
     tpo->cb (tpo->cb_cls,
              &hr,
-             NULL,
              0,
              NULL);
     tpo->cb = NULL;
   }
-  TALER_MERCHANT_tip_pickup_cancel (tpo);
+  TALER_MERCHANT_tip_pickup2_cancel (tpo);
 }
 
 
@@ -236,16 +235,16 @@ handle_tip_pickup_finished (void *cls,
  * @param pickup_cb_cls closure to pass to @a pickup_cb
  * @return handle for this operation, NULL upon errors
  */
-struct TALER_MERCHANT_TipPickupOperation *
-TALER_MERCHANT_tip_pickup (struct GNUNET_CURL_Context *ctx,
-                           const char *backend_url,
-                           const struct GNUNET_HashCode *tip_id,
-                           unsigned int num_planchets,
-                           struct TALER_PlanchetDetail *planchets,
-                           TALER_MERCHANT_TipPickupCallback pickup_cb,
-                           void *pickup_cb_cls)
+struct TALER_MERCHANT_TipPickup2Operation *
+TALER_MERCHANT_tip_pickup2 (struct GNUNET_CURL_Context *ctx,
+                            const char *backend_url,
+                            const struct GNUNET_HashCode *tip_id,
+                            unsigned int num_planchets,
+                            struct TALER_PlanchetDetail *planchets,
+                            TALER_MERCHANT_TipPickup2Callback pickup_cb,
+                            void *pickup_cb_cls)
 {
-  struct TALER_MERCHANT_TipPickupOperation *tpo;
+  struct TALER_MERCHANT_TipPickup2Operation *tpo;
   CURL *eh;
   json_t *pa;
   json_t *tp_obj;
@@ -295,7 +294,7 @@ TALER_MERCHANT_tip_pickup (struct GNUNET_CURL_Context *ctx,
     GNUNET_break (0);
     return NULL;
   }
-  tpo = GNUNET_new (struct TALER_MERCHANT_TipPickupOperation);
+  tpo = GNUNET_new (struct TALER_MERCHANT_TipPickup2Operation);
   tpo->num_planchets = num_planchets;
   tpo->ctx = ctx;
   tpo->cb = pickup_cb;
@@ -347,7 +346,8 @@ TALER_MERCHANT_tip_pickup (struct GNUNET_CURL_Context *ctx,
  * @param tpo handle to the tracking operation being cancelled
  */
 void
-TALER_MERCHANT_tip_pickup_cancel (struct TALER_MERCHANT_TipPickupOperation 
*tpo)
+TALER_MERCHANT_tip_pickup2_cancel (
+  struct TALER_MERCHANT_TipPickup2Operation *tpo)
 {
   if (NULL != tpo->job)
   {
@@ -360,4 +360,4 @@ TALER_MERCHANT_tip_pickup_cancel (struct 
TALER_MERCHANT_TipPickupOperation *tpo)
 }
 
 
-/* end of merchant_api_tip_pickup.c */
+/* end of merchant_api_tip_pickup2.c */
diff --git a/src/lib/testing_api_cmd_tip_pickup.c 
b/src/lib/testing_api_cmd_tip_pickup.c
index 21045a2..dd96352 100644
--- a/src/lib/testing_api_cmd_tip_pickup.c
+++ b/src/lib/testing_api_cmd_tip_pickup.c
@@ -101,12 +101,6 @@ struct TipPickupState
    */
   struct TALER_PlanchetSecretsP *psa;
 
-  /**
-   * Temporary data structure of @e num_coins entries for the
-   * withdraw operations.
-   */
-  struct WithdrawHandle *withdraws;
-
   /**
    * Set (by the interpreter) to an array of @a num_coins
    * signatures created from the (successful) tip operation.
@@ -121,89 +115,6 @@ struct TipPickupState
 };
 
 
-/**
- * Internal withdraw handle used when withdrawing tips.
- */
-struct WithdrawHandle
-{
-  /**
-   * Withdraw operation this handle represents.
-   */
-  struct TALER_EXCHANGE_WithdrawHandle *wsh;
-
-  /**
-   * Interpreter state.
-   */
-  struct TALER_TESTING_Interpreter *is;
-
-  /**
-   * Offset of this withdraw operation in the current
-   * @e is command.
-   */
-  unsigned int off;
-
-  /**
-   * Internal state of the "pickup" CMD.
-   */
-  struct TipPickupState *tps;
-};
-
-
-/**
- * This callback handles the response of a withdraw operation
- * from the exchange, that is the final step in getting the tip.
- *
- * @param cls closure, a `struct WithdrawHandle *`
- * @param hr HTTP response details
- * @param sig signature over the coin, NULL on error
- */
-static void
-pickup_withdraw_cb (void *cls,
-                    const struct TALER_EXCHANGE_HttpResponse *hr,
-                    const struct TALER_DenominationSignature *sig)
-{
-  struct WithdrawHandle *wh = cls;
-  struct TALER_TESTING_Interpreter *is = wh->is;
-
-  struct TipPickupState *tps = wh->tps;
-
-  wh->wsh = NULL;
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Withdraw operation %u completed with %u (%d)\n",
-              wh->off,
-              hr->http_status,
-              hr->ec);
-  GNUNET_assert (wh->off < tps->num_coins);
-  if ( (MHD_HTTP_OK != hr->http_status) ||
-       (TALER_EC_NONE != hr->ec) )
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "Unexpected response code %u (%d) to command %s when 
withdrawing\n",
-                hr->http_status,
-                hr->ec,
-                TALER_TESTING_interpreter_get_current_label (is));
-    TALER_TESTING_interpreter_fail (is);
-    return;
-  }
-  if (NULL == tps->sigs)
-    tps->sigs = GNUNET_new_array
-                  (tps->num_coins, struct TALER_DenominationSignature);
-
-  GNUNET_assert (NULL == tps->sigs[wh->off].rsa_signature);
-  tps->sigs[wh->off].rsa_signature
-    = GNUNET_CRYPTO_rsa_signature_dup (sig->rsa_signature);
-
-  for (unsigned int i = 0; i<tps->num_coins; i++)
-    if (NULL != tps->withdraws[wh->off].wsh)
-      return;
-  /* still some ops ongoing */
-
-  GNUNET_free (tps->withdraws);
-  tps->withdraws = NULL;
-  TALER_TESTING_interpreter_next (is);
-}
-
-
 /**
  * Callback for a /tip-pickup request, it mainly checks if
  * values returned from the backend are as expected, and if so
@@ -211,19 +122,15 @@ pickup_withdraw_cb (void *cls,
  *
  * @param cls closure
  * @param hr HTTP response
- * @param reserve_pub public key of the reserve that made the
- *        @a reserve_sigs, NULL on error
- * @param num_reserve_sigs length of the @a reserve_sigs array,
+ * @param num_sigs length of the @a sigs array,
  *        0 on error
- * @param reserve_sigs array of signatures authorizing withdrawals,
- *        NULL on error
+ * @param sigs array of signatures over the coins, NULL on error
  */
 static void
 pickup_cb (void *cls,
            const struct TALER_MERCHANT_HttpResponse *hr,
-           const struct TALER_ReservePublicKeyP *reserve_pub,
-           unsigned int num_reserve_sigs,
-           const struct TALER_ReserveSignatureP *reserve_sigs)
+           unsigned int num_sigs,
+           const struct TALER_DenominationSignature *sigs)
 {
   struct TipPickupState *tps = cls;
 
@@ -248,40 +155,14 @@ pickup_cb (void *cls,
     TALER_TESTING_interpreter_next (tps->is);
     return;
   }
-  if (num_reserve_sigs != tps->num_coins)
+  if (num_sigs != tps->num_coins)
     TALER_TESTING_FAIL (tps->is);
-
-  /* pickup successful, now withdraw! */
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Obtained %u signatures for withdrawal from picking up a tip\n",
-              num_reserve_sigs);
-
-  GNUNET_assert (NULL == tps->withdraws);
-  tps->withdraws = GNUNET_new_array (num_reserve_sigs,
-                                     struct WithdrawHandle);
-
-  for (unsigned int i = 0; i<num_reserve_sigs; i++)
-  {
-    struct WithdrawHandle *wh = &tps->withdraws[i];
-
-    wh->off = i;
-    wh->is = tps->is;
-    wh->tps = tps;
-    GNUNET_assert ( (NULL == wh->wsh) &&
-                    ( (NULL == tps->sigs) ||
-                      (NULL == tps->sigs[wh->off].rsa_signature) ) );
-    wh->wsh = TALER_EXCHANGE_withdraw2 (tps->is->exchange,
-                                        tps->dks[i],
-                                        &reserve_sigs[i],
-                                        reserve_pub,
-                                        &tps->psa[i],
-                                        &pickup_withdraw_cb,
-                                        wh);
-    if (NULL == wh->wsh)
-      TALER_TESTING_FAIL (tps->is);
-  }
-  if (0 == num_reserve_sigs)
-    TALER_TESTING_interpreter_next (tps->is);
+  tps->sigs = GNUNET_new_array (tps->num_coins,
+                                struct TALER_DenominationSignature);
+  for (unsigned int i = 0; i<num_sigs; i++)
+    tps->sigs[i].rsa_signature
+      = GNUNET_CRYPTO_rsa_signature_dup (sigs[i].rsa_signature);
+  TALER_TESTING_interpreter_next (tps->is);
 }
 
 
@@ -341,7 +222,7 @@ tip_pickup_run (void *cls,
 
   tps->num_coins = num_planchets;
   {
-    struct TALER_PlanchetDetail planchets[num_planchets];
+    struct TALER_MERCHANT_PlanchetData planchets[num_planchets];
 
     tps->psa = GNUNET_new_array (num_planchets,
                                  struct TALER_PlanchetSecretsP);
@@ -349,7 +230,6 @@ tip_pickup_run (void *cls,
                                  const struct TALER_EXCHANGE_DenomPublicKey *);
     tps->amounts_obj = GNUNET_new_array (num_planchets,
                                          struct TALER_Amount);
-
     for (unsigned int i = 0; i<num_planchets; i++)
     {
       if (NULL == replay_cmd)
@@ -379,12 +259,8 @@ tip_pickup_run (void *cls,
           TALER_TESTING_FAIL (is);
         tps->psa[i] = *ps;
       }
-
-      if (GNUNET_OK !=
-          TALER_planchet_prepare (&tps->dks[i]->key,
-                                  &tps->psa[i],
-                                  &planchets[i]))
-        TALER_TESTING_FAIL (is);
+      planchets[i].pk = tps->dks[i];
+      planchets[i].ps = tps->psa[i];
     }
     if (GNUNET_OK !=
         TALER_TESTING_get_trait_tip_id (authorize_cmd,
@@ -399,12 +275,6 @@ tip_pickup_run (void *cls,
                                           planchets,
                                           &pickup_cb,
                                           tps);
-    for (unsigned int i = 0; i<num_planchets; i++)
-    {
-      GNUNET_free (planchets[i].coin_ev);
-      planchets[i].coin_ev = NULL;
-      planchets[i].coin_ev_size = 0;
-    }
     GNUNET_assert (NULL != tps->tpo);
   }
 }
@@ -426,7 +296,6 @@ tip_pickup_cleanup (void *cls,
   GNUNET_free_non_null (tps->amounts_obj);
   GNUNET_free_non_null (tps->dks);
   GNUNET_free_non_null (tps->psa);
-  GNUNET_free_non_null (tps->withdraws);
   if (NULL != tps->sigs)
   {
     for (unsigned int i = 0; i<tps->num_coins; i++)
@@ -488,8 +357,7 @@ tip_pickup_traits (void *cls,
 
 
 /**
- * Define a /tip-pickup CMD, equipped with the expected error
- * code.
+ * Define a /tip-pickup CMD.
  *
  * @param label the command label
  * @param merchant_url base URL of the backend which will serve
@@ -499,17 +367,13 @@ tip_pickup_traits (void *cls,
  *        that offers a tip id to pick up.
  * @param amounts array of string-defined amounts that specifies
  *        which denominations will be accepted for tipping.
- * @param exchange connection handle to the exchange that will
- *        eventually serve the withdraw operation.
- * @param ec expected Taler error code.
  */
 struct TALER_TESTING_Command
-TALER_TESTING_cmd_tip_pickup_with_ec (const char *label,
-                                      const char *merchant_url,
-                                      unsigned int http_status,
-                                      const char *authorize_reference,
-                                      const char **amounts,
-                                      enum TALER_ErrorCode ec)
+TALER_TESTING_cmd_tip_pickup (const char *label,
+                              const char *merchant_url,
+                              unsigned int http_status,
+                              const char *authorize_reference,
+                              const char **amounts)
 {
   struct TipPickupState *tps;
 
@@ -518,7 +382,6 @@ TALER_TESTING_cmd_tip_pickup_with_ec (const char *label,
   tps->authorize_reference = authorize_reference;
   tps->amounts = amounts;
   tps->http_status = http_status;
-  tps->expected_ec = ec;
   {
     struct TALER_TESTING_Command cmd = {
       .cls = tps,
@@ -534,7 +397,8 @@ TALER_TESTING_cmd_tip_pickup_with_ec (const char *label,
 
 
 /**
- * Define a /tip-pickup CMD.
+ * Define a /tip-pickup CMD, equipped with the expected error
+ * code.
  *
  * @param label the command label
  * @param merchant_url base URL of the backend which will serve
@@ -544,32 +408,29 @@ TALER_TESTING_cmd_tip_pickup_with_ec (const char *label,
  *        that offers a tip id to pick up.
  * @param amounts array of string-defined amounts that specifies
  *        which denominations will be accepted for tipping.
+ * @param exchange connection handle to the exchange that will
+ *        eventually serve the withdraw operation.
+ * @param ec expected Taler error code.
  */
 struct TALER_TESTING_Command
-TALER_TESTING_cmd_tip_pickup (const char *label,
-                              const char *merchant_url,
-                              unsigned int http_status,
-                              const char *authorize_reference,
-                              const char **amounts)
+TALER_TESTING_cmd_tip_pickup_with_ec (const char *label,
+                                      const char *merchant_url,
+                                      unsigned int http_status,
+                                      const char *authorize_reference,
+                                      const char **amounts,
+                                      enum TALER_ErrorCode ec)
 {
+  struct TALER_TESTING_Command cmd;
   struct TipPickupState *tps;
 
-  tps = GNUNET_new (struct TipPickupState);
-  tps->merchant_url = merchant_url;
-  tps->authorize_reference = authorize_reference;
-  tps->amounts = amounts;
-  tps->http_status = http_status;
-  {
-    struct TALER_TESTING_Command cmd = {
-      .cls = tps,
-      .label = label,
-      .run = &tip_pickup_run,
-      .cleanup = &tip_pickup_cleanup,
-      .traits = &tip_pickup_traits
-    };
-
-    return cmd;
-  }
+  cmd = TALER_TESTING_cmd_tip_pickup (label,
+                                      merchant_url,
+                                      http_status,
+                                      authorize_reference,
+                                      amounts);
+  tps = cmd.cls;
+  tps->expected_ec = ec;
+  return cmd;
 }
 
 

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



reply via email to

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