summaryrefslogtreecommitdiff
path: root/src/mint-lib
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2016-01-30 13:49:29 +0100
committerChristian Grothoff <christian@grothoff.org>2016-01-30 13:49:29 +0100
commita396f4e7fa39f17aec35360eb12098629649c831 (patch)
treee3e94b05bd85f548e52859af50660e5aea44d456 /src/mint-lib
parent3bb757b3a7bddbd132805dc1147158b40238e543 (diff)
parentae45b7ac9579cc9fcb9c3008162e07b694eb52f8 (diff)
downloadexchange-a396f4e7fa39f17aec35360eb12098629649c831.tar.gz
exchange-a396f4e7fa39f17aec35360eb12098629649c831.tar.bz2
exchange-a396f4e7fa39f17aec35360eb12098629649c831.zip
Merge branch 'master' of ssh://taler.net:/var/git/mint
Diffstat (limited to 'src/mint-lib')
-rw-r--r--src/mint-lib/Makefile.am4
-rw-r--r--src/mint-lib/mint_api_admin.c2
-rw-r--r--src/mint-lib/mint_api_common.c2
-rw-r--r--src/mint-lib/mint_api_common.h2
-rw-r--r--src/mint-lib/mint_api_context.c4
-rw-r--r--src/mint-lib/mint_api_context.h2
-rw-r--r--src/mint-lib/mint_api_deposit.c13
-rw-r--r--src/mint-lib/mint_api_deposit_wtid.c379
-rw-r--r--src/mint-lib/mint_api_handle.c4
-rw-r--r--src/mint-lib/mint_api_handle.h2
-rw-r--r--src/mint-lib/mint_api_json.c34
-rw-r--r--src/mint-lib/mint_api_json.h21
-rw-r--r--src/mint-lib/mint_api_refresh.c13
-rw-r--r--src/mint-lib/mint_api_refresh_link.c40
-rw-r--r--src/mint-lib/mint_api_reserve.c2
-rw-r--r--src/mint-lib/mint_api_wire.c2
-rw-r--r--src/mint-lib/mint_api_wire_deposits.c284
-rw-r--r--src/mint-lib/test_mint_api.c406
18 files changed, 1161 insertions, 55 deletions
diff --git a/src/mint-lib/Makefile.am b/src/mint-lib/Makefile.am
index ccea4ec58..171a42464 100644
--- a/src/mint-lib/Makefile.am
+++ b/src/mint-lib/Makefile.am
@@ -20,10 +20,12 @@ libtalermint_la_SOURCES = \
mint_api_handle.c mint_api_handle.h \
mint_api_admin.c \
mint_api_deposit.c \
+ mint_api_deposit_wtid.c \
mint_api_refresh.c \
mint_api_refresh_link.c \
mint_api_reserve.c \
- mint_api_wire.c
+ mint_api_wire.c \
+ mint_api_wire_deposits.c
libtalermint_la_LIBADD = \
-lgnunetutil \
diff --git a/src/mint-lib/mint_api_admin.c b/src/mint-lib/mint_api_admin.c
index 472b02e7d..641e0690f 100644
--- a/src/mint-lib/mint_api_admin.c
+++ b/src/mint-lib/mint_api_admin.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
+ Copyright (C) 2014, 2015 GNUnet e.V.
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
diff --git a/src/mint-lib/mint_api_common.c b/src/mint-lib/mint_api_common.c
index fd85fbdc4..faba38c74 100644
--- a/src/mint-lib/mint_api_common.c
+++ b/src/mint-lib/mint_api_common.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2015 Christian Grothoff (and other contributing authors)
+ Copyright (C) 2015 GNUnet e.V.
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
diff --git a/src/mint-lib/mint_api_common.h b/src/mint-lib/mint_api_common.h
index d256fa428..10a202146 100644
--- a/src/mint-lib/mint_api_common.h
+++ b/src/mint-lib/mint_api_common.h
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2015 Christian Grothoff (and other contributing authors)
+ Copyright (C) 2015 GNUnet e.V.
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
diff --git a/src/mint-lib/mint_api_context.c b/src/mint-lib/mint_api_context.c
index e60e01b07..2767906b5 100644
--- a/src/mint-lib/mint_api_context.c
+++ b/src/mint-lib/mint_api_context.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
+ Copyright (C) 2014, 2015 GNUnet e.V.
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
@@ -288,7 +288,7 @@ TALER_MINT_perform (struct TALER_MINT_Context *ctx)
GNUNET_assert (CURLE_OK ==
curl_easy_getinfo (cmsg->easy_handle,
CURLINFO_PRIVATE,
- (char *) &job));
+ (char **) &job));
GNUNET_assert (job->ctx == ctx);
job->jcc (job->jcc_cls,
cmsg->easy_handle);
diff --git a/src/mint-lib/mint_api_context.h b/src/mint-lib/mint_api_context.h
index 79613cc8b..181a4808f 100644
--- a/src/mint-lib/mint_api_context.h
+++ b/src/mint-lib/mint_api_context.h
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
+ Copyright (C) 2014, 2015 GNUnet e.V.
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
diff --git a/src/mint-lib/mint_api_deposit.c b/src/mint-lib/mint_api_deposit.c
index 8f7b6db06..400372925 100644
--- a/src/mint-lib/mint_api_deposit.c
+++ b/src/mint-lib/mint_api_deposit.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
+ Copyright (C) 2014, 2015 GNUnet e.V.
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
@@ -434,6 +434,14 @@ TALER_MINT_deposit (struct TALER_MINT_Handle *mint,
TALER_LOG_WARNING ("Denomination key unknown to mint\n");
return NULL;
}
+ if (GNUNET_SYSERR ==
+ TALER_amount_subtract (&amount_without_fee,
+ amount,
+ &dki->fee_deposit))
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
if (GNUNET_OK !=
verify_signatures (dki,
@@ -492,9 +500,6 @@ TALER_MINT_deposit (struct TALER_MINT_Handle *mint,
dh->depconf.transaction_id = GNUNET_htonll (transaction_id);
dh->depconf.timestamp = GNUNET_TIME_absolute_hton (timestamp);
dh->depconf.refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline);
- TALER_amount_subtract (&amount_without_fee,
- amount,
- &dki->fee_deposit);
TALER_amount_hton (&dh->depconf.amount_without_fee,
&amount_without_fee);
dh->depconf.coin_pub = *coin_pub;
diff --git a/src/mint-lib/mint_api_deposit_wtid.c b/src/mint-lib/mint_api_deposit_wtid.c
new file mode 100644
index 000000000..d29f406e3
--- /dev/null
+++ b/src/mint-lib/mint_api_deposit_wtid.c
@@ -0,0 +1,379 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015, 2016 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file mint-lib/mint_api_deposit_wtid.c
+ * @brief Implementation of the /deposit/wtid request of the mint's HTTP API
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <curl/curl.h>
+#include <jansson.h>
+#include <microhttpd.h> /* just for HTTP status codes */
+#include <gnunet/gnunet_util_lib.h>
+#include "taler_mint_service.h"
+#include "mint_api_common.h"
+#include "mint_api_json.h"
+#include "mint_api_context.h"
+#include "mint_api_handle.h"
+#include "taler_signatures.h"
+
+
+/**
+ * @brief A Deposit Wtid Handle
+ */
+struct TALER_MINT_DepositWtidHandle
+{
+
+ /**
+ * The connection to mint this request handle will use
+ */
+ struct TALER_MINT_Handle *mint;
+
+ /**
+ * The url for this request.
+ */
+ char *url;
+
+ /**
+ * JSON encoding of the request to POST.
+ */
+ char *json_enc;
+
+ /**
+ * Handle for the request.
+ */
+ struct MAC_Job *job;
+
+ /**
+ * Function to call with the result.
+ */
+ TALER_MINT_DepositWtidCallback cb;
+
+ /**
+ * Closure for @a cb.
+ */
+ void *cb_cls;
+
+ /**
+ * Download buffer
+ */
+ struct MAC_DownloadBuffer db;
+
+ /**
+ * Information the mint should sign in response.
+ * (with pre-filled fields from the request).
+ */
+ struct TALER_ConfirmWirePS depconf;
+
+};
+
+
+/**
+ * Verify that the signature on the "200 OK" response
+ * from the mint is valid.
+ *
+ * @param dwh deposit wtid handle
+ * @param json json reply with the signature
+ * @return #GNUNET_OK if the signature is valid, #GNUNET_SYSERR if not
+ */
+static int
+verify_deposit_wtid_signature_ok (const struct TALER_MINT_DepositWtidHandle *dwh,
+ json_t *json)
+{
+ struct TALER_MintSignatureP mint_sig;
+ struct TALER_MintPublicKeyP mint_pub;
+ const struct TALER_MINT_Keys *key_state;
+ struct MAJ_Specification spec[] = {
+ MAJ_spec_fixed_auto ("mint_sig", &mint_sig),
+ MAJ_spec_fixed_auto ("mint_pub", &mint_pub),
+ MAJ_spec_end
+ };
+
+ if (GNUNET_OK !=
+ MAJ_parse_json (json,
+ spec))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ key_state = TALER_MINT_get_keys (dwh->mint);
+ if (GNUNET_OK !=
+ TALER_MINT_test_signing_key (key_state,
+ &mint_pub))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MINT_CONFIRM_WIRE,
+ &dwh->depconf.purpose,
+ &mint_sig.eddsa_signature,
+ &mint_pub.eddsa_pub))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Function called when we're done processing the
+ * HTTP /deposit/wtid request.
+ *
+ * @param cls the `struct TALER_MINT_DepositWtidHandle`
+ * @param eh the curl request handle
+ */
+static void
+handle_deposit_wtid_finished (void *cls,
+ CURL *eh)
+{
+ struct TALER_MINT_DepositWtidHandle *dwh = cls;
+ long response_code;
+ json_t *json;
+ const struct TALER_WireTransferIdentifierRawP *wtid = NULL;
+ struct GNUNET_TIME_Absolute execution_time = GNUNET_TIME_UNIT_FOREVER_ABS;
+ const struct TALER_Amount *coin_contribution = NULL;
+ struct TALER_Amount coin_contribution_s;
+
+ dwh->job = NULL;
+ json = MAC_download_get_result (&dwh->db,
+ eh,
+ &response_code);
+ switch (response_code)
+ {
+ case 0:
+ break;
+ case MHD_HTTP_OK:
+ {
+ struct MAJ_Specification spec[] = {
+ MAJ_spec_fixed_auto ("wtid", &dwh->depconf.wtid),
+ MAJ_spec_absolute_time ("execution_time", &execution_time),
+ MAJ_spec_amount ("coin_contribution", &coin_contribution_s),
+ MAJ_spec_end
+ };
+
+ if (GNUNET_OK !=
+ MAJ_parse_json (json,
+ spec))
+ {
+ GNUNET_break_op (0);
+ response_code = 0;
+ break;
+ }
+ wtid = &dwh->depconf.wtid;
+ dwh->depconf.execution_time = GNUNET_TIME_absolute_hton (execution_time);
+ TALER_amount_hton (&dwh->depconf.coin_contribution,
+ &coin_contribution_s);
+ coin_contribution = &coin_contribution_s;
+ if (GNUNET_OK !=
+ verify_deposit_wtid_signature_ok (dwh,
+ json))
+ {
+ GNUNET_break_op (0);
+ response_code = 0;
+ }
+ }
+ break;
+ case MHD_HTTP_ACCEPTED:
+ {
+ /* Transaction known, but not executed yet */
+ struct MAJ_Specification spec[] = {
+ MAJ_spec_absolute_time ("execution_time", &execution_time),
+ MAJ_spec_end
+ };
+
+ if (GNUNET_OK !=
+ MAJ_parse_json (json,
+ spec))
+ {
+ GNUNET_break_op (0);
+ response_code = 0;
+ break;
+ }
+ }
+ break;
+ case MHD_HTTP_BAD_REQUEST:
+ /* This should never happen, either us or the mint is buggy
+ (or API version conflict); just pass JSON reply to the application */
+ break;
+ case MHD_HTTP_UNAUTHORIZED:
+ /* Nothing really to verify, mint says one of the signatures is
+ invalid; as we checked them, this should never happen, we
+ should pass the JSON reply to the application */
+ break;
+ case MHD_HTTP_NOT_FOUND:
+ /* Mint does not know about transaction;
+ we should pass the reply to the application */
+ break;
+ case MHD_HTTP_INTERNAL_SERVER_ERROR:
+ /* Server had an internal issue; we should retry, but this API
+ leaves this to the application */
+ break;
+ default:
+ /* unexpected response code */
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u\n",
+ response_code);
+ GNUNET_break (0);
+ response_code = 0;
+ break;
+ }
+ dwh->cb (dwh->cb_cls,
+ response_code,
+ json,
+ wtid,
+ execution_time,
+ coin_contribution);
+ json_decref (json);
+ TALER_MINT_deposit_wtid_cancel (dwh);
+}
+
+
+/**
+ * Obtain wire transfer details about an existing deposit operation.
+ *
+ * @param mint the mint to query
+ * @param merchant_priv the merchant's private key
+ * @param h_wire hash of merchant's wire transfer details
+ * @param h_contract hash of the contract
+ * @param coin_pub public key of the coin
+ * @param transaction_id transaction identifier
+ * @param cb function to call with the result
+ * @param cb_cls closure for @a cb
+ * @return handle to abort request
+ */
+struct TALER_MINT_DepositWtidHandle *
+TALER_MINT_deposit_wtid (struct TALER_MINT_Handle *mint,
+ const struct TALER_MerchantPrivateKeyP *merchant_priv,
+ const struct GNUNET_HashCode *h_wire,
+ const struct GNUNET_HashCode *h_contract,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ uint64_t transaction_id,
+ TALER_MINT_DepositWtidCallback cb,
+ void *cb_cls)
+{
+ struct TALER_DepositTrackPS dtp;
+ struct TALER_MerchantSignatureP merchant_sig;
+ struct TALER_MINT_DepositWtidHandle *dwh;
+ struct TALER_MINT_Context *ctx;
+ json_t *deposit_wtid_obj;
+ CURL *eh;
+
+ if (GNUNET_YES !=
+ MAH_handle_is_ready (mint))
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+ dtp.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_DEPOSIT_WTID);
+ dtp.purpose.size = htonl (sizeof (dtp));
+ dtp.h_contract = *h_contract;
+ dtp.h_wire = *h_wire;
+ dtp.transaction_id = GNUNET_htonll (transaction_id);
+ GNUNET_CRYPTO_eddsa_key_get_public (&merchant_priv->eddsa_priv,
+ &dtp.merchant.eddsa_pub);
+
+ dtp.coin_pub = *coin_pub;
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CRYPTO_eddsa_sign (&merchant_priv->eddsa_priv,
+ &dtp.purpose,
+ &merchant_sig.eddsa_sig));
+ deposit_wtid_obj = json_pack ("{s:o, s:o," /* H_wire, H_contract */
+ " s:o, s:I," /* coin_pub, transaction_id */
+ " s:o, s:o}", /* merchant_pub, merchant_sig */
+ "H_wire", TALER_json_from_data (h_wire,
+ sizeof (struct GNUNET_HashCode)),
+ "H_contract", TALER_json_from_data (h_contract,
+ sizeof (struct GNUNET_HashCode)),
+ "coin_pub", TALER_json_from_data (coin_pub,
+ sizeof (*coin_pub)),
+ "transaction_id", (json_int_t) transaction_id,
+ "merchant_pub", TALER_json_from_data (&dtp.merchant,
+ sizeof (struct TALER_MerchantPublicKeyP)),
+ "merchant_sig", TALER_json_from_data (&merchant_sig,
+ sizeof (merchant_sig)));
+
+ dwh = GNUNET_new (struct TALER_MINT_DepositWtidHandle);
+ dwh->mint = mint;
+ dwh->cb = cb;
+ dwh->cb_cls = cb_cls;
+ dwh->url = MAH_path_to_url (mint, "/deposit/wtid");
+ dwh->depconf.purpose.size = htonl (sizeof (struct TALER_DepositConfirmationPS));
+ dwh->depconf.purpose.purpose = htonl (TALER_SIGNATURE_MINT_CONFIRM_WIRE);
+ dwh->depconf.h_wire = *h_wire;
+ dwh->depconf.h_contract = *h_contract;
+ dwh->depconf.coin_pub = *coin_pub;
+ dwh->depconf.transaction_id = GNUNET_htonll (transaction_id);
+
+ eh = curl_easy_init ();
+ GNUNET_assert (NULL != (dwh->json_enc =
+ json_dumps (deposit_wtid_obj,
+ JSON_COMPACT)));
+ json_decref (deposit_wtid_obj);
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_URL,
+ dwh->url));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_POSTFIELDS,
+ dwh->json_enc));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_POSTFIELDSIZE,
+ strlen (dwh->json_enc)));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_WRITEFUNCTION,
+ &MAC_download_cb));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_WRITEDATA,
+ &dwh->db));
+ ctx = MAH_handle_to_context (mint);
+ dwh->job = MAC_job_add (ctx,
+ eh,
+ GNUNET_YES,
+ &handle_deposit_wtid_finished,
+ dwh);
+ return dwh;
+}
+
+
+/**
+ * Cancel deposit wtid request. This function cannot be used on a request
+ * handle if a response is already served for it.
+ *
+ * @param dwh the wire deposits request handle
+ */
+void
+TALER_MINT_deposit_wtid_cancel (struct TALER_MINT_DepositWtidHandle *dwh)
+{
+ if (NULL != dwh->job)
+ {
+ MAC_job_cancel (dwh->job);
+ dwh->job = NULL;
+ }
+ GNUNET_free_non_null (dwh->db.buf);
+ GNUNET_free (dwh->url);
+ GNUNET_free (dwh->json_enc);
+ GNUNET_free (dwh);
+}
+
+
+/* end of mint_api_deposit_wtid.c */
diff --git a/src/mint-lib/mint_api_handle.c b/src/mint-lib/mint_api_handle.c
index 1b0b73c50..ef26cd838 100644
--- a/src/mint-lib/mint_api_handle.c
+++ b/src/mint-lib/mint_api_handle.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
+ Copyright (C) 2014, 2015 GNUnet e.V.
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
@@ -755,7 +755,7 @@ TALER_MINT_connect (struct TALER_MINT_Context *ctx,
GNUNET_assert (CURLE_OK ==
curl_easy_setopt (c,
CURLOPT_VERBOSE,
- 1));
+ 0));
GNUNET_assert (CURLE_OK ==
curl_easy_setopt (c,
CURLOPT_STDERR,
diff --git a/src/mint-lib/mint_api_handle.h b/src/mint-lib/mint_api_handle.h
index fae30a309..0dae58db6 100644
--- a/src/mint-lib/mint_api_handle.h
+++ b/src/mint-lib/mint_api_handle.h
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
+ Copyright (C) 2014, 2015 GNUnet e.V.
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
diff --git a/src/mint-lib/mint_api_json.c b/src/mint-lib/mint_api_json.c
index a728a5495..7de33e5eb 100644
--- a/src/mint-lib/mint_api_json.c
+++ b/src/mint-lib/mint_api_json.c
@@ -232,6 +232,20 @@ parse_json (json_t *root,
}
break;
+ case MAJ_CMD_UINT64:
+ {
+ json_int_t val;
+
+ if (! json_is_integer (pos))
+ {
+ GNUNET_break_op (0);
+ return i;
+ }
+ val = json_integer_value (pos);
+ *spec[i].details.u64 = (uint64_t) val;
+ }
+ break;
+
case MAJ_CMD_JSON_OBJECT:
{
if (! (json_is_object (pos) || json_is_array (pos)) )
@@ -429,6 +443,26 @@ MAJ_spec_uint16 (const char *name,
/**
+ * 64-bit integer.
+ *
+ * @param name name of the JSON field
+ * @param[out] u64 where to store the integer found under @a name
+ */
+struct MAJ_Specification
+MAJ_spec_uint64 (const char *name,
+ uint64_t *u64)
+{
+ struct MAJ_Specification ret =
+ {
+ .cmd = MAJ_CMD_UINT64,
+ .field = name,
+ .details.u64 = u64
+ };
+ return ret;
+}
+
+
+/**
* JSON object.
*
* @param name name of the JSON field
diff --git a/src/mint-lib/mint_api_json.h b/src/mint-lib/mint_api_json.h
index 68809059e..6bc3a5572 100644
--- a/src/mint-lib/mint_api_json.h
+++ b/src/mint-lib/mint_api_json.h
@@ -79,6 +79,11 @@ enum MAJ_Command
MAJ_CMD_UINT16,
/**
+ * Parse `uint64_t` integer at the current position.
+ */
+ MAJ_CMD_UINT64,
+
+ /**
* Parse JSON object at the current position.
*/
MAJ_CMD_JSON_OBJECT,
@@ -192,6 +197,11 @@ struct MAJ_Specification
uint16_t *u16;
/**
+ * Where to store 64-bit integer.
+ */
+ uint64_t *u64;
+
+ /**
* Where to store a JSON object.
*/
json_t **obj;
@@ -283,6 +293,17 @@ MAJ_spec_uint16 (const char *name,
/**
+ * 64-bit integer.
+ *
+ * @param name name of the JSON field
+ * @param[out] u64 where to store the integer found under @a name
+ */
+struct MAJ_Specification
+MAJ_spec_uint64 (const char *name,
+ uint64_t *u64);
+
+
+/**
* JSON object.
*
* @param name name of the JSON field
diff --git a/src/mint-lib/mint_api_refresh.c b/src/mint-lib/mint_api_refresh.c
index a779bdbc3..cea16b153 100644
--- a/src/mint-lib/mint_api_refresh.c
+++ b/src/mint-lib/mint_api_refresh.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2015 Christian Grothoff (and other contributing authors)
+ Copyright (C) 2015 GNUnet e.V.
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
@@ -334,12 +334,9 @@ free_melt_data (struct MeltData *md)
for (i=0;i<TALER_CNC_KAPPA;i++)
{
- if (NULL != md->fresh_coins)
- {
- for (j=0;j<md->num_fresh_coins;j++)
- free_fresh_coin (&md->fresh_coins[i][j]);
- GNUNET_free (md->fresh_coins[i]);
- }
+ for (j=0;j<md->num_fresh_coins;j++)
+ free_fresh_coin (&md->fresh_coins[i][j]);
+ GNUNET_free (md->fresh_coins[i]);
}
/* Finally, clean up a bit...
(NOTE: compilers might optimize this away, so this is
@@ -774,7 +771,7 @@ deserialize_melt_data (const char *buf,
&buf[off],
buf_size - off,
&ok);
- if (off != buf_size)
+ if (off != buf_size)
{
GNUNET_break (0);
ok = GNUNET_NO;
diff --git a/src/mint-lib/mint_api_refresh_link.c b/src/mint-lib/mint_api_refresh_link.c
index d4060bd1c..dcd2326ca 100644
--- a/src/mint-lib/mint_api_refresh_link.c
+++ b/src/mint-lib/mint_api_refresh_link.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2015 Christian Grothoff (and other contributing authors)
+ Copyright (C) 2015, 2016 GNUnet e.V.
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
@@ -185,6 +185,17 @@ parse_refresh_link_ok (struct TALER_MINT_RefreshLinkHandle *rlh,
return GNUNET_SYSERR;
}
num_coins = 0;
+ /* Theoretically, a coin may have been melted repeatedly
+ into different sessions; so the response is an array
+ which contains information by melting session. That
+ array contains another array. However, our API returns
+ a single 1d array, so we flatten the 2d array that is
+ returned into a single array. Note that usually a coin
+ is melted at most once, and so we'll only run this
+ loop once for 'session=0' in most cases.
+
+ num_coins tracks the size of the 1d array we return,
+ whilst 'i' and 'session' track the 2d array. */
for (session=0;session<json_array_size (json); session++)
{
json_t *jsona;
@@ -194,7 +205,7 @@ parse_refresh_link_ok (struct TALER_MINT_RefreshLinkHandle *rlh,
};
if (GNUNET_OK !=
- MAJ_parse_json (json_array_get (json,
+ MAJ_parse_json (json_array_get (json,
session),
spec))
{
@@ -212,13 +223,17 @@ parse_refresh_link_ok (struct TALER_MINT_RefreshLinkHandle *rlh,
num_coins += json_array_size (jsona);
MAJ_parse_free (spec);
}
+ /* Now that we know how big the 1d array is, allocate
+ and fill it. */
{
- unsigned int off_coin;
+ unsigned int off_coin; /* index into 1d array */
unsigned int i;
struct TALER_CoinSpendPrivateKeyP coin_privs[num_coins];
struct TALER_DenominationSignature sigs[num_coins];
struct TALER_DenominationPublicKey pubs[num_coins];
-
+
+ memset (sigs, 0, sizeof (sigs));
+ memset (pubs, 0, sizeof (pubs));
off_coin = 0;
for (session=0;session<json_array_size (json); session++)
{
@@ -233,7 +248,7 @@ parse_refresh_link_ok (struct TALER_MINT_RefreshLinkHandle *rlh,
};
if (GNUNET_OK !=
- MAJ_parse_json (json_array_get (json,
+ MAJ_parse_json (json_array_get (json,
session),
spec))
{
@@ -246,13 +261,13 @@ parse_refresh_link_ok (struct TALER_MINT_RefreshLinkHandle *rlh,
MAJ_parse_free (spec);
return GNUNET_SYSERR;
}
-
+
/* decode all coins */
for (i=0;i<json_array_size (jsona);i++)
{
if (GNUNET_OK !=
parse_refresh_link_coin (rlh,
- json_array_get (jsona,
+ json_array_get (jsona,
i),
&trans_pub,
&secret_enc,
@@ -265,6 +280,7 @@ parse_refresh_link_ok (struct TALER_MINT_RefreshLinkHandle *rlh,
}
}
/* check if we really got all, then invoke callback */
+ off_coin += i;
if (i != json_array_size (jsona))
{
GNUNET_break_op (0);
@@ -272,9 +288,9 @@ parse_refresh_link_ok (struct TALER_MINT_RefreshLinkHandle *rlh,
MAJ_parse_free (spec);
break;
}
- off_coin += json_array_size (jsona);
MAJ_parse_free (spec);
- }
+ } /* end of for (session) */
+
if (off_coin == num_coins)
{
rlh->link_cb (rlh->link_cb_cls,
@@ -294,9 +310,13 @@ parse_refresh_link_ok (struct TALER_MINT_RefreshLinkHandle *rlh,
}
/* clean up */
- for (i=0;i<num_coins;i++)
+ for (i=0;i<off_coin;i++)
+ {
if (NULL != sigs[i].rsa_signature)
GNUNET_CRYPTO_rsa_signature_free (sigs[i].rsa_signature);
+ if (NULL != pubs[i].rsa_public_key)
+ GNUNET_CRYPTO_rsa_public_key_free (pubs[i].rsa_public_key);
+ }
}
return ret;
}
diff --git a/src/mint-lib/mint_api_reserve.c b/src/mint-lib/mint_api_reserve.c
index a726eca46..1f8140cff 100644
--- a/src/mint-lib/mint_api_reserve.c
+++ b/src/mint-lib/mint_api_reserve.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
+ Copyright (C) 2014, 2015 GNUnet e.V.
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
diff --git a/src/mint-lib/mint_api_wire.c b/src/mint-lib/mint_api_wire.c
index 5fc82f72d..0947354ad 100644
--- a/src/mint-lib/mint_api_wire.c
+++ b/src/mint-lib/mint_api_wire.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
+ Copyright (C) 2014, 2015 GNUnet e.V.
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
diff --git a/src/mint-lib/mint_api_wire_deposits.c b/src/mint-lib/mint_api_wire_deposits.c
new file mode 100644
index 000000000..f71c5b696
--- /dev/null
+++ b/src/mint-lib/mint_api_wire_deposits.c
@@ -0,0 +1,284 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015, 2016 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file mint-lib/mint_api_wire_deposits.c
+ * @brief Implementation of the /wire/deposits request of the mint's HTTP API
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <curl/curl.h>
+#include <jansson.h>
+#include <microhttpd.h> /* just for HTTP status codes */
+#include <gnunet/gnunet_util_lib.h>
+#include "taler_mint_service.h"
+#include "mint_api_common.h"
+#include "mint_api_json.h"
+#include "mint_api_context.h"
+#include "mint_api_handle.h"
+#include "taler_signatures.h"
+
+
+/**
+ * @brief A /wire/deposits Handle
+ */
+struct TALER_MINT_WireDepositsHandle
+{
+
+ /**
+ * The connection to mint this request handle will use
+ */
+ struct TALER_MINT_Handle *mint;
+
+ /**
+ * The url for this request.
+ */
+ char *url;
+
+ /**
+ * Handle for the request.
+ */
+ struct MAC_Job *job;
+
+ /**
+ * Function to call with the result.
+ */
+ TALER_MINT_WireDepositsCallback cb;
+
+ /**
+ * Closure for @a cb.
+ */
+ void *cb_cls;
+
+ /**
+ * Download buffer
+ */
+ struct MAC_DownloadBuffer db;
+
+};
+
+
+/**
+ * Function called when we're done processing the
+ * HTTP /wire/deposits request.
+ *
+ * @param cls the `struct TALER_MINT_WireDepositsHandle`
+ * @param eh the curl request handle
+ */
+static void
+handle_wire_deposits_finished (void *cls,
+ CURL *eh)
+{
+ struct TALER_MINT_WireDepositsHandle *wdh = cls;
+ long response_code;
+ json_t *json;
+
+ wdh->job = NULL;
+ json = MAC_download_get_result (&wdh->db,
+ eh,
+ &response_code);
+ switch (response_code)
+ {
+ case 0:
+ break;
+ case MHD_HTTP_OK:
+ {
+ json_t *details_j;
+ struct GNUNET_HashCode h_wire;
+ struct TALER_Amount total_amount;
+ struct TALER_MerchantPublicKeyP merchant_pub;
+ unsigned int num_details;
+ struct MAJ_Specification spec[] = {
+ MAJ_spec_fixed_auto ("H_wire", &h_wire),
+ MAJ_spec_fixed_auto ("merchant_pub", &merchant_pub),
+ MAJ_spec_amount ("total_amount", &total_amount),
+ MAJ_spec_json ("details", &details_j),
+ MAJ_spec_end
+ };
+
+ if (GNUNET_OK !=
+ MAJ_parse_json (json,
+ spec))
+ {
+ GNUNET_break_op (0);
+ response_code = 0;
+ break;
+ }
+ num_details = json_array_size (details_j);
+ {
+ struct TALER_WireDepositDetails details[num_details];
+ unsigned int i;
+
+ for (i=0;i<num_details;i++)
+ {
+ struct TALER_WireDepositDetails *detail = &details[i];
+ struct json_t *detail_j = json_array_get (details_j, i);
+ struct MAJ_Specification spec_detail[] = {
+ MAJ_spec_fixed_auto ("H_contract", &detail->h_contract),
+ MAJ_spec_amount ("deposit_value", &detail->coin_value),
+ MAJ_spec_amount ("deposit_fee", &detail->coin_fee),
+ MAJ_spec_uint64 ("transaction_id", &detail->transaction_id),
+ MAJ_spec_fixed_auto ("coin_pub", &detail->coin_pub),
+ MAJ_spec_end
+ };
+
+ if (GNUNET_OK !=
+ MAJ_parse_json (detail_j,
+ spec_detail))
+ {
+ GNUNET_break_op (0);
+ response_code = 0;
+ break;
+ }
+ }
+ if (0 == response_code)
+ break;
+ wdh->cb (wdh->cb_cls,
+ response_code,
+ json,
+ &h_wire,
+ &total_amount,
+ num_details,
+ details);
+ json_decref (json);
+ TALER_MINT_wire_deposits_cancel (wdh);
+ return;
+ }
+ }
+ break;
+ case MHD_HTTP_BAD_REQUEST:
+ /* This should never happen, either us or the mint is buggy
+ (or API version conflict); just pass JSON reply to the application */
+ break;
+ case MHD_HTTP_UNAUTHORIZED:
+ /* Nothing really to verify, mint says one of the signatures is
+ invalid; as we checked them, this should never happen, we
+ should pass the JSON reply to the application */
+ break;
+ case MHD_HTTP_NOT_FOUND:
+ /* Mint does not know about transaction;
+ we should pass the reply to the application */
+ break;
+ case MHD_HTTP_INTERNAL_SERVER_ERROR:
+ /* Server had an internal issue; we should retry, but this API
+ leaves this to the application */
+ break;
+ default:
+ /* unexpected response code */
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u\n",
+ response_code);
+ GNUNET_break (0);
+ response_code = 0;
+ break;
+ }
+ wdh->cb (wdh->cb_cls,
+ response_code,
+ json,
+ NULL, NULL, 0, NULL);
+ json_decref (json);
+ TALER_MINT_wire_deposits_cancel (wdh);
+}
+
+
+/**
+ * Query the mint about which transactions were combined
+ * to create a wire transfer.
+ *
+ * @param mint mint to query
+ * @param wtid raw wire transfer identifier to get information about
+ * @param cb callback to call
+ * @param cb_cls closure for @a cb
+ * @return handle to cancel operation
+ */
+struct TALER_MINT_WireDepositsHandle *
+TALER_MINT_wire_deposits (struct TALER_MINT_Handle *mint,
+ const struct TALER_WireTransferIdentifierRawP *wtid,
+ TALER_MINT_WireDepositsCallback cb,
+ void *cb_cls)
+{
+ struct TALER_MINT_WireDepositsHandle *wdh;
+ struct TALER_MINT_Context *ctx;
+ char *buf;
+ char *path;
+ CURL *eh;
+
+ if (GNUNET_YES !=
+ MAH_handle_is_ready (mint))
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+
+ wdh = GNUNET_new (struct TALER_MINT_WireDepositsHandle);
+ wdh->mint = mint;
+ wdh->cb = cb;
+ wdh->cb_cls = cb_cls;
+
+ buf = GNUNET_STRINGS_data_to_string_alloc (wtid,
+ sizeof (struct TALER_WireTransferIdentifierRawP));
+ GNUNET_asprintf (&path,
+ "/wire/deposits?wtid=%s",
+ buf);
+ wdh->url = MAH_path_to_url (wdh->mint,
+ path);
+ GNUNET_free (buf);
+ GNUNET_free (path);
+
+ eh = curl_easy_init ();
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_URL,
+ wdh->url));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_WRITEFUNCTION,
+ &MAC_download_cb));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_WRITEDATA,
+ &wdh->db));
+ ctx = MAH_handle_to_context (mint);
+ wdh->job = MAC_job_add (ctx,
+ eh,
+ GNUNET_YES,
+ &handle_wire_deposits_finished,
+ wdh);
+ return wdh;
+}
+
+
+/**
+ * Cancel wire deposits request. This function cannot be used on a request
+ * handle if a response is already served for it.
+ *
+ * @param wdh the wire deposits request handle
+ */
+void
+TALER_MINT_wire_deposits_cancel (struct TALER_MINT_WireDepositsHandle *wdh)
+{
+ if (NULL != wdh->job)
+ {
+ MAC_job_cancel (wdh->job);
+ wdh->job = NULL;
+ }
+ GNUNET_free_non_null (wdh->db.buf);
+ GNUNET_free (wdh->url);
+ GNUNET_free (wdh);
+}
+
+
+/* end of mint_api_wire_deposits.c */
diff --git a/src/mint-lib/test_mint_api.c b/src/mint-lib/test_mint_api.c
index 024e080fc..e41d01805 100644
--- a/src/mint-lib/test_mint_api.c
+++ b/src/mint-lib/test_mint_api.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
+ Copyright (C) 2014, 2015, 2016 GNUnet e.V.
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
@@ -111,7 +111,17 @@ enum OpCode
/**
* Verify the mint's /wire-method.
*/
- OC_WIRE
+ OC_WIRE,
+
+ /**
+ * Verify mint's /wire/deposits method.
+ */
+ OC_WIRE_DEPOSITS,
+
+ /**
+ * Verify mint's /deposit/wtid method.
+ */
+ OC_DEPOSIT_WTID
};
@@ -470,6 +480,60 @@ struct Command
} wire;
+ /**
+ * Information for the /wire/deposits's command.
+ */
+ struct {
+
+ /**
+ * Handle to the wire deposits request.
+ */
+ struct TALER_MINT_WireDepositsHandle *wdh;
+
+ /**
+ * Reference to a /deposit/wtid command. If set, we use the
+ * WTID from that command.
+ */
+ const char *wtid_ref;
+
+ /**
+ * WTID to use (used if @e wtid_ref is NULL).
+ */
+ struct TALER_WireTransferIdentifierRawP wtid;
+
+ /* TODO: may want to add list of deposits we expected
+ to see aggregated here in the future. */
+
+ } wire_deposits;
+
+ /**
+ * Information for the /deposit/wtid command.
+ */
+ struct {
+
+ /**
+ * Handle to the deposit wtid request.
+ */
+ struct TALER_MINT_DepositWtidHandle *dwh;
+
+ /**
+ * Which /deposit operation should we obtain WTID data for?
+ */
+ const char *deposit_ref;
+
+ /**
+ * What is the expected total amount? Only used if
+ * @e expected_response_code was #MHD_HTTP_OK.
+ */
+ struct TALER_Amount total_amount_expected;
+
+ /**
+ * Wire transfer identifier, set if #MHD_HTTP_OK was the response code.
+ */
+ struct TALER_WireTransferIdentifierRawP wtid;
+
+ } deposit_wtid;
+
} details;
};
@@ -1220,6 +1284,158 @@ wire_cb (void *cls,
/**
+ * Function called with detailed wire transfer data, including all
+ * of the coin transactions that were combined into the wire transfer.
+ *
+ * @param cls closure
+ * @param http_status HTTP status code we got, 0 on mint protocol violation
+ * @param json original json reply (may include signatures, those have then been
+ * validated already)
+ * @param wtid extracted wire transfer identifier, or NULL if the mint could
+ * not provide any (set only if @a http_status is #MHD_HTTP_OK)
+ * @param total_amount total amount of the wire transfer, or NULL if the mint could
+ * not provide any @a wtid (set only if @a http_status is #MHD_HTTP_OK)
+ * @param details_length length of the @a details array
+ * @param details array with details about the combined transactions
+ */
+static void
+wire_deposits_cb (void *cls,
+ unsigned int http_status,
+ json_t *json,
+ const struct GNUNET_HashCode *h_wire,
+ const struct TALER_Amount *total_amount,
+ unsigned int details_length,
+ const struct TALER_WireDepositDetails *details)
+{
+ struct InterpreterState *is = cls;
+ struct Command *cmd = &is->commands[is->ip];
+ const struct Command *ref;
+
+ cmd->details.wire_deposits.wdh = NULL;
+ ref = find_command (is,
+ cmd->details.wire_deposits.wtid_ref);
+ if (cmd->expected_response_code != http_status)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u to command %s\n",
+ http_status,
+ cmd->label);
+ json_dumpf (json, stderr, 0);
+ fail (is);
+ return;
+ }
+ switch (http_status)
+ {
+ case MHD_HTTP_OK:
+ if (0 != TALER_amount_cmp (total_amount,
+ &ref->details.deposit_wtid.total_amount_expected))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Total amount missmatch to command %s\n",
+ http_status,
+ cmd->label);
+ json_dumpf (json, stderr, 0);
+ fail (is);
+ return;
+ }
+ if (NULL != ref->details.deposit_wtid.deposit_ref)
+ {
+ const struct Command *dep;
+ struct GNUNET_HashCode hw;
+
+ dep = find_command (is,
+ ref->details.deposit_wtid.deposit_ref);
+ GNUNET_CRYPTO_hash (dep->details.deposit.wire_details,
+ strlen (dep->details.deposit.wire_details),
+ &hw);
+ if (0 != memcmp (&hw,
+ h_wire,
+ sizeof (struct GNUNET_HashCode)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Wire hash missmatch to command %s\n",
+ cmd->label);
+ json_dumpf (json, stderr, 0);
+ fail (is);
+ return;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* move to next command */
+ is->ip++;
+ is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
+ is);
+}
+
+
+/**
+ * Function called with detailed wire transfer data.
+ *
+ * @param cls closure
+ * @param http_status HTTP status code we got, 0 on mint protocol violation
+ * @param json original json reply (may include signatures, those have then been
+ * validated already)
+ * @param wtid wire transfer identifier used by the mint, NULL if mint did not
+ * yet execute the transaction
+ * @param execution_time actual or planned execution time for the wire transfer
+ * @param coin_contribution contribution to the @a total_amount of the deposited coin (may be NULL)
+ * @param total_amount total amount of the wire transfer, or NULL if the mint could
+ * not provide any @a wtid (set only if @a http_status is #MHD_HTTP_OK)
+ */
+static void
+deposit_wtid_cb (void *cls,
+ unsigned int http_status,
+ json_t *json,
+ const struct TALER_WireTransferIdentifierRawP *wtid,
+ struct GNUNET_TIME_Absolute execution_time,
+ const struct TALER_Amount *coin_contribution,
+ const struct TALER_Amount *total_amount)
+{
+ struct InterpreterState *is = cls;
+ struct Command *cmd = &is->commands[is->ip];
+
+ cmd->details.deposit_wtid.dwh = NULL;
+ if (cmd->expected_response_code != http_status)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u to command %s\n",
+ http_status,
+ cmd->label);
+ json_dumpf (json, stderr, 0);
+ fail (is);
+ return;
+ }
+ switch (http_status)
+ {
+ case MHD_HTTP_OK:
+ cmd->details.deposit_wtid.wtid = *wtid;
+ if (0 != TALER_amount_cmp (total_amount,
+ &cmd->details.deposit_wtid.total_amount_expected))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Total amount missmatch to command %s\n",
+ cmd->label);
+ json_dumpf (json, stderr, 0);
+ fail (is);
+ return;
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* move to next command */
+ is->ip++;
+ is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
+ is);
+}
+
+
+/**
* Run the main interpreter loop that performs mint operations.
*
* @param cls contains the `struct InterpreterState`
@@ -1401,7 +1617,9 @@ interpreter_run (void *cls,
struct GNUNET_TIME_Absolute refund_deadline;
struct GNUNET_TIME_Absolute wire_deadline;
struct GNUNET_TIME_Absolute timestamp;
+ struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
struct TALER_MerchantPublicKeyP merchant_pub;
+ json_t *contract;
json_t *wire;
GNUNET_assert (NULL !=
@@ -1444,37 +1662,51 @@ interpreter_run (void *cls,
fail (is);
return;
}
- GNUNET_CRYPTO_hash (cmd->details.deposit.contract,
- strlen (cmd->details.deposit.contract),
- &h_contract);
+ contract = json_loads (cmd->details.deposit.contract,
+ JSON_REJECT_DUPLICATES,
+ NULL);
+ if (NULL == contract)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to parse contract details `%s' at %u/%s\n",
+ cmd->details.deposit.contract,
+ is->ip,
+ cmd->label);
+ fail (is);
+ return;
+ }
+ TALER_hash_json (contract,
+ &h_contract);
wire = json_loads (cmd->details.deposit.wire_details,
JSON_REJECT_DUPLICATES,
NULL);
if (NULL == wire)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to parse wire details `%s' at %u\n",
+ "Failed to parse wire details `%s' at %u/%s\n",
cmd->details.deposit.wire_details,
- is->ip);
+ is->ip,
+ cmd->label);
fail (is);
return;
}
GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv,
&coin_pub.eddsa_pub);
+ priv = GNUNET_CRYPTO_eddsa_key_create ();
+ cmd->details.deposit.merchant_priv.eddsa_priv = *priv;
+ GNUNET_free (priv);
if (0 != cmd->details.deposit.refund_deadline.rel_value_us)
{
- struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
-
- priv = GNUNET_CRYPTO_eddsa_key_create ();
- cmd->details.deposit.merchant_priv.eddsa_priv = *priv;
- GNUNET_free (priv);
refund_deadline = GNUNET_TIME_relative_to_absolute (cmd->details.deposit.refund_deadline);
}
else
{
refund_deadline = GNUNET_TIME_UNIT_ZERO_ABS;
}
+ GNUNET_CRYPTO_eddsa_key_get_public (&cmd->details.deposit.merchant_priv.eddsa_priv,
+ &merchant_pub.eddsa_pub);
+
wire_deadline = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_DAYS);
timestamp = GNUNET_TIME_absolute_get ();
TALER_round_abs_time (&timestamp);
@@ -1686,6 +1918,85 @@ interpreter_run (void *cls,
is);
trigger_context_task ();
return;
+ case OC_WIRE_DEPOSITS:
+ if (NULL != cmd->details.wire_deposits.wtid_ref)
+ {
+ ref = find_command (is,
+ cmd->details.wire_deposits.wtid_ref);
+ GNUNET_assert (NULL != ref);
+ cmd->details.wire_deposits.wtid = ref->details.deposit_wtid.wtid;
+ }
+ cmd->details.wire_deposits.wdh
+ = TALER_MINT_wire_deposits (mint,
+ &cmd->details.wire_deposits.wtid,
+ &wire_deposits_cb,
+ is);
+ trigger_context_task ();
+ return;
+ case OC_DEPOSIT_WTID:
+ {
+ struct GNUNET_HashCode h_wire;
+ struct GNUNET_HashCode h_contract;
+ json_t *wire;
+ json_t *contract;
+ const struct Command *coin;
+ struct TALER_CoinSpendPublicKeyP coin_pub;
+
+ ref = find_command (is,
+ cmd->details.deposit_wtid.deposit_ref);
+ GNUNET_assert (NULL != ref);
+ coin = find_command (is,
+ ref->details.deposit.coin_ref);
+ GNUNET_assert (NULL != coin);
+ switch (coin->oc)
+ {
+ case OC_WITHDRAW_SIGN:
+ GNUNET_CRYPTO_eddsa_key_get_public (&coin->details.reserve_withdraw.coin_priv.eddsa_priv,
+ &coin_pub.eddsa_pub);
+ break;
+ case OC_REFRESH_REVEAL:
+ {
+ const struct FreshCoin *fc;
+ unsigned int idx;
+
+ idx = ref->details.deposit.coin_idx;
+ GNUNET_assert (idx < coin->details.refresh_reveal.num_fresh_coins);
+ fc = &coin->details.refresh_reveal.fresh_coins[idx];
+
+ GNUNET_CRYPTO_eddsa_key_get_public (&fc->coin_priv.eddsa_priv,
+ &coin_pub.eddsa_pub);
+ }
+ break;
+ default:
+ GNUNET_assert (0);
+ }
+
+ wire = json_loads (ref->details.deposit.wire_details,
+ JSON_REJECT_DUPLICATES,
+ NULL);
+ GNUNET_assert (NULL != wire);
+ TALER_hash_json (wire,
+ &h_wire);
+ json_decref (wire);
+ contract = json_loads (ref->details.deposit.contract,
+ JSON_REJECT_DUPLICATES,
+ NULL);
+ GNUNET_assert (NULL != contract);
+ TALER_hash_json (contract,
+ &h_contract);
+ json_decref (contract);
+ cmd->details.deposit_wtid.dwh
+ = TALER_MINT_deposit_wtid (mint,
+ &ref->details.deposit.merchant_priv,
+ &h_wire,
+ &h_contract,
+ &coin_pub,
+ ref->details.deposit.transaction_id,
+ &deposit_wtid_cb,
+ is);
+ trigger_context_task ();
+ }
+ return;
default:
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unknown instruction %d at %u (%s)\n",
@@ -1695,8 +2006,6 @@ interpreter_run (void *cls,
fail (is);
return;
}
- is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
- is);
}
@@ -1829,10 +2138,36 @@ do_shutdown (void *cls,
case OC_WIRE:
if (NULL != cmd->details.wire.wh)
{
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Command %u (%s) did not complete\n",
+ i,
+ cmd->label);
TALER_MINT_wire_cancel (cmd->details.wire.wh);
cmd->details.wire.wh = NULL;
}
break;
+ case OC_WIRE_DEPOSITS:
+ if (NULL != cmd->details.wire_deposits.wdh)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Command %u (%s) did not complete\n",
+ i,
+ cmd->label);
+ TALER_MINT_wire_deposits_cancel (cmd->details.wire_deposits.wdh);
+ cmd->details.wire_deposits.wdh = NULL;
+ }
+ break;
+ case OC_DEPOSIT_WTID:
+ if (NULL != cmd->details.deposit_wtid.dwh)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Command %u (%s) did not complete\n",
+ i,
+ cmd->label);
+ TALER_MINT_deposit_wtid_cancel (cmd->details.deposit_wtid.dwh);
+ cmd->details.deposit_wtid.dwh = NULL;
+ }
+ break;
default:
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unknown instruction %d at %u (%s)\n",
@@ -2047,7 +2382,7 @@ run (void *cls,
.details.deposit.amount = "EUR:5",
.details.deposit.coin_ref = "withdraw-coin-1",
.details.deposit.wire_details = "{ \"type\":\"TEST\", \"bank\":\"dest bank\", \"account\":42 }",
- .details.deposit.contract = "{ \"items\"={ \"name\":\"ice cream\", \"value\":1 } }",
+ .details.deposit.contract = "{ \"items\": [ { \"name\":\"ice cream\", \"value\":1 } ] }",
.details.deposit.transaction_id = 1 },
/* Try to overdraw funds ... */
@@ -2064,7 +2399,7 @@ run (void *cls,
.details.deposit.amount = "EUR:5",
.details.deposit.coin_ref = "withdraw-coin-1",
.details.deposit.wire_details = "{ \"type\":\"TEST\", \"bank\":\"dest bank\", \"account\":43 }",
- .details.deposit.contract = "{ \"items\"={ \"name\":\"ice cream\", \"value\":1 } }",
+ .details.deposit.contract = "{ \"items\": [ { \"name\":\"ice cream\", \"value\":1 } ] }",
.details.deposit.transaction_id = 1 },
/* Try to double-spend the 5 EUR coin at the same merchant (but different
transaction ID) */
@@ -2074,7 +2409,7 @@ run (void *cls,
.details.deposit.amount = "EUR:5",
.details.deposit.coin_ref = "withdraw-coin-1",
.details.deposit.wire_details = "{ \"type\":\"TEST\", \"bank\":\"dest bank\", \"account\":42 }",
- .details.deposit.contract = "{ \"items\"={ \"name\":\"ice cream\", \"value\":1 } }",
+ .details.deposit.contract = "{ \"items\": [ { \"name\":\"ice cream\", \"value\":1 } ] }",
.details.deposit.transaction_id = 2 },
/* Try to double-spend the 5 EUR coin at the same merchant (but different
contract) */
@@ -2084,7 +2419,7 @@ run (void *cls,
.details.deposit.amount = "EUR:5",
.details.deposit.coin_ref = "withdraw-coin-1",
.details.deposit.wire_details = "{ \"type\":\"TEST\", \"bank\":\"dest bank\", \"account\":42 }",
- .details.deposit.contract = "{ \"items\"={ \"name\":\"ice cream\", \"value\":2 } }",
+ .details.deposit.contract = "{ \"items\":[{ \"name\":\"ice cream\", \"value\":2 } ] }",
.details.deposit.transaction_id = 1 },
/* ***************** /refresh testing ******************** */
@@ -2109,7 +2444,7 @@ run (void *cls,
.details.deposit.amount = "EUR:1",
.details.deposit.coin_ref = "refresh-withdraw-coin-1",
.details.deposit.wire_details = "{ \"type\":\"TEST\", \"bank\":\"dest bank\", \"account\":42 }",
- .details.deposit.contract = "{ \"items\"={ \"name\":\"ice cream\", \"value\"EUR:1 } }",
+ .details.deposit.contract = "{ \"items\" : [ { \"name\":\"ice cream\", \"value\":\"EUR:1\" } ] }",
.details.deposit.transaction_id = 42421 },
/* Melt the rest of the coin's value (EUR:4.00 = 3x EUR:1.03 + 7x EUR:0.13) */
@@ -2143,7 +2478,7 @@ run (void *cls,
.details.deposit.coin_ref = "refresh-reveal-1",
.details.deposit.coin_idx = 0,
.details.deposit.wire_details = "{ \"type\":\"TEST\", \"bank\":\"dest bank\", \"account\":42 }",
- .details.deposit.contract = "{ \"items\"={ \"name\":\"ice cream\", \"value\":3 } }",
+ .details.deposit.contract = "{ \"items\": [ { \"name\":\"ice cream\", \"value\":3 } ] }",
.details.deposit.transaction_id = 2 },
/* Test successfully spending coins from the refresh operation:
@@ -2155,7 +2490,7 @@ run (void *cls,
.details.deposit.coin_ref = "refresh-reveal-1",
.details.deposit.coin_idx = 4,
.details.deposit.wire_details = "{ \"type\":\"TEST\", \"bank\":\"dest bank\", \"account\":42 }",
- .details.deposit.contract = "{ \"items\"={ \"name\":\"ice cream\", \"value\":3 } }",
+ .details.deposit.contract = "{ \"items\": [ { \"name\":\"ice cream\", \"value\":3 } ] }",
.details.deposit.transaction_id = 2 },
/* Test running a failing melt operation (same operation again must fail) */
@@ -2168,6 +2503,35 @@ run (void *cls,
// FIXME: also test with coin that was already melted
// (signature differs from coin that was deposited...)
/* *************** end of /refresh testing ************** */
+
+ /* ************** Test tracking API ******************** */
+ /* Try resolving a deposit's WTID, as we never triggered
+ execution of transactions, the answer should be that
+ the mint knows about the deposit, but has no WTID yet. */
+ { .oc = OC_DEPOSIT_WTID,
+ .label = "deposit-wtid-found",
+ .expected_response_code = MHD_HTTP_ACCEPTED,
+ .details.deposit_wtid.deposit_ref = "deposit-simple" },
+ /* Try resolving a deposit's WTID for a failed deposit.
+ As the deposit failed, the answer should be that
+ the mint does NOT know about the deposit. */
+ { .oc = OC_DEPOSIT_WTID,
+ .label = "deposit-wtid-failing",
+ .expected_response_code = MHD_HTTP_NOT_FOUND,
+ .details.deposit_wtid.deposit_ref = "deposit-double-2" },
+ /* Try resolving an undefined (all zeros) WTID; this
+ should fail as obviously the mint didn't use that
+ WTID value for any transaction. */
+ { .oc = OC_WIRE_DEPOSITS,
+ .label = "wire-deposit-failing",
+ .expected_response_code = MHD_HTTP_NOT_FOUND },
+
+ /* TODO: trigger aggregation logic and then check the
+ cases where tracking succeeds! */
+
+ /* ************** End of tracking API testing************* */
+
+
#endif
{ .oc = OC_END }