gnunet-svn
[Top][All Lists]
Advanced

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

[taler-exchange] 01/02: adapt withdraw2 API to support new tip-pickup de


From: gnunet
Subject: [taler-exchange] 01/02: adapt withdraw2 API to support new tip-pickup design (#6173)
Date: Sun, 12 Apr 2020 20:46:58 +0200

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

grothoff pushed a commit to branch master
in repository exchange.

commit 9e3371ae9b67a154f1c03f7003a10aa75f0e9470
Author: Christian Grothoff <address@hidden>
AuthorDate: Sun Apr 12 19:22:45 2020 +0200

    adapt withdraw2 API to support new tip-pickup design (#6173)
---
 src/include/taler_error_codes.h                    |  10 +-
 src/include/taler_exchange_service.h               |  63 ++-
 src/lib/Makefile.am                                |   1 +
 src/lib/exchange_api_withdraw.c                    | 551 +++------------------
 ...nge_api_withdraw.c => exchange_api_withdraw2.c} | 402 +++++----------
 5 files changed, 252 insertions(+), 775 deletions(-)

diff --git a/src/include/taler_error_codes.h b/src/include/taler_error_codes.h
index cff88857..2134e68d 100644
--- a/src/include/taler_error_codes.h
+++ b/src/include/taler_error_codes.h
@@ -416,6 +416,12 @@ enum TALER_ErrorCode
    */
   TALER_EC_WITHDRAW_REPLY_MALFORMED = 1118,
 
+  /**
+   * The client failed to unblind the blind signature. This error is not
+   * used in the protocol but created client-side.
+   */
+  TALER_EC_WITHDRAW_UNBLIND_FAILURE = 1119,
+
   /**
    * The exchange failed to obtain the transaction history of the given
    * reserve from the database. This response is provided with HTTP
@@ -1203,14 +1209,14 @@ enum TALER_ErrorCode
    * insufficient to satisfy the required amount for the contract.  The
    * client should revisit the logic used to calculate fees it must
    * cover. This response is provided with HTTP status code
-   * #MHD_HTTP_BAD_REQUEST.
+   * #MHD_HTTP_ACCEPTED.
    */
   TALER_EC_PAY_PAYMENT_INSUFFICIENT_DUE_TO_FEES = 2108,
 
   /**
    * Even if we do not consider deposit and wire fees, the payment is
    * insufficient to satisfy the required amount for the contract.  This
-   * response is provided with HTTP status code #MHD_HTTP_BAD_REQUEST.
+   * response is provided with HTTP status code #MHD_HTTP_ACCEPTED.
    */
   TALER_EC_PAY_PAYMENT_INSUFFICIENT = 2109,
 
diff --git a/src/include/taler_exchange_service.h 
b/src/include/taler_exchange_service.h
index 146d37a2..3505195f 100644
--- a/src/include/taler_exchange_service.h
+++ b/src/include/taler_exchange_service.h
@@ -1249,10 +1249,45 @@ TALER_EXCHANGE_withdraw (
   void *res_cb_cls);
 
 
+/**
+ * Cancel a withdraw status request.  This function cannot be used
+ * on a request handle if a response is already served for it.
+ *
+ * @param wh the withdraw handle
+ */
+void
+TALER_EXCHANGE_withdraw_cancel (struct TALER_EXCHANGE_WithdrawHandle *wh);
+
+
+/**
+ * Callbacks of this type are used to serve the result of submitting a
+ * withdraw request to a exchange without the (un)blinding factor.
+ *
+ * @param cls closure
+ * @param hr HTTP response data
+ * @param blind_sig blind signature over the coin, NULL on error
+ */
+typedef void
+(*TALER_EXCHANGE_Withdraw2Callback) (
+  void *cls,
+  const struct TALER_EXCHANGE_HttpResponse *hr,
+  const struct GNUNET_CRYPTO_RsaSignature *blind_sig);
+
+
+/**
+ * @brief A /reserves/$RESERVE_PUB/withdraw Handle, 2nd variant.
+ * This variant does not do the blinding/unblinding and only
+ * fetches the blind signature on the already blinded planchet.
+ * Used internally by the `struct TALER_EXCHANGE_WithdrawHandle`
+ * implementation as well as for the tipping logic of merchants.
+ */
+struct TALER_EXCHANGE_Withdraw2Handle;
+
+
 /**
  * Withdraw a coin from the exchange using a /reserves/$RESERVE_PUB/withdraw
- * request.  This API is typically used by a wallet to withdraw a tip
- * where the reserve's signature was created by the merchant already.
+ * request.  This API is typically used by a merchant to withdraw a tip
+ * where the blinding factor is unknown to the merchant.
  *
  * Note that to ensure that no money is lost in case of hardware
  * failures, the caller must have committed (most of) the arguments to
@@ -1260,26 +1295,20 @@ TALER_EXCHANGE_withdraw (
  * same arguments in case of failures.
  *
  * @param exchange the exchange handle; the exchange must be ready to operate
- * @param pk kind of coin to create
- * @param reserve_sig signature from the reserve authorizing the withdrawal
- * @param reserve_pub public key of the reserve to withdraw from
- * @param ps secrets of the planchet
- *        caller must have committed this value to disk before the call (with 
@a pk)
+ * @param pd planchet details of the planchet to withdraw
+ * @param reserve_priv private key of the reserve to withdraw from
  * @param res_cb the callback to call when the final result for this request 
is available
  * @param res_cb_cls closure for @a res_cb
  * @return NULL
  *         if the inputs are invalid (i.e. denomination key not with this 
exchange).
  *         In this case, the callback is not called.
  */
-struct TALER_EXCHANGE_WithdrawHandle *
-TALER_EXCHANGE_withdraw2 (
-  struct TALER_EXCHANGE_Handle *exchange,
-  const struct TALER_EXCHANGE_DenomPublicKey *pk,
-  const struct TALER_ReserveSignatureP *reserve_sig,
-  const struct TALER_ReservePublicKeyP *reserve_pub,
-  const struct TALER_PlanchetSecretsP *ps,
-  TALER_EXCHANGE_WithdrawCallback res_cb,
-  void *res_cb_cls);
+struct TALER_EXCHANGE_Withdraw2Handle *
+TALER_EXCHANGE_withdraw2 (struct TALER_EXCHANGE_Handle *exchange,
+                          const struct TALER_PlanchetDetail *pd,
+                          const struct TALER_ReservePrivateKeyP *reserve_priv,
+                          TALER_EXCHANGE_Withdraw2Callback res_cb,
+                          void *res_cb_cls);
 
 
 /**
@@ -1289,7 +1318,7 @@ TALER_EXCHANGE_withdraw2 (
  * @param wh the withdraw handle
  */
 void
-TALER_EXCHANGE_withdraw_cancel (struct TALER_EXCHANGE_WithdrawHandle *wh);
+TALER_EXCHANGE_withdraw2_cancel (struct TALER_EXCHANGE_Withdraw2Handle *wh);
 
 
 /* ********************* /refresh/melt+reveal ***************************** */
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
index 87f34309..830ecf65 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -35,6 +35,7 @@ libtalerexchange_la_SOURCES = \
   exchange_api_reserves_get.c \
   exchange_api_transfers_get.c \
   exchange_api_withdraw.c \
+  exchange_api_withdraw2.c \
   exchange_api_wire.c
 libtalerexchange_la_LIBADD = \
   libtalerauditor.la \
diff --git a/src/lib/exchange_api_withdraw.c b/src/lib/exchange_api_withdraw.c
index 8cd1ac01..6b20fb84 100644
--- a/src/lib/exchange_api_withdraw.c
+++ b/src/lib/exchange_api_withdraw.c
@@ -16,7 +16,7 @@
 */
 /**
  * @file lib/exchange_api_withdraw.c
- * @brief Implementation of the /reserves/$RESERVE_PUB/withdraw requests
+ * @brief Implementation of /reserves/$RESERVE_PUB/withdraw requests with 
blinding/unblinding
  * @author Christian Grothoff
  */
 #include "platform.h"
@@ -44,25 +44,19 @@ struct TALER_EXCHANGE_WithdrawHandle
   struct TALER_EXCHANGE_Handle *exchange;
 
   /**
-   * The url for this request.
+   * Handle for the actual (internal) withdraw operation.
    */
-  char *url;
+  struct TALER_EXCHANGE_Withdraw2Handle *wh2;
 
   /**
-   * Context for #TEH_curl_easy_post(). Keeps the data that must
-   * persist for Curl to make the upload.
-   */
-  struct TALER_CURL_PostContext ctx;
-
-  /**
-   * Handle for the request.
+   * Function to call with the result.
    */
-  struct GNUNET_CURL_Job *job;
+  TALER_EXCHANGE_WithdrawCallback cb;
 
   /**
-   * Function to call with the result.
+   * Closure for @a cb.
    */
-  TALER_EXCHANGE_WithdrawCallback cb;
+  void *cb_cls;
 
   /**
    * Secrets of the planchet.
@@ -74,409 +68,68 @@ struct TALER_EXCHANGE_WithdrawHandle
    */
   struct TALER_EXCHANGE_DenomPublicKey pk;
 
-  /**
-   * Closure for @a cb.
-   */
-  void *cb_cls;
-
   /**
    * Hash of the public key of the coin we are signing.
    */
   struct GNUNET_HashCode c_hash;
 
-  /**
-   * Public key of the reserve we are withdrawing from.
-   */
-  struct TALER_ReservePublicKeyP reserve_pub;
-
 };
 
 
