summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2016-01-24 15:17:36 +0100
committerChristian Grothoff <christian@grothoff.org>2016-01-24 15:17:36 +0100
commitd89c91e64aac6b8ba0a77eb8b95d975776969e2a (patch)
treeead8a1cac5ac5419370b7e61b414a3298f2a6863
parent76b5350c30bb6d36ee548a7de554f388b5068e01 (diff)
parentd6553966f11e24f8f86aa21c0ce3760b6e966006 (diff)
downloadexchange-d89c91e64aac6b8ba0a77eb8b95d975776969e2a.tar.gz
exchange-d89c91e64aac6b8ba0a77eb8b95d975776969e2a.tar.bz2
exchange-d89c91e64aac6b8ba0a77eb8b95d975776969e2a.zip
Merge branch 'master' of git+ssh://taler.net/var/git/mint
-rw-r--r--src/include/taler_mint_service.h160
-rw-r--r--src/include/taler_mintdb_plugin.h65
-rw-r--r--src/mint-lib/Makefile.am4
-rw-r--r--src/mint-lib/mint_api_context.c2
-rw-r--r--src/mint-lib/mint_api_deposit_wtid.c386
-rw-r--r--src/mint-lib/mint_api_handle.c2
-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_link.c27
-rw-r--r--src/mint-lib/mint_api_wire_deposits.c284
-rw-r--r--src/mint-lib/test_mint_api.c406
-rw-r--r--src/mint/taler-mint-httpd_db.c108
-rw-r--r--src/mint/taler-mint-httpd_db.h2
-rw-r--r--src/mint/taler-mint-httpd_responses.c24
-rw-r--r--src/mint/taler-mint-httpd_tracking.c14
-rw-r--r--src/mintdb/perf_taler_mintdb_init.c18
-rw-r--r--src/mintdb/plugin_mintdb_postgres.c330
-rw-r--r--src/mintdb/test_mintdb.c209
18 files changed, 1927 insertions, 169 deletions
diff --git a/src/include/taler_mint_service.h b/src/include/taler_mint_service.h
index a7b6afd11..b151cb009 100644
--- a/src/include/taler_mint_service.h
+++ b/src/include/taler_mint_service.h
@@ -1059,5 +1059,165 @@ void
TALER_MINT_admin_add_incoming_cancel (struct TALER_MINT_AdminAddIncomingHandle *aai);
+/* ********************* /wire/deposits *********************** */
+
+/**
+ * @brief A /wire/deposits Handle
+ */
+struct TALER_MINT_WireDepositsHandle;
+
+
+/**
+ * Details for one of the /deposit operations that the
+ * mint combined into a single wire transfer.
+ */
+struct TALER_WireDepositDetails
+{
+ /**
+ * Hash of the contract.
+ */
+ struct GNUNET_HashCode h_contract;
+
+ /**
+ * Which coin was deposited?
+ */
+ struct TALER_CoinSpendPublicKeyP coin_pub;
+
+ /**
+ * Value of the deposit (including fee).
+ */
+ struct TALER_Amount coin_value;
+
+ /**
+ * Fee charged by the mint for the deposit.
+ */
+ struct TALER_Amount coin_fee;
+
+ /**
+ * Merchant's transaction identifier.
+ */
+ uint64_t transaction_id;
+
+};
+
+
+/**
+ * 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
+ */
+typedef void
+(*TALER_MINT_WireDepositsCallback)(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);
+
+
+/**
+ * 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);
+
+
+/**
+ * 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);
+
+
+/* ********************* /deposit/wtid *********************** */
+
+
+/**
+ * @brief A /deposit/wtid Handle
+ */
+struct TALER_MINT_DepositWtidHandle;
+
+
+/**
+ * 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)
+ */
+typedef void
+(*TALER_MINT_DepositWtidCallback)(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);
+
+
+/**
+ * Obtain the wire transfer details for a given deposit.
+ *
+ * @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);
+
+
+/**
+ * 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);
+
#endif /* _TALER_MINT_SERVICE_H */
diff --git a/src/include/taler_mintdb_plugin.h b/src/include/taler_mintdb_plugin.h
index baf587886..e5cf6d6f1 100644
--- a/src/include/taler_mintdb_plugin.h
+++ b/src/include/taler_mintdb_plugin.h
@@ -570,23 +570,24 @@ typedef void
/**
* Function called with the results of the lookup of the
- * wire transfer identifier information.
+ * wire transfer identifier information. Only called if
+ * we are at least aware of the transaction existing.
*
* @param cls closure
* @param wtid wire transfer identifier, NULL
* if the transaction was not yet done
* @param coin_contribution how much did the coin we asked about
- * contribute to the total transfer value? (deposit value minus fee)
+ * contribute to the total transfer value? (deposit value including fee)
+ * @param coin_fee how much did the mint charge for the deposit fee
* @param total_amount how much was the total wire transfer?
* @param execution_time when was the transaction done, or
- * when we expect it to be done (if @a wtid was NULL);
- * #GNUNET_TIME_UNIT_FOREVER_ABS if the /deposit is unknown
- * to the mint
+ * when we expect it to be done (if @a wtid was NULL)
*/
typedef void
(*TALER_MINTDB_DepositWtidCallback)(void *cls,
const struct TALER_WireTransferIdentifierRawP *wtid,
const struct TALER_Amount *coin_contribution,
+ const struct TALER_Amount *coin_fee,
const struct TALER_Amount *total_amount,
struct GNUNET_TIME_Absolute execution_time);
@@ -601,18 +602,20 @@ typedef void
* @param h_contract which contract was this payment about
* @param transaction_id merchant's transaction ID for the payment
* @param coin_pub which public key was this payment about
- * @param deposit_value amount contributed by this coin in total
- * @param deposit_fee deposit fee charged by mint for this coin
+ * @param coin_value amount contributed by this coin in total (with fee)
+ * @param coin_fee applicable fee for this coin
+ * @param transfer_value total amount of the wire transfer
*/
typedef void
-(*TALER_MINTDB_TransactionDataCallback)(void *cls,
- const struct TALER_MerchantPublicKeyP *merchant_pub,
- const struct GNUNET_HashCode *h_wire,
- const struct GNUNET_HashCode *h_contract,
- uint64_t transaction_id,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- const struct TALER_Amount *deposit_value,
- const struct TALER_Amount *deposit_fee);
+(*TALER_MINTDB_WireTransferDataCallback)(void *cls,
+ const struct TALER_MerchantPublicKeyP *merchant_pub,
+ const struct GNUNET_HashCode *h_wire,
+ const struct GNUNET_HashCode *h_contract,
+ uint64_t transaction_id,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const struct TALER_Amount *coin_value,
+ const struct TALER_Amount *coin_fee,
+ const struct TALER_Amount *transfer_value);
/**
@@ -1229,16 +1232,19 @@ struct TALER_MINTDB_Plugin
* into a wire transfer by the respective @a raw_wtid.
*
* @param cls the @e cls of this struct with the plugin-specific state
+ * @param session database connection
* @param wtid the raw wire transfer identifier we used
* @param cb function to call on each transaction found
* @param cb_cls closure for @a cb
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on database errors
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on database errors,
+ * #GNUNET_NO if we found no results
*/
int
- (*lookup_wire_transactions) (void *cls,
- const struct TALER_WireTransferIdentifierRawP *wtid,
- TALER_MINTDB_TransactionDataCallback cb,
- void *cb_cls);
+ (*lookup_wire_transfer) (void *cls,
+ struct TALER_MINTDB_Session *session,
+ const struct TALER_WireTransferIdentifierRawP *wtid,
+ TALER_MINTDB_WireTransferDataCallback cb,
+ void *cb_cls);
/**
@@ -1247,6 +1253,7 @@ struct TALER_MINTDB_Plugin
* to be executed.
*
* @param cls closure
+ * @param session database connection
* @param h_contract hash of the contract
* @param h_wire hash of merchant wire details
* @param coin_pub public key of deposited coin
@@ -1254,10 +1261,12 @@ struct TALER_MINTDB_Plugin
* @param transaction_id transaction identifier
* @param cb function to call with the result
* @param cb_cls closure to pass to @a cb
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on DB errors
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on DB errors,
+ * #GNUNET_NO if nothing was found
*/
int
(*wire_lookup_deposit_wtid)(void *cls,
+ struct TALER_MINTDB_Session *session,
const struct GNUNET_HashCode *h_contract,
const struct GNUNET_HashCode *h_wire,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
@@ -1271,26 +1280,32 @@ struct TALER_MINTDB_Plugin
* Function called to insert aggregation information into the DB.
*
* @param cls closure
+ * @param session database connection
* @param wtid the raw wire transfer identifier we used
* @param merchant_pub public key of the merchant (should be same for all callbacks with the same @e cls)
* @param h_wire hash of wire transfer details of the merchant (should be same for all callbacks with the same @e cls)
* @param h_contract which contract was this payment about
* @param transaction_id merchant's transaction ID for the payment
+ * @param execution_time when did we execute the transaction
* @param coin_pub which public key was this payment about
- * @param deposit_value amount contributed by this coin in total
- * @param deposit_fee deposit fee charged by mint for this coin
+ * @param coin_value amount contributed by this coin in total
+ * @param coin_fee deposit fee charged by mint for this coin
+ * @param transfer_value total amount of the wire transfer
* @return #GNUNET_OK on success, #GNUNET_SYSERR on DB errors
*/
int
(*insert_aggregation_tracking)(void *cls,
+ struct TALER_MINTDB_Session *session,
const struct TALER_WireTransferIdentifierRawP *wtid,
const struct TALER_MerchantPublicKeyP *merchant_pub,
const struct GNUNET_HashCode *h_wire,
const struct GNUNET_HashCode *h_contract,
uint64_t transaction_id,
+ struct GNUNET_TIME_Absolute execution_time,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
- const struct TALER_Amount *deposit_value,
- const struct TALER_Amount *deposit_fee);
+ const struct TALER_Amount *coin_value,
+ const struct TALER_Amount *coin_fee,
+ const struct TALER_Amount *transfer_value);
};
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_context.c b/src/mint-lib/mint_api_context.c
index 3a86efb64..2767906b5 100644
--- a/src/mint-lib/mint_api_context.c
+++ b/src/mint-lib/mint_api_context.c
@@ -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_deposit_wtid.c b/src/mint-lib/mint_api_deposit_wtid.c
new file mode 100644
index 000000000..50f9c55d8
--- /dev/null
+++ b/src/mint-lib/mint_api_deposit_wtid.c
@@ -0,0 +1,386 @@
+/*
+ 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;
+ const struct TALER_Amount *total_amount = NULL;
+ struct TALER_Amount coin_contribution_s;
+ struct TALER_Amount total_amount_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_amount ("total_amount", &total_amount_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;
+ TALER_amount_hton (&dwh->depconf.total_amount,
+ &total_amount_s);
+ total_amount = &total_amount_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,
+ total_amount);
+ 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 077e42c24..c8898d5c3 100644
--- a/src/mint-lib/mint_api_handle.c
+++ b/src/mint-lib/mint_api_handle.c
@@ -757,7 +757,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_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_link.c b/src/mint-lib/mint_api_refresh_link.c
index 9ae55b2ae..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 GNUnet e.V.
+ 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;
@@ -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++)
{
@@ -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,7 +288,6 @@ 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) */
@@ -295,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_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 0e3b2bed8..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 GNUnet e.V.
+ 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 }
diff --git a/src/mint/taler-mint-httpd_db.c b/src/mint/taler-mint-httpd_db.c
index d31dcd2ba..c39cbbcf7 100644
--- a/src/mint/taler-mint-httpd_db.c
+++ b/src/mint/taler-mint-httpd_db.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014, 2015 GNUnet e.V.
+ 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
@@ -1566,6 +1566,12 @@ struct WtidTransactionContext
struct TALER_Amount total;
/**
+ * Value we find in the DB for the @e total; only valid if @e is_valid
+ * is #GNUNET_YES.
+ */
+ struct TALER_Amount db_transaction_value;
+
+ /**
* Public key of the merchant, only valid if @e is_valid
* is #GNUNET_YES.
*/
@@ -1606,6 +1612,7 @@ struct WtidTransactionContext
* @param coin_pub which public key was this payment about
* @param deposit_value amount contributed by this coin in total
* @param deposit_fee deposit fee charged by mint for this coin
+ * @param transaction_value total value of the wire transaction
*/
static void
handle_transaction_data (void *cls,
@@ -1615,7 +1622,8 @@ handle_transaction_data (void *cls,
uint64_t transaction_id,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
const struct TALER_Amount *deposit_value,
- const struct TALER_Amount *deposit_fee)
+ const struct TALER_Amount *deposit_fee,
+ const struct TALER_Amount *transaction_value)
{
struct WtidTransactionContext *ctx = cls;
struct TALER_Amount delta;
@@ -1626,6 +1634,7 @@ handle_transaction_data (void *cls,
{
ctx->merchant_pub = *merchant_pub;
ctx->h_wire = *h_wire;
+ ctx->db_transaction_value = *transaction_value;
ctx->is_valid = GNUNET_YES;
if (GNUNET_OK !=
TALER_amount_subtract (&ctx->total,
@@ -1644,7 +1653,9 @@ handle_transaction_data (void *cls,
sizeof (struct TALER_MerchantPublicKeyP))) ||
(0 != memcmp (&ctx->h_wire,
h_wire,
- sizeof (struct GNUNET_HashCode))) )
+ sizeof (struct GNUNET_HashCode))) ||
+ (0 != TALER_amount_cmp (transaction_value,
+ &ctx->db_transaction_value)) )
{
GNUNET_break (0);
ctx->is_valid = GNUNET_SYSERR;
@@ -1693,17 +1704,25 @@ handle_transaction_data (void *cls,
*/
int
TMH_DB_execute_wire_deposits (struct MHD_Connection *connection,
- const struct TALER_WireTransferIdentifierP *wtid)
+ const struct TALER_WireTransferIdentifierRawP *wtid)
{
int ret;
struct WtidTransactionContext ctx;
+ struct TALER_MINTDB_Session *session;
+ if (NULL == (session = TMH_plugin->get_session (TMH_plugin->cls,
+ TMH_test_mode)))
+ {
+ GNUNET_break (0);
+ return TMH_RESPONSE_reply_internal_db_error (connection);
+ }
ctx.is_valid = GNUNET_NO;
ctx.deposits = json_array ();
- ret = TMH_plugin->lookup_wire_transactions (TMH_plugin->cls,
- &wtid->raw,
- &handle_transaction_data,
- &ctx);
+ ret = TMH_plugin->lookup_wire_transfer (TMH_plugin->cls,
+ session,
+ wtid,
+ &handle_transaction_data,
+ &ctx);
if (GNUNET_SYSERR == ret)
{
GNUNET_break (0);
@@ -1722,8 +1741,15 @@ TMH_DB_execute_wire_deposits (struct MHD_Connection *connection,
return TMH_RESPONSE_reply_arg_unknown (connection,
"wtid");
}
+ if (0 != TALER_amount_cmp (&ctx.total,
+ &ctx.db_transaction_value))
+ {
+ /* FIXME: this CAN actually differ, due to rounding
+ down. But we should still check that the values
+ do match after rounding 'total' down! */
+ }
return TMH_RESPONSE_reply_wire_deposit_details (connection,
- &ctx.total,
+ &ctx.db_transaction_value,
&ctx.merchant_pub,
&ctx.h_wire,
ctx.deposits);
@@ -1776,7 +1802,8 @@ struct DepositWtidContext
* @param wtid raw wire transfer identifier, NULL
* if the transaction was not yet done
* @param coin_contribution how much did the coin we asked about
- * contribute to the total transfer value? (deposit value minus fee)
+ * contribute to the total transfer value? (deposit value including fee)
+ * @param coin_fee how much did the mint charge for the deposit fee
* @param total_amount how much was the total wire transfer?
* @param execution_time when was the transaction done, or
* when we expect it to be done (if @a wtid was NULL);
@@ -1787,31 +1814,40 @@ static void
handle_wtid_data (void *cls,
const struct TALER_WireTransferIdentifierRawP *wtid,
const struct TALER_Amount *coin_contribution,
+ const struct TALER_Amount *coin_fee,
const struct TALER_Amount *total_amount,
struct GNUNET_TIME_Absolute execution_time)
{
struct DepositWtidContext *ctx = cls;
+ struct TALER_Amount coin_delta;
if (NULL == wtid)
{
- if (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us ==
- execution_time.abs_value_us)
- ctx->res = TMH_RESPONSE_reply_deposit_unknown (ctx->connection);
- else
- ctx->res = TMH_RESPONSE_reply_deposit_pending (ctx->connection,
- execution_time);
+ ctx->res = TMH_RESPONSE_reply_deposit_pending (ctx->connection,
+ execution_time);
}
else
{
- ctx->res = TMH_RESPONSE_reply_deposit_wtid (ctx->connection,
- &ctx->h_contract,
- &ctx->h_wire,
- &ctx->coin_pub,
- coin_contribution,
- total_amount,
- ctx->transaction_id,
- wtid,
- execution_time);
+ if (GNUNET_SYSERR ==
+ TALER_amount_subtract (&coin_delta,
+ coin_contribution,
+ coin_fee))
+ {
+ GNUNET_break (0);
+ ctx->res = TMH_RESPONSE_reply_internal_db_error (ctx->connection);
+ }
+ else
+ {
+ ctx->res = TMH_RESPONSE_reply_deposit_wtid (ctx->connection,
+ &ctx->h_contract,
+ &ctx->h_wire,
+ &ctx->coin_pub,
+ &coin_delta,
+ total_amount,
+ ctx->transaction_id,
+ wtid,
+ execution_time);
+ }
}
}
@@ -1838,14 +1874,22 @@ TMH_DB_execute_deposit_wtid (struct MHD_Connection *connection,
{
int ret;
struct DepositWtidContext ctx;
+ struct TALER_MINTDB_Session *session;
+ if (NULL == (session = TMH_plugin->get_session (TMH_plugin->cls,
+ TMH_test_mode)))
+ {
+ GNUNET_break (0);
+ return TMH_RESPONSE_reply_internal_db_error (connection);
+ }
ctx.connection = connection;
ctx.h_contract = *h_contract;
ctx.h_wire = *h_wire;
ctx.coin_pub = *coin_pub;
ctx.transaction_id = transaction_id;
- ctx.res = MHD_NO; /* this value should never be read... */
+ ctx.res = GNUNET_SYSERR;
ret = TMH_plugin->wire_lookup_deposit_wtid (TMH_plugin->cls,
+ session,
h_contract,
h_wire,
coin_pub,
@@ -1856,8 +1900,20 @@ TMH_DB_execute_deposit_wtid (struct MHD_Connection *connection,
if (GNUNET_SYSERR == ret)
{
GNUNET_break (0);
+ GNUNET_break (GNUNET_SYSERR == ctx.res);
return TMH_RESPONSE_reply_internal_db_error (connection);
}
+ if (GNUNET_NO == ret)
+ {
+ GNUNET_break (GNUNET_SYSERR == ctx.res);
+ return TMH_RESPONSE_reply_deposit_unknown (connection);
+ }
+ if (GNUNET_SYSERR == ctx.res)
+ {
+ GNUNET_break (0);
+ return TMH_RESPONSE_reply_internal_error (connection,
+ "bug resolving deposit wtid");
+ }
return ctx.res;
}
diff --git a/src/mint/taler-mint-httpd_db.h b/src/mint/taler-mint-httpd_db.h
index e366112dd..0327bef2a 100644
--- a/src/mint/taler-mint-httpd_db.h
+++ b/src/mint/taler-mint-httpd_db.h
@@ -202,7 +202,7 @@ TMH_DB_execute_admin_add_incoming (struct MHD_Connection *connection,
*/
int
TMH_DB_execute_wire_deposits (struct MHD_Connection *connection,
- const struct TALER_WireTransferIdentifierP *wtid);
+ const struct TALER_WireTransferIdentifierRawP *wtid);
/**
diff --git a/src/mint/taler-mint-httpd_responses.c b/src/mint/taler-mint-httpd_responses.c
index 98c362836..041f694bf 100644
--- a/src/mint/taler-mint-httpd_responses.c
+++ b/src/mint/taler-mint-httpd_responses.c
@@ -1081,7 +1081,7 @@ TMH_RESPONSE_reply_deposit_pending (struct MHD_Connection *connection,
struct GNUNET_TIME_Absolute planned_exec_time)
{
return TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_FOUND,
+ MHD_HTTP_ACCEPTED,
"{s:o}",
"execution_time", TALER_json_from_abs (planned_exec_time));
}
@@ -1117,11 +1117,7 @@ TMH_RESPONSE_reply_deposit_wtid (struct MHD_Connection *connection,
struct TALER_ConfirmWirePS cw;
struct TALER_MintPublicKeyP pub;
struct TALER_MintSignatureP sig;
- struct TALER_WireTransferIdentifierP wtid_crc;
- char *wtid_s;
- int ret;
- /* Create signature for the reply */
cw.purpose.purpose = htonl (TALER_SIGNATURE_MINT_CONFIRM_WIRE);
cw.purpose.size = htonl (sizeof (struct TALER_ConfirmWirePS));
cw.h_wire = *h_wire;
@@ -1137,24 +1133,18 @@ TMH_RESPONSE_reply_deposit_wtid (struct MHD_Connection *connection,
TMH_KS_sign (&cw.purpose,
&pub,
&sig);
- /* Compute checksum and crockford encoding if wire transfer subject */
- wtid_crc.raw = *wtid;
- wtid_crc.crc8 = GNUNET_CRYPTO_crc8_n (wtid,
- sizeof (struct TALER_WireTransferIdentifierRawP));
-
- wtid_s = GNUNET_STRINGS_data_to_string_alloc (&wtid_crc,
- sizeof (wtid_crc));
- ret = TMH_RESPONSE_reply_json_pack (connection,
+ return TMH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_OK,
- "{s:s, s:o, s:o, s:o}",
- "wtid", wtid_s,
+ "{s:o, s:o, s:o, s:o, s:o, s:o}",
+ "wtid", TALER_json_from_data (wtid,
+ sizeof (*wtid)),
"execution_time", TALER_json_from_abs (exec_time),
+ "coin_contribution", TALER_json_from_amount (coin_contribution),
+ "total_amount", TALER_json_from_amount (total_amount),
"mint_sig", TALER_json_from_data (&sig,
sizeof (sig)),
"mint_pub", TALER_json_from_data (&pub,
sizeof (pub)));
- GNUNET_free (wtid_s);
- return ret;
}
diff --git a/src/mint/taler-mint-httpd_tracking.c b/src/mint/taler-mint-httpd_tracking.c
index e61b4bae1..a6b41cf86 100644
--- a/src/mint/taler-mint-httpd_tracking.c
+++ b/src/mint/taler-mint-httpd_tracking.c
@@ -46,22 +46,17 @@ TMH_TRACKING_handler_wire_deposits (struct TMH_RequestHandler *rh,
const char *upload_data,
size_t *upload_data_size)
{
- struct TALER_WireTransferIdentifierP wtid;
+ struct TALER_WireTransferIdentifierRawP wtid;
int res;
res = TMH_PARSE_mhd_request_arg_data (connection,
"wtid",
&wtid,
- sizeof (struct TALER_WireTransferIdentifierP));
+ sizeof (struct TALER_WireTransferIdentifierRawP));
if (GNUNET_SYSERR == res)
return MHD_NO; /* internal error */
if (GNUNET_NO == res)
return MHD_YES; /* parse error */
- if (wtid.crc8 !=
- GNUNET_CRYPTO_crc8_n (&wtid.raw,
- sizeof (wtid.raw)))
- return TMH_RESPONSE_reply_arg_invalid (connection,
- "wtid");
return TMH_DB_execute_wire_deposits (connection,
&wtid);
}
@@ -126,13 +121,12 @@ TMH_TRACKING_handler_deposit_wtid (struct TMH_RequestHandler *rh,
struct TALER_DepositTrackPS tps;
uint64_t transaction_id;
struct TALER_MerchantSignatureP merchant_sig;
- struct TALER_MerchantPublicKeyP merchant_pub;
struct TMH_PARSE_FieldSpecification spec[] = {
TMH_PARSE_member_fixed ("H_wire", &tps.h_wire),
TMH_PARSE_member_fixed ("H_contract", &tps.h_contract),
TMH_PARSE_member_fixed ("coin_pub", &tps.coin_pub),
TMH_PARSE_member_uint64 ("transaction_id", &transaction_id),
- TMH_PARSE_member_fixed ("merchant_pub", &merchant_pub),
+ TMH_PARSE_member_fixed ("merchant_pub", &tps.merchant),
TMH_PARSE_member_fixed ("merchant_sig", &merchant_sig),
TMH_PARSE_MEMBER_END
};
@@ -159,7 +153,7 @@ TMH_TRACKING_handler_deposit_wtid (struct TMH_RequestHandler *rh,
tps.transaction_id = GNUNET_htonll (transaction_id);
res = check_and_handle_deposit_wtid_request (connection,
&tps,
- &merchant_pub,
+ &tps.merchant,
&merchant_sig,
transaction_id);
TMH_PARSE_release_data (spec);
diff --git a/src/mintdb/perf_taler_mintdb_init.c b/src/mintdb/perf_taler_mintdb_init.c
index 97a1b4c99..ccfc6a05a 100644
--- a/src/mintdb/perf_taler_mintdb_init.c
+++ b/src/mintdb/perf_taler_mintdb_init.c
@@ -67,9 +67,11 @@ PERF_TALER_MINTDB_denomination_init ()
properties.expire_withdraw = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_forever_());
properties.expire_spend = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_forever_());
properties.expire_legal = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_forever_());
- TALER_string_to_amount (CURRENCY ":1.1", &amount);
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (CURRENCY ":1.1", &amount));
TALER_amount_hton (&properties.value, &amount);
- TALER_string_to_amount (CURRENCY ":0.1", &amount);
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (CURRENCY ":0.1", &amount));
TALER_amount_hton (&properties.fee_withdraw, &amount);
TALER_amount_hton (&properties.fee_deposit, &amount);
TALER_amount_hton (&properties.fee_refresh, &amount);
@@ -467,8 +469,8 @@ PERF_TALER_MINTDB_refresh_session_free (struct TALER_MINTDB_RefreshSession *refr
{
if (NULL == refresh_session)
return GNUNET_OK;
- return GNUNET_OK;
GNUNET_free (refresh_session);
+ return GNUNET_OK;
}
@@ -502,10 +504,12 @@ PERF_TALER_MINTDB_refresh_melt_init (struct GNUNET_HashCode *session,
&to_sign.purpose,
&coin_sig.eddsa_signature);
}
- GNUNET_assert (GNUNET_OK == TALER_string_to_amount (CURRENCY ":1.1",
- &amount));
- GNUNET_assert (GNUNET_OK == TALER_string_to_amount (CURRENCY ":0.1",
- &amount_with_fee));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (CURRENCY ":1.1",
+ &amount));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (CURRENCY ":0.1",
+ &amount_with_fee));
melt = GNUNET_new (struct TALER_MINTDB_RefreshMelt);
melt->coin.coin_pub = coin->public_info.coin_pub;
melt->coin.denom_sig.rsa_signature =
diff --git a/src/mintdb/plugin_mintdb_postgres.c b/src/mintdb/plugin_mintdb_postgres.c
index ca8edcffd..8da986714 100644
--- a/src/mintdb/plugin_mintdb_postgres.c
+++ b/src/mintdb/plugin_mintdb_postgres.c
@@ -451,8 +451,8 @@ postgres_create_tables (void *cls,
/* Table for the tracking API, mapping from wire transfer identifiers
to transactions and back */
SQLEXEC("CREATE TABLE IF NOT EXISTS aggregation_tracking "
- "(h_contract BYTEA PRIMARY KEY CHECK (LENGTH(h_contract)=64)"
- ",h_wire BYTEA PRIMARY KEY CHECK (LENGTH(h_wire)=64)"
+ "(h_contract BYTEA CHECK (LENGTH(h_contract)=64)"
+ ",h_wire BYTEA CHECK (LENGTH(h_wire)=64)"
",coin_pub BYTEA NOT NULL CHECK (LENGTH(coin_pub)=32)"
",merchant_pub BYTEA NOT NULL CHECK (LENGTH(merchant_pub)=32)"
",transaction_id INT8 NOT NULL"
@@ -461,9 +461,12 @@ postgres_create_tables (void *cls,
",coin_amount_val INT8 NOT NULL"
",coin_amount_frac INT4 NOT NULL"
",coin_amount_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL"
- ",transaction_total_val INT8 NOT NULL"
- ",transaction_total_frac INT4 NOT NULL"
- ",transaction_total_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL"
+ ",coin_fee_val INT8 NOT NULL"
+ ",coin_fee_frac INT4 NOT NULL"
+ ",coin_fee_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL"
+ ",transfer_total_val INT8 NOT NULL"
+ ",transfer_total_frac INT4 NOT NULL"
+ ",transfer_total_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL"
")");
/* Index for lookup_transactions statement on wtid */
SQLEXEC_INDEX("CREATE INDEX aggregation_tracking_wtid_index "
@@ -708,7 +711,7 @@ postgres_prepare (PGconn *db_conn)
"SELECT"
" denom_pub"
",denom_sig"
- " FROM known_coins "
+ " FROM known_coins"
" WHERE coin_pub=$1",
1, NULL);
/* Used in #postgres_insert_known_coin() to store
@@ -875,6 +878,26 @@ postgres_prepare (PGconn *db_conn)
" (merchant_pub=$3)"
" )",
3, NULL);
+ /* Fetch an existing deposit request.
+ Used in #postgres_wire_lookup_deposit_wtid(). */
+ PREPARE ("get_deposit_for_wtid",
+ "SELECT"
+ " amount_with_fee_val"
+ ",amount_with_fee_frac"
+ ",amount_with_fee_curr"
+ ",deposit_fee_val"
+ ",deposit_fee_frac"
+ ",deposit_fee_curr"
+ ",wire_deadline"
+ " FROM deposits"
+ " WHERE ("
+ " (coin_pub=$1) AND"
+ " (transaction_id=$2) AND"
+ " (merchant_pub=$3) AND"
+ " (h_contract=$4) AND"
+ " (h_wire=$5)"
+ " )",
+ 5, NULL);
/* Used in #postgres_iterate_deposits() */
PREPARE ("deposits_iterate",
@@ -972,7 +995,7 @@ postgres_prepare (PGconn *db_conn)
" AND rm.oldcoin_index = rcl.oldcoin_index"
" AND rcl.cnc_index=rs.noreveal_index",
1, NULL);
- /* Used in #postgres_lookup_wire_transactions */
+ /* Used in #postgres_lookup_wire_transfer */
PREPARE ("lookup_transactions",
"SELECT"
" h_contract"
@@ -984,9 +1007,12 @@ postgres_prepare (PGconn *db_conn)
",coin_amount_val"
",coin_amount_frac"
",coin_amount_curr"
- ",transaction_total_val"
- ",transaction_total_frac"
- ",transaction_total_curr"
+ ",coin_fee_val"
+ ",coin_fee_frac"
+ ",coin_fee_curr"
+ ",transfer_total_val"
+ ",transfer_total_frac"
+ ",transfer_total_curr"
" FROM aggregation_tracking"
" WHERE wtid_raw=$1",
1, NULL);
@@ -998,9 +1024,12 @@ postgres_prepare (PGconn *db_conn)
",coin_amount_val"
",coin_amount_frac"
",coin_amount_curr"
- ",transaction_total_val"
- ",transaction_total_frac"
- ",transaction_total_curr"
+ ",coin_fee_val"
+ ",coin_fee_frac"
+ ",coin_fee_curr"
+ ",transfer_total_val"
+ ",transfer_total_frac"
+ ",transfer_total_curr"
" FROM aggregation_tracking"
" WHERE"
" coin_pub=$1 AND"
@@ -1022,12 +1051,15 @@ postgres_prepare (PGconn *db_conn)
",coin_amount_val"
",coin_amount_frac"
",coin_amount_curr"
- ",transaction_total_val"
- ",transaction_total_frac"
- ",transaction_total_curr"
+ ",coin_fee_val"
+ ",coin_fee_frac"
+ ",coin_fee_curr"
+ ",transfer_total_val"
+ ",transfer_total_frac"
+ ",transfer_total_curr"
") VALUES "
- "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)",
- 13, NULL);
+ "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16)",
+ 16, NULL);
return GNUNET_OK;
#undef PREPARE
@@ -3451,19 +3483,87 @@ postgres_get_coin_transactions (void *cls,
* into a wire transfer by the respective @a wtid.
*
* @param cls closure
+ * @param session database connection
* @param wtid the raw wire transfer identifier we used
* @param cb function to call on each transaction found
* @param cb_cls closure for @a cb
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on database errors
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on database errors,
+ * #GNUNET_NO if we found no results
*/
static int
-postgres_lookup_wire_transactions (void *cls,
- const struct TALER_WireTransferIdentifierRawP *wtid,
- TALER_MINTDB_TransactionDataCallback cb,
- void *cb_cls)
+postgres_lookup_wire_transfer (void *cls,
+ struct TALER_MINTDB_Session *session,
+ const struct TALER_WireTransferIdentifierRawP *wtid,
+ TALER_MINTDB_WireTransferDataCallback cb,
+ void *cb_cls)
{
- GNUNET_break (0); // not implemented!
- return GNUNET_SYSERR;
+ PGresult *result;
+ struct TALER_PQ_QueryParam params[] = {
+ TALER_PQ_query_param_auto_from_type (wtid),
+ TALER_PQ_query_param_end
+ };
+ int nrows;
+ int i;
+
+ /* check if the melt record exists and get it */
+ result = TALER_PQ_exec_prepared (session->conn,
+ "lookup_transactions",
+ params);
+ if (PGRES_TUPLES_OK != PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ nrows = PQntuples (result);
+ if (0 == nrows)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "lookup_wire_transfer() returned 0 matching rows\n");
+ PQclear (result);
+ return GNUNET_NO;
+ }
+ for (i=0;i<nrows;i++)
+ {
+ struct GNUNET_HashCode h_contract;
+ struct GNUNET_HashCode h_wire;
+ struct TALER_CoinSpendPublicKeyP coin_pub;
+ struct TALER_MerchantPublicKeyP merchant_pub;
+ uint64_t transaction_id;
+ struct GNUNET_TIME_Absolute exec_time;
+ struct TALER_Amount coin_amount;
+ struct TALER_Amount coin_fee;
+ struct TALER_Amount transfer_amount;
+ struct TALER_PQ_ResultSpec rs[] = {
+ TALER_PQ_result_spec_auto_from_type ("h_contract", &h_contract),
+ TALER_PQ_result_spec_auto_from_type ("h_wire", &h_wire),
+ TALER_PQ_result_spec_auto_from_type ("coin_pub", &coin_pub),
+ TALER_PQ_result_spec_auto_from_type ("merchant_pub", &merchant_pub),
+ TALER_PQ_result_spec_uint64 ("transaction_id", &transaction_id),
+ TALER_PQ_result_spec_absolute_time ("execution_time", &exec_time),
+ TALER_PQ_result_spec_amount ("coin_amount", &coin_amount),
+ TALER_PQ_result_spec_amount ("coin_fee", &coin_fee),
+ TALER_PQ_result_spec_amount ("transfer_total", &transfer_amount),
+ TALER_PQ_result_spec_end
+ };
+ if (GNUNET_OK != TALER_PQ_extract_result (result, rs, i))
+ {
+ GNUNET_break (0);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ cb (cb_cls,
+ &merchant_pub,
+ &h_wire,
+ &h_contract,
+ transaction_id,
+ &coin_pub,
+ &coin_amount,
+ &coin_fee,
+ &transfer_amount);
+ }
+ PQclear (result);
+ return GNUNET_OK;
}
@@ -3473,6 +3573,7 @@ postgres_lookup_wire_transactions (void *cls,
* to be executed.
*
* @param cls closure
+ * @param session database connection
* @param h_contract hash of the contract
* @param h_wire hash of merchant wire details
* @param coin_pub public key of deposited coin
@@ -3480,10 +3581,12 @@ postgres_lookup_wire_transactions (void *cls,
* @param transaction_id transaction identifier
* @param cb function to call with the result
* @param cb_cls closure to pass to @a cb
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on DB errors
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on DB errors,
+ * #GNUNET_NO if nothing was found
*/
static int
postgres_wire_lookup_deposit_wtid (void *cls,
+ struct TALER_MINTDB_Session *session,
const struct GNUNET_HashCode *h_contract,
const struct GNUNET_HashCode *h_wire,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
@@ -3492,8 +3595,130 @@ postgres_wire_lookup_deposit_wtid (void *cls,
TALER_MINTDB_DepositWtidCallback cb,
void *cb_cls)
{
- GNUNET_break (0); // not implemented
- return GNUNET_SYSERR;
+ PGresult *result;
+ struct TALER_PQ_QueryParam params[] = {
+ TALER_PQ_query_param_auto_from_type (coin_pub),
+ TALER_PQ_query_param_auto_from_type (h_contract),
+ TALER_PQ_query_param_auto_from_type (h_wire),
+ TALER_PQ_query_param_uint64 (&transaction_id),
+ TALER_PQ_query_param_auto_from_type (merchant_pub),
+ TALER_PQ_query_param_end
+ };
+ int nrows;
+
+ /* check if the melt record exists and get it */
+ result = TALER_PQ_exec_prepared (session->conn,
+ "lookup_deposit_wtid",
+ params);
+ if (PGRES_TUPLES_OK != PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ nrows = PQntuples (result);
+ if (0 == nrows)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "lookup_deposit_wtid returned 0 matching rows\n");
+ PQclear (result);
+
+ /* Check if transaction exists in deposits, so that we just
+ do not have a WTID yet, if so, do call the CB with a NULL wtid
+ and return GNUNET_YES! */
+ {
+ struct TALER_PQ_QueryParam params2[] = {
+ TALER_PQ_query_param_auto_from_type (coin_pub),
+ TALER_PQ_query_param_uint64 (&transaction_id),
+ TALER_PQ_query_param_auto_from_type (merchant_pub),
+ TALER_PQ_query_param_auto_from_type (h_contract),
+ TALER_PQ_query_param_auto_from_type (h_wire),
+ TALER_PQ_query_param_end
+ };
+
+ result = TALER_PQ_exec_prepared (session->conn,
+ "get_deposit_for_wtid",
+ params2);
+ if (PGRES_TUPLES_OK != PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ }
+ nrows = PQntuples (result);
+ if (0 == nrows)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "get_deposit_for_wtid returned 0 matching rows\n");
+ PQclear (result);
+ return GNUNET_NO;
+ }
+
+ /* Ok, we're aware of the transaction, but it has not yet been
+ executed */
+ {
+ struct GNUNET_TIME_Absolute exec_time;
+ struct TALER_Amount coin_amount;
+ struct TALER_Amount coin_fee;
+ struct TALER_PQ_ResultSpec rs[] = {
+ TALER_PQ_result_spec_amount ("amount_with_fee", &coin_amount),
+ TALER_PQ_result_spec_amount ("deposit_fee", &coin_fee),
+ TALER_PQ_result_spec_absolute_time ("wire_deadline", &exec_time),
+ TALER_PQ_result_spec_end
+ };
+
+ if (GNUNET_OK != TALER_PQ_extract_result (result, rs, 0))
+ {
+ GNUNET_break (0);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ cb (cb_cls,
+ NULL,
+ &coin_amount,
+ &coin_fee,
+ NULL,
+ exec_time);
+ PQclear (result);
+ return GNUNET_YES;
+ }
+ }
+ if (1 != nrows)
+ {
+ GNUNET_break (0);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ {
+ struct TALER_WireTransferIdentifierRawP wtid;
+ struct GNUNET_TIME_Absolute exec_time;
+ struct TALER_Amount coin_amount;
+ struct TALER_Amount coin_fee;
+ struct TALER_Amount transaction_amount;
+ struct TALER_PQ_ResultSpec rs[] = {
+ TALER_PQ_result_spec_auto_from_type ("wtid_raw", &wtid),
+ TALER_PQ_result_spec_absolute_time ("execution_time", &exec_time),
+ TALER_PQ_result_spec_amount ("coin_amount", &coin_amount),
+ TALER_PQ_result_spec_amount ("coin_fee", &coin_fee),
+ TALER_PQ_result_spec_amount ("transfer_total", &transaction_amount),
+ TALER_PQ_result_spec_end
+ };
+ if (GNUNET_OK != TALER_PQ_extract_result (result, rs, 0))
+ {
+ GNUNET_break (0);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ cb (cb_cls,
+ &wtid,
+ &coin_amount,
+ &coin_fee,
+ &transaction_amount,
+ exec_time);
+ }
+ PQclear (result);
+ return GNUNET_OK;
}
@@ -3501,29 +3726,64 @@ postgres_wire_lookup_deposit_wtid (void *cls,
* Function called to insert aggregation information into the DB.
*
* @param cls closure
+ * @param session database connection
* @param wtid the raw wire transfer identifier we used
* @param merchant_pub public key of the merchant (should be same for all callbacks with the same @e cls)
* @param h_wire hash of wire transfer details of the merchant (should be same for all callbacks with the same @e cls)
* @param h_contract which contract was this payment about
* @param transaction_id merchant's transaction ID for the payment
* @param coin_pub which public key was this payment about
- * @param deposit_value amount contributed by this coin in total
- * @param deposit_fee deposit fee charged by mint for this coin
+ * @param coin_value amount contributed by this coin in total
+ * @param coin_fee deposit fee charged by mint for this coin
+ * @param transfer_value total amount of the wire transfer
* @return #GNUNET_OK on success, #GNUNET_SYSERR on DB errors
*/
static int
postgres_insert_aggregation_tracking (void *cls,
+ struct TALER_MINTDB_Session *session,
const struct TALER_WireTransferIdentifierRawP *wtid,
const struct TALER_MerchantPublicKeyP *merchant_pub,
const struct GNUNET_HashCode *h_wire,
const struct GNUNET_HashCode *h_contract,
uint64_t transaction_id,
+ struct GNUNET_TIME_Absolute execution_time,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
- const struct TALER_Amount *deposit_value,
- const struct TALER_Amount *deposit_fee)
+ const struct TALER_Amount *coin_value,
+ const struct TALER_Amount *coin_fee,
+ const struct TALER_Amount *transfer_value)
{
- GNUNET_break (0); // not implemented
- return GNUNET_SYSERR;
+ struct TALER_PQ_QueryParam params[] = {
+ TALER_PQ_query_param_auto_from_type (h_contract),
+ TALER_PQ_query_param_auto_from_type (h_wire),
+ TALER_PQ_query_param_auto_from_type (coin_pub),
+ TALER_PQ_query_param_auto_from_type (merchant_pub),
+ TALER_PQ_query_param_uint64 (&transaction_id),
+ TALER_PQ_query_param_auto_from_type (wtid),
+ TALER_PQ_query_param_absolute_time (&execution_time),
+ TALER_PQ_query_param_amount (coin_value),
+ TALER_PQ_query_param_amount (coin_fee),
+ TALER_PQ_query_param_amount (transfer_value),
+ TALER_PQ_query_param_end
+ };
+ PGresult *result;
+
+ result = TALER_PQ_exec_prepared (session->conn,
+ "insert_aggregation_tracking",
+ params);
+ if (PGRES_COMMAND_OK != PQresultStatus (result))
+ {
+ BREAK_DB_ERR (result);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ if (0 != strcmp ("1", PQcmdTuples (result)))
+ {
+ GNUNET_break (0);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ PQclear (result);
+ return GNUNET_OK;
}
@@ -3596,7 +3856,7 @@ libtaler_plugin_mintdb_postgres_init (void *cls)
plugin->get_transfer = &postgres_get_transfer;
plugin->get_coin_transactions = &postgres_get_coin_transactions;
plugin->free_coin_transaction_list = &common_free_coin_transaction_list;
- plugin->lookup_wire_transactions = &postgres_lookup_wire_transactions;
+ plugin->lookup_wire_transfer = &postgres_lookup_wire_transfer;
plugin->wire_lookup_deposit_wtid = &postgres_wire_lookup_deposit_wtid;
plugin->insert_aggregation_tracking = &postgres_insert_aggregation_tracking;
return plugin;
diff --git a/src/mintdb/test_mintdb.c b/src/mintdb/test_mintdb.c
index 0cd660a4d..07f5d078a 100644
--- a/src/mintdb/test_mintdb.c
+++ b/src/mintdb/test_mintdb.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014, 2015 GNUnet e.V.
+ 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
@@ -14,7 +14,7 @@
TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
*/
/**
- * @file mint/test_mintdb.c
+ * @file mintdb/test_mintdb.c
* @brief test cases for DB interaction functions
* @author Sree Harsha Totakura <sreeharsha@totakura.in>
*/
@@ -305,8 +305,10 @@ test_melting (struct TALER_MINTDB_Session *session)
RND_BLK (&refresh_session);
RND_BLK (&session_hash);
melts = NULL;
+ dkp = NULL;
new_dkp = NULL;
new_denom_pubs = NULL;
+ ret_denom_pubs = NULL;
/* create and test a refresh session */
refresh_session.num_oldcoins = MELT_OLD_COINS;
refresh_session.num_newcoins = 1;
@@ -324,11 +326,11 @@ test_melting (struct TALER_MINTDB_Session *session)
sizeof (refresh_session)));
/* create a denomination (value: 1; fraction: 100) */
- dkp = create_denom_key_pair(512, session,
- &value,
- &fee_withdraw,
- &fee_deposit,
- &fee_refresh);
+ dkp = create_denom_key_pair (512, session,
+ &value,
+ &fee_withdraw,
+ &fee_deposit,
+ &fee_refresh);
/* create MELT_OLD_COINS number of refresh melts */
melts = GNUNET_new_array (MELT_OLD_COINS, struct TALER_MINTDB_RefreshMelt);
for (cnt=0; cnt < MELT_OLD_COINS; cnt++)
@@ -416,7 +418,8 @@ test_melting (struct TALER_MINTDB_Session *session)
ret = GNUNET_OK;
drop:
- destroy_denom_key_pair (dkp);
+ if (NULL != dkp)
+ destroy_denom_key_pair (dkp);
if (NULL != melts)
{
for (cnt = 0; cnt < MELT_OLD_COINS; cnt++)
@@ -440,6 +443,114 @@ test_melting (struct TALER_MINTDB_Session *session)
/**
+ * Callback that should never be called.
+ */
+static void
+cb_wt_never (void *cls,
+ const struct TALER_MerchantPublicKeyP *merchant_pub,
+ const struct GNUNET_HashCode *h_wire,
+ const struct GNUNET_HashCode *h_contract,
+ uint64_t transaction_id,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const struct TALER_Amount *coin_value,
+ const struct TALER_Amount *coin_fee,
+ const struct TALER_Amount *transfer_value)
+{
+ GNUNET_assert (0); /* this statement should be unreachable */
+}
+
+
+/**
+ * Callback that should never be called.
+ */
+static void
+cb_wtid_never (void *cls,
+ const struct TALER_WireTransferIdentifierRawP *wtid,
+ const struct TALER_Amount *coin_contribution,
+ const struct TALER_Amount *coin_fee,
+ const struct TALER_Amount *total_amount,
+ struct GNUNET_TIME_Absolute execution_time)
+{
+ GNUNET_assert (0);
+}
+
+
+static struct TALER_MerchantPublicKeyP merchant_pub_wt;
+static struct GNUNET_HashCode h_wire_wt;
+static struct GNUNET_HashCode h_contract_wt;
+static uint64_t transaction_id_wt;
+static struct TALER_CoinSpendPublicKeyP coin_pub_wt;
+static struct TALER_Amount coin_value_wt;
+static struct TALER_Amount coin_fee_wt;
+static struct TALER_Amount transfer_value_wt;
+static struct GNUNET_TIME_Absolute execution_time_wt;
+static struct TALER_WireTransferIdentifierRawP wtid_wt;
+
+
+/**
+ * Callback that should be called with the WT data.
+ */
+static void
+cb_wt_check (void *cls,
+ const struct TALER_MerchantPublicKeyP *merchant_pub,
+ const struct GNUNET_HashCode *h_wire,
+ const struct GNUNET_HashCode *h_contract,
+ uint64_t transaction_id,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const struct TALER_Amount *coin_value,
+ const struct TALER_Amount *coin_fee,
+ const struct TALER_Amount *transfer_value)
+{
+ GNUNET_assert (cls == &cb_wt_never);
+ GNUNET_assert (0 == memcmp (merchant_pub,
+ &merchant_pub_wt,
+ sizeof (struct TALER_MerchantPublicKeyP)));
+ GNUNET_assert (0 == memcmp (h_wire,
+ &h_wire_wt,
+ sizeof (struct GNUNET_HashCode)));
+ GNUNET_assert (0 == memcmp (h_contract,
+ &h_contract_wt,
+ sizeof (struct GNUNET_HashCode)));
+ GNUNET_assert (transaction_id == transaction_id_wt);
+ GNUNET_assert (0 == memcmp (coin_pub,
+ &coin_pub_wt,
+ sizeof (struct TALER_CoinSpendPublicKeyP)));
+ GNUNET_assert (0 == TALER_amount_cmp (coin_value,
+ &coin_value_wt));
+ GNUNET_assert (0 == TALER_amount_cmp (coin_fee,
+ &coin_fee_wt));
+ GNUNET_assert (0 == TALER_amount_cmp (transfer_value,
+ &transfer_value_wt));
+}
+
+
+/**
+ * Callback that should be called with the WT data.
+ */
+static void
+cb_wtid_check (void *cls,
+ const struct TALER_WireTransferIdentifierRawP *wtid,
+ const struct TALER_Amount *coin_contribution,
+ const struct TALER_Amount *coin_fee,
+ const struct TALER_Amount *total_amount,
+ struct GNUNET_TIME_Absolute execution_time)
+{
+ GNUNET_assert (cls == &cb_wtid_never);
+ GNUNET_assert (0 == memcmp (wtid,
+ &wtid_wt,
+ sizeof (struct TALER_WireTransferIdentifierRawP)));
+ GNUNET_assert (execution_time.abs_value_us ==
+ execution_time_wt.abs_value_us);
+ GNUNET_assert (0 == TALER_amount_cmp (coin_contribution,
+ &coin_value_wt));
+ GNUNET_assert (0 == TALER_amount_cmp (coin_fee,
+ &coin_fee_wt));
+ GNUNET_assert (0 == TALER_amount_cmp (total_amount,
+ &transfer_value_wt));
+}
+
+
+/**
* Main function that will be run by the scheduler.
*
* @param cls closure
@@ -455,7 +566,6 @@ run (void *cls,
{
struct TALER_MINTDB_Session *session;
struct TALER_ReservePublicKeyP reserve_pub;
- struct TALER_Amount amount;
struct DenomKeyPair *dkp;
struct TALER_MINTDB_CollectableBlindcoin cbc;
struct TALER_MINTDB_CollectableBlindcoin cbc2;
@@ -465,6 +575,7 @@ run (void *cls,
struct TALER_MINTDB_CollectableBlindcoin *withdraw;
struct TALER_MINTDB_Deposit deposit;
struct TALER_MINTDB_Deposit deposit2;
+ struct TALER_WireTransferIdentifierRawP wtid;
json_t *wire;
json_t *just;
const char * const json_wire_str =
@@ -563,11 +674,7 @@ run (void *cls,
= GNUNET_CRYPTO_rsa_sign (dkp->priv.rsa_private_key,
&cbc.h_coin_envelope,
sizeof (cbc.h_coin_envelope));
- (void) memcpy (&cbc.reserve_pub,
- &reserve_pub,
- sizeof (reserve_pub));
- amount.value--;
- amount.fraction--;
+ cbc.reserve_pub = reserve_pub;
cbc.amount_with_fee = value;
GNUNET_assert (GNUNET_OK ==
TALER_amount_get_zero (CURRENCY, &cbc.withdraw_fee));
@@ -652,9 +759,7 @@ run (void *cls,
plugin->have_deposit (plugin->cls,
session,
&deposit));
- (void) memcpy (&deposit2,
- &deposit,
- sizeof (deposit));
+ deposit2 = deposit;
deposit2.transaction_id++; /* should fail if transaction id is different */
FAILIF (GNUNET_NO !=
plugin->have_deposit (plugin->cls,
@@ -666,15 +771,79 @@ run (void *cls,
plugin->have_deposit (plugin->cls,
session,
&deposit2));
- (void) memcpy (&deposit2.merchant_pub,
- &deposit.merchant_pub,
- sizeof (deposit.merchant_pub));
+ deposit2.merchant_pub = deposit.merchant_pub;
RND_BLK (&deposit2.coin.coin_pub); /* should fail if coin is different */
FAILIF (GNUNET_NO !=
plugin->have_deposit (plugin->cls,
session,
&deposit2));
FAILIF (GNUNET_OK != test_melting (session));
+
+ /* setup values for wire transfer aggregation data */
+ memset (&wtid, 42, sizeof (wtid));
+ memset (&merchant_pub_wt, 43, sizeof (merchant_pub_wt));
+ memset (&h_wire_wt, 44, sizeof (h_wire_wt));
+ memset (&h_contract_wt, 45, sizeof (h_contract_wt));
+ memset (&coin_pub_wt, 46, sizeof (coin_pub_wt));
+ transaction_id_wt = 47;
+ execution_time_wt = GNUNET_TIME_absolute_get ();
+ memset (&merchant_pub_wt, 48, sizeof (merchant_pub_wt));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (CURRENCY "KUDOS:1.000010",
+ &coin_value_wt));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (CURRENCY "KUDOS:0.000010",
+ &coin_fee_wt));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (CURRENCY "KUDOS:1.000000",
+ &transfer_value_wt));
+
+ FAILIF (GNUNET_NO !=
+ plugin->lookup_wire_transfer (plugin->cls,
+ session,
+ &wtid_wt,
+ &cb_wt_never,
+ NULL));
+ FAILIF (GNUNET_NO !=
+ plugin->wire_lookup_deposit_wtid (plugin->cls,
+ session,
+ &h_contract_wt,
+ &h_wire_wt,
+ &coin_pub_wt,
+ &merchant_pub_wt,
+ transaction_id_wt,
+ &cb_wtid_never,
+ NULL));
+ /* insert WT data */
+ FAILIF (GNUNET_OK !=
+ plugin->insert_aggregation_tracking (plugin->cls,
+ session,
+ &wtid_wt,
+ &merchant_pub_wt,
+ &h_wire_wt,
+ &h_contract_wt,
+ transaction_id_wt,
+ execution_time_wt,
+ &coin_pub_wt,
+ &coin_value_wt,
+ &coin_fee_wt,
+ &transfer_value_wt));
+ FAILIF (GNUNET_OK !=
+ plugin->lookup_wire_transfer (plugin->cls,
+ session,
+ &wtid_wt,
+ &cb_wt_check,
+ &cb_wt_never));
+ FAILIF (GNUNET_OK !=
+ plugin->wire_lookup_deposit_wtid (plugin->cls,
+ session,
+ &h_contract_wt,
+ &h_wire_wt,
+ &coin_pub_wt,
+ &merchant_pub_wt,
+ transaction_id_wt,
+ &cb_wtid_check,
+ &cb_wtid_never));
result = 0;
drop: