summaryrefslogtreecommitdiff
path: root/src/mint
diff options
context:
space:
mode:
Diffstat (limited to 'src/mint')
-rw-r--r--src/mint/Makefile.am24
-rw-r--r--src/mint/taler-mint-aggregator.c914
-rw-r--r--src/mint/taler-mint-httpd.c45
-rw-r--r--src/mint/taler-mint-httpd.h8
-rw-r--r--src/mint/taler-mint-httpd_admin.c4
-rw-r--r--src/mint/taler-mint-httpd_db.c297
-rw-r--r--src/mint/taler-mint-httpd_db.h16
-rw-r--r--src/mint/taler-mint-httpd_deposit.c4
-rw-r--r--src/mint/taler-mint-httpd_responses.c101
-rw-r--r--src/mint/taler-mint-httpd_responses.h43
-rw-r--r--src/mint/taler-mint-httpd_tracking.c24
-rw-r--r--src/mint/taler-mint-httpd_validation.c231
-rw-r--r--src/mint/taler-mint-httpd_validation.h76
-rw-r--r--src/mint/taler-mint-httpd_wire.c31
14 files changed, 1695 insertions, 123 deletions
diff --git a/src/mint/Makefile.am b/src/mint/Makefile.am
index a115d63a0..8e2eae77b 100644
--- a/src/mint/Makefile.am
+++ b/src/mint/Makefile.am
@@ -7,21 +7,33 @@ if USE_COVERAGE
endif
bin_PROGRAMS = \
+ taler-mint-aggregator \
taler-mint-httpd
+taler_mint_aggregator_SOURCES = \
+ taler-mint-aggregator.c
+taler_mint_aggregator_LDADD = \
+ $(LIBGCRYPT_LIBS) \
+ $(top_builddir)/src/util/libtalerutil.la \
+ $(top_builddir)/src/wire/libtalerwire.la \
+ $(top_builddir)/src/mintdb/libtalermintdb.la \
+ -ljansson \
+ -lgnunetutil
+
taler_mint_httpd_SOURCES = \
taler-mint-httpd.c taler-mint-httpd.h \
- taler-mint-httpd_keystate.c taler-mint-httpd_keystate.h \
- taler-mint-httpd_db.c taler-mint-httpd_db.h \
- taler-mint-httpd_parsing.c taler-mint-httpd_parsing.h \
- taler-mint-httpd_responses.c taler-mint-httpd_responses.h \
- taler-mint-httpd_mhd.c taler-mint-httpd_mhd.h \
taler-mint-httpd_admin.c taler-mint-httpd_admin.h \
+ taler-mint-httpd_db.c taler-mint-httpd_db.h \
taler-mint-httpd_deposit.c taler-mint-httpd_deposit.h \
+ taler-mint-httpd_keystate.c taler-mint-httpd_keystate.h \
+ taler-mint-httpd_mhd.c taler-mint-httpd_mhd.h \
+ taler-mint-httpd_parsing.c taler-mint-httpd_parsing.h \
+ taler-mint-httpd_refresh.c taler-mint-httpd_refresh.h \
taler-mint-httpd_reserve.c taler-mint-httpd_reserve.h \
+ taler-mint-httpd_responses.c taler-mint-httpd_responses.h \
taler-mint-httpd_tracking.c taler-mint-httpd_tracking.h \
taler-mint-httpd_wire.c taler-mint-httpd_wire.h \
- taler-mint-httpd_refresh.c taler-mint-httpd_refresh.h
+ taler-mint-httpd_validation.c taler-mint-httpd_validation.h
taler_mint_httpd_LDADD = \
$(LIBGCRYPT_LIBS) \
$(top_builddir)/src/util/libtalerutil.la \
diff --git a/src/mint/taler-mint-aggregator.c b/src/mint/taler-mint-aggregator.c
new file mode 100644
index 000000000..5e05c8673
--- /dev/null
+++ b/src/mint/taler-mint-aggregator.c
@@ -0,0 +1,914 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2016 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Affero 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+
+/**
+ * @file taler-mint-aggregator.c
+ * @brief Process that aggregates outgoing transactions and executes them
+ * @author Christian Grothoff
+ *
+ * TODO:
+ * - simplify global_ret: make it a global!
+ * - handle shutdown more nicely (call 'cancel' method on wire transfers)
+ */
+#include "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include <jansson.h>
+#include <pthread.h>
+#include "taler_mintdb_lib.h"
+#include "taler_mintdb_plugin.h"
+#include "taler_wire_lib.h"
+
+/**
+ * Which currency is used by this mint?
+ */
+static char *mint_currency_string;
+
+/**
+ * Which wireformat should be supported by this aggregator?
+ */
+static char *mint_wireformat;
+
+/**
+ * Base directory of the mint (global)
+ */
+static char *mint_directory;
+
+/**
+ * The mint's configuration (global)
+ */
+static struct GNUNET_CONFIGURATION_Handle *cfg;
+
+/**
+ * Our DB plugin.
+ */
+static struct TALER_MINTDB_Plugin *db_plugin;
+
+/**
+ * Our wire plugin.
+ */
+static struct TALER_WIRE_Plugin *wire_plugin;
+
+/**
+ * Task for the main #run() function.
+ */
+static struct GNUNET_SCHEDULER_Task *task;
+
+/**
+ * Limit on the number of transactions we aggregate at once. Note
+ * that the limit must be big enough to ensure that when transactions
+ * of the smallest possible unit are aggregated, they do surpass the
+ * "tiny" threshold beyond which we never trigger a wire transaction!
+ *
+ * TODO: make configurable (via config file or command line option)
+ */
+static unsigned int aggregation_limit = 10000;
+
+
+/**
+ * Load configuration parameters for the mint
+ * server into the corresponding global variables.
+ *
+ * @param mint_directory the mint's directory
+ * @return #GNUNET_OK on success
+ */
+static int
+mint_serve_process_config (const char *mint_directory)
+{
+ char *type;
+
+ cfg = TALER_config_load (mint_directory);
+ if (NULL == cfg)
+ {
+ fprintf (stderr,
+ "Failed to load mint configuration\n");
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ "mint",
+ "currency",
+ &mint_currency_string))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "mint",
+ "currency");
+ return GNUNET_SYSERR;
+ }
+ if (strlen (mint_currency_string) >= TALER_CURRENCY_LEN)
+ {
+ fprintf (stderr,
+ "Currency `%s' longer than the allowed limit of %u characters.",
+ mint_currency_string,
+ (unsigned int) TALER_CURRENCY_LEN);
+ return GNUNET_SYSERR;
+ }
+ if (NULL != mint_wireformat)
+ GNUNET_CONFIGURATION_set_value_string (cfg,
+ "mint",
+ "wireformat",
+ mint_wireformat);
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ "mint",
+ "wireformat",
+ &type))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "mint",
+ "wireformat");
+ return GNUNET_SYSERR;
+ }
+
+ if (NULL ==
+ (db_plugin = TALER_MINTDB_plugin_load (cfg)))
+ {
+ fprintf (stderr,
+ "Failed to initialize DB subsystem\n");
+ GNUNET_free (type);
+ return GNUNET_SYSERR;
+ }
+
+ if (NULL ==
+ (wire_plugin = TALER_WIRE_plugin_load (cfg,
+ type)))
+ {
+ fprintf (stderr,
+ "Failed to load wire plugin for `%s'\n",
+ type);
+ GNUNET_free (type);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_free (type);
+
+ return GNUNET_OK;
+}
+
+
+/**
+ * Information about one aggregation process to
+ * be executed.
+ */
+struct AggregationUnit
+{
+ /**
+ * Public key of the merchant.
+ */
+ struct TALER_MerchantPublicKeyP merchant_pub;
+
+ /**
+ * Total amount to be transferred.
+ */
+ struct TALER_Amount total_amount;
+
+ /**
+ * Hash of @e wire.
+ */
+ struct GNUNET_HashCode h_wire;
+
+ /**
+ * Wire transfer identifier we use.
+ */
+ struct TALER_WireTransferIdentifierRawP wtid;
+
+ /**
+ * Row ID of the transaction that started it all.
+ */
+ unsigned long long row_id;
+
+ /**
+ * The current time.
+ */
+ struct GNUNET_TIME_Absolute execution_time;
+
+ /**
+ * Wire details of the merchant.
+ */
+ json_t *wire;
+
+ /**
+ * Database session for all of our transactions.
+ */
+ struct TALER_MINTDB_Session *session;
+
+ /**
+ * Wire preparation handle.
+ */
+ struct TALER_WIRE_PrepareHandle *ph;
+
+ /**
+ * Array of #aggregation_limit row_ids from the
+ * aggregation.
+ */
+ unsigned long long *additional_rows;
+
+ /**
+ * Pointer to global return value. Closure for #run().
+ */
+ int *global_ret;
+
+ /**
+ * Offset specifying how many #additional_rows are in use.
+ */
+ unsigned int rows_offset;
+
+ /**
+ * Set to #GNUNET_YES if we have to abort due to failure.
+ */
+ int failed;
+
+};
+
+
+/**
+ * Function called with details about deposits that have been made,
+ * with the goal of executing the corresponding wire transaction.
+ *
+ * @param cls closure with the `struct AggregationUnit`
+ * @param row_id identifies database entry
+ * @param merchant_pub public key of the merchant
+ * @param coin_pub public key of the coin
+ * @param amount_with_fee amount that was deposited including fee
+ * @param deposit_fee amount the mint gets to keep as transaction fees
+ * @param transaction_id unique transaction ID chosen by the merchant
+ * @param h_contract hash of the contract between merchant and customer
+ * @param wire_deadline by which the merchant adviced that he would like the
+ * wire transfer to be executed
+ * @param wire wire details for the merchant
+ * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
+ */
+static int
+deposit_cb (void *cls,
+ unsigned long long row_id,
+ const struct TALER_MerchantPublicKeyP *merchant_pub,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const struct TALER_Amount *amount_with_fee,
+ const struct TALER_Amount *deposit_fee,
+ uint64_t transaction_id,
+ const struct GNUNET_HashCode *h_contract,
+ struct GNUNET_TIME_Absolute wire_deadline,
+ const json_t *wire)
+{
+ struct AggregationUnit *au = cls;
+
+ au->merchant_pub = *merchant_pub;
+ if (GNUNET_OK !=
+ TALER_amount_subtract (&au->total_amount,
+ amount_with_fee,
+ deposit_fee))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Fatally malformed record at %llu\n",
+ row_id);
+ return GNUNET_SYSERR;
+ }
+ au->row_id = row_id;
+ au->wire = (json_t *) wire;
+ au->execution_time = GNUNET_TIME_absolute_get ();
+ TALER_hash_json (au->wire,
+ &au->h_wire);
+ json_incref (au->wire);
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
+ &au->wtid,
+ sizeof (au->wtid));
+ if (GNUNET_OK !=
+ db_plugin->insert_aggregation_tracking (db_plugin->cls,
+ au->session,
+ &au->wtid,
+ merchant_pub,
+ &au->h_wire,
+ h_contract,
+ transaction_id,
+ au->execution_time,
+ coin_pub,
+ amount_with_fee,
+ deposit_fee))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ db_plugin->mark_deposit_done (db_plugin->cls,
+ au->session,
+ row_id))
+ {
+ GNUNET_break (0);
+ au->failed = GNUNET_YES;
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+
+/**
+ * Function called with details about another deposit we
+ * can aggregate into an existing aggregation unit.
+ *
+ * @param cls closure with the `struct AggregationUnit`
+ * @param row_id identifies database entry
+ * @param merchant_pub public key of the merchant
+ * @param coin_pub public key of the coin
+ * @param amount_with_fee amount that was deposited including fee
+ * @param deposit_fee amount the mint gets to keep as transaction fees
+ * @param transaction_id unique transaction ID chosen by the merchant
+ * @param h_contract hash of the contract between merchant and customer
+ * @param wire_deadline by which the merchant adviced that he would like the
+ * wire transfer to be executed
+ * @param wire wire details for the merchant
+ * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
+ */
+static int
+aggregate_cb (void *cls,
+ unsigned long long row_id,
+ const struct TALER_MerchantPublicKeyP *merchant_pub,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const struct TALER_Amount *amount_with_fee,
+ const struct TALER_Amount *deposit_fee,
+ uint64_t transaction_id,
+ const struct GNUNET_HashCode *h_contract,
+ struct GNUNET_TIME_Absolute wire_deadline,
+ const json_t *wire)
+{
+ struct AggregationUnit *au = cls;
+ struct TALER_Amount delta;
+
+ GNUNET_break (0 ==
+ memcmp (&au->merchant_pub,
+ merchant_pub,
+ sizeof (struct TALER_MerchantPublicKeyP)));
+ /* compute contribution of this coin after fees */
+ if (GNUNET_OK !=
+ TALER_amount_subtract (&delta,
+ amount_with_fee,
+ deposit_fee))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Fatally malformed record at %llu\n",
+ row_id);
+ return GNUNET_SYSERR;
+ }
+ /* add to total */
+ if (GNUNET_OK !=
+ TALER_amount_add (&au->total_amount,
+ &au->total_amount,
+ &delta))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Overflow or currency incompatibility during aggregation at %llu\n",
+ row_id);
+ /* Skip this one, but keep going! */
+ return GNUNET_OK;
+ }
+ if (au->rows_offset >= aggregation_limit)
+ {
+ /* Bug: we asked for at most #aggregation_limit results! */
+ GNUNET_break (0);
+ /* Skip this one, but keep going. */
+ return GNUNET_OK;
+ }
+ if (NULL == au->additional_rows)
+ au->additional_rows = GNUNET_new_array (aggregation_limit,
+ unsigned long long);
+ /* "append" to our list of rows */
+ au->additional_rows[au->rows_offset++] = row_id;
+ /* insert into aggregation tracking table */
+ if (GNUNET_OK !=
+ db_plugin->insert_aggregation_tracking (db_plugin->cls,
+ au->session,
+ &au->wtid,
+ merchant_pub,
+ &au->h_wire,
+ h_contract,
+ transaction_id,
+ au->execution_time,
+ coin_pub,
+ amount_with_fee,
+ deposit_fee))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ db_plugin->mark_deposit_done (db_plugin->cls,
+ au->session,
+ row_id))
+ {
+ GNUNET_break (0);
+ au->failed = GNUNET_YES;
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Function to be called with the prepared transfer data.
+ *
+ * @param cls closure with the `struct AggregationUnit`
+ * @param buf transaction data to persist, NULL on error
+ * @param buf_size number of bytes in @a buf, 0 on error
+ */
+static void
+prepare_cb (void *cls,
+ const char *buf,
+ size_t buf_size);
+
+
+/**
+ * Main work function that queries the DB and aggregates transactions
+ * into larger wire transfers.
+ *
+ * @param cls pointer to an `int` which we will return from main()
+ * @param tc scheduler context
+ */
+static void
+run_aggregation (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ int *global_ret = cls;
+ struct TALER_MINTDB_Session *session;
+ struct AggregationUnit *au;
+ unsigned int i;
+ int ret;
+
+ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+ return;
+ if (NULL == (session = db_plugin->get_session (db_plugin->cls,
+ GNUNET_NO)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to obtain database session!\n");
+ *global_ret = GNUNET_SYSERR;
+ return;
+ }
+ if (GNUNET_OK !=
+ db_plugin->start (db_plugin->cls,
+ session))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to start database transaction!\n");
+ *global_ret = GNUNET_SYSERR;
+ return;
+ }
+ au = GNUNET_new (struct AggregationUnit);
+ au->session = session;
+ ret = db_plugin->get_ready_deposit (db_plugin->cls,
+ session,
+ &deposit_cb,
+ au);
+ if (GNUNET_OK != ret)
+ {
+ GNUNET_free (au);
+ db_plugin->rollback (db_plugin->cls,
+ session);
+ if (0 != ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to execute deposit iteration!\n");
+ *global_ret = GNUNET_SYSERR;
+ return;
+ }
+ /* nothing to do, sleep for a minute and try again */
+ task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
+ &run_aggregation,
+ global_ret);
+ return;
+ }
+ /* Now try to find other deposits to aggregate */
+ ret = db_plugin->iterate_matching_deposits (db_plugin->cls,
+ session,
+ &au->h_wire,
+ &au->merchant_pub,
+ &aggregate_cb,
+ au,
+ aggregation_limit);
+ if ( (GNUNET_SYSERR == ret) ||
+ (GNUNET_YES == au->failed) )
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to execute deposit iteration!\n");
+ GNUNET_free_non_null (au->additional_rows);
+ GNUNET_free (au);
+ db_plugin->rollback (db_plugin->cls,
+ session);
+ *global_ret = GNUNET_SYSERR;
+ return;
+ }
+ /* Round to the unit supported by the wire transfer method */
+ GNUNET_assert (GNUNET_SYSERR !=
+ wire_plugin->amount_round (wire_plugin->cls,
+ &au->total_amount));
+ /* Check if after rounding down, we still have an amount to transfer */
+ if ( (0 == au->total_amount.value) &&
+ (0 == au->total_amount.fraction) )
+ {
+ /* Rollback ongoing transaction, as we will not use the respective
+ WTID and thus need to remove the tracking data */
+ db_plugin->rollback (db_plugin->cls,
+ session);
+ /* Start another transaction to mark all* of the selected deposits
+ *as minor! */
+ if (GNUNET_OK !=
+ db_plugin->start (db_plugin->cls,
+ session))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to start database transaction!\n");
+ *global_ret = GNUNET_SYSERR;
+ GNUNET_free_non_null (au->additional_rows);
+ GNUNET_free (au);
+ return;
+ }
+ /* Mark transactions by row_id as minor */
+ ret = GNUNET_OK;
+ if (GNUNET_OK !=
+ db_plugin->mark_deposit_tiny (db_plugin->cls,
+ session,
+ au->row_id))
+ ret = GNUNET_SYSERR;
+ else
+ for (i=0;i<au->rows_offset;i++)
+ if (GNUNET_OK !=
+ db_plugin->mark_deposit_tiny (db_plugin->cls,
+ session,
+ au->additional_rows[i]))
+ ret = GNUNET_SYSERR;
+ /* commit */
+ if (GNUNET_OK !=
+ db_plugin->commit (db_plugin->cls,
+ session))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Failed to commit database transaction!\n");
+ }
+ GNUNET_free_non_null (au->additional_rows);
+ GNUNET_free (au);
+ /* start again */
+ task = GNUNET_SCHEDULER_add_now (&run_aggregation,
+ global_ret);
+ return;
+ }
+ au->global_ret = global_ret;
+ au->ph = wire_plugin->prepare_wire_transfer (wire_plugin->cls,
+ au->wire,
+ &au->total_amount,
+ &au->wtid,
+ &prepare_cb,
+ au);
+ /* FIXME: currently we have no clean-up plan on
+ shutdown to call prepare_wire_transfer_cancel!
+ Maybe make 'au' global? */
+ if (NULL == au->ph)
+ {
+ GNUNET_break (0); /* why? how to best recover? */
+ db_plugin->rollback (db_plugin->cls,
+ session);
+ GNUNET_free_non_null (au->additional_rows);
+ GNUNET_free (au);
+ /* start again */
+ task = GNUNET_SCHEDULER_add_now (&run_aggregation,
+ global_ret);
+ return;
+ }
+ /* otherwise we continue with #prepare_cb(), see below */
+}
+
+
+/**
+ * Execute the wire transfers that we have committed to
+ * do.
+ *
+ * @param cls pointer to an `int` which we will return from main()
+ * @param tc scheduler context
+ */
+static void
+run_transfers (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+
+/**
+ * Function to be called with the prepared transfer data.
+ *
+ * @param cls closure with the `struct AggregationUnit`
+ * @param buf transaction data to persist, NULL on error
+ * @param buf_size number of bytes in @a buf, 0 on error
+ */
+static void
+prepare_cb (void *cls,
+ const char *buf,
+ size_t buf_size)
+{
+ struct AggregationUnit *au = cls;
+ int *global_ret = au->global_ret;
+ struct TALER_MINTDB_Session *session = au->session;
+
+ GNUNET_free_non_null (au->additional_rows);
+ GNUNET_free (au);
+ if (NULL == buf)
+ {
+ GNUNET_break (0); /* why? how to best recover? */
+ db_plugin->rollback (db_plugin->cls,
+ session);
+ /* start again */
+ task = GNUNET_SCHEDULER_add_now (&run_aggregation,
+ global_ret);
+ return;
+ }
+
+ /* Commit our intention to execute the wire transfer! */
+ if (GNUNET_OK !=
+ db_plugin->wire_prepare_data_insert (db_plugin->cls,
+ session,
+ mint_wireformat,
+ buf,
+ buf_size))
+ {
+ GNUNET_break (0); /* why? how to best recover? */
+ db_plugin->rollback (db_plugin->cls,
+ session);
+ /* start again */
+ task = GNUNET_SCHEDULER_add_now (&run_aggregation,
+ global_ret);
+ return;
+ }
+
+ /* Now we can finally commit the overall transaction, as we are
+ again consistent if all of this passes. */
+ if (GNUNET_OK !=
+ db_plugin->commit (db_plugin->cls,
+ session))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Failed to commit database transaction!\n");
+ /* try again */
+ task = GNUNET_SCHEDULER_add_now (&run_aggregation,
+ global_ret);
+ return;
+ }
+
+ /* run alternative task: actually do wire transfer! */
+ task = GNUNET_SCHEDULER_add_now (&run_transfers,
+ &global_ret);
+}
+
+
+/**
+ * Data we keep to #run_transfers().
+ */
+struct WirePrepareData
+{
+
+ /**
+ * Database session for all of our transactions.
+ */
+ struct TALER_MINTDB_Session *session;
+
+ /**
+ * Wire execution handle.
+ */
+ struct TALER_WIRE_ExecuteHandle *eh;
+
+ /**
+ * Pointer to global return value. Closure for #run().
+ */
+ int *global_ret;
+
+
+ /**
+ * Row ID of the transfer.
+ */
+ unsigned long long row_id;
+
+};
+
+
+/**
+ * Function called with the result from the execute step.
+ *
+ * @param cls closure with the `struct WirePrepareData`
+ * @param success #GNUNET_OK on success, #GNUNET_SYSERR on failure
+ * @param emsg NULL on success, otherwise an error message
+ */
+static void
+wire_confirm_cb (void *cls,
+ int success,
+ const char *emsg)
+{
+ struct WirePrepareData *wpd = cls;
+ int *global_ret = wpd->global_ret;
+ struct TALER_MINTDB_Session *session = wpd->session;
+
+ wpd->eh = NULL;
+ if (GNUNET_SYSERR == success)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Wire transaction failed: %s\n",
+ emsg);
+ db_plugin->rollback (db_plugin->cls,
+ session);
+ *global_ret = GNUNET_SYSERR;
+ GNUNET_free (wpd);
+ return;
+ }
+ if (GNUNET_OK !=
+ db_plugin->wire_prepare_data_mark_finished (db_plugin->cls,
+ session,
+ wpd->row_id))
+ {
+ GNUNET_break (0); /* why!? */
+ db_plugin->rollback (db_plugin->cls,
+ session);
+ *global_ret = GNUNET_SYSERR;
+ GNUNET_free (wpd);
+ return;
+ }
+ GNUNET_free (wpd);
+ if (GNUNET_OK !=
+ db_plugin->commit (db_plugin->cls,
+ session))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Failed to commit database transaction!\n");
+ /* try again */
+ task = GNUNET_SCHEDULER_add_now (&run_aggregation,
+ global_ret);
+ return;
+ }
+ /* continue with #run_transfers(), just to guard
+ against the unlikely case that there are more. */
+ task = GNUNET_SCHEDULER_add_now (&run_transfers,
+ &global_ret);
+
+}
+
+
+/**
+ * Callback with data about a prepared transaction.
+ *
+ * @param cls closure with the `struct WirePrepareData`
+ * @param rowid row identifier used to mark prepared transaction as done
+ * @param buf transaction data that was persisted, NULL on error
+ * @param buf_size number of bytes in @a buf, 0 on error
+ */
+static void
+wire_prepare_cb (void *cls,
+ unsigned long long rowid,
+ const char *buf,
+ size_t buf_size)
+{
+ struct WirePrepareData *wpd = cls;
+ int *global_ret = wpd->global_ret;
+
+ wpd->row_id = rowid;
+ wpd->eh = wire_plugin->execute_wire_transfer (wire_plugin->cls,
+ buf,
+ buf_size,
+ &wire_confirm_cb,
+ wpd);
+ /* FIXME: currently we have no clean-up plan on
+ shutdown to call execute_wire_transfer_cancel!
+ Maybe make 'wpd' global? */
+ if (NULL == wpd->eh)
+ {
+ GNUNET_break (0); /* why? how to best recover? */
+ db_plugin->rollback (db_plugin->cls,
+ wpd->session);
+ *global_ret = GNUNET_SYSERR;
+ GNUNET_free (wpd);
+ return;
+ }
+}
+
+
+/**
+ * Execute the wire transfers that we have committed to
+ * do.
+ *
+ * @param cls pointer to an `int` which we will return from main()
+ * @param tc scheduler context
+ */
+static void
+run_transfers (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ int *global_ret = cls;
+ int ret;
+ struct WirePrepareData *wpd;
+ struct TALER_MINTDB_Session *session;
+
+ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+ return;
+ if (NULL == (session = db_plugin->get_session (db_plugin->cls,
+ GNUNET_NO)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to obtain database session!\n");
+ *global_ret = GNUNET_SYSERR;
+ return;
+ }
+ if (GNUNET_OK !=
+ db_plugin->start (db_plugin->cls,
+ session))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to start database transaction!\n");
+ *global_ret = GNUNET_SYSERR;
+ return;
+ }
+ wpd = GNUNET_new (struct WirePrepareData);
+ wpd->session = session;
+ wpd->global_ret = global_ret;
+ ret = db_plugin->wire_prepare_data_get (db_plugin->cls,
+ session,
+ mint_wireformat,
+ &wire_prepare_cb,
+ wpd);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_break (0); /* why? how to best recover? */
+ db_plugin->rollback (db_plugin->cls,
+ session);
+ *global_ret = GNUNET_SYSERR;
+ GNUNET_free (wpd);
+ return;
+ }
+ if (GNUNET_NO == ret)
+ {
+ /* no more prepared wire transfers, go back to aggregation! */
+ db_plugin->rollback (db_plugin->cls,
+ session);
+ task = GNUNET_SCHEDULER_add_now (&run_aggregation,
+ global_ret);
+ GNUNET_free (wpd);
+ return;
+ }
+ /* otherwise, continues in #wire_prepare_cb() */
+}
+
+
+/**
+ * The main function of the taler-mint-httpd server ("the mint").
+ *
+ * @param argc number of arguments from the command line
+ * @param argv command line arguments
+ * @return 0 ok, 1 on error
+ */
+int
+main (int argc,
+ char *const *argv)
+{
+ static const struct GNUNET_GETOPT_CommandLineOption options[] = {
+ {'d', "mint-dir", "DIR",
+ "mint directory with configuration and keys for operating the mint", 1,
+ &GNUNET_GETOPT_set_filename, &mint_directory},
+ {'f', "format", "WIREFORMAT",
+ "wireformat to use, overrides WIREFORMAT option in [mint] section", 1,
+ &GNUNET_GETOPT_set_filename, &mint_wireformat},
+ TALER_GETOPT_OPTION_HELP ("background process that aggregates and executes wire transfers to merchants"),
+ GNUNET_GETOPT_OPTION_VERSION (VERSION "-" VCS_VERSION),
+ GNUNET_GETOPT_OPTION_END
+ };
+ int ret = GNUNET_OK;
+
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_log_setup ("taler-mint-aggregator",
+ "INFO",
+ NULL));
+ if (0 >=
+ GNUNET_GETOPT_run ("taler-mint-aggregator",
+ options,
+ argc, argv))
+ return 1;
+ if (NULL == mint_directory)
+ {
+ fprintf (stderr,
+ "Mint directory not specified\n");
+ return 1;
+ }
+ if (GNUNET_OK !=
+ mint_serve_process_config (mint_directory))
+ {
+ return 1;
+ }
+
+ GNUNET_SCHEDULER_run (&run_transfers, &ret);
+
+ TALER_MINTDB_plugin_unload (db_plugin);
+ TALER_WIRE_plugin_unload (wire_plugin);
+ return (GNUNET_SYSERR == ret) ? 1 : 0;
+}
+
+/* end of taler-mint-aggregator.c */
diff --git a/src/mint/taler-mint-httpd.c b/src/mint/taler-mint-httpd.c
index 26a440c95..5d6aa0589 100644
--- a/src/mint/taler-mint-httpd.c
+++ b/src/mint/taler-mint-httpd.c
@@ -39,6 +39,7 @@
#include "taler-mint-httpd_test.h"
#endif
#include "taler_mintdb_plugin.h"
+#include "taler-mint-httpd_validation.h"
/**
* Which currency is used by this mint?
@@ -67,13 +68,6 @@ struct GNUNET_CONFIGURATION_Handle *cfg;
struct GNUNET_CRYPTO_EddsaPublicKey TMH_master_public_key;
/**
- * In which format does this MINT expect wiring instructions?
- * NULL-terminated array of 0-terminated wire format types,
- * suitable for passing to #TALER_json_validate_wireformat().
- */
-const char **TMH_expected_wire_formats;
-
-/**
* Our DB plugin.
*/
struct TALER_MINTDB_Plugin *TMH_plugin;
@@ -384,9 +378,6 @@ mint_serve_process_config (const char *mint_directory)
{
unsigned long long port;
char *TMH_master_public_key_str;
- char *wireformats;
- const char *token;
- unsigned int len;
cfg = TALER_config_load (mint_directory);
if (NULL == cfg)
@@ -414,35 +405,9 @@ mint_serve_process_config (const char *mint_directory)
(unsigned int) TALER_CURRENCY_LEN);
return GNUNET_SYSERR;
}
- /* Find out list of supported wire formats */
if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "mint",
- "wireformat",
- &wireformats))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "mint",
- "wireformat");
+ TMH_VALIDATION_init (cfg))
return GNUNET_SYSERR;
- }
- /* build NULL-terminated array of TMH_expected_wire_formats */
- TMH_expected_wire_formats = GNUNET_new_array (1,
- const char *);
- len = 1;
- for (token = strtok (wireformats,
- " ");
- NULL != token;
- token = strtok (NULL,
- " "))
- {
- /* Grow by 1, appending NULL-terminator */
- GNUNET_array_append (TMH_expected_wire_formats,
- len,
- NULL);
- TMH_expected_wire_formats[len - 2] = GNUNET_strdup (token);
- }
- GNUNET_free (wireformats);
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_string (cfg,
@@ -453,6 +418,7 @@ mint_serve_process_config (const char *mint_directory)
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
"mint",
"master_public_key");
+ TMH_VALIDATION_done ();
return GNUNET_SYSERR;
}
if (GNUNET_OK !=
@@ -463,6 +429,7 @@ mint_serve_process_config (const char *mint_directory)
fprintf (stderr,
"Invalid master public key given in mint configuration.");
GNUNET_free (TMH_master_public_key_str);
+ TMH_VALIDATION_done ();
return GNUNET_SYSERR;
}
GNUNET_free (TMH_master_public_key_str);
@@ -472,6 +439,7 @@ mint_serve_process_config (const char *mint_directory)
{
fprintf (stderr,
"Failed to initialize DB subsystem\n");
+ TMH_VALIDATION_done ();
return GNUNET_SYSERR;
}
if (GNUNET_YES ==
@@ -496,6 +464,7 @@ mint_serve_process_config (const char *mint_directory)
"mint",
"port",
"port number required");
+ TMH_VALIDATION_done ();
return GNUNET_SYSERR;
}
@@ -505,6 +474,7 @@ mint_serve_process_config (const char *mint_directory)
fprintf (stderr,
"Invalid configuration (value out of range): %llu is not a valid port\n",
port);
+ TMH_VALIDATION_done ();
return GNUNET_SYSERR;
}
serve_port = (uint16_t) port;
@@ -772,6 +742,7 @@ main (int argc,
session);
}
TALER_MINTDB_plugin_unload (TMH_plugin);
+ TMH_VALIDATION_done ();
return (GNUNET_SYSERR == ret) ? 1 : 0;
}
diff --git a/src/mint/taler-mint-httpd.h b/src/mint/taler-mint-httpd.h
index e83dd66f2..d45325aa6 100644
--- a/src/mint/taler-mint-httpd.h
+++ b/src/mint/taler-mint-httpd.h
@@ -27,6 +27,7 @@
#include <microhttpd.h>
+
/**
* Which currency is used by this mint?
*/
@@ -53,13 +54,6 @@ extern int TMH_test_mode;
extern char *TMH_mint_directory;
/**
- * In which formats does this MINT expect wiring instructions?
- * NULL-terminated array of 0-terminated wire format types,
- * suitable for passing to #TALER_json_validate_wireformat().
- */
-extern const char **TMH_expected_wire_formats;
-
-/**
* Master public key (according to the
* configuration in the mint directory).
*/
diff --git a/src/mint/taler-mint-httpd_admin.c b/src/mint/taler-mint-httpd_admin.c
index 99f256418..e6f186f0b 100644
--- a/src/mint/taler-mint-httpd_admin.c
+++ b/src/mint/taler-mint-httpd_admin.c
@@ -24,6 +24,7 @@
#include "taler-mint-httpd_admin.h"
#include "taler-mint-httpd_parsing.h"
#include "taler-mint-httpd_responses.h"
+#include "taler-mint-httpd_validation.h"
/**
@@ -144,8 +145,7 @@ TMH_ADMIN_handler_admin_add_incoming (struct TMH_RequestHandler *rh,
return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
}
if (GNUNET_YES !=
- TALER_json_validate_wireformat (TMH_expected_wire_formats,
- wire))
+ TMH_json_validate_wireformat (wire))
{
GNUNET_break_op (0);
TMH_PARSE_release_data (spec);
diff --git a/src/mint/taler-mint-httpd_db.c b/src/mint/taler-mint-httpd_db.c
index 2b4ade595..b93ead3af 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 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
@@ -1552,9 +1552,214 @@ TMH_DB_execute_admin_add_incoming (struct MHD_Connection *connection,
/**
+ * Closure for #handle_transaction_data.
+ */
+struct WtidTransactionContext
+{
+
+ /**
+ * Total amount of the wire transfer, as calculated by
+ * summing up the individual amounts. To be rounded down
+ * to calculate the real transfer amount at the end.
+ * Only valid if @e is_valid is #GNUNET_YES.
+ */
+ 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.
+ */
+ struct TALER_MerchantPublicKeyP merchant_pub;
+
+ /**
+ * Hash of the wire details of the merchant (identical for all
+ * deposits), only valid if @e is_valid is #GNUNET_YES.
+ */
+ struct GNUNET_HashCode h_wire;
+
+ /**
+ * JSON array with details about the individual deposits.
+ */
+ json_t *deposits;
+
+ /**
+ * Initially #GNUNET_NO, if we found no deposits so far. Set to
+ * #GNUNET_YES if we got transaction data, and the database replies
+ * remained consistent with respect to @e merchant_pub and @e h_wire
+ * (as they should). Set to #GNUNET_SYSERR if we encountered an
+ * internal error.
+ */
+ int is_valid;
+
+};
+
+
+/**
+ * Function called with the results of the lookup of the
+ * transaction data for the given wire transfer identifier.
+ *
+ * @param cls our context for transmission
+ * @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 transaction_value total value of the wire transaction
+ */
+static void
+handle_transaction_data (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,
+ const struct TALER_Amount *transaction_value)
+{
+ struct WtidTransactionContext *ctx = cls;
+ struct TALER_Amount delta;
+
+ if (GNUNET_SYSERR == ctx->is_valid)
+ return;
+ if (GNUNET_NO == ctx->is_valid)
+ {
+ 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,
+ deposit_value,
+ deposit_fee))
+ {
+ GNUNET_break (0);
+ ctx->is_valid = GNUNET_SYSERR;
+ return;
+ }
+ }
+ else
+ {
+ if ( (0 != memcmp (&ctx->merchant_pub,
+ merchant_pub,
+ sizeof (struct TALER_MerchantPublicKeyP))) ||
+ (0 != memcmp (&ctx->h_wire,
+ h_wire,
+ sizeof (struct GNUNET_HashCode))) ||
+ (0 != TALER_amount_cmp (transaction_value,
+ &ctx->db_transaction_value)) )
+ {
+ GNUNET_break (0);
+ ctx->is_valid = GNUNET_SYSERR;
+ return;
+ }
+ if (GNUNET_OK !=
+ TALER_amount_subtract (&delta,
+ deposit_value,
+ deposit_fee))
+ {
+ GNUNET_break (0);
+ ctx->is_valid = GNUNET_SYSERR;
+ return;
+ }
+ if (GNUNET_OK !=
+ TALER_amount_add (&ctx->total,
+ &ctx->total,
+ &delta))
+ {
+ GNUNET_break (0);
+ ctx->is_valid = GNUNET_SYSERR;
+ return;
+ }
+ }
+ /* NOTE: We usually keep JSON stuff out of the _DB file, and this
+ is also ugly if we ever add signatures over this data. (#4135) */
+ json_array_append (ctx->deposits,
+ json_pack ("{s:o, s:o, s:o, s:I, s:o}",
+ "deposit_value", TALER_json_from_amount (deposit_value),
+ "deposit_fee", TALER_json_from_amount (deposit_fee),
+ "H_contract", TALER_json_from_data (h_contract,
+ sizeof (struct GNUNET_HashCode)),
+ "transaction_id", (json_int_t) transaction_id,
+ "coin_pub", TALER_json_from_data (coin_pub,
+ sizeof (struct TALER_CoinSpendPublicKeyP))));
+}
+
+
+/**
+ * Execute a "/wire/deposits". Returns the transaction information
+ * associated with the given wire transfer identifier.
+ *
+ * @param connection the MHD connection to handle
+ * @param wtid wire transfer identifier to resolve
+ * @return MHD result code
+ */
+int
+TMH_DB_execute_wire_deposits (struct MHD_Connection *connection,
+ 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_transfer (TMH_plugin->cls,
+ session,
+ wtid,
+ &handle_transaction_data,
+ &ctx);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_break (0);
+ json_decref (ctx.deposits);
+ return TMH_RESPONSE_reply_internal_db_error (connection);
+ }
+ if (GNUNET_SYSERR == ctx.is_valid)
+ {
+ GNUNET_break (0);
+ json_decref (ctx.deposits);
+ return TMH_RESPONSE_reply_internal_db_error (connection);
+ }
+ if (GNUNET_NO == ctx.is_valid)
+ {
+ json_decref (ctx.deposits);
+ 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.db_transaction_value,
+ &ctx.merchant_pub,
+ &ctx.h_wire,
+ ctx.deposits);
+}
+
+
+/**
* Closure for #handle_wtid_data.
*/
-struct DepositWtidContext
+struct DepositWtidContext
{
/**
@@ -1563,6 +1768,26 @@ struct DepositWtidContext
struct MHD_Connection *connection;
/**
+ * Hash of the contract we are looking up.
+ */
+ struct GNUNET_HashCode h_contract;
+
+ /**
+ * Hash of the wire transfer details we are looking up.
+ */
+ struct GNUNET_HashCode h_wire;
+
+ /**
+ * Public key we are looking up.
+ */
+ struct TALER_CoinSpendPublicKeyP coin_pub;
+
+ /**
+ * Transaction ID we are looking up.
+ */
+ uint64_t transaction_id;
+
+ /**
* MHD result code to return.
*/
int res;
@@ -1572,10 +1797,13 @@ struct DepositWtidContext
/**
* Function called with the results of the lookup of the
* wire transfer identifier information.
- *
+ *
* @param cls our context for transmission
- * @param wtid base32-encoded wire transfer identifier, NULL
+ * @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 including fee)
+ * @param coin_fee how much did the mint charge for the deposit fee
* @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
@@ -1583,23 +1811,41 @@ struct DepositWtidContext
*/
static void
handle_wtid_data (void *cls,
- const char *wtid,
+ const struct TALER_WireTransferIdentifierRawP *wtid,
+ const struct TALER_Amount *coin_contribution,
+ const struct TALER_Amount *coin_fee,
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);
+ ctx->res = TMH_RESPONSE_reply_deposit_pending (ctx->connection,
+ execution_time);
}
else
{
- ctx->res = TMH_RESPONSE_reply_deposit_wtid (ctx->connection);
- }
+ 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,
+ ctx->transaction_id,
+ wtid,
+ execution_time);
+ }
+ }
}
@@ -1625,21 +1871,46 @@ 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 = GNUNET_SYSERR;
ret = TMH_plugin->wire_lookup_deposit_wtid (TMH_plugin->cls,
+ session,
h_contract,
h_wire,
coin_pub,
merchant_pub,
transaction_id,
&handle_wtid_data,
- connection);
+ &ctx);
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 d9adba2d9..0327bef2a 100644
--- a/src/mint/taler-mint-httpd_db.h
+++ b/src/mint/taler-mint-httpd_db.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
@@ -193,6 +193,19 @@ TMH_DB_execute_admin_add_incoming (struct MHD_Connection *connection,
/**
+ * Execute a "/wire/deposits". Returns the transaction information
+ * associated with the given wire transfer identifier.
+ *
+ * @param connection the MHD connection to handle
+ * @param wtid wire transfer identifier to resolve
+ * @return MHD result code
+ */
+int
+TMH_DB_execute_wire_deposits (struct MHD_Connection *connection,
+ const struct TALER_WireTransferIdentifierRawP *wtid);
+
+
+/**
* Execute a "/deposit/wtid". Returns the transfer information
* associated with the given deposit.
*
@@ -212,5 +225,6 @@ TMH_DB_execute_deposit_wtid (struct MHD_Connection *connection,
const struct TALER_MerchantPublicKeyP *merchant_pub,
uint64_t transaction_id);
+
#endif
/* TALER_MINT_HTTPD_DB_H */
diff --git a/src/mint/taler-mint-httpd_deposit.c b/src/mint/taler-mint-httpd_deposit.c
index 0aef4775c..40c5a4db7 100644
--- a/src/mint/taler-mint-httpd_deposit.c
+++ b/src/mint/taler-mint-httpd_deposit.c
@@ -34,6 +34,7 @@
#include "taler-mint-httpd_deposit.h"
#include "taler-mint-httpd_responses.h"
#include "taler-mint-httpd_keystate.h"
+#include "taler-mint-httpd_validation.h"
/**
@@ -162,8 +163,7 @@ parse_and_handle_deposit_request (struct MHD_Connection *connection,
return MHD_YES; /* failure */
if (GNUNET_YES !=
- TALER_json_validate_wireformat (TMH_expected_wire_formats,
- wire))
+ TMH_json_validate_wireformat (wire))
{
TMH_PARSE_release_data (spec);
return TMH_RESPONSE_reply_arg_unknown (connection,
diff --git a/src/mint/taler-mint-httpd_responses.c b/src/mint/taler-mint-httpd_responses.c
index f3498b469..2ebd0d331 100644
--- a/src/mint/taler-mint-httpd_responses.c
+++ b/src/mint/taler-mint-httpd_responses.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 Affero General Public License as published by the Free Software
@@ -1056,15 +1056,15 @@ TMH_RESPONSE_reply_refresh_link_success (struct MHD_Connection *connection,
* 404 reply.
*
* @param connection connection to the client
- * @param
* @return MHD result code
*/
int
-TMH_RESPONSE_reply_deposit_unknown (struct MHD_Connection *connection,
- ...)
+TMH_RESPONSE_reply_deposit_unknown (struct MHD_Connection *connection)
{
- GNUNET_break (0); // FIXME: not implemented
- return MHD_NO;
+ return TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_NOT_FOUND,
+ "{s:s}",
+ "error", "Deposit unknown");
}
@@ -1073,15 +1073,17 @@ TMH_RESPONSE_reply_deposit_unknown (struct MHD_Connection *connection,
* we did not execute the deposit yet. Generate a 202 reply.
*
* @param connection connection to the client
- * @param
+ * @param planned_exec_time planned execution time
* @return MHD result code
*/
int
TMH_RESPONSE_reply_deposit_pending (struct MHD_Connection *connection,
- ...)
+ struct GNUNET_TIME_Absolute planned_exec_time)
{
- GNUNET_break (0); // FIXME: not implemented
- return MHD_NO;
+ return TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_ACCEPTED,
+ "{s:o}",
+ "execution_time", TALER_json_from_abs (planned_exec_time));
}
@@ -1090,15 +1092,86 @@ TMH_RESPONSE_reply_deposit_pending (struct MHD_Connection *connection,
* them. Generates the 200 reply.
*
* @param connection connection to the client
- * @param
+ * @param h_contract hash of the contract
+ * @param h_wire hash of wire account details
+ * @param coin_pub public key of the coin
+ * @param coin_contribution how much did the coin we asked about
+ * contribute to the total transfer value? (deposit value minus fee)
+ * @param transaction_id merchant transaction identifier
+ * @param wtid raw wire transfer identifier
+ * @param exec_time execution time of the wire transfer
* @return MHD result code
*/
int
TMH_RESPONSE_reply_deposit_wtid (struct MHD_Connection *connection,
- ...)
+ const struct GNUNET_HashCode *h_contract,
+ const struct GNUNET_HashCode *h_wire,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const struct TALER_Amount *coin_contribution,
+ uint64_t transaction_id,
+ const struct TALER_WireTransferIdentifierRawP *wtid,
+ struct GNUNET_TIME_Absolute exec_time)
+{
+ struct TALER_ConfirmWirePS cw;
+ struct TALER_MintPublicKeyP pub;
+ struct TALER_MintSignatureP sig;
+
+ cw.purpose.purpose = htonl (TALER_SIGNATURE_MINT_CONFIRM_WIRE);
+ cw.purpose.size = htonl (sizeof (struct TALER_ConfirmWirePS));
+ cw.h_wire = *h_wire;
+ cw.h_contract = *h_contract;
+ cw.wtid = *wtid;
+ cw.coin_pub = *coin_pub;
+ cw.transaction_id = GNUNET_htonll (transaction_id);
+ cw.execution_time = GNUNET_TIME_absolute_hton (exec_time);
+ TALER_amount_hton (&cw.coin_contribution,
+ coin_contribution);
+ TMH_KS_sign (&cw.purpose,
+ &pub,
+ &sig);
+ return TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_OK,
+ "{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),
+ "mint_sig", TALER_json_from_data (&sig,
+ sizeof (sig)),
+ "mint_pub", TALER_json_from_data (&pub,
+ sizeof (pub)));
+}
+
+
+/**
+ * A merchant asked for transaction details about a wire transfer.
+ * Provide them. Generates the 200 reply.
+ *
+ * @param connection connection to the client
+ * @param total total amount that was transferred
+ * @param merchant_pub public key of the merchant
+ * @param h_wire destination account
+ * @param deposits details about the combined deposits
+ * @return MHD result code
+ */
+int
+TMH_RESPONSE_reply_wire_deposit_details (struct MHD_Connection *connection,
+ const struct TALER_Amount *total,
+ const struct TALER_MerchantPublicKeyP *merchant_pub,
+ const struct GNUNET_HashCode *h_wire,
+ json_t *deposits)
{
- GNUNET_break (0); // FIXME: not implemented
- return MHD_NO;
+ /* FIXME: #4135: signing not implemented here */
+ return TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_OK,
+ "{s:o, s:o, s:o, s:o}",
+ "total", TALER_json_from_amount (total),
+ "merchant_pub", TALER_json_from_data (merchant_pub,
+ sizeof (struct TALER_MerchantPublicKeyP)),
+ "h_wire", TALER_json_from_data (h_wire,
+ sizeof (struct GNUNET_HashCode)),
+ "deposits", deposits);
}
+
/* end of taler-mint-httpd_responses.c */
diff --git a/src/mint/taler-mint-httpd_responses.h b/src/mint/taler-mint-httpd_responses.h
index 5d1523b4b..a0396c8a1 100644
--- a/src/mint/taler-mint-httpd_responses.h
+++ b/src/mint/taler-mint-httpd_responses.h
@@ -253,12 +253,10 @@ TMH_RESPONSE_reply_deposit_insufficient_funds (struct MHD_Connection *connection
* 404 reply.
*
* @param connection connection to the client
- * @param
* @return MHD result code
*/
int
-TMH_RESPONSE_reply_deposit_unknown (struct MHD_Connection *connection,
- ...);
+TMH_RESPONSE_reply_deposit_unknown (struct MHD_Connection *connection);
/**
@@ -266,12 +264,12 @@ TMH_RESPONSE_reply_deposit_unknown (struct MHD_Connection *connection,
* we did not execute the deposit yet. Generate a 202 reply.
*
* @param connection connection to the client
- * @param
+ * @param planned_exec_time planned execution time
* @return MHD result code
*/
int
TMH_RESPONSE_reply_deposit_pending (struct MHD_Connection *connection,
- ...);
+ struct GNUNET_TIME_Absolute planned_exec_time);
/**
@@ -279,12 +277,43 @@ TMH_RESPONSE_reply_deposit_pending (struct MHD_Connection *connection,
* them. Generates the 200 reply.
*
* @param connection connection to the client
- * @param
+ * @param h_contract hash of the contract
+ * @param h_wire hash of wire account details
+ * @param coin_pub public key of the coin
+ * @param coin_contribution contribution of this coin to the total amount transferred
+ * @param transaction_id merchant transaction identifier
+ * @param wtid raw wire transfer identifier
+ * @param exec_time execution time of the wire transfer
* @return MHD result code
*/
int
TMH_RESPONSE_reply_deposit_wtid (struct MHD_Connection *connection,
- ...);
+ const struct GNUNET_HashCode *h_contract,
+ const struct GNUNET_HashCode *h_wire,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const struct TALER_Amount *coin_contribution,
+ uint64_t transaction_id,
+ const struct TALER_WireTransferIdentifierRawP *wtid,
+ struct GNUNET_TIME_Absolute exec_time);
+
+
+/**
+ * A merchant asked for transaction details about a wire transfer.
+ * Provide them. Generates the 200 reply.
+ *
+ * @param connection connection to the client
+ * @param total total amount that was transferred
+ * @param merchant_pub public key of the merchant
+ * @param h_wire destination account
+ * @param deposits details about the combined deposits
+ * @return MHD result code
+ */
+int
+TMH_RESPONSE_reply_wire_deposit_details (struct MHD_Connection *connection,
+ const struct TALER_Amount *total,
+ const struct TALER_MerchantPublicKeyP *merchant_pub,
+ const struct GNUNET_HashCode *h_wire,
+ json_t *deposits);
/**
diff --git a/src/mint/taler-mint-httpd_tracking.c b/src/mint/taler-mint-httpd_tracking.c
index 59d029429..a6b41cf86 100644
--- a/src/mint/taler-mint-httpd_tracking.c
+++ b/src/mint/taler-mint-httpd_tracking.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 Affero General Public License as published by the Free Software
@@ -46,8 +46,19 @@ TMH_TRACKING_handler_wire_deposits (struct TMH_RequestHandler *rh,
const char *upload_data,
size_t *upload_data_size)
{
- GNUNET_break (0); // not implemented
- return MHD_NO;
+ struct TALER_WireTransferIdentifierRawP wtid;
+ int res;
+
+ res = TMH_PARSE_mhd_request_arg_data (connection,
+ "wtid",
+ &wtid,
+ sizeof (struct TALER_WireTransferIdentifierRawP));
+ if (GNUNET_SYSERR == res)
+ return MHD_NO; /* internal error */
+ if (GNUNET_NO == res)
+ return MHD_YES; /* parse error */
+ return TMH_DB_execute_wire_deposits (connection,
+ &wtid);
}
@@ -57,7 +68,7 @@ TMH_TRACKING_handler_wire_deposits (struct TMH_RequestHandler *rh,
*
* @param connection the MHD connection to handle
* @param tps signed request to execute
- * @param merchant_pub public key from the merchant
+ * @param merchant_pub public key from the merchant
* @param merchant_sig signature from the merchant (to be checked)
* @param transaction_id transaction ID (in host byte order)
* @return MHD result code
@@ -110,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
};
@@ -143,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/mint/taler-mint-httpd_validation.c b/src/mint/taler-mint-httpd_validation.c
new file mode 100644
index 000000000..461e88759
--- /dev/null
+++ b/src/mint/taler-mint-httpd_validation.c
@@ -0,0 +1,231 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2016 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Affero 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+
+/**
+ * @file taler-mint-httpd_validation.c
+ * @brief helpers for calling the wire plugins to validate addresses
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include "taler-mint-httpd_validation.h"
+#include "taler_wire_plugin.h"
+
+
+/**
+ * Information we keep for each plugin.
+ */
+struct Plugin
+{
+
+ /**
+ * We keep plugins in a DLL.
+ */
+ struct Plugin *next;
+
+ /**
+ * We keep plugins in a DLL.
+ */
+ struct Plugin *prev;
+
+ /**
+ * Type of the wireformat.
+ */
+ char *type;
+
+ /**
+ * Pointer to the plugin.
+ */
+ struct TALER_WIRE_Plugin *plugin;
+
+};
+
+/**
+ * Head of DLL of wire plugins.
+ */
+static struct Plugin *wire_head;
+
+/**
+ * Tail of DLL of wire plugins.
+ */
+static struct Plugin *wire_tail;
+
+
+/**
+ * Initialize validation subsystem.
+ *
+ * @param cfg configuration to use
+ * @return #GNUNET_OK on success
+ */
+int
+TMH_VALIDATION_init (const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ struct Plugin *p;
+ char *wireformats;
+ char *lib_name;
+ const char *token;
+
+ /* Find out list of supported wire formats */
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ "mint",
+ "wireformat",
+ &wireformats))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "mint",
+ "wireformat");
+ return GNUNET_SYSERR;
+ }
+ for (token = strtok (wireformats,
+ " ");
+ NULL != token;
+ token = strtok (NULL,
+ " "))
+ {
+ (void) GNUNET_asprintf (&lib_name,
+ "libtaler_plugin_wire_%s",
+ lib_name);
+ p = GNUNET_new (struct Plugin);
+ p->type = GNUNET_strdup (token);
+ p->plugin = GNUNET_PLUGIN_load (lib_name,
+ (void *) cfg);
+ if (NULL == p->plugin)
+ {
+ GNUNET_free (p);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to load plugin %s\n",
+ lib_name);
+ GNUNET_free (lib_name);
+ TMH_VALIDATION_done ();
+ return GNUNET_SYSERR;
+ }
+ p->plugin->library_name = lib_name;
+ GNUNET_CONTAINER_DLL_insert (wire_head,
+ wire_tail,
+ p);
+ }
+ GNUNET_free (wireformats);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Shutdown validation subsystem.
+ */
+void
+TMH_VALIDATION_done ()
+{
+ struct Plugin *p;
+ char *lib_name;
+
+ while (NULL != (p = wire_head))
+ {
+ GNUNET_CONTAINER_DLL_remove (wire_head,
+ wire_tail,
+ p);
+ lib_name = p->plugin->library_name;
+ GNUNET_assert (NULL == GNUNET_PLUGIN_unload (lib_name,
+ p->plugin));
+ GNUNET_free (lib_name);
+ GNUNET_free (p->type);
+ GNUNET_free (p);
+ }
+}
+
+
+/**
+ * Check if the given wire format JSON object is correctly formatted as
+ * a wire address.
+ *
+ * @param wire the JSON wire format object
+ * @return #GNUNET_YES if correctly formatted; #GNUNET_NO if not
+ */
+int
+TMH_json_validate_wireformat (const json_t *wire)
+{
+ const char *stype;
+ json_error_t error;
+ struct Plugin *p;
+
+ if (0 != json_unpack_ex ((json_t *) wire,
+ &error, 0,
+ "{s:s}",
+ "type", &stype))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ for (p=wire_head; NULL != p; p = p->next)
+ if (0 == strcasecmp (p->type,
+ stype))
+ return p->plugin->wire_validate (wire);
+ return GNUNET_NO;
+}
+
+
+/**
+ * Check if we support the given wire method.
+ *
+ * @param type type of wire method to check
+ * @return #GNUNET_YES if the method is supported
+ */
+int
+TMH_VALIDATION_test_method (const char *type)
+{
+ struct Plugin *p;
+
+ for (p=wire_head;NULL != p;p = p->next)
+ if (0 == strcasecmp (type,
+ p->type))
+ return GNUNET_YES;
+ return GNUNET_NO;
+}
+
+
+/**
+ * Obtain supported validation methods as a JSON array,
+ * and as a hash.
+ *
+ * @param[out] h set to the hash of the JSON methods
+ * @return JSON array with the supported validation methods
+ */
+json_t *
+TMH_VALIDATION_get_methods (struct GNUNET_HashCode *h)
+{
+ json_t *methods;
+ struct GNUNET_HashContext *hc;
+ const char *wf;
+ struct Plugin *p;
+
+ methods = json_array ();
+ hc = GNUNET_CRYPTO_hash_context_start ();
+ for (p=wire_head;NULL != p;p = p->next)
+ {
+ wf = p->type;
+ json_array_append_new (methods,
+ json_string (wf));
+ GNUNET_CRYPTO_hash_context_read (hc,
+ wf,
+ strlen (wf) + 1);
+ }
+ GNUNET_CRYPTO_hash_context_finish (hc,
+ h);
+ return methods;
+}
+
+
+/* end of taler-mint-httpd_validation.c */
diff --git a/src/mint/taler-mint-httpd_validation.h b/src/mint/taler-mint-httpd_validation.h
new file mode 100644
index 000000000..f5fb19003
--- /dev/null
+++ b/src/mint/taler-mint-httpd_validation.h
@@ -0,0 +1,76 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2016 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Affero 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+
+/**
+ * @file taler-mint-httpd_validation.h
+ * @brief helpers for calling the wire plugins to validate addresses
+ * @author Christian Grothoff
+ */
+#ifndef TALER_MINT_HTTPD_VALIDATION_H
+#define TALER_MINT_HTTPD_VALIDATION_H
+#include <gnunet/gnunet_util_lib.h>
+#include <jansson.h>
+
+
+/**
+ * Initialize validation subsystem.
+ *
+ * @param cfg configuration to use
+ * @return #GNUNET_OK on success
+ */
+int
+TMH_VALIDATION_init (const struct GNUNET_CONFIGURATION_Handle *cfg);
+
+
+/**
+ * Shutdown validation subsystem.
+ */
+void
+TMH_VALIDATION_done (void);
+
+
+/**
+ * Check if the given wire format JSON object is correctly formatted as
+ * a wire address.
+ *
+ * @param wire the JSON wire format object
+ * @return #GNUNET_YES if correctly formatted; #GNUNET_NO if not
+ */
+int
+TMH_json_validate_wireformat (const json_t *wire);
+
+/**
+ * Check if we support the given wire method.
+ *
+ * @param type type of wire method to check
+ * @return #GNUNET_YES if the method is supported
+ */
+int
+TMH_VALIDATION_test_method (const char *type);
+
+
+/**
+ * Obtain supported validation methods as a JSON array,
+ * and as a hash.
+ *
+ * @param[out] h set to the hash of the JSON methods
+ * @return JSON array with the supported validation methods
+ */
+json_t *
+TMH_VALIDATION_get_methods (struct GNUNET_HashCode *h);
+
+
+#endif
diff --git a/src/mint/taler-mint-httpd_wire.c b/src/mint/taler-mint-httpd_wire.c
index 1eb3f6bef..020a7e108 100644
--- a/src/mint/taler-mint-httpd_wire.c
+++ b/src/mint/taler-mint-httpd_wire.c
@@ -21,6 +21,7 @@
#include "platform.h"
#include "taler-mint-httpd_keystate.h"
#include "taler-mint-httpd_responses.h"
+#include "taler-mint-httpd_validation.h"
#include "taler-mint-httpd_wire.h"
#include <jansson.h>
@@ -45,24 +46,10 @@ TMH_WIRE_handler_wire (struct TMH_RequestHandler *rh,
struct TALER_MintPublicKeyP pub;
struct TALER_MintSignatureP sig;
json_t *methods;
- struct GNUNET_HashContext *hc;
- unsigned int i;
- const char *wf;
- methods = json_array ();
- hc = GNUNET_CRYPTO_hash_context_start ();
- for (i=0;NULL != (wf = TMH_expected_wire_formats[i]); i++)
- {
- json_array_append_new (methods,
- json_string (wf));
- GNUNET_CRYPTO_hash_context_read (hc,
- wf,
- strlen (wf) + 1);
- }
wsm.purpose.size = htonl (sizeof (wsm));
wsm.purpose.purpose = htonl (TALER_SIGNATURE_MINT_WIRE_TYPES);
- GNUNET_CRYPTO_hash_context_finish (hc,
- &wsm.h_wire_types);
+ methods = TMH_VALIDATION_get_methods (&wsm.h_wire_types);
TMH_KS_sign (&wsm.purpose,
&pub,
&sig);
@@ -97,7 +84,6 @@ TMH_WIRE_handler_wire_test (struct TMH_RequestHandler *rh,
struct MHD_Response *response;
int ret;
char *wire_test_redirect;
- unsigned int i;
response = MHD_create_response_from_buffer (0, NULL,
MHD_RESPMEM_PERSISTENT);
@@ -107,11 +93,7 @@ TMH_WIRE_handler_wire_test (struct TMH_RequestHandler *rh,
return MHD_NO;
}
TMH_RESPONSE_add_global_headers (response);
- for (i=0;NULL != TMH_expected_wire_formats[i];i++)
- if (0 == strcasecmp ("test",
- TMH_expected_wire_formats[i]))
- break;
- if (NULL == TMH_expected_wire_formats[i])
+ if (GNUNET_NO == TMH_VALIDATION_test_method ("test"))
{
/* Return 501: not implemented */
ret = MHD_queue_response (connection,
@@ -165,13 +147,8 @@ TMH_WIRE_handler_wire_sepa (struct TMH_RequestHandler *rh,
char *sepa_wire_file;
int fd;
struct stat sbuf;
- unsigned int i;
- for (i=0;NULL != TMH_expected_wire_formats[i];i++)
- if (0 == strcasecmp ("sepa",
- TMH_expected_wire_formats[i]))
- break;
- if (NULL == TMH_expected_wire_formats[i])
+ if (GNUNET_NO == TMH_VALIDATION_test_method ("sepa"))
{
/* Return 501: not implemented */
response = MHD_create_response_from_buffer (0, NULL,