-/**
- * We got a 200 OK response for the /reserves/$RESERVE_PUB/withdraw operation.
- * Extract the coin's signature and return it to the caller.  The signature we
- * get from the exchange is for the blinded value.  Thus, we first must
- * unblind it and then should verify its validity against our coin's hash.
- *
- * If everything checks out, we return the unblinded signature
- * to the application via the callback.
- *
- * @param wh operation handle
- * @param json reply from the exchange
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on errors
- */
-static int
-reserve_withdraw_ok (struct TALER_EXCHANGE_WithdrawHandle *wh,
-                     const json_t *json)
-{
-  struct GNUNET_CRYPTO_RsaSignature *blind_sig;
-  struct TALER_FreshCoin fc;
-  struct GNUNET_JSON_Specification spec[] = {
-    GNUNET_JSON_spec_rsa_signature ("ev_sig",
-                                    &blind_sig),
-    GNUNET_JSON_spec_end ()
-  };
-  struct TALER_EXCHANGE_HttpResponse hr = {
-    .reply = json,
-    .http_status = MHD_HTTP_OK
-  };
-
-  if (GNUNET_OK !=
-      GNUNET_JSON_parse (json,
-                         spec,
-                         NULL, NULL))
-  {
-    GNUNET_break_op (0);
-    return GNUNET_SYSERR;
-  }
-  if (GNUNET_OK !=
-      TALER_planchet_to_coin (&wh->pk.key,
-                              blind_sig,
-                              &wh->ps,
-                              &wh->c_hash,
-                              &fc))
-  {
-    GNUNET_break_op (0);
-    GNUNET_JSON_parse_free (spec);
-    return GNUNET_SYSERR;
-  }
-  GNUNET_JSON_parse_free (spec);
-
-  /* signature is valid, return it to the application */
-  wh->cb (wh->cb_cls,
-          &hr,
-          &fc.sig);
-  /* make sure callback isn't called again after return */
-  wh->cb = NULL;
-  GNUNET_CRYPTO_rsa_signature_free (fc.sig.rsa_signature);
-  return GNUNET_OK;
-}
-
-
-/**
- * We got a 409 CONFLICT response for the /reserves/$RESERVE_PUB/withdraw 
operation.
- * Check the signatures on the withdraw transactions in the provided
- * history and that the balances add up.  We don't do anything directly
- * with the information, as the JSON will be returned to the application.
- * However, our job is ensuring that the exchange followed the protocol, and
- * this in particular means checking all of the signatures in the history.
- *
- * @param wh operation handle
- * @param json reply from the exchange
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on errors
- */
-static int
-reserve_withdraw_payment_required (
-  struct TALER_EXCHANGE_WithdrawHandle *wh,
-  const json_t *json)
-{
-  struct TALER_Amount balance;
-  struct TALER_Amount balance_from_history;
-  struct TALER_Amount requested_amount;
-  json_t *history;
-  size_t len;
-  struct GNUNET_JSON_Specification spec[] = {
-    TALER_JSON_spec_amount ("balance", &balance),
-    GNUNET_JSON_spec_end ()
-  };
-
-  if (GNUNET_OK !=
-      GNUNET_JSON_parse (json,
-                         spec,
-                         NULL, NULL))
-  {
-    GNUNET_break_op (0);
-    return GNUNET_SYSERR;
-  }
-  history = json_object_get (json,
-                             "history");
-  if (NULL == history)
-  {
-    GNUNET_break_op (0);
-    return GNUNET_SYSERR;
-  }
-
-  /* go over transaction history and compute
-     total incoming and outgoing amounts */
-  len = json_array_size (history);
-  {
-    struct TALER_EXCHANGE_ReserveHistory *rhistory;
-
-    /* Use heap allocation as "len" may be very big and thus this may
-       not fit on the stack. Use "GNUNET_malloc_large" as a malicious
-       exchange may theoretically try to crash us by giving a history
-       that does not fit into our memory. */
-    rhistory = GNUNET_malloc_large (sizeof (struct
-                                            TALER_EXCHANGE_ReserveHistory)
-                                    * len);
-    if (NULL == rhistory)
-    {
-      GNUNET_break (0);
-      return GNUNET_SYSERR;
-    }
-
-    if (GNUNET_OK !=
-        TALER_EXCHANGE_parse_reserve_history (wh->exchange,
-                                              history,
-                                              &wh->reserve_pub,
-                                              balance.currency,
-                                              &balance_from_history,
-                                              len,
-                                              rhistory))
-    {
-      GNUNET_break_op (0);
-      TALER_EXCHANGE_free_reserve_history (rhistory,
-                                           len);
-      return GNUNET_SYSERR;
-    }
-    TALER_EXCHANGE_free_reserve_history (rhistory,
-                                         len);
-  }
-
-  if (0 !=
-      TALER_amount_cmp (&balance_from_history,
-                        &balance))
-  {
-    /* exchange cannot add up balances!? */
-    GNUNET_break_op (0);
-    return GNUNET_SYSERR;
-  }
-  /* Compute how much we expected to charge to the reserve */
-  if (0 >
-      TALER_amount_add (&requested_amount,
-                        &wh->pk.value,
-                        &wh->pk.fee_withdraw))
-  {
-    /* Overflow here? Very strange, our CPU must be fried... */
-    GNUNET_break (0);
-    return GNUNET_SYSERR;
-  }
-  /* Check that funds were really insufficient */
-  if (0 >= TALER_amount_cmp (&requested_amount,
-                             &balance))
-  {
-    /* Requested amount is smaller or equal to reported balance,
-       so this should not have failed. */
-    GNUNET_break_op (0);
-    return GNUNET_SYSERR;
-  }
-  return GNUNET_OK;
-}
-
-
 /**
  * Function called when we're done processing the
  * HTTP /reserves/$RESERVE_PUB/withdraw request.
  *
  * @param cls the `struct TALER_EXCHANGE_WithdrawHandle`
- * @param response_code HTTP response code, 0 on error
- * @param response parsed JSON result, NULL on error
+ * @param hr HTTP response data
+ * @param blind_sig blind signature over the coin, NULL on error
  */
 static void
-handle_reserve_withdraw_finished (void *cls,
-                                  long response_code,
-                                  const void *response)
+handle_reserve_withdraw_finished (
+  void *cls,
+  const struct TALER_EXCHANGE_HttpResponse *hr,
+  const struct GNUNET_CRYPTO_RsaSignature *blind_sig)
 {
   struct TALER_EXCHANGE_WithdrawHandle *wh = cls;
-  const json_t *j = response;
-  struct TALER_EXCHANGE_HttpResponse hr = {
-    .reply = j,
-    .http_status = (unsigned int) response_code
-  };
 
-  wh->job = NULL;
-  switch (response_code)
+  wh->wh2 = NULL;
+  if (MHD_HTTP_OK != hr->http_status)
   {
-  case 0:
-    hr.ec = TALER_EC_INVALID_RESPONSE;
-    break;
-  case MHD_HTTP_OK:
-    if (GNUNET_OK !=
-        reserve_withdraw_ok (wh,
-                             j))
-    {
-      GNUNET_break_op (0);
-      hr.http_status = 0;
-      hr.ec = TALER_EC_WITHDRAW_REPLY_MALFORMED;
-      break;
-    }
-    GNUNET_assert (NULL == wh->cb);
-    TALER_EXCHANGE_withdraw_cancel (wh);
-    return;
-  case MHD_HTTP_BAD_REQUEST:
-    /* This should never happen, either us or the exchange is buggy
-       (or API version conflict); just pass JSON reply to the application */
-    hr.ec = TALER_JSON_get_error_code (j);
-    hr.hint = TALER_JSON_get_error_hint (j);
-    break;
-  case MHD_HTTP_CONFLICT:
-    /* The exchange says that the reserve has insufficient funds;
-       check the signatures in the history... */
+    wh->cb (wh->cb_cls,
+            hr,
+            NULL);
+  }
+  else
+  {
+    struct TALER_FreshCoin fc;
+
     if (GNUNET_OK !=
-        reserve_withdraw_payment_required (wh,
-                                           j))
+        TALER_planchet_to_coin (&wh->pk.key,
+                                blind_sig,
+                                &wh->ps,
+                                &wh->c_hash,
+                                &fc))
     {
-      GNUNET_break_op (0);
-      hr.http_status = 0;
-      hr.ec = TALER_EC_WITHDRAW_REPLY_MALFORMED;
+      struct TALER_EXCHANGE_HttpResponse hrx = {
+        .reply = hr->reply,
+        .http_status = 0,
+        .ec = TALER_EC_WITHDRAW_UNBLIND_FAILURE
+      };
+
+      wh->cb (wh->cb_cls,
+              &hrx,
+              NULL);
     }
     else
     {
-      hr.ec = TALER_JSON_get_error_code (j);
-      hr.hint = TALER_JSON_get_error_hint (j);
+      wh->cb (wh->cb_cls,
+              hr,
+              &fc.sig);
+      GNUNET_CRYPTO_rsa_signature_free (fc.sig.rsa_signature);
     }
-    break;
-  case MHD_HTTP_FORBIDDEN:
-    GNUNET_break_op (0);
-    /* Nothing really to verify, exchange says one of the signatures is
-       invalid; as we checked them, this should never happen, we
-       should pass the JSON reply to the application */
-    hr.ec = TALER_JSON_get_error_code (j);
-    hr.hint = TALER_JSON_get_error_hint (j);
-    break;
-  case MHD_HTTP_NOT_FOUND:
-    /* Nothing really to verify, the exchange basically just says
-       that it doesn't know this reserve.  Can happen if we
-       query before the wire transfer went through.
-       We should simply pass the JSON reply to the application. */
-    hr.ec = TALER_JSON_get_error_code (j);
-    hr.hint = TALER_JSON_get_error_hint (j);
-    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 (j);
-    hr.hint = TALER_JSON_get_error_hint (j);
-    break;
-  default:
-    /* unexpected response code */
-    GNUNET_break_op (0);
-    hr.ec = TALER_JSON_get_error_code (j);
-    hr.hint = TALER_JSON_get_error_hint (j);
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "Unexpected response code %u/%d\n",
-                (unsigned int) response_code,
-                (int) hr.ec);
-    break;
-  }
-  if (NULL != wh->cb)
-  {
-    wh->cb (wh->cb_cls,
-            &hr,
-            NULL);
-    wh->cb = NULL;
-  }
-  TALER_EXCHANGE_withdraw_cancel (wh);
-}
-
-
-/**
- * Helper function for #TALER_EXCHANGE_withdraw2() and
- * #TALER_EXCHANGE_withdraw().
- *
- * @param exchange the exchange handle; the exchange must be ready to operate
- * @param pk kind of coin to create
- * @param reserve_sig signature from the reserve authorizing the withdrawal
- * @param reserve_pub public key of the reserve to withdraw from
- * @param ps secrets of the planchet
- *        caller must have committed this value to disk before the call (with 
@a pk)
- * @param pd planchet details matching @a ps
- * @param c_hash hash over the coin's public key
- * @param res_cb the callback to call when the final result for this request 
is available
- * @param res_cb_cls closure for @a res_cb
- * @return NULL
- *         if the inputs are invalid (i.e. denomination key not with this 
exchange).
- *         In this case, the callback is not called.
- */
-struct TALER_EXCHANGE_WithdrawHandle *
-reserve_withdraw_internal (struct TALER_EXCHANGE_Handle *exchange,
-                           const struct TALER_EXCHANGE_DenomPublicKey *pk,
-                           const struct TALER_ReserveSignatureP *reserve_sig,
-                           const struct TALER_ReservePublicKeyP *reserve_pub,
-                           const struct TALER_PlanchetSecretsP *ps,
-                           const struct TALER_PlanchetDetail *pd,
-                           const struct GNUNET_HashCode *c_hash,
-                           TALER_EXCHANGE_WithdrawCallback res_cb,
-                           void *res_cb_cls)
-{
-  struct TALER_EXCHANGE_WithdrawHandle *wh;
-  struct GNUNET_CURL_Context *ctx;
-  json_t *withdraw_obj;
-  CURL *eh;
-  struct GNUNET_HashCode h_denom_pub;
-  char arg_str[sizeof (struct TALER_ReservePublicKeyP) * 2 + 32];
 
-  {
-    char pub_str[sizeof (struct TALER_ReservePublicKeyP) * 2];
-    char *end;
-
-    end = GNUNET_STRINGS_data_to_string (reserve_pub,
-                                         sizeof (struct
-                                                 TALER_ReservePublicKeyP),
-                                         pub_str,
-                                         sizeof (pub_str));
-    *end = '\0';
-    GNUNET_snprintf (arg_str,
-                     sizeof (arg_str),
-                     "/reserves/%s/withdraw",
-                     pub_str);
   }
-  wh = GNUNET_new (struct TALER_EXCHANGE_WithdrawHandle);
-  wh->exchange = exchange;
-  wh->cb = res_cb;
-  wh->cb_cls = res_cb_cls;
-  wh->pk = *pk;
-  wh->pk.key.rsa_public_key
-    = GNUNET_CRYPTO_rsa_public_key_dup (pk->key.rsa_public_key);
-  wh->reserve_pub = *reserve_pub;
-  wh->c_hash = *c_hash;
-  GNUNET_CRYPTO_rsa_public_key_hash (pk->key.rsa_public_key,
-                                     &h_denom_pub);
-  withdraw_obj = json_pack ("{s:o, s:o," /* denom_pub_hash and coin_ev */
-                            " s:o}",/* reserve_pub and reserve_sig */
-                            "denom_pub_hash", GNUNET_JSON_from_data_auto (
-                              &h_denom_pub),
-                            "coin_ev", GNUNET_JSON_from_data (pd->coin_ev,
-                                                              
pd->coin_ev_size),
-                            "reserve_sig", GNUNET_JSON_from_data_auto (
-                              reserve_sig));
-  if (NULL == withdraw_obj)
-  {
-    GNUNET_break (0);
-    GNUNET_CRYPTO_rsa_public_key_free (wh->pk.key.rsa_public_key);
-    GNUNET_free (wh);
-    return NULL;
-  }
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-              "Attempting to withdraw from reserve %s\n",
-              TALER_B2S (reserve_pub));
-  wh->ps = *ps;
-  wh->url = TEAH_path_to_url (exchange,
-                              arg_str);
-  eh = TALER_EXCHANGE_curl_easy_get_ (wh->url);
-  if ( (NULL == eh) ||
-       (GNUNET_OK !=
-        TALER_curl_easy_post (&wh->ctx,
-                              eh,
-                              withdraw_obj)) )
-  {
-    GNUNET_break (0);
-    if (NULL != eh)
-      curl_easy_cleanup (eh);
-    json_decref (withdraw_obj);
-    GNUNET_free (wh->url);
-    GNUNET_CRYPTO_rsa_public_key_free (wh->pk.key.rsa_public_key);
-    GNUNET_free (wh);
-    return NULL;
-  }
-  json_decref (withdraw_obj);
-  ctx = TEAH_handle_to_context (exchange);
-  wh->job = GNUNET_CURL_job_add2 (ctx,
-                                  eh,
-                                  wh->ctx.headers,
-                                  &handle_reserve_withdraw_finished,
-                                  wh);
-  return wh;
+  TALER_EXCHANGE_withdraw_cancel (wh);
 }
 
 
@@ -507,114 +160,32 @@ TALER_EXCHANGE_withdraw (
   TALER_EXCHANGE_WithdrawCallback res_cb,
   void *res_cb_cls)
 {
-  struct TALER_Amount amount_with_fee;
-  struct TALER_ReserveSignatureP reserve_sig;
-  struct TALER_WithdrawRequestPS req;
   struct TALER_PlanchetDetail pd;
   struct TALER_EXCHANGE_WithdrawHandle *wh;
-  struct GNUNET_HashCode c_hash;
-
-  GNUNET_CRYPTO_eddsa_key_get_public (&reserve_priv->eddsa_priv,
-                                      &req.reserve_pub.eddsa_pub);
-  req.purpose.size = htonl (sizeof (struct TALER_WithdrawRequestPS));
-  req.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW);
-  if (0 >
-      TALER_amount_add (&amount_with_fee,
-                        &pk->fee_withdraw,
-                        &pk->value))
-  {
-    /* exchange gave us denomination keys that overflow like this!? */
-    GNUNET_break_op (0);
-    return NULL;
-  }
-  TALER_amount_hton (&req.amount_with_fee,
-                     &amount_with_fee);
-  TALER_amount_hton (&req.withdraw_fee,
-                     &pk->fee_withdraw);
-  if (GNUNET_OK !=
-      TALER_planchet_prepare (&pk->key,
-                              ps,
-                              &c_hash,
-                              &pd))
-  {
-    GNUNET_break_op (0);
-    return NULL;
-  }
-  req.h_denomination_pub = pd.denom_pub_hash;
-  GNUNET_CRYPTO_hash (pd.coin_ev,
-                      pd.coin_ev_size,
-                      &req.h_coin_envelope);
-  GNUNET_CRYPTO_eddsa_sign (&reserve_priv->eddsa_priv,
-                            &req,
-                            &reserve_sig.eddsa_signature);
-  wh = reserve_withdraw_internal (exchange,
-                                  pk,
-                                  &reserve_sig,
-                                  &req.reserve_pub,
-                                  ps,
-                                  &pd,
-                                  &c_hash,
-                                  res_cb,
-                                  res_cb_cls);
-  GNUNET_free (pd.coin_ev);
-  return wh;
-}
-
-
-/**
- * Withdraw a coin from the exchange using a /reserve/withdraw
- * request.  This API is typically used by a wallet to withdraw a tip
- * where the reserve's signature was created by the merchant already.
- *
- * Note that to ensure that no money is lost in case of hardware
- * failures, the caller must have committed (most of) the arguments to
- * disk before calling, and be ready to repeat the request with the
- * same arguments in case of failures.
- *
- * @param exchange the exchange handle; the exchange must be ready to operate
- * @param pk kind of coin to create
- * @param reserve_sig signature from the reserve authorizing the withdrawal
- * @param reserve_pub public key of the reserve to withdraw from
- * @param ps secrets of the planchet
- *        caller must have committed this value to disk before the call (with 
@a pk)
- * @param res_cb the callback to call when the final result for this request 
is available
- * @param res_cb_cls closure for @a res_cb
- * @return NULL
- *         if the inputs are invalid (i.e. denomination key not with this 
exchange).
- *         In this case, the callback is not called.
- */
-struct TALER_EXCHANGE_WithdrawHandle *
-TALER_EXCHANGE_withdraw2 (
-  struct TALER_EXCHANGE_Handle *exchange,
-  const struct TALER_EXCHANGE_DenomPublicKey *pk,
-  const struct TALER_ReserveSignatureP *reserve_sig,
-  const struct TALER_ReservePublicKeyP *reserve_pub,
-  const struct TALER_PlanchetSecretsP *ps,
-  TALER_EXCHANGE_WithdrawCallback res_cb,
-  void *res_cb_cls)
-{
-  struct TALER_EXCHANGE_WithdrawHandle *wh;
-  struct GNUNET_HashCode c_hash;
-  struct TALER_PlanchetDetail pd;
 
+  wh = GNUNET_new (struct TALER_EXCHANGE_WithdrawHandle);
+  wh->exchange = exchange;
+  wh->cb = res_cb;
+  wh->cb_cls = res_cb_cls;
+  wh->pk = *pk;
+  wh->ps = *ps;
   if (GNUNET_OK !=
       TALER_planchet_prepare (&pk->key,
                               ps,
-                              &c_hash,
+                              &wh->c_hash,
                               &pd))
   {
     GNUNET_break_op (0);
+    GNUNET_free (wh);
     return NULL;
   }
-  wh = reserve_withdraw_internal (exchange,
-                                  pk,
-                                  reserve_sig,
-                                  reserve_pub,
-                                  ps,
-                                  &pd,
-                                  &c_hash,
-                                  res_cb,
-                                  res_cb_cls);
+  wh->pk.key.rsa_public_key
+    = GNUNET_CRYPTO_rsa_public_key_dup (pk->key.rsa_public_key);
+  wh->wh2 = TALER_EXCHANGE_withdraw2 (exchange,
+                                      &pd,
+                                      reserve_priv,
+                                      &handle_reserve_withdraw_finished,
+                                      wh);
   GNUNET_free (pd.coin_ev);
   return wh;
 }
@@ -629,13 +200,11 @@ TALER_EXCHANGE_withdraw2 (
 void
 TALER_EXCHANGE_withdraw_cancel (struct TALER_EXCHANGE_WithdrawHandle *wh)
 {
-  if (NULL != wh->job)
+  if (NULL != wh->wh2)
   {
-    GNUNET_CURL_job_cancel (wh->job);
-    wh->job = NULL;
+    TALER_EXCHANGE_withdraw2_cancel (wh->wh2);
+    wh->wh2 = NULL;
   }
-  GNUNET_free (wh->url);
-  TALER_curl_easy_post_finished (&wh->ctx);
   GNUNET_CRYPTO_rsa_public_key_free (wh->pk.key.rsa_public_key);
   GNUNET_free (wh);
 }
diff --git a/src/lib/exchange_api_withdraw.c b/src/lib/exchange_api_withdraw2.c
similarity index 55%
copy from src/lib/exchange_api_withdraw.c
copy to src/lib/exchange_api_withdraw2.c
index 8cd1ac01..f9468927 100644
--- a/src/lib/exchange_api_withdraw.c
+++ b/src/lib/exchange_api_withdraw2.c
@@ -15,8 +15,8 @@
   <http://www.gnu.org/licenses/>
 */
 /**
- * @file lib/exchange_api_withdraw.c
- * @brief Implementation of the /reserves/$RESERVE_PUB/withdraw requests
+ * @file lib/exchange_api_withdraw2.c
+ * @brief Implementation of /reserves/$RESERVE_PUB/withdraw requests without 
blinding/unblinding
  * @author Christian Grothoff
  */
 #include "platform.h"
@@ -35,7 +35,7 @@
 /**
  * @brief A Withdraw Handle
  */
-struct TALER_EXCHANGE_WithdrawHandle
+struct TALER_EXCHANGE_Withdraw2Handle
 {
 
   /**
@@ -48,12 +48,6 @@ struct TALER_EXCHANGE_WithdrawHandle
    */
   char *url;
 
-  /**
-   * Context for #TEH_curl_easy_post(). Keeps the data that must
-   * persist for Curl to make the upload.
-   */
-  struct TALER_CURL_PostContext ctx;
-
   /**
    * Handle for the request.
    */
@@ -62,27 +56,23 @@ struct TALER_EXCHANGE_WithdrawHandle
   /**
    * Function to call with the result.
    */
-  TALER_EXCHANGE_WithdrawCallback cb;
+  TALER_EXCHANGE_Withdraw2Callback cb;
 
   /**
-   * Secrets of the planchet.
-   */
-  struct TALER_PlanchetSecretsP ps;
-
-  /**
-   * Denomination key we are withdrawing.
+   * Closure for @a cb.
    */
-  struct TALER_EXCHANGE_DenomPublicKey pk;
+  void *cb_cls;
 
   /**
-   * Closure for @a cb.
+   * Context for #TEH_curl_easy_post(). Keeps the data that must
+   * persist for Curl to make the upload.
    */
-  void *cb_cls;
+  struct TALER_CURL_PostContext post_ctx;
 
   /**
-   * Hash of the public key of the coin we are signing.
+   * Total amount requested (value plus withdraw fee).
    */
-  struct GNUNET_HashCode c_hash;
+  struct TALER_Amount requested_amount;
 
   /**
    * Public key of the reserve we are withdrawing from.
@@ -106,11 +96,10 @@ struct TALER_EXCHANGE_WithdrawHandle
  * @return #GNUNET_OK on success, #GNUNET_SYSERR on errors
  */
 static int
-reserve_withdraw_ok (struct TALER_EXCHANGE_WithdrawHandle *wh,
+reserve_withdraw_ok (struct TALER_EXCHANGE_Withdraw2Handle *wh,
                      const json_t *json)
 {
   struct GNUNET_CRYPTO_RsaSignature *blind_sig;
-  struct TALER_FreshCoin fc;
   struct GNUNET_JSON_Specification spec[] = {
     GNUNET_JSON_spec_rsa_signature ("ev_sig",
                                     &blind_sig),
@@ -129,26 +118,14 @@ reserve_withdraw_ok (struct TALER_EXCHANGE_WithdrawHandle 
*wh,
     GNUNET_break_op (0);
     return GNUNET_SYSERR;
   }
-  if (GNUNET_OK !=
-      TALER_planchet_to_coin (&wh->pk.key,
-                              blind_sig,
-                              &wh->ps,
-                              &wh->c_hash,
-                              &fc))
-  {
-    GNUNET_break_op (0);
-    GNUNET_JSON_parse_free (spec);
-    return GNUNET_SYSERR;
-  }
-  GNUNET_JSON_parse_free (spec);
 
   /* signature is valid, return it to the application */
   wh->cb (wh->cb_cls,
           &hr,
-          &fc.sig);
+          blind_sig);
   /* make sure callback isn't called again after return */
   wh->cb = NULL;
-  GNUNET_CRYPTO_rsa_signature_free (fc.sig.rsa_signature);
+  GNUNET_JSON_parse_free (spec);
   return GNUNET_OK;
 }
 
@@ -167,12 +144,11 @@ reserve_withdraw_ok (struct TALER_EXCHANGE_WithdrawHandle 
*wh,
  */
 static int
 reserve_withdraw_payment_required (
-  struct TALER_EXCHANGE_WithdrawHandle *wh,
+  struct TALER_EXCHANGE_Withdraw2Handle *wh,
   const json_t *json)
 {
   struct TALER_Amount balance;
   struct TALER_Amount balance_from_history;
-  struct TALER_Amount requested_amount;
   json_t *history;
   size_t len;
   struct GNUNET_JSON_Specification spec[] = {
@@ -241,18 +217,8 @@ reserve_withdraw_payment_required (
     GNUNET_break_op (0);
     return GNUNET_SYSERR;
   }
-  /* Compute how much we expected to charge to the reserve */
-  if (0 >
-      TALER_amount_add (&requested_amount,
-                        &wh->pk.value,
-                        &wh->pk.fee_withdraw))
-  {
-    /* Overflow here? Very strange, our CPU must be fried... */
-    GNUNET_break (0);
-    return GNUNET_SYSERR;
-  }
   /* Check that funds were really insufficient */
-  if (0 >= TALER_amount_cmp (&requested_amount,
+  if (0 >= TALER_amount_cmp (&wh->requested_amount,
                              &balance))
   {
     /* Requested amount is smaller or equal to reported balance,
@@ -277,7 +243,7 @@ handle_reserve_withdraw_finished (void *cls,
                                   long response_code,
                                   const void *response)
 {
-  struct TALER_EXCHANGE_WithdrawHandle *wh = cls;
+  struct TALER_EXCHANGE_Withdraw2Handle *wh = cls;
   const json_t *j = response;
   struct TALER_EXCHANGE_HttpResponse hr = {
     .reply = j,
@@ -301,7 +267,7 @@ handle_reserve_withdraw_finished (void *cls,
       break;
     }
     GNUNET_assert (NULL == wh->cb);
-    TALER_EXCHANGE_withdraw_cancel (wh);
+    TALER_EXCHANGE_withdraw2_cancel (wh);
     return;
   case MHD_HTTP_BAD_REQUEST:
     /* This should never happen, either us or the exchange is buggy
@@ -366,13 +332,19 @@ handle_reserve_withdraw_finished (void *cls,
             NULL);
     wh->cb = NULL;
   }
-  TALER_EXCHANGE_withdraw_cancel (wh);
+  TALER_EXCHANGE_withdraw2_cancel (wh);
 }
 
 
 /**
- * Helper function for #TALER_EXCHANGE_withdraw2() and
- * #TALER_EXCHANGE_withdraw().
+ * Withdraw a coin from the exchange using a /reserve/withdraw
+ * request.  This API is typically used by a wallet to withdraw a tip
+ * where the reserve's signature was created by the merchant already.
+ *
+ * Note that to ensure that no money is lost in case of hardware
+ * failures, the caller must have committed (most of) the arguments to
+ * disk before calling, and be ready to repeat the request with the
+ * same arguments in case of failures.
  *
  * @param exchange the exchange handle; the exchange must be ready to operate
  * @param pk kind of coin to create
@@ -380,242 +352,143 @@ handle_reserve_withdraw_finished (void *cls,
  * @param reserve_pub public key of the reserve to withdraw from
  * @param ps secrets of the planchet
  *        caller must have committed this value to disk before the call (with 
@a pk)
- * @param pd planchet details matching @a ps
- * @param c_hash hash over the coin's public key
  * @param res_cb the callback to call when the final result for this request 
is available
  * @param res_cb_cls closure for @a res_cb
  * @return NULL
  *         if the inputs are invalid (i.e. denomination key not with this 
exchange).
  *         In this case, the callback is not called.
  */
-struct TALER_EXCHANGE_WithdrawHandle *
-reserve_withdraw_internal (struct TALER_EXCHANGE_Handle *exchange,
-                           const struct TALER_EXCHANGE_DenomPublicKey *pk,
-                           const struct TALER_ReserveSignatureP *reserve_sig,
-                           const struct TALER_ReservePublicKeyP *reserve_pub,
-                           const struct TALER_PlanchetSecretsP *ps,
-                           const struct TALER_PlanchetDetail *pd,
-                           const struct GNUNET_HashCode *c_hash,
-                           TALER_EXCHANGE_WithdrawCallback res_cb,
-                           void *res_cb_cls)
+struct TALER_EXCHANGE_Withdraw2Handle *
+TALER_EXCHANGE_withdraw2 (
+  struct TALER_EXCHANGE_Handle *exchange,
+  const struct TALER_PlanchetDetail *pd,
+  const struct TALER_ReservePrivateKeyP *reserve_priv,
+  TALER_EXCHANGE_Withdraw2Callback res_cb,
+  void *res_cb_cls)
 {
-  struct TALER_EXCHANGE_WithdrawHandle *wh;
-  struct GNUNET_CURL_Context *ctx;
-  json_t *withdraw_obj;
-  CURL *eh;
-  struct GNUNET_HashCode h_denom_pub;
+  struct TALER_EXCHANGE_Withdraw2Handle *wh;
+  const struct TALER_EXCHANGE_Keys *keys;
+  const struct TALER_EXCHANGE_DenomPublicKey *dk;
+  struct TALER_ReserveSignatureP reserve_sig;
   char arg_str[sizeof (struct TALER_ReservePublicKeyP) * 2 + 32];
 
+  keys = TALER_EXCHANGE_get_keys (exchange);
+  if (NULL == keys)
   {
-    char pub_str[sizeof (struct TALER_ReservePublicKeyP) * 2];
-    char *end;
-
-    end = GNUNET_STRINGS_data_to_string (reserve_pub,
-                                         sizeof (struct
-                                                 TALER_ReservePublicKeyP),
-                                         pub_str,
-                                         sizeof (pub_str));
-    *end = '\0';
-    GNUNET_snprintf (arg_str,
-                     sizeof (arg_str),
-                     "/reserves/%s/withdraw",
-                     pub_str);
+    GNUNET_break (0);
+    return NULL;
   }
-  wh = GNUNET_new (struct TALER_EXCHANGE_WithdrawHandle);
-  wh->exchange = exchange;
-  wh->cb = res_cb;
-  wh->cb_cls = res_cb_cls;
-  wh->pk = *pk;
-  wh->pk.key.rsa_public_key
-    = GNUNET_CRYPTO_rsa_public_key_dup (pk->key.rsa_public_key);
-  wh->reserve_pub = *reserve_pub;
-  wh->c_hash = *c_hash;
-  GNUNET_CRYPTO_rsa_public_key_hash (pk->key.rsa_public_key,
-                                     &h_denom_pub);
-  withdraw_obj = json_pack ("{s:o, s:o," /* denom_pub_hash and coin_ev */
-                            " s:o}",/* reserve_pub and reserve_sig */
-                            "denom_pub_hash", GNUNET_JSON_from_data_auto (
-                              &h_denom_pub),
-                            "coin_ev", GNUNET_JSON_from_data (pd->coin_ev,
-                                                              
pd->coin_ev_size),
-                            "reserve_sig", GNUNET_JSON_from_data_auto (
-                              reserve_sig));
-  if (NULL == withdraw_obj)
+  dk = TALER_EXCHANGE_get_denomination_key_by_hash (keys,
+                                                    &pd->denom_pub_hash);
+  if (NULL == dk)
   {
     GNUNET_break (0);
-    GNUNET_CRYPTO_rsa_public_key_free (wh->pk.key.rsa_public_key);
-    GNUNET_free (wh);
     return NULL;
   }
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-              "Attempting to withdraw from reserve %s\n",
-              TALER_B2S (reserve_pub));
-  wh->ps = *ps;
-  wh->url = TEAH_path_to_url (exchange,
-                              arg_str);
-  eh = TALER_EXCHANGE_curl_easy_get_ (wh->url);
-  if ( (NULL == eh) ||
-       (GNUNET_OK !=
-        TALER_curl_easy_post (&wh->ctx,
-                              eh,
-                              withdraw_obj)) )
+  wh = GNUNET_new (struct TALER_EXCHANGE_Withdraw2Handle);
+  wh->exchange = exchange;
+  wh->cb = res_cb;
+  wh->cb_cls = res_cb_cls;
+  /* Compute how much we expected to charge to the reserve */
+  if (0 >
+      TALER_amount_add (&wh->requested_amount,
+                        &dk->value,
+                        &dk->fee_withdraw))
   {
+    /* Overflow here? Very strange, our CPU must be fried... */
     GNUNET_break (0);
-    if (NULL != eh)
-      curl_easy_cleanup (eh);
-    json_decref (withdraw_obj);
-    GNUNET_free (wh->url);
-    GNUNET_CRYPTO_rsa_public_key_free (wh->pk.key.rsa_public_key);
     GNUNET_free (wh);
     return NULL;
   }
-  json_decref (withdraw_obj);
-  ctx = TEAH_handle_to_context (exchange);
-  wh->job = GNUNET_CURL_job_add2 (ctx,
-                                  eh,
-                                  wh->ctx.headers,
-                                  &handle_reserve_withdraw_finished,
-                                  wh);
-  return wh;
-}
-
-
-/**
- * Withdraw a coin from the exchange using a /reserve/withdraw request.  Note
- * that to ensure that no money is lost in case of hardware failures,
- * the caller must have committed (most of) the arguments to disk
- * before calling, and be ready to repeat the request with the same
- * arguments in case of failures.
- *
- * @param exchange the exchange handle; the exchange must be ready to operate
- * @param pk kind of coin to create
- * @param reserve_priv private key of the reserve to withdraw from
- * @param ps secrets of the planchet
- *        caller must have committed this value to disk before the call (with 
@a pk)
- * @param res_cb the callback to call when the final result for this request 
is available
- * @param res_cb_cls closure for the above callback
- * @return handle for the operation on success, NULL on error, i.e.
- *         if the inputs are invalid (i.e. denomination key not with this 
exchange).
- *         In this case, the callback is not called.
- */
-struct TALER_EXCHANGE_WithdrawHandle *
-TALER_EXCHANGE_withdraw (
-  struct TALER_EXCHANGE_Handle *exchange,
-  const struct TALER_EXCHANGE_DenomPublicKey *pk,
-  const struct TALER_ReservePrivateKeyP *reserve_priv,
-  const struct TALER_PlanchetSecretsP *ps,
-  TALER_EXCHANGE_WithdrawCallback res_cb,
-  void *res_cb_cls)
-{
-  struct TALER_Amount amount_with_fee;
-  struct TALER_ReserveSignatureP reserve_sig;
-  struct TALER_WithdrawRequestPS req;
-  struct TALER_PlanchetDetail pd;
-  struct TALER_EXCHANGE_WithdrawHandle *wh;
-  struct GNUNET_HashCode c_hash;
 
   GNUNET_CRYPTO_eddsa_key_get_public (&reserve_priv->eddsa_priv,
-                                      &req.reserve_pub.eddsa_pub);
-  req.purpose.size = htonl (sizeof (struct TALER_WithdrawRequestPS));
-  req.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW);
-  if (0 >
-      TALER_amount_add (&amount_with_fee,
-                        &pk->fee_withdraw,
-                        &pk->value))
+                                      &wh->reserve_pub.eddsa_pub);
+
   {
-    /* exchange gave us denomination keys that overflow like this!? */
-    GNUNET_break_op (0);
-    return NULL;
+    char pub_str[sizeof (struct TALER_ReservePublicKeyP) * 2];
+    char *end;
+
+    end = GNUNET_STRINGS_data_to_string (
+      &wh->reserve_pub,
+      sizeof (struct TALER_ReservePublicKeyP),
+      pub_str,
+      sizeof (pub_str));
+    *end = '\0';
+    GNUNET_snprintf (arg_str,
+                     sizeof (arg_str),
+                     "/reserves/%s/withdraw",
+                     pub_str);
   }
-  TALER_amount_hton (&req.amount_with_fee,
-                     &amount_with_fee);
-  TALER_amount_hton (&req.withdraw_fee,
-                     &pk->fee_withdraw);
-  if (GNUNET_OK !=
-      TALER_planchet_prepare (&pk->key,
-                              ps,
-                              &c_hash,
-                              &pd))
   {
-    GNUNET_break_op (0);
-    return NULL;
+    struct TALER_WithdrawRequestPS req = {
+      .purpose.size = htonl (sizeof (struct TALER_WithdrawRequestPS)),
+      .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW),
+      .reserve_pub = wh->reserve_pub,
+      .h_denomination_pub = pd->denom_pub_hash
+    };
+
+    TALER_amount_hton (&req.amount_with_fee,
+                       &wh->requested_amount);
+    TALER_amount_hton (&req.withdraw_fee,
+                       &dk->fee_withdraw);
+    GNUNET_CRYPTO_hash (pd->coin_ev,
+                        pd->coin_ev_size,
+                        &req.h_coin_envelope);
+    GNUNET_CRYPTO_eddsa_sign (&reserve_priv->eddsa_priv,
+                              &req,
+                              &reserve_sig.eddsa_signature);
   }
-  req.h_denomination_pub = pd.denom_pub_hash;
-  GNUNET_CRYPTO_hash (pd.coin_ev,
-                      pd.coin_ev_size,
-                      &req.h_coin_envelope);
-  GNUNET_CRYPTO_eddsa_sign (&reserve_priv->eddsa_priv,
-                            &req,
-                            &reserve_sig.eddsa_signature);
-  wh = reserve_withdraw_internal (exchange,
-                                  pk,
-                                  &reserve_sig,
-                                  &req.reserve_pub,
-                                  ps,
-                                  &pd,
-                                  &c_hash,
-                                  res_cb,
-                                  res_cb_cls);
-  GNUNET_free (pd.coin_ev);
-  return wh;
-}
-
-
-/**
- * Withdraw a coin from the exchange using a /reserve/withdraw
- * request.  This API is typically used by a wallet to withdraw a tip
- * where the reserve's signature was created by the merchant already.
- *
- * Note that to ensure that no money is lost in case of hardware
- * failures, the caller must have committed (most of) the arguments to
- * disk before calling, and be ready to repeat the request with the
- * same arguments in case of failures.
- *
- * @param exchange the exchange handle; the exchange must be ready to operate
- * @param pk kind of coin to create
- * @param reserve_sig signature from the reserve authorizing the withdrawal
- * @param reserve_pub public key of the reserve to withdraw from
- * @param ps secrets of the planchet
- *        caller must have committed this value to disk before the call (with 
@a pk)
- * @param res_cb the callback to call when the final result for this request 
is available
- * @param res_cb_cls closure for @a res_cb
- * @return NULL
- *         if the inputs are invalid (i.e. denomination key not with this 
exchange).
- *         In this case, the callback is not called.
- */
-struct TALER_EXCHANGE_WithdrawHandle *
-TALER_EXCHANGE_withdraw2 (
-  struct TALER_EXCHANGE_Handle *exchange,
-  const struct TALER_EXCHANGE_DenomPublicKey *pk,
-  const struct TALER_ReserveSignatureP *reserve_sig,
-  const struct TALER_ReservePublicKeyP *reserve_pub,
-  const struct TALER_PlanchetSecretsP *ps,
-  TALER_EXCHANGE_WithdrawCallback res_cb,
-  void *res_cb_cls)
-{
-  struct TALER_EXCHANGE_WithdrawHandle *wh;
-  struct GNUNET_HashCode c_hash;
-  struct TALER_PlanchetDetail pd;
 
-  if (GNUNET_OK !=
-      TALER_planchet_prepare (&pk->key,
-                              ps,
-                              &c_hash,
-                              &pd))
   {
-    GNUNET_break_op (0);
-    return NULL;
+    json_t *withdraw_obj;
+
+    withdraw_obj = json_pack ("{s:o, s:o, s:o}",
+                              "denom_pub_hash",
+                              GNUNET_JSON_from_data_auto (&pd->denom_pub_hash),
+                              "coin_ev",
+                              GNUNET_JSON_from_data (pd->coin_ev,
+                                                     pd->coin_ev_size),
+                              "reserve_sig",
+                              GNUNET_JSON_from_data_auto (&reserve_sig));
+    if (NULL == withdraw_obj)
+    {
+      GNUNET_break (0);
+      GNUNET_free (wh);
+      return NULL;
+    }
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "Attempting to withdraw from reserve %s\n",
+                TALER_B2S (&wh->reserve_pub));
+    wh->url = TEAH_path_to_url (exchange,
+                                arg_str);
+    {
+      CURL *eh;
+      struct GNUNET_CURL_Context *ctx;
+
+      ctx = TEAH_handle_to_context (exchange);
+      eh = TALER_EXCHANGE_curl_easy_get_ (wh->url);
+      if ( (NULL == eh) ||
+           (GNUNET_OK !=
+            TALER_curl_easy_post (&wh->post_ctx,
+                                  eh,
+                                  withdraw_obj)) )
+      {
+        GNUNET_break (0);
+        if (NULL != eh)
+          curl_easy_cleanup (eh);
+        json_decref (withdraw_obj);
+        GNUNET_free (wh->url);
+        GNUNET_free (wh);
+        return NULL;
+      }
+      json_decref (withdraw_obj);
+      wh->job = GNUNET_CURL_job_add2 (ctx,
+                                      eh,
+                                      wh->post_ctx.headers,
+                                      &handle_reserve_withdraw_finished,
+                                      wh);
+    }
   }
-  wh = reserve_withdraw_internal (exchange,
-                                  pk,
-                                  reserve_sig,
-                                  reserve_pub,
-                                  ps,
-                                  &pd,
-                                  &c_hash,
-                                  res_cb,
-                                  res_cb_cls);
-  GNUNET_free (pd.coin_ev);
   return wh;
 }
 
@@ -627,7 +500,7 @@ TALER_EXCHANGE_withdraw2 (
  * @param wh the withdraw sign request handle
  */
 void
-TALER_EXCHANGE_withdraw_cancel (struct TALER_EXCHANGE_WithdrawHandle *wh)
+TALER_EXCHANGE_withdraw2_cancel (struct TALER_EXCHANGE_Withdraw2Handle *wh)
 {
   if (NULL != wh->job)
   {
@@ -635,7 +508,6 @@ TALER_EXCHANGE_withdraw_cancel (struct 
TALER_EXCHANGE_WithdrawHandle *wh)
     wh->job = NULL;
   }
   GNUNET_free (wh->url);
-  TALER_curl_easy_post_finished (&wh->ctx);
-  GNUNET_CRYPTO_rsa_public_key_free (wh->pk.key.rsa_public_key);
+  TALER_curl_easy_post_finished (&wh->post_ctx);
   GNUNET_free (wh);
 }

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



reply via email to

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