gnunet-svn
[Top][All Lists]
Advanced

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

[GNUnet-SVN] [taler-exchange] branch master updated: Benchmark.


From: gnunet
Subject: [GNUnet-SVN] [taler-exchange] branch master updated: Benchmark.
Date: Wed, 25 Jul 2018 13:27:59 +0200

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

marcello pushed a commit to branch master
in repository exchange.

The following commit(s) were added to refs/heads/master by this push:
     new de925a3  Benchmark.
de925a3 is described below

commit de925a355627dac7dbf4232790a58cddf36b2021
Author: Marcello Stanisci <address@hidden>
AuthorDate: Wed Jul 25 13:26:47 2018 +0200

    Benchmark.
    
    Removing "-new" part from the source file.
---
 src/benchmark/Makefile.am                    |    2 +-
 src/benchmark/taler-exchange-benchmark-new.c |  432 ------
 src/benchmark/taler-exchange-benchmark.c     | 2003 ++++----------------------
 3 files changed, 310 insertions(+), 2127 deletions(-)

diff --git a/src/benchmark/Makefile.am b/src/benchmark/Makefile.am
index 49fb3cd..08d7e03 100644
--- a/src/benchmark/Makefile.am
+++ b/src/benchmark/Makefile.am
@@ -10,7 +10,7 @@ bin_PROGRAMS = \
   taler-exchange-benchmark
 
 taler_exchange_benchmark_SOURCES = \
-  taler-exchange-benchmark-new.c
+  taler-exchange-benchmark.c
 taler_exchange_benchmark_LDADD = \
   $(LIBGCRYPT_LIBS) \
   $(top_builddir)/src/json/libtalerjson.la \
diff --git a/src/benchmark/taler-exchange-benchmark-new.c 
b/src/benchmark/taler-exchange-benchmark-new.c
deleted file mode 100644
index abe57b1..0000000
--- a/src/benchmark/taler-exchange-benchmark-new.c
+++ /dev/null
@@ -1,432 +0,0 @@
-/*
-  This file is part of TALER
-  (C) 2014-2018 Taler Systems SA
-
-  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
-  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,
-  see <http://www.gnu.org/licenses/>
-*/
-
-/**
- * @file merchant/backend/taler-merchant-httpd.c
- * @brief HTTP serving layer intended to perform crypto-work and
- * communication with the exchange
- * @author Marcello Stanisci
- */
-
-#include "platform.h"
-#include <taler/taler_util.h>
-#include <taler/taler_signatures.h>
-#include <taler/taler_exchange_service.h>
-#include <taler/taler_json_lib.h>
-#include <gnunet/gnunet_util_lib.h>
-#include <microhttpd.h>
-#include <taler/taler_bank_service.h>
-#include <taler/taler_fakebank_lib.h>
-#include <taler/taler_testing_lib.h>
-#include <taler/taler_testing_bank_lib.h>
-#include <taler/taler_error_codes.h>
-
-/* Error codes.  */
-enum BenchmarkError {
-
-  MISSING_BANK_URL,
-  FAILED_TO_LAUNCH_BANK,
-  BAD_CLI_ARG,
-  BAD_CONFIG_FILE,
-  NO_CONFIG_FILE_GIVEN
-};
-
-/**
- * Probability that a spent coin will be refreshed.
- */
-#define REFRESH_PROBABILITY 0.1
-
-/**
- * The whole benchmark is a repetition of a "unit".  Each
- * unit is a array containing a withdraw+deposit operation,
- * and _possibly_ a refresh of the deposited coin.
- */
-#define UNITY_SIZE 6
-
-/* Hard-coded params.  Note, the bank is expected to
- * have the Tor user with account number 3 and password 'x'.
- *
- * This is not a problem _so far_, as the fakebank mocks logins,
- * and the Python bank makes that account by default.  */
-#define USER_ACCOUNT_NO 3
-#define EXCHANGE_ACCOUNT_NO 2
-#define USER_LOGIN_NAME "Tor"
-#define USER_LOGIN_PASS "x"
-#define EXCHANGE_URL "http://example.com/";
-
-#define FIRST_INSTRUCTION -1
-
-#define CMD_TRANSFER_TO_EXCHANGE(label,amount) \
-   TALER_TESTING_cmd_fakebank_transfer (label, amount, \
-     fakebank_url, USER_ACCOUNT_NO, EXCHANGE_ACCOUNT_NO, \
-     USER_LOGIN_NAME, USER_LOGIN_PASS, EXCHANGE_URL)
-
-
-/**
- * Exchange URL; never used, just needed by exchange preparator.
- */
-static char *exchange_url;
-
-/**
- * Time snapshot taken right before executing the CMDs.
- */
-static struct GNUNET_TIME_Absolute start_time;
-
-/**
- * Benchmark duration time taken right after the CMD interpreter
- * returns.
- */
-static struct GNUNET_TIME_Relative duration;
-
-/**
- * Exit code.
- */
-static unsigned int result;
-
-/**
- * How many refreshes got executed.
- */
-static unsigned int howmany_refreshes;
-
-/**
- * How many coins we want to create.
- */
-static unsigned int howmany_coins = 1;
-
-/**
- * Log level used during the run.
- */
-static char *loglev;
-
-/**
- * Log file.
- */
-static char *logfile;
-
-/**
- * Config filename.
- */
-static char *cfg_filename;
-
-/**
- * Fake bank base URL.
- */
-static char *fakebank_url;
-
-/**
- * Currency used.
- */
-static char *currency;
-
-/**
- * Convenience macros to allocate all the currency-dependant
- * strings;  note that the argument list of the macro is ignored.
- * It is kept as a way to make the macro more auto-descriptive
- * where it is called.
- */
-
-#define ALLOCATE_AMOUNTS(...) \
-  char *AMOUNT_5; \
-  char *AMOUNT_4; \
-  char *AMOUNT_1; \
-  \
-  GNUNET_asprintf (&AMOUNT_5, \
-                   "%s:5", \
-                   currency); \
-  GNUNET_asprintf (&AMOUNT_4, \
-                   "%s:4", \
-                   currency); \
-  GNUNET_asprintf (&AMOUNT_1, \
-                   "%s:1", \
-                   currency);
-
-/**
- * Throw a weighted coin with @a probability.
- *
- * @return #GNUNET_OK with @a probability,
- *         #GNUNET_NO with 1 - @a probability
- */
-static unsigned int
-eval_probability (float probability)
-{
-  uint64_t random;
-  float random_01;
-
-  random = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
-                                    UINT64_MAX);
-  random_01 = (double) random / UINT64_MAX;
-  return (random_01 <= probability) ? GNUNET_OK : GNUNET_NO;
-}
-
-
-/**
- * Actual commands collection.
- */
-static void
-run (void *cls,
-     struct TALER_TESTING_Interpreter *is)
-{
-  struct TALER_Amount total_reserve_amount;
-  struct TALER_Amount withdraw_fee;
-  char *withdraw_fee_str;
-
-  struct TALER_TESTING_Command all_commands
-    [1 + /* Withdraw block */
-     howmany_coins + /* All units */
-     1 /* End CMD */];
-
-  ALLOCATE_AMOUNTS
-    (AMOUNT_5,
-     AMOUNT_4,
-     AMOUNT_1);
-
-  total_reserve_amount.value = 5 * howmany_coins;
-  strncpy (total_reserve_amount.currency,
-           currency,
-           TALER_CURRENCY_LEN);
-
-  GNUNET_asprintf (&withdraw_fee_str,
-                   "%s:0.1",
-                   currency);
-  TALER_string_to_amount (withdraw_fee_str,
-                          &withdraw_fee);
-  for (unsigned int i = 0; i < howmany_coins; i++)
-    TALER_amount_add (&total_reserve_amount,
-                      &total_reserve_amount,
-                      &withdraw_fee);
-
-  struct TALER_TESTING_Command make_reserve[] = {
-
-    CMD_TRANSFER_TO_EXCHANGE
-      ("create-reserve",
-       TALER_amount_to_string (&total_reserve_amount)),
-
-    TALER_TESTING_cmd_exec_wirewatch
-      ("wirewatch",
-       cfg_filename),
-
-    TALER_TESTING_cmd_end ()
-
-  };
-
-  all_commands[0] = TALER_TESTING_cmd_batch ("make-reserve",
-                                             make_reserve);
-  for (unsigned int i = 0; i < howmany_coins; i++)
-  {
-    char *withdraw_label;
-    char *order_enc;
-    struct TALER_TESTING_Command unit[UNITY_SIZE];
-
-    GNUNET_asprintf (&withdraw_label,
-                     "withdraw-%u",
-                     i);
-
-    GNUNET_asprintf (&order_enc,
-                     "{\"nonce\": %u}",
-                     i);
-
-    unit[0] = TALER_TESTING_cmd_withdraw_amount
-      (withdraw_label,
-       is->exchange,
-       "create-reserve",
-       AMOUNT_5,
-       MHD_HTTP_OK);
-
-    unit[1] = TALER_TESTING_cmd_deposit
-      ("deposit",
-       is->exchange,
-       withdraw_label,
-       0, /* Index of the one withdrawn coin in the traits.  */
-       TALER_TESTING_make_wire_details
-         (24,
-          "no-aggregation"),
-       order_enc,
-       GNUNET_TIME_UNIT_ZERO,
-       AMOUNT_1,
-       MHD_HTTP_OK);
-
-    if (eval_probability (REFRESH_PROBABILITY))
-    {
-      char *melt_label;
-      char *reveal_label;
-
-      howmany_refreshes++;
-      GNUNET_asprintf (&melt_label,
-                       "refresh-melt-%u",
-                       i);
-
-      GNUNET_asprintf (&reveal_label,
-                       "refresh-reveal-%u",
-                       i);
-
-      unit[2] = TALER_TESTING_cmd_refresh_melt
-        (melt_label,
-         is->exchange,
-         AMOUNT_4,
-         withdraw_label,
-         MHD_HTTP_OK);
-
-      unit[3] = TALER_TESTING_cmd_refresh_reveal
-        (reveal_label,
-         is->exchange,
-         melt_label,
-         MHD_HTTP_OK);
-
-      unit[4] = TALER_TESTING_cmd_refresh_link
-        ("refresh-link",
-         is->exchange,
-         reveal_label,
-         MHD_HTTP_OK);
-
-      unit[5] = TALER_TESTING_cmd_end ();
-    }
-    else unit[2] = TALER_TESTING_cmd_end ();
-    
-    all_commands[1 + i] = TALER_TESTING_cmd_batch ("unit",
-                                                   unit);
-  }
-  all_commands[1 + howmany_coins] = TALER_TESTING_cmd_end ();
-  start_time = GNUNET_TIME_absolute_get ();
-  TALER_TESTING_run_with_fakebank (is,
-                                   all_commands,
-                                   fakebank_url);
-  result = 1;
-}
-
-/**
- * The main function of the serve tool
- *
- * @param argc number of arguments from the command line
- * @param argv command line arguments
- * @return 0 ok, or `enum PaymentGeneratorError` on error
- */
-int
-main (int argc,
-      char *const *argv)
-{
-  struct GNUNET_CONFIGURATION_Handle *cfg;
-
-  loglev = NULL;
-  GNUNET_log_setup ("taler-exchange-benchmark",
-                    loglev,
-                    logfile);
-
-  struct GNUNET_GETOPT_CommandLineOption options[] = {
-
-    GNUNET_GETOPT_option_cfgfile
-      (&cfg_filename),
-
-    GNUNET_GETOPT_option_version
-      (PACKAGE_VERSION " " VCS_VERSION),
-
-    GNUNET_GETOPT_option_help
-      ("Exchange benchmark"),
-
-    GNUNET_GETOPT_option_loglevel
-      (&loglev),
-
-    GNUNET_GETOPT_option_uint
-      ('n',
-       "coins-number",
-       "CN",
-       "How many coins we should instantiate",
-       &howmany_coins),
-
-    GNUNET_GETOPT_option_string
-      ('b',
-       "bank-url",
-       "BU",
-       "bank base url, mandatory,"
-       " must match exchange's escrow bank",
-       &fakebank_url),
-
-    GNUNET_GETOPT_option_string
-      ('l',
-       "logfile",
-       "LF",
-       "will log to file LF",
-       &logfile),
-
-    GNUNET_GETOPT_OPTION_END
-  };
-  
-  if (GNUNET_SYSERR == (result = GNUNET_GETOPT_run
-      ("taler-exchange-benchmark",
-       options,
-       argc,
-       argv))) 
-  {
-    TALER_LOG_ERROR ("Unparsable CLI options\n");
-    return BAD_CLI_ARG;
-  }
-
-  if (NULL == cfg_filename)
-  {
-    TALER_LOG_ERROR ("-c option is mandatory\n");
-    return NO_CONFIG_FILE_GIVEN;
-  }
-
-  cfg = GNUNET_CONFIGURATION_create ();
-  if (GNUNET_OK != GNUNET_CONFIGURATION_load
-      (cfg,
-       cfg_filename))
-  {
-    TALER_LOG_ERROR ("Could not parse configuration\n");
-    return BAD_CONFIG_FILE;
-  }
-  if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string
-      (cfg,
-       "taler",
-       "currency",
-       &currency))
-  {
-    GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
-                               "taler",
-                               "currency");
-    GNUNET_CONFIGURATION_destroy (cfg);
-    return BAD_CONFIG_FILE;
-  }
-  GNUNET_CONFIGURATION_destroy (cfg);
-
-  if (NULL == fakebank_url)
-  {
-    TALER_LOG_ERROR ("Option -b is mandatory!\n");
-    return MISSING_BANK_URL;
-  }
-
-  GNUNET_assert (GNUNET_OK == TALER_TESTING_prepare_exchange
-    (cfg_filename,
-     &exchange_url)); // never used, we do all via handle.
-  result = TALER_TESTING_setup_with_exchange
-    (run,
-     NULL,
-     cfg_filename);
-
-  duration = GNUNET_TIME_absolute_get_duration (start_time);
-
-  TALER_LOG_INFO ("Executed W=%u, D=%u, R=%u, operations in %s\n",
-                  howmany_coins,
-                  howmany_coins,
-                  howmany_refreshes,
-                  GNUNET_STRINGS_relative_time_to_string
-                    (duration,
-                     GNUNET_YES));
-
-  return (GNUNET_OK == result) ? 0 : result;
-}
diff --git a/src/benchmark/taler-exchange-benchmark.c 
b/src/benchmark/taler-exchange-benchmark.c
index 3fd31ed..abe57b1 100644
--- a/src/benchmark/taler-exchange-benchmark.c
+++ b/src/benchmark/taler-exchange-benchmark.c
@@ -1,443 +1,166 @@
 /*
   This file is part of TALER
-  Copyright (C) 2014, 2015, 2016, 2017 Taler Systems SA
+  (C) 2014-2018 Taler Systems SA
 
-  TALER is free software; you can redistribute it and/or modify it under the
-  terms of the GNU Lesser General Public License as published by the Free 
Software
-  Foundation; either version 2.1, or (at your option) any later version.
+  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 Lesser General Public License for more 
details.
+  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 Lesser General Public License 
along with
-  TALER; see the file COPYING.LGPL.  If not, see <http://www.gnu.org/licenses/>
+  You should have received a copy of the GNU General Public License
+  along with TALER; see the file COPYING.  If not,
+  see <http://www.gnu.org/licenses/>
 */
+
 /**
- * @file src/benchmark/taler-exchange-benchmark.c
- * @brief exchange's benchmark
+ * @file merchant/backend/taler-merchant-httpd.c
+ * @brief HTTP serving layer intended to perform crypto-work and
+ * communication with the exchange
  * @author Marcello Stanisci
- * @author Christian Grothoff
  */
+
 #include "platform.h"
-#include "taler_util.h"
-#include "taler_signatures.h"
-#include "taler_exchange_service.h"
-#include "taler_json_lib.h"
+#include <taler/taler_util.h>
+#include <taler/taler_signatures.h>
+#include <taler/taler_exchange_service.h>
+#include <taler/taler_json_lib.h>
 #include <gnunet/gnunet_util_lib.h>
-#include <gnunet/gnunet_curl_lib.h>
-#include "taler_bank_service.h"
-#include "taler_fakebank_lib.h"
 #include <microhttpd.h>
-#include <jansson.h>
-
-/**
- * How much slack do we leave in terms of coins that are invalid (and
- * thus available for refresh)?  Should be significantly larger
- * than #REFRESH_SLOTS_NEEDED, and must be below #pool_size.
- */
-#define INVALID_COIN_SLACK 20
-
-/**
- * How much slack must we have to do a refresh? Should be the
- * maximum number of coins a refresh can generate, and thus
- * larger than log(base 2) of #COIN_VALUE.  Must also be
- * smaller than #INVALID_COIN_SLACK and smaller than 64.
- */
-#define REFRESH_SLOTS_NEEDED 5
-
-/**
- * The benchmark withdraws always the same denomination, since the
- * calculation for refreshing is statically done (at least in this
- * first version).  In the future, this will be the largest value
- * we ever withdraw.
- */
-#define COIN_VALUE 8
-
-/**
- * Probability a coin can be refreshed.
- * This probability multiplied by the number of coins
- * generated during the average refresh must be smaller
- * than one.  The variance must be covered by the
- * #INVALID_COIN_SLACK.
- */
-#define REFRESH_PROBABILITY 0.1
-
-/**
- * What is the amount we deposit into a reserve each time.
- * We keep it simple and always deposit the same amount for now.
- */
-#define RESERVE_VALUE 1000
-
-/**
- * What should be the ratio of coins withdrawn per reserve?
- * We roughly match #RESERVE_VALUE / #COIN_VALUE, as that
- * matches draining the reserve.
- */
-#define COINS_PER_RESERVE 12
-
-/**
- * How many times must #benchmark_run() execute before we
- * consider ourselves warm?
- */
-#define WARM_THRESHOLD 1000LL
-
-/**
- * List of coins to get in return to a melt operation, in order
- * of preference. The values from this structure are converted
- * to the #refresh_pk array.  Must be NULL-terminated.  The
- * currency is omitted as we get that from /keys.
- */
-static const char *refresh_denoms[] = {
-  "4.00",
-  "2.00",
-  "1.00",
-  NULL
+#include <taler/taler_bank_service.h>
+#include <taler/taler_fakebank_lib.h>
+#include <taler/taler_testing_lib.h>
+#include <taler/taler_testing_bank_lib.h>
+#include <taler/taler_error_codes.h>
+
+/* Error codes.  */
+enum BenchmarkError {
+
+  MISSING_BANK_URL,
+  FAILED_TO_LAUNCH_BANK,
+  BAD_CLI_ARG,
+  BAD_CONFIG_FILE,
+  NO_CONFIG_FILE_GIVEN
 };
 
-
-/**
- * Needed information for a reserve. Other values are the same for all 
reserves, therefore defined in global variables
- */
-struct Reserve
-{
-  /**
-   * DLL of reserves to fill.
-   */
-  struct Reserve *next;
-
-  /**
-   * DLL of reserves to fill.
-   */
-  struct Reserve *prev;
-
-  /**
-   * Set (by the interpreter) to the reserve's private key
-   * we used to fill the reserve.
-   */
-  struct TALER_ReservePrivateKeyP reserve_priv;
-
-  /**
-   * Set to the API's handle during the operation.
-   */
-  struct TALER_BANK_AdminAddIncomingHandle *aih;
-
-  /**
-   * How much is left in this reserve.
-   */
-  struct TALER_Amount left;
-
-  /**
-   * Index of this reserve in the #reserves array.
-   */
-  unsigned int reserve_index;
-
-};
-
-
 /**
- * Information regarding a coin
+ * Probability that a spent coin will be refreshed.
  */
-struct Coin
-{
-
-  /**
-   * DLL of coins to withdraw.
-   */
-  struct Coin *next;
-
-  /**
-   * DLL of coins to withdraw.
-   */
-  struct Coin *prev;
-
-  /**
-   * Set (by the interpreter) to the exchange's signature over the
-   * coin's public key.
-   */
-  struct TALER_DenominationSignature sig;
-
-  /**
-   * Set to the coin's private key.
-   */
-  struct TALER_CoinSpendPrivateKeyP coin_priv;
-
-  /**
-   * This specifies the denomination key to use.
-   */
-  const struct TALER_EXCHANGE_DenomPublicKey *pk;
-
-  /**
-   * Withdraw handle (while operation is running).
-   */
-  struct TALER_EXCHANGE_ReserveWithdrawHandle *wsh;
-
-  /**
-   * Refresh melt handle
-   */
-  struct TALER_EXCHANGE_RefreshMeltHandle *rmh;
-
-  /**
-   * Refresh reveal handle
-   */
-  struct TALER_EXCHANGE_RefreshRevealHandle *rrh;
-
-  /**
-   * Deposit handle (while operation is running).
-   */
-  struct TALER_EXCHANGE_DepositHandle *dh;
-
-  /**
-   * Array of denominations we expect to get from melt.
-   */
-  struct TALER_Amount *denoms;
-
-  /**
-   * The result of a #TALER_EXCHANGE_refresh_prepare() call
-   */
-  char *blob;
-
-  /**
-   * Size of @e blob
-   */
-  size_t blob_size;
-
-  /**
-   * Flag indicating if the coin is going to be refreshed
-   */
-  unsigned int refresh;
-
-  /**
-   * #GNUNET_YES if this coin is in the #invalid_coins_head DLL.
-   */
-  int invalid;
-
-  /**
-   * Index in the reserve's global array indicating which
-   * reserve this coin is to be retrieved. If the coin comes
-   * from a refresh, then this value is set to the melted coin's
-   * reserve index
-   */
-  unsigned int reserve_index;
-
-  /**
-   * Index of this coin in the #coins array.
-   */
-  unsigned int coin_index;
-
-  /**
-   * If the coin has to be refreshed, this value indicates
-   * how much is left on this coin
-   */
-  struct TALER_Amount left;
-
-};
-
-
-/**
- * Handle to our fakebank.
- */
-static struct TALER_FAKEBANK_Handle *fakebank;
-
-/**
- * DLL of reserves to fill.
- */
-static struct Reserve *empty_reserve_head;
-
-/**
- * DLL of reserves to fill.
- */
-static struct Reserve *empty_reserve_tail;
-
-/**
- * DLL of coins to withdraw.
- */
-static struct Coin *invalid_coins_head;
-
-/**
- * DLL of coins to withdraw.
- */
-static struct Coin *invalid_coins_tail;
-
-/**
- * How many coins are in the #invalid_coins_head DLL?
- */
-static unsigned int num_invalid_coins;
-
-/**
- * Should we initialize and start the exchange, if #GNUNET_NO,
- * we expect one to be already up and running.
- */
-static int run_exchange;
-
-/**
- * Enables printing of "C" and "W" to indicate progress (warm/cold)
- * every 50 iterations. Also includes how long the iteration took,
- * so we can see if it is stable.
- */
-static unsigned int be_verbose;
-
-/**
- * How many coins the benchmark should operate on
- */
-static unsigned int pool_size = 100;
-
-/**
- * Configuration file path
- */
-static char *config_file;
-
-/**
- * Configuation object (used to get BANK_URL)
- */
-static struct GNUNET_CONFIGURATION_Handle *cfg;
-
-/**
- * How many reserves ought to be created given the pool size
- */
-static unsigned int nreserves;
-
-/**
- * How many coins are in the #coins array. This is needed
- * as the number of coins is not always #nreserves * #COINS_PER_RESERVE
- * due to refresh operations
- */
-static unsigned int ncoins;
-
-/**
- * Bank details of who creates reserves
- */
-static json_t *bank_details;
-
-/**
- * Bank details of who deposits coins
- */
-static json_t *merchant_details;
-
-/**
- * Array of denomination keys needed to perform the refresh operation
- */
-static struct TALER_EXCHANGE_DenomPublicKey *refresh_pk;
-
-/**
- * Size of #refresh_pk
- */
-static unsigned int refresh_pk_len;
-
-/**
- * Same blinding key for all coins
- */
-static struct TALER_DenominationBlindingKeyP blinding_key;
+#define REFRESH_PROBABILITY 0.1
 
 /**
- * Handle to the exchange's process
+ * The whole benchmark is a repetition of a "unit".  Each
+ * unit is a array containing a withdraw+deposit operation,
+ * and _possibly_ a refresh of the deposited coin.
  */
-static struct GNUNET_OS_Process *exchanged;
+#define UNITY_SIZE 6
 
-/**
- * Context for running the #ctx's event loop.
- */
-static struct GNUNET_CURL_RescheduleContext *rc;
+/* Hard-coded params.  Note, the bank is expected to
+ * have the Tor user with account number 3 and password 'x'.
+ *
+ * This is not a problem _so far_, as the fakebank mocks logins,
+ * and the Python bank makes that account by default.  */
+#define USER_ACCOUNT_NO 3
+#define EXCHANGE_ACCOUNT_NO 2
+#define USER_LOGIN_NAME "Tor"
+#define USER_LOGIN_PASS "x"
+#define EXCHANGE_URL "http://example.com/";
 
-/**
- * Benchmark's task
- */
-static struct GNUNET_SCHEDULER_Task *benchmark_task;
+#define FIRST_INSTRUCTION -1
 
-/**
- * Main execution context for the main loop of the exchange.
- */
-static struct GNUNET_CURL_Context *ctx;
-
-/**
- * Handle to access the exchange.
- */
-static struct TALER_EXCHANGE_Handle *exchange;
+#define CMD_TRANSFER_TO_EXCHANGE(label,amount) \
+   TALER_TESTING_cmd_fakebank_transfer (label, amount, \
+     fakebank_url, USER_ACCOUNT_NO, EXCHANGE_ACCOUNT_NO, \
+     USER_LOGIN_NAME, USER_LOGIN_PASS, EXCHANGE_URL)
 
-/**
- * The array of all reserves, of length #nreserves.
- */
-static struct Reserve *reserves;
 
 /**
- * The array of all coins, of length #ncoins.
- */
-static struct Coin *coins;
-
-/**
- * This key (usually provided by merchants) is needed when depositing coins,
- * even though there is no merchant acting in the benchmark
- */
-static struct TALER_MerchantPrivateKeyP merchant_priv;
-
-/**
- * URL under which the exchange is reachable during the benchmark.
+ * Exchange URL; never used, just needed by exchange preparator.
  */
 static char *exchange_url;
 
 /**
- * URL under which the administrative exchange is reachable during the
- * benchmark.
+ * Time snapshot taken right before executing the CMDs.
  */
-static char *exchange_admin_url;
+static struct GNUNET_TIME_Absolute start_time;
 
 /**
- * Used currency (read from /keys' output)
+ * Benchmark duration time taken right after the CMD interpreter
+ * returns.
  */
-static char *currency;
+static struct GNUNET_TIME_Relative duration;
 
 /**
- * What time did we start to really measure performance?
+ * Exit code.
  */
-static struct GNUNET_TIME_Absolute start_time;
+static unsigned int result;
 
 /**
- * Number of times #benchmark_run has executed. Used
- * to indicate when we consider us warm.
+ * How many refreshes got executed.
  */
-static unsigned long long warm;
+static unsigned int howmany_refreshes;
 
 /**
- * Number of times #benchmark_run should execute
- * before we shut down.
+ * How many coins we want to create.
  */
-static unsigned int num_iterations;
+static unsigned int howmany_coins = 1;
 
 /**
- * Number of /deposit operations we have executed since #start_time.
+ * Log level used during the run.
  */
-static unsigned long long num_deposit;
+static char *loglev;
 
 /**
- * Number of /withdraw operations we have executed since #start_time.
+ * Log file.
  */
-static unsigned long long num_withdraw;
+static char *logfile;
 
 /**
- * Number of /refresh operations we have executed since #start_time.
+ * Config filename.
  */
-static unsigned long long num_refresh;
+static char *cfg_filename;
 
 /**
- * Number of /admin operations we have executed since #start_time.
+ * Fake bank base URL.
  */
-static unsigned long long num_admin;
+static char *fakebank_url;
 
 /**
- * Process for the wirewatcher.
+ * Currency used.
  */
-static struct GNUNET_OS_Process *wirewatch_proc;
+static char *currency;
 
 /**
- * ID of task called whenever we get a SIGCHILD.
+ * Convenience macros to allocate all the currency-dependant
+ * strings;  note that the argument list of the macro is ignored.
+ * It is kept as a way to make the macro more auto-descriptive
+ * where it is called.
  */
-static struct GNUNET_SCHEDULER_Task *child_death_task;
 
+#define ALLOCATE_AMOUNTS(...) \
+  char *AMOUNT_5; \
+  char *AMOUNT_4; \
+  char *AMOUNT_1; \
+  \
+  GNUNET_asprintf (&AMOUNT_5, \
+                   "%s:5", \
+                   currency); \
+  GNUNET_asprintf (&AMOUNT_4, \
+                   "%s:4", \
+                   currency); \
+  GNUNET_asprintf (&AMOUNT_1, \
+                   "%s:1", \
+                   currency);
 
 /**
  * Throw a weighted coin with @a probability.
  *
- * @return #GNUNET_OK with @a probability, #GNUNET_NO with 1 - @a probability
+ * @return #GNUNET_OK with @a probability,
+ *         #GNUNET_NO with 1 - @a probability
  */
 static unsigned int
 eval_probability (float probability)
@@ -453,1365 +176,257 @@ eval_probability (float probability)
 
 
 /**
- * Shutdown benchmark in case of errors
- *
- * @param msg error message to print in logs
- */
-static void
-fail (const char *msg)
-{
-  if (NULL != msg)
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "%s\n",
-                msg);
-  GNUNET_SCHEDULER_shutdown ();
-}
-
-
-/**
- * Main task for the benchmark.
- *
- * @param cls NULL
- */
-static void
-benchmark_run (void *cls);
-
-
-/**
- * Run the main task for the benchmark.
- */
-static void
-continue_master_task ()
-{
-  benchmark_task = GNUNET_SCHEDULER_add_now (&benchmark_run,
-                                             NULL);
-}
-
-
-/**
- * Find denomination key matching the given amount.
- *
- * @param keys array of keys to search
- * @param amount coin value to look for
- * @return NULL if no matching key was found
- */
-static const struct TALER_EXCHANGE_DenomPublicKey *
-find_pk (const struct TALER_EXCHANGE_Keys *keys,
-         const struct TALER_Amount *amount)
-{
-  struct GNUNET_TIME_Absolute now;
-  struct TALER_EXCHANGE_DenomPublicKey *pk;
-  char *str;
-
-  now = GNUNET_TIME_absolute_get ();
-  for (unsigned int i=0;i<keys->num_denom_keys;i++)
-  {
-    pk = &keys->denom_keys[i];
-    if ( (0 == TALER_amount_cmp (amount,
-                                 &pk->value)) &&
-         (now.abs_value_us >= pk->valid_from.abs_value_us) &&
-         (now.abs_value_us < pk->withdraw_valid_until.abs_value_us) )
-      return pk;
-  }
-  /* do 2nd pass to check if expiration times are to blame for failure */
-  str = TALER_amount_to_string (amount);
-  for (unsigned int i=0;i<keys->num_denom_keys;i++)
-  {
-    pk = &keys->denom_keys[i];
-    if ( (0 == TALER_amount_cmp (amount,
-                                 &pk->value)) &&
-         ( (now.abs_value_us < pk->valid_from.abs_value_us) ||
-           (now.abs_value_us > pk->withdraw_valid_until.abs_value_us) ) )
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                  "Have denomination key for `%s', but with wrong expiration 
range %llu vs [%llu,%llu)\n",
-                  str,
-                  (unsigned long long) now.abs_value_us,
-                  (unsigned long long) pk->valid_from.abs_value_us,
-                  (unsigned long long) pk->withdraw_valid_until.abs_value_us);
-      GNUNET_free (str);
-      return NULL;
-    }
-  }
-  GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-              "No denomination key for amount %s found\n",
-              str);
-  GNUNET_free (str);
-  return NULL;
-}
-
-
-/**
- * Function called with the result of the /refresh/reveal operation.
- *
- * @param cls closure with the `struct Coin *`
- * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful 
status request
- *                    0 if the exchange's reply is bogus (fails to follow the 
protocol)
- * @param ec taler-specific error code, #TALER_EC_NONE on success
- * @param num_coins number of fresh coins created, length of the @a sigs and 
@a coin_privs arrays, 0 if the operation failed
- * @param coin_privs array of @a num_coins private keys for the coins that 
were created, NULL on error
- * @param sigs array of signature over @a num_coins coins, NULL on error
- * @param full_response full response from the exchange (for logging, in case 
of errors)
- */
-static void
-reveal_cb (void *cls,
-           unsigned int http_status,
-          enum TALER_ErrorCode ec,
-           unsigned int num_coins,
-           const struct TALER_CoinSpendPrivateKeyP *coin_privs,
-           const struct TALER_DenominationSignature *sigs,
-           const json_t *full_response)
-{
-  struct Coin *coin = cls;
-  unsigned int i;
-  const struct TALER_EXCHANGE_Keys *keys;
-
-  coin->rrh = NULL;
-  if (MHD_HTTP_OK != http_status)
-  {
-    json_dumpf (full_response, stderr, 0);
-    fail ("Not all coins correctly revealed");
-    return;
-  }
-  else
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                "Coin #%d revealed!\n",
-                coin->coin_index);
-    coin->left.value = 0;
-  }
-
-  keys = TALER_EXCHANGE_get_keys (exchange);
-  for (i=0; i<num_coins; i++)
-  {
-    struct Coin *fresh_coin;
-    char *revealed_str;
-
-    revealed_str = TALER_amount_to_string (&coin->denoms[i]);
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                "revealing %s # of coins after refresh: %d\n",
-                revealed_str,
-                ncoins);
-    GNUNET_free (revealed_str);
-
-    fresh_coin = invalid_coins_head;
-    if (NULL == fresh_coin)
-    {
-      /* #REFRESH_SLOTS_NEEDED too low? */
-      GNUNET_break (0);
-      continue;
-    }
-    GNUNET_CONTAINER_DLL_remove (invalid_coins_head,
-                                invalid_coins_tail,
-                                fresh_coin);
-    num_invalid_coins--;
-    fresh_coin->invalid = GNUNET_NO;
-    fresh_coin->pk = find_pk (keys, &coin->denoms[i]);
-    GNUNET_assert (NULL == fresh_coin->sig.rsa_signature);
-    fresh_coin->sig.rsa_signature =
-      GNUNET_CRYPTO_rsa_signature_dup (sigs[i].rsa_signature);
-    fresh_coin->coin_priv = coin_privs[i];
-    fresh_coin->left = coin->denoms[i];
-  }
-  GNUNET_free (coin->denoms);
-  coin->denoms = NULL;
-  continue_master_task ();
-}
-
-
-/**
- * Function called with the result of the /refresh/melt operation.
- *
- * @param cls closure with the `struct Coin *`
- * @param http_status HTTP response code, never #MHD_HTTP_OK (200) as for 
successful intermediate response this callback is skipped.
- *                    0 if the exchange's reply is bogus (fails to follow the 
protocol)
- * @param ec taler-specific error code, #TALER_EC_NONE on success
- * @param noreveal_index choice by the exchange in the cut-and-choose protocol,
- *                    UINT16_MAX on error
- * @param exchange_pub public key the exchange used for signing
- * @param full_response full response from the exchange (for logging, in case 
of errors)
- */
-static void
-melt_cb (void *cls,
-         unsigned int http_status,
-        enum TALER_ErrorCode ec,
-         uint32_t noreveal_index,
-         const struct TALER_ExchangePublicKeyP *exchange_pub,
-         const json_t *full_response)
-{
-  struct Coin *coin = cls;
-
-  coin->rmh = NULL;
-  if (MHD_HTTP_OK != http_status)
-  {
-    json_dumpf (full_response, stderr, 0);
-    fail ("Coin not correctly melted!");
-    return;
-  }
-
-  coin->rrh
-    = TALER_EXCHANGE_refresh_reveal (exchange,
-                                     coin->blob_size,
-                                     coin->blob,
-                                     noreveal_index,
-                                     &reveal_cb,
-                                     coin);
-  GNUNET_free (coin->blob);
-  coin->blob = NULL;
-  if (NULL == coin->rrh)
-  {
-    fail ("Failed on reveal during refresh!");
-    return;
-  }
-}
-
-
-/**
- * Mark coin as invalid.
- *
- * @param coin coin to mark invalid
- */
-static void
-invalidate_coin (struct Coin *coin)
-{
-  GNUNET_CONTAINER_DLL_insert (invalid_coins_head,
-                              invalid_coins_tail,
-                              coin);
-  num_invalid_coins++;
-  coin->invalid = GNUNET_YES;
-  if (NULL != coin->sig.rsa_signature)
-  {
-    GNUNET_CRYPTO_rsa_signature_free (coin->sig.rsa_signature);
-    coin->sig.rsa_signature = NULL;
-  }
-}
-
-
-/**
- * Refresh the given @a coin
- *
- * @param coin coin to refresh
- */
-static void
-refresh_coin (struct Coin *coin)
-{
-  char *blob;
-  size_t blob_size;
-  struct TALER_Amount *denoms = NULL;
-  struct TALER_EXCHANGE_DenomPublicKey *dpks = NULL;
-  const struct TALER_EXCHANGE_DenomPublicKey *curr_dpk;
-  struct TALER_Amount curr;
-  struct TALER_Amount left;
-  unsigned int ndenoms = 0;
-  unsigned int ndenoms2 = 0;
-  unsigned int off;
-
-  GNUNET_break (NULL == coin->denoms);
-  GNUNET_assert (GNUNET_OK ==
-                 TALER_amount_get_zero (currency, &curr));
-  left = coin->left;
-  off = 0;
-  while (0 != TALER_amount_cmp (&curr,
-                               &left))
-  {
-    if (off >= refresh_pk_len)
-    {
-      /* refresh currency choices do not add up! */
-      GNUNET_break (0);
-      break;
-    }
-    curr_dpk = &refresh_pk[off];
-    while (-1 != TALER_amount_cmp (&left,
-                                  &curr_dpk->value))
-    {
-      GNUNET_array_append (denoms,
-                          ndenoms,
-                          curr_dpk->value);
-      GNUNET_array_append (dpks,
-                          ndenoms2,
-                          *curr_dpk);
-      GNUNET_assert (GNUNET_SYSERR !=
-                    TALER_amount_subtract (&left,
-                                           &left,
-                                           &curr_dpk->value));
-    }
-    off++;
-  }
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-             "# of coins to get in melt: %d\n",
-             ndenoms2);
-  GNUNET_break (ndenoms2 <= REFRESH_SLOTS_NEEDED);
-  blob = TALER_EXCHANGE_refresh_prepare (&coin->coin_priv,
-                                        &coin->left,
-                                        &coin->sig,
-                                        coin->pk,
-                                        GNUNET_YES,
-                                        ndenoms2,
-                                        dpks,
-                                        &blob_size);
-  invalidate_coin (coin);
-  GNUNET_array_grow (dpks,
-                    ndenoms2,
-                    0);
-  if (NULL == blob)
-  {
-    fail ("Failed to prepare refresh");
-    return;
-  }
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Prepared blob of size %d for refresh\n",
-             (unsigned int) blob_size);
-
-  coin->blob = blob;
-  coin->blob_size = blob_size;
-  coin->denoms = denoms;
-  if (warm >= WARM_THRESHOLD)
-    num_refresh++;
-  coin->rmh = TALER_EXCHANGE_refresh_melt (exchange,
-                                          blob_size,
-                                          blob,
-                                          &melt_cb,
-                                          coin);
-  if (NULL == coin->rmh)
-  {
-    fail ("Impossible to issue a melt request to the exchange");
-    return;
-  }
-}
-
-
-/**
- * Function called with the result of a /deposit operation.
- *
- * @param cls closure with the `struct Coin` that we are processing
- * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful 
deposit;
- *                    0 if the exchange's reply is bogus (fails to follow the 
protocol)
- * @param ec taler-specific error code, #TALER_EC_NONE on success
- * @param exchange_pub public key used by the exchange for signing
- * @param obj the received JSON reply, should be kept as proof (and, in case 
of errors,
- *            be forwarded to the customer)
- */
-static void
-deposit_cb (void *cls,
-            unsigned int http_status,
-           enum TALER_ErrorCode ec,
-            const struct TALER_ExchangePublicKeyP *exchange_pub,
-            const json_t *obj)
-{
-  struct Coin *coin = cls;
-
-  coin->dh = NULL;
-  if (MHD_HTTP_OK != http_status)
-  {
-    json_dumpf (obj, stderr, 0);
-    fail ("At least one coin has not been deposited, status: %d");
-    return;
-  }
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-              "Coin #%d correctly spent!\n",
-              coin->coin_index);
-  if (GNUNET_YES == coin->refresh)
-  {
-    refresh_coin (coin);
-  }
-  else
-  {
-    invalidate_coin (coin);
-    continue_master_task ();
-  }
-}
-
-
-/**
- * Spend the given coin.  Also triggers refresh
- * with a certain probability.
- *
- * @param coin coin to spend
- * @param do_refresh should we also do the refresh?
- */
-static void
-spend_coin (struct Coin *coin,
-           int do_refresh)
-{
-  struct TALER_Amount amount;
-  struct GNUNET_TIME_Absolute wire_deadline;
-  struct GNUNET_TIME_Absolute timestamp;
-  struct GNUNET_TIME_Absolute refund_deadline;
-  struct GNUNET_HashCode h_contract_terms;
-  struct TALER_CoinSpendPublicKeyP coin_pub;
-  struct TALER_DepositRequestPS dr;
-  struct TALER_MerchantPublicKeyP merchant_pub;
-  struct TALER_CoinSpendSignatureP coin_sig;
-
-  GNUNET_CRYPTO_eddsa_key_get_public (&coin->coin_priv.eddsa_priv,
-                                     &coin_pub.eddsa_pub);
-  GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
-                             &h_contract_terms,
-                             sizeof (h_contract_terms));
-  timestamp = GNUNET_TIME_absolute_get ();
-  wire_deadline = GNUNET_TIME_absolute_add (timestamp,
-                                           GNUNET_TIME_UNIT_WEEKS);
-  refund_deadline = GNUNET_TIME_absolute_add (timestamp,
-                                             GNUNET_TIME_UNIT_DAYS);
-  GNUNET_TIME_round_abs (&timestamp);
-  GNUNET_TIME_round_abs (&wire_deadline);
-  GNUNET_TIME_round_abs (&refund_deadline);
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Spending %d-th coin\n",
-             coin->coin_index);
-
-  if (do_refresh)
-  {
-    /**
-     * Always spending 1 out of 8 KUDOS. To be improved by randomly
-     * picking the spent amount
-     */
-    struct TALER_Amount one;
-
-    GNUNET_assert (GNUNET_OK ==
-                   TALER_amount_get_zero (currency, &one));
-    one.value = 1;
-
-    GNUNET_assert (GNUNET_SYSERR !=
-                   TALER_amount_subtract (&amount,
-                                          &one,
-                                          &coin->pk->fee_deposit));
-    GNUNET_assert (GNUNET_SYSERR !=
-                   TALER_amount_subtract (&coin->left,
-                                          &coin->pk->value,
-                                          &one));
-    coin->refresh = GNUNET_YES;
-  }
-  else
-  {
-    GNUNET_assert (GNUNET_SYSERR !=
-                   TALER_amount_subtract (&amount,
-                                          &coin->pk->value,
-                                          &coin->pk->fee_deposit));
-    coin->refresh = GNUNET_NO;
-  }
-  memset (&dr, 0, sizeof (dr));
-  dr.purpose.size = htonl (sizeof (struct TALER_DepositRequestPS));
-  dr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT);
-  dr.h_contract_terms = h_contract_terms;
-  GNUNET_assert (GNUNET_OK ==
-                 TALER_JSON_wire_signature_hash (merchant_details,
-                                                 &dr.h_wire));
-
-  dr.timestamp = GNUNET_TIME_absolute_hton (timestamp);
-  dr.refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline);
-
-  TALER_amount_hton (&dr.amount_with_fee,
-                    &amount);
-  TALER_amount_hton (&dr.deposit_fee,
-                    &coin->pk->fee_deposit);
-
-  GNUNET_CRYPTO_eddsa_key_get_public (&merchant_priv.eddsa_priv,
-                                     &merchant_pub.eddsa_pub);
-  dr.merchant = merchant_pub;
-  dr.coin_pub = coin_pub;
-  GNUNET_assert (GNUNET_OK ==
-                GNUNET_CRYPTO_eddsa_sign (&coin->coin_priv.eddsa_priv,
-                                          &dr.purpose,
-                                          &coin_sig.eddsa_signature));
-  if (warm >= WARM_THRESHOLD)
-    num_deposit++;
-  coin->dh = TALER_EXCHANGE_deposit (exchange,
-                                    &amount,
-                                    wire_deadline,
-                                    merchant_details,
-                                    &h_contract_terms,
-                                    &coin_pub,
-                                    &coin->sig,
-                                    &coin->pk->key,
-                                    timestamp,
-                                    &merchant_pub,
-                                    refund_deadline,
-                                    &coin_sig,
-                                    &deposit_cb,
-                                    coin);
-  if (NULL == coin->dh)
-  {
-    fail ("An error occurred while calling deposit API");
-    return;
-  }
-}
-
-
-/**
- * Function called upon completion of our /reserve/withdraw request.
- * This is merely the function which spends withdrawn coins. For each
- * spent coin, it either refresh it or re-withdraw it.
- *
- * @param cls closure with our `struct Coin`
- * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful 
status request
- *                    0 if the exchange's reply is bogus (fails to follow the 
protocol)
- * @param ec taler-specific error code, #TALER_EC_NONE on success
- * @param sig signature over the coin, NULL on error
- * @param full_response full response from the exchange (for logging, in case 
of errors)
- */
-static void
-reserve_withdraw_cb (void *cls,
-                     unsigned int http_status,
-                    enum TALER_ErrorCode ec,
-                     const struct TALER_DenominationSignature *sig,
-                     const json_t *full_response)
-{
-  struct Coin *coin = cls;
-
-  coin->wsh = NULL;
-  if (MHD_HTTP_OK != http_status)
-  {
-    json_dumpf (full_response, stderr, 0);
-    fail ("At least one coin has not correctly been withdrawn");
-    return;
-  }
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "%d-th coin withdrawn\n",
-              coin->coin_index);
-  coin->sig.rsa_signature =
-    GNUNET_CRYPTO_rsa_signature_dup (sig->rsa_signature);
-  GNUNET_CONTAINER_DLL_remove (invalid_coins_head,
-                              invalid_coins_tail,
-                              coin);
-  num_invalid_coins--;
-  coin->invalid = GNUNET_NO;
-  continue_master_task ();
-}
-
-
-/**
- * Withdraw the given coin from the respective reserve.
- *
- * @param coin coin to withdraw
+ * Actual commands collection.
  */
 static void
-withdraw_coin (struct Coin *coin)
+run (void *cls,
+     struct TALER_TESTING_Interpreter *is)
 {
-  struct GNUNET_CRYPTO_EddsaPrivateKey *coin_priv;
-  struct TALER_Amount amount;
-  struct TALER_Amount left;
-  const struct TALER_EXCHANGE_Keys *keys;
-  struct Reserve *r;
-  struct TALER_PlanchetSecretsP ps;
-
-  keys = TALER_EXCHANGE_get_keys (exchange);
-  r = &reserves[coin->reserve_index];
-  coin_priv = GNUNET_CRYPTO_eddsa_key_create ();
-  coin->coin_priv.eddsa_priv = *coin_priv;
-  GNUNET_free (coin_priv);
-  GNUNET_assert (GNUNET_OK ==
-                 TALER_amount_get_zero (currency,
-                                        &amount));
-  amount.value = COIN_VALUE;
-  GNUNET_assert (-1 != TALER_amount_cmp (&r->left,
-                                        &amount));
-  GNUNET_assert (NULL != (coin->pk = find_pk (keys, &amount)));
-  if (warm >= WARM_THRESHOLD)
-    num_withdraw++;
-  ps.coin_priv = coin->coin_priv;
-  ps.blinding_key = blinding_key;
-  coin->wsh =
-    TALER_EXCHANGE_reserve_withdraw (exchange,
-                                    coin->pk,
-                                    &r->reserve_priv,
-                                    &ps,
-                                    &reserve_withdraw_cb,
-                                    coin);
-  GNUNET_assert (GNUNET_SYSERR !=
-                TALER_amount_subtract (&left,
-                                       &r->left,
-                                       &amount));
-  r->left = left;
-  if (-1 == TALER_amount_cmp (&left,
-                             &amount))
-  {
-    /* not enough left in the reserve for future withdrawals,
-       create a new reserve! */
-    GNUNET_CONTAINER_DLL_insert (empty_reserve_head,
-                                empty_reserve_tail,
-                                r);
-  }
-}
-
-
-/**
- * Pipe used to communicate child death via signal.
- */
-static struct GNUNET_DISK_PipeHandle *sigpipe;
-
-
-/**
- * Signal handler called for SIGCHLD.  Triggers the
- * respective handler by writing to the trigger pipe.
- */
-static void
-sighandler_child_death ()
-{
-  static char c;
-  int old_errno = errno;       /* back-up errno */
-
-  GNUNET_break (1 ==
-               GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle
-                                       (sigpipe, GNUNET_DISK_PIPE_END_WRITE),
-                                       &c, sizeof (c)));
-  errno = old_errno;           /* restore errno */
-}
+  struct TALER_Amount total_reserve_amount;
+  struct TALER_Amount withdraw_fee;
+  char *withdraw_fee_str;
+
+  struct TALER_TESTING_Command all_commands
+    [1 + /* Withdraw block */
+     howmany_coins + /* All units */
+     1 /* End CMD */];
+
+  ALLOCATE_AMOUNTS
+    (AMOUNT_5,
+     AMOUNT_4,
+     AMOUNT_1);
+
+  total_reserve_amount.value = 5 * howmany_coins;
+  strncpy (total_reserve_amount.currency,
+           currency,
+           TALER_CURRENCY_LEN);
+
+  GNUNET_asprintf (&withdraw_fee_str,
+                   "%s:0.1",
+                   currency);
+  TALER_string_to_amount (withdraw_fee_str,
+                          &withdraw_fee);
+  for (unsigned int i = 0; i < howmany_coins; i++)
+    TALER_amount_add (&total_reserve_amount,
+                      &total_reserve_amount,
+                      &withdraw_fee);
+
+  struct TALER_TESTING_Command make_reserve[] = {
+
+    CMD_TRANSFER_TO_EXCHANGE
+      ("create-reserve",
+       TALER_amount_to_string (&total_reserve_amount)),
+
+    TALER_TESTING_cmd_exec_wirewatch
+      ("wirewatch",
+       cfg_filename),
+
+    TALER_TESTING_cmd_end ()
 
+  };
 
-/**
- * Task triggered whenever we receive a SIGCHLD (child
- * process died).
- *
- * @param cls closure, NULL if we need to self-restart
- */
-static void
-maint_wirewatch_death (void *cls)
-{
-  const struct GNUNET_DISK_FileHandle *pr;
-  char c[16];
-
-  child_death_task = NULL;
-  pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ);
-  GNUNET_break (0 < GNUNET_DISK_file_read (pr, &c, sizeof (c)));
-  GNUNET_OS_process_wait (wirewatch_proc);
-  GNUNET_OS_process_destroy (wirewatch_proc);
-  wirewatch_proc = NULL;
-  continue_master_task ();
-}
-
-
-/**
- * Function called upon completion of our /admin/add/incoming request.
- * Its duty is withdrawing coins on the freshly created reserve.
- *
- * @param cls closure with the `struct Reserve *`
- * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful 
status request
- *                    0 if the exchange's reply is bogus (fails to follow the 
protocol)
- * @param ec taler-specific error code, #TALER_EC_NONE on success
- * @param rowid unique wire transfer identifier of the bank
- * @param full_response full response from the exchange (for logging, in case 
of errors)
- */
-static void
-add_incoming_cb (void *cls,
-                 unsigned int http_status,
-                enum TALER_ErrorCode ec,
-                 uint64_t rowid,
-                 const json_t *full_response)
-{
-  struct Reserve *r = cls;
-
-  r->aih = NULL;
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "/admin/add/incoming callback called on %d-th reserve\n",
-              r->reserve_index);
-  if (MHD_HTTP_OK != http_status)
-  {
-    json_dumpf (full_response, stderr, 0);
-    fail ("At least one reserve failed in being created");
-    return;
-  }
-  GNUNET_CONTAINER_DLL_remove (empty_reserve_head,
-                              empty_reserve_tail,
-                              r);
-  if (NULL == empty_reserve_head)
-  {
-    const struct GNUNET_DISK_FileHandle *pr;
-
-    wirewatch_proc
-      = GNUNET_OS_start_process (GNUNET_NO,
-                                 GNUNET_OS_INHERIT_STD_ALL,
-                                 NULL, NULL, NULL,
-                                 "taler-exchange-wirewatch",
-                                 "taler-exchange-wirewatch",
-                                 "-c", config_file,
-                                 "-t", "test", /* use Taler's bank/fakebank */
-                                 "-T", /* exit when done */
-                                 NULL);
-    if (NULL == wirewatch_proc)
+  all_commands[0] = TALER_TESTING_cmd_batch ("make-reserve",
+                                             make_reserve);
+  for (unsigned int i = 0; i < howmany_coins; i++)
+  {
+    char *withdraw_label;
+    char *order_enc;
+    struct TALER_TESTING_Command unit[UNITY_SIZE];
+
+    GNUNET_asprintf (&withdraw_label,
+                     "withdraw-%u",
+                     i);
+
+    GNUNET_asprintf (&order_enc,
+                     "{\"nonce\": %u}",
+                     i);
+
+    unit[0] = TALER_TESTING_cmd_withdraw_amount
+      (withdraw_label,
+       is->exchange,
+       "create-reserve",
+       AMOUNT_5,
+       MHD_HTTP_OK);
+
+    unit[1] = TALER_TESTING_cmd_deposit
+      ("deposit",
+       is->exchange,
+       withdraw_label,
+       0, /* Index of the one withdrawn coin in the traits.  */
+       TALER_TESTING_make_wire_details
+         (24,
+          "no-aggregation"),
+       order_enc,
+       GNUNET_TIME_UNIT_ZERO,
+       AMOUNT_1,
+       MHD_HTTP_OK);
+
+    if (eval_probability (REFRESH_PROBABILITY))
     {
-      GNUNET_break (0);
-      fail ("could not start wirewatch process");
-      return;
+      char *melt_label;
+      char *reveal_label;
+
+      howmany_refreshes++;
+      GNUNET_asprintf (&melt_label,
+                       "refresh-melt-%u",
+                       i);
+
+      GNUNET_asprintf (&reveal_label,
+                       "refresh-reveal-%u",
+                       i);
+
+      unit[2] = TALER_TESTING_cmd_refresh_melt
+        (melt_label,
+         is->exchange,
+         AMOUNT_4,
+         withdraw_label,
+         MHD_HTTP_OK);
+
+      unit[3] = TALER_TESTING_cmd_refresh_reveal
+        (reveal_label,
+         is->exchange,
+         melt_label,
+         MHD_HTTP_OK);
+
+      unit[4] = TALER_TESTING_cmd_refresh_link
+        ("refresh-link",
+         is->exchange,
+         reveal_label,
+         MHD_HTTP_OK);
+
+      unit[5] = TALER_TESTING_cmd_end ();
     }
-    pr = GNUNET_DISK_pipe_handle (sigpipe,
-                                  GNUNET_DISK_PIPE_END_READ);
-    child_death_task
-      = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
-                                        pr,
-                                        &maint_wirewatch_death, NULL);
-    return;
-  }
-  continue_master_task ();
+    else unit[2] = TALER_TESTING_cmd_end ();
+    
+    all_commands[1 + i] = TALER_TESTING_cmd_batch ("unit",
+                                                   unit);
+  }
+  all_commands[1 + howmany_coins] = TALER_TESTING_cmd_end ();
+  start_time = GNUNET_TIME_absolute_get ();
+  TALER_TESTING_run_with_fakebank (is,
+                                   all_commands,
+                                   fakebank_url);
+  result = 1;
 }
 
-
 /**
- * Fill a reserve using /admin/add/incoming
+ * The main function of the serve tool
  *
- * @param r reserve to fill
+ * @param argc number of arguments from the command line
+ * @param argv command line arguments
+ * @return 0 ok, or `enum PaymentGeneratorError` on error
  */
-static void
-fill_reserve (struct Reserve *r)
+int
+main (int argc,
+      char *const *argv)
 {
-  struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
-  struct TALER_ReservePublicKeyP reserve_pub;
-  struct GNUNET_TIME_Absolute execution_date;
-  struct TALER_Amount reserve_amount;
-  char *subject;
-  struct TALER_BANK_AuthenticationData auth;
-
-  GNUNET_assert (GNUNET_OK ==
-                 TALER_amount_get_zero (currency,
-                                        &reserve_amount));
-  reserve_amount.value = RESERVE_VALUE;
-  execution_date = GNUNET_TIME_absolute_get ();
-  GNUNET_TIME_round_abs (&execution_date);
-
-  priv = GNUNET_CRYPTO_eddsa_key_create ();
-  r->reserve_priv.eddsa_priv = *priv;
-  GNUNET_free (priv);
-  GNUNET_CRYPTO_eddsa_key_get_public (&r->reserve_priv.eddsa_priv,
-                                     &reserve_pub.eddsa_pub);
-  r->left = reserve_amount;
-  if (warm >= WARM_THRESHOLD)
-    num_admin++;
-  auth.method = TALER_BANK_AUTH_BASIC;
-  auth.details.basic.username = "Admin";
-  auth.details.basic.password = "x";
-  subject = GNUNET_STRINGS_data_to_string_alloc (&reserve_pub,
-                                                 sizeof (reserve_pub));
-  r->aih = TALER_BANK_admin_add_incoming (ctx,
-                                          "http://localhost:8082/";,
-                                          &auth,
-                                          "https://exchange/";,
-                                          subject,
-                                          &reserve_amount,
-                                          1, /* origin */
-                                          2, /* exchange account */
-                                          &add_incoming_cb,
-                                          r);
-  GNUNET_assert (NULL != r->aih);
-  GNUNET_free (subject);
-}
+  struct GNUNET_CONFIGURATION_Handle *cfg;
 
+  loglev = NULL;
+  GNUNET_log_setup ("taler-exchange-benchmark",
+                    loglev,
+                    logfile);
 
-/**
- * Main task for the benchmark.
- *
- * @param cls NULL
- */
-static void
-benchmark_run (void *cls)
-{
-  int refresh;
-  struct Coin *coin;
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
 
-  benchmark_task = NULL;
-  /* First, always make sure all reserves are full */
-  if (NULL != empty_reserve_head)
-  {
-    fill_reserve (empty_reserve_head);
-    return;
-  }
-  /* Second, withdraw until #num_invalid_coins is less than
-     #INVALID_COIN_SLACK */
-  if (num_invalid_coins > INVALID_COIN_SLACK)
-  {
-    withdraw_coin (invalid_coins_head);
-    return;
-  }
-  warm++;
-  if ( be_verbose &&
-       (0 == (warm % 50)) )
-  {
-    static struct GNUNET_TIME_Absolute last;
-    struct GNUNET_TIME_Relative duration;
-
-    if (0 != last.abs_value_us)
-      duration = GNUNET_TIME_absolute_get_duration (last);
-    else
-      duration = GNUNET_TIME_UNIT_FOREVER_REL;
-    last = GNUNET_TIME_absolute_get ();
-    fprintf (stderr,
-            "%s - %s\n",
-            WARM_THRESHOLD < warm ? "WARM" : "COLD",
-            GNUNET_STRINGS_relative_time_to_string (duration,
-                                                    GNUNET_YES));
-  }
-  if (WARM_THRESHOLD == warm)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-               "Benchmark warm.\n");
-    start_time = GNUNET_TIME_absolute_get ();
-  }
-  if ( (warm > num_iterations) &&
-       (0 != num_iterations) )
-  {
-    GNUNET_SCHEDULER_shutdown ();
-    return;
-  }
+    GNUNET_GETOPT_option_cfgfile
+      (&cfg_filename),
 
-  /* By default, pick a random valid coin to spend */
-  for (unsigned int i=0;i<1000;i++)
-  {
-    coin = &coins[GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
-                                           ncoins)];
-    if (GNUNET_YES == coin->invalid)
-      continue; /* unlucky draw, try again */
-    if (1 == coin->left.value)
-      refresh = GNUNET_NO; /* cannot refresh, coin is already at unit */
-    else
-      refresh = eval_probability (REFRESH_PROBABILITY);
-    if (num_invalid_coins < REFRESH_SLOTS_NEEDED)
-      refresh = GNUNET_NO;
-    spend_coin (coin,
-               refresh);
-    return;
-  }
-  fail ("Too many invalid coins, is your INVALID_COIN_SLACK too high?");
-}
+    GNUNET_GETOPT_option_version
+      (PACKAGE_VERSION " " VCS_VERSION),
 
+    GNUNET_GETOPT_option_help
+      ("Exchange benchmark"),
 
-/**
- * Populates the global array of denominations which will
- * be withdrawn in a refresh operation. It sums up 4 #currency units,
- * since that is the only amount refreshed so far by the benchmark
- *
- * @return #GNUNET_OK if the array is correctly built, #GNUNET_SYSERR
- * otherwise
- */
-static int
-build_refresh ()
-{
-  char *amount_str;
-  struct TALER_Amount amount;
-  const struct TALER_EXCHANGE_DenomPublicKey *picked_denom;
-  const struct TALER_EXCHANGE_Keys *keys;
-
-  GNUNET_array_grow (refresh_pk,
-                    refresh_pk_len,
-                    0);
-  keys = TALER_EXCHANGE_get_keys (exchange);
-  for (unsigned int i=0; NULL != refresh_denoms[i]; i++)
-  {
-    GNUNET_asprintf (&amount_str,
-                    "%s:%s",
-                    currency,
-                    refresh_denoms[i]);
-    GNUNET_assert (GNUNET_OK ==
-                  TALER_string_to_amount (amount_str,
-                                          &amount));
-    picked_denom = find_pk (keys,
-                           &amount);
-    if (NULL == picked_denom)
-    {
-      GNUNET_break (0);
-      GNUNET_free (amount_str);
-      return GNUNET_SYSERR;
-    }
-    GNUNET_array_append (refresh_pk,
-                        refresh_pk_len,
-                        *picked_denom);
-    GNUNET_free (amount_str);
-  }
-  return GNUNET_OK;
-}
+    GNUNET_GETOPT_option_loglevel
+      (&loglev),
 
+    GNUNET_GETOPT_option_uint
+      ('n',
+       "coins-number",
+       "CN",
+       "How many coins we should instantiate",
+       &howmany_coins),
 
-/**
- * Functions of this type are called to provide the retrieved signing and
- * denomination keys of the exchange.  No TALER_EXCHANGE_*() functions should 
be called
- * in this callback.
- *
- * @param cls closure
- * @param _keys information about keys of the exchange
- * @param vc compatibility information
- */
-static void
-cert_cb (void *cls,
-         const struct TALER_EXCHANGE_Keys *_keys,
-        enum TALER_EXCHANGE_VersionCompatibility vc)
-{
-  /* check that keys is OK */
-  if (NULL == _keys)
-  {
-    fail ("Exchange returned no keys!");
-    return;
-  }
-  if ( (0 == _keys->num_sign_keys) ||
-       (0 == _keys->num_denom_keys) )
-  {
-    GNUNET_break (0);
-    fail ("Bad /keys response");
-    return;
-  }
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Read %u signing keys and %u denomination keys\n",
-              _keys->num_sign_keys,
-              _keys->num_denom_keys);
-  if (NULL != currency)
-  {
-    /* we've been here before, still need to update refresh_denoms */
-    if (GNUNET_SYSERR ==
-       build_refresh ())
-    {
-      fail ("Initializing denominations failed");
-      return;
-    }
-    return;
-  }
-  currency = GNUNET_strdup (_keys->denom_keys[0].value.currency);
-  if (GNUNET_SYSERR ==
-      build_refresh ())
-  {
-    fail ("Initializing denominations failed");
-    return;
-  }
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Using currency: %s\n",
-             currency);
-  continue_master_task ();
-}
-
+    GNUNET_GETOPT_option_string
+      ('b',
+       "bank-url",
+       "BU",
+       "bank base url, mandatory,"
+       " must match exchange's escrow bank",
+       &fakebank_url),
 
-/**
- * Function run when the benchmark terminates (good or bad).
- * Cleans up our state.
- *
- * @param cls the interpreter state.
- */
-static void
-do_shutdown (void *cls)
-{
-  struct GNUNET_TIME_Relative duration;
+    GNUNET_GETOPT_option_string
+      ('l',
+       "logfile",
+       "LF",
+       "will log to file LF",
+       &logfile),
 
-  if (warm >= WARM_THRESHOLD)
-    duration = GNUNET_TIME_absolute_get_duration (start_time);
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-             "Shutting down...\n");
-  if (NULL != benchmark_task)
-  {
-    GNUNET_SCHEDULER_cancel (benchmark_task);
-    benchmark_task = NULL;
-  }
-  for (unsigned int i=0; i<nreserves; i++)
+    GNUNET_GETOPT_OPTION_END
+  };
+  
+  if (GNUNET_SYSERR == (result = GNUNET_GETOPT_run
+      ("taler-exchange-benchmark",
+       options,
+       argc,
+       argv))) 
   {
-    if (NULL != reserves[i].aih)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                  "Cancelling %d-th reserve\n",
-                  i);
-      TALER_BANK_admin_add_incoming_cancel(reserves[i].aih);
-      reserves[i].aih = NULL;
-    }
+    TALER_LOG_ERROR ("Unparsable CLI options\n");
+    return BAD_CLI_ARG;
   }
-  for (unsigned int i=0; i<COINS_PER_RESERVE * nreserves; i++)
-  {
-    struct Coin *coin = &coins[i];
 
-    if (NULL != coin->wsh)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                  "Cancelling %d-th coin withdraw handle\n",
-                  i);
-      TALER_EXCHANGE_reserve_withdraw_cancel (coin->wsh);
-      coin->wsh = NULL;
-    }
-    if (NULL != coin->dh)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                  "Cancelling %d-th coin deposit handle\n",
-                  i);
-      TALER_EXCHANGE_deposit_cancel(coin->dh);
-      coin->dh = NULL;
-    }
-    if (NULL != coin->rmh)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                  "Cancelling %d-th coin melt handle\n",
-                  i);
-      TALER_EXCHANGE_refresh_melt_cancel (coin->rmh);
-      coin->rmh = NULL;
-    }
-    if (NULL != coin->rrh)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                  "Cancelling %d-th coin reveal handle\n",
-                  i);
-      TALER_EXCHANGE_refresh_reveal_cancel (coin->rrh);
-      coin->rmh = NULL;
-    }
-    if (NULL != coin->blob)
-    {
-      GNUNET_free (coin->blob);
-      coin->blob = NULL;
-    }
-    if (NULL != coin->sig.rsa_signature)
-    {
-      GNUNET_CRYPTO_rsa_signature_free (coin->sig.rsa_signature);
-      coin->sig.rsa_signature = NULL;
-    }
-    if (NULL != coin->denoms)
-    {
-      GNUNET_free (coin->denoms);
-      coin->denoms = NULL;
-    }
-  }
-  if (NULL != fakebank)
-  {
-    TALER_FAKEBANK_stop (fakebank);
-    fakebank = NULL;
-  }
-  if (NULL != bank_details)
-  {
-    json_decref (bank_details);
-    bank_details = NULL;
-  }
-  if (NULL != merchant_details)
-  {
-    json_decref (merchant_details);
-    merchant_details = NULL;
-  }
-  GNUNET_free_non_null (reserves);
-  reserves = NULL;
-  GNUNET_free_non_null (coins);
-  coins = NULL;
-  GNUNET_free_non_null (currency);
-  currency = NULL;
-
-  if (NULL != exchange)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                "Disconnecting from exchange\n");
-    TALER_EXCHANGE_disconnect (exchange);
-    exchange = NULL;
-  }
-  if (NULL != ctx)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                "Invoking GNUNET_CURL_fini()\n");
-    GNUNET_CURL_fini (ctx);
-    ctx = NULL;
-  }
-  if (NULL != rc)
+  if (NULL == cfg_filename)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                "Invoking GNUNET_CURL_gnunet_rc_destroy()\n");
-    GNUNET_CURL_gnunet_rc_destroy (rc);
-    rc = NULL;
+    TALER_LOG_ERROR ("-c option is mandatory\n");
+    return NO_CONFIG_FILE_GIVEN;
   }
-  GNUNET_CONFIGURATION_destroy (cfg);
-  cfg = NULL;
-  if (warm >= WARM_THRESHOLD)
-  {
-    fprintf (stderr,
-            "Executed A=%llu/W=%llu/D=%llu/R=%llu operations in %s\n",
-            num_admin,
-            num_withdraw,
-            num_deposit,
-            num_refresh,
-            GNUNET_STRINGS_relative_time_to_string (duration,
-                                                    GNUNET_YES));
-  }
-  else
-  {
-    fprintf (stdout,
-            "Sorry, no results, benchmark did not get warm!\n");
-  }
-}
-
 
-/**
- * Main function that will be run by the scheduler.
- * Prepares everything for the benchmark.
- *
- * @param cls closure
- */
-static void
-run (void *cls)
-{
-  char *bank_details_filename;
-  char *merchant_details_filename;
-  struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "gotten pool_size of %d\n",
-              pool_size);
   cfg = GNUNET_CONFIGURATION_create ();
-  GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
-                                NULL);
-  if (GNUNET_SYSERR ==
-      GNUNET_CONFIGURATION_parse (cfg,
-                                  config_file))
+  if (GNUNET_OK != GNUNET_CONFIGURATION_load
+      (cfg,
+       cfg_filename))
   {
-    fail ("Failed to parse configuration file");
-    return;
+    TALER_LOG_ERROR ("Could not parse configuration\n");
+    return BAD_CONFIG_FILE;
   }
-  if (pool_size < INVALID_COIN_SLACK)
-  {
-    fail ("Pool size given too small.");
-    return;
-  }
-  if (GNUNET_SYSERR ==
-      GNUNET_CONFIGURATION_get_value_filename (cfg,
-                                              "benchmark",
-                                              "bank_details",
-                                              &bank_details_filename))
-  {
-    GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
-                              "benchmark",
-                              "bank_details");
-    fail ("Failed to get BANK_DETAILS value");
-    return;
-  }
-
-  bank_details = json_load_file (bank_details_filename,
-                                JSON_REJECT_DUPLICATES,
-                                NULL);
-  GNUNET_free (bank_details_filename);
-  if (NULL == bank_details)
-  {
-    fail ("Failed to parse file with BANK_DETAILS");
-    return;
-  }
-  if (GNUNET_SYSERR ==
-      GNUNET_CONFIGURATION_get_value_filename (cfg,
-                                              "benchmark",
-                                              "merchant_details",
-                                              &merchant_details_filename))
+  if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string
+      (cfg,
+       "taler",
+       "currency",
+       &currency))
   {
     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
-                              "benchmark",
-                              "merchant_details");
-    fail ("Failed to get MERCHANT_DETAILS value");
-    return;
-  }
-  merchant_details = json_load_file (merchant_details_filename,
-                                     JSON_REJECT_DUPLICATES,
-                                     NULL);
-  GNUNET_free (merchant_details_filename);
-  if (NULL == merchant_details)
-  {
-    fail ("Failed to parse file with MERCHANT_DETAILS");
-    return;
-  }
-
-  priv = GNUNET_CRYPTO_eddsa_key_create ();
-  merchant_priv.eddsa_priv = *priv;
-  GNUNET_free (priv);
-
-  GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
-                              &blinding_key,
-                              sizeof (blinding_key));
-
-  nreserves = pool_size / COINS_PER_RESERVE;
-  if (COINS_PER_RESERVE * nreserves < pool_size)
-    nreserves++;
-  reserves = GNUNET_new_array (nreserves,
-                               struct Reserve);
-  ncoins = COINS_PER_RESERVE * nreserves;
-  coins = GNUNET_new_array (ncoins,
-                            struct Coin);
-  for (unsigned int i=0;i < nreserves;i++)
-  {
-    struct Reserve *r = &reserves[i];
-
-    r->reserve_index = i;
-    GNUNET_CONTAINER_DLL_insert (empty_reserve_head,
-                                empty_reserve_tail,
-                                r);
-    for (unsigned int j=0; j < COINS_PER_RESERVE; j++)
-    {
-      struct Coin *coin;
-      unsigned int coin_index;
-
-      coin_index = i * COINS_PER_RESERVE + j;
-      coin = &coins[coin_index];
-      coin->coin_index = coin_index;
-      coin->reserve_index = i;
-      invalidate_coin (coin);
-    }
+                               "taler",
+                               "currency");
+    GNUNET_CONFIGURATION_destroy (cfg);
+    return BAD_CONFIG_FILE;
   }
+  GNUNET_CONFIGURATION_destroy (cfg);
 
-  ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
-                          &rc);
-  GNUNET_assert (NULL != ctx);
-  rc = GNUNET_CURL_gnunet_rc_create (ctx);
-  GNUNET_assert (NULL != rc);
-  fakebank = TALER_FAKEBANK_start (8082);
-  exchange = TALER_EXCHANGE_connect (ctx,
-                                     exchange_url,
-                                     &cert_cb, NULL,
-                                     TALER_EXCHANGE_OPTION_END);
-  if (NULL == exchange)
+  if (NULL == fakebank_url)
   {
-    fail ("Failed to connect to the exchange!");
-    return;
+    TALER_LOG_ERROR ("Option -b is mandatory!\n");
+    return MISSING_BANK_URL;
   }
-}
 
+  GNUNET_assert (GNUNET_OK == TALER_TESTING_prepare_exchange
+    (cfg_filename,
+     &exchange_url)); // never used, we do all via handle.
+  result = TALER_TESTING_setup_with_exchange
+    (run,
+     NULL,
+     cfg_filename);
 
-int
-main (int argc,
-      char * const *argv)
-{
-  struct GNUNET_OS_Process *proc;
-  unsigned int cnt;
-  struct GNUNET_SIGNAL_Context *shc_chld;
-  const struct GNUNET_GETOPT_CommandLineOption options[] = {
-    GNUNET_GETOPT_option_flag ('a',
-                               "automate",
-                               "Initialize and start the exchange",
-                               &run_exchange),
-    GNUNET_GETOPT_option_mandatory
-    (GNUNET_GETOPT_option_cfgfile (&config_file)),
-    GNUNET_GETOPT_option_string ('e',
-                                 "exchange-url",
-                                 "URL",
-                                 "URL of the exchange",
-                                 &exchange_url),
-    GNUNET_GETOPT_option_string ('E',
-                                 "exchange-admin-url",
-                                 "URL",
-                                 "URL of the administrative interface of the 
exchange",
-                                 &exchange_admin_url),
-    GNUNET_GETOPT_option_help ("tool to benchmark the Taler exchange"),
-    GNUNET_GETOPT_option_uint ('s',
-                               "pool-size",
-                               "SIZE",
-                               "How many coins this benchmark should 
instantiate",
-                               &pool_size),
-    GNUNET_GETOPT_option_uint ('l',
-                               "limit",
-                               "LIMIT",
-                               "Terminate the benchmark after LIMIT 
operations",
-                               &num_iterations),
-    GNUNET_GETOPT_option_verbose (&be_verbose),
-    GNUNET_GETOPT_OPTION_END
-  };
-  int ret;
+  duration = GNUNET_TIME_absolute_get_duration (start_time);
 
-  GNUNET_log_setup ("taler-exchange-benchmark",
-                    "WARNING",
-                    NULL);
-  GNUNET_assert (INVALID_COIN_SLACK >= REFRESH_SLOTS_NEEDED);
-  GNUNET_assert (COIN_VALUE <= (1LL << REFRESH_SLOTS_NEEDED));
-  ret = GNUNET_GETOPT_run ("taler-exchange-benchmark",
-                          options, argc, argv);
-  if (GNUNET_SYSERR == ret)
-  {
-    fprintf (stderr,
-            "Invalid command line arguments\n");
-    return 1;
-  }
-  if (GNUNET_NO == ret)
-    return 0;
-  if ( (0 != num_iterations) &&
-       (WARM_THRESHOLD >= num_iterations) )
-    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-               "Number of iterations below WARM_THRESHOLD of %llu\n",
-               WARM_THRESHOLD);
-  if ( (NULL == exchange_url) ||
-       (0 == strlen (exchange_url) ))
-  {
-    GNUNET_free_non_null (exchange_url);
-    exchange_url = GNUNET_strdup ("http://localhost:8081/";);
-  }
-  if (NULL == exchange_admin_url)
-    exchange_admin_url = GNUNET_strdup ("http://localhost:18080/";);
-  if (run_exchange)
-  {
-    char *wget;
-
-    proc = GNUNET_OS_start_process (GNUNET_NO,
-                                   GNUNET_OS_INHERIT_STD_ALL,
-                                   NULL, NULL, NULL,
-                                   "taler-exchange-keyup",
-                                   "taler-exchange-keyup",
-                                   "-c", config_file,
-                                   NULL);
-    if (NULL == proc)
-    {
-      fprintf (stderr,
-              "Failed to run taler-exchange-keyup. Check your PATH.\n");
-      return 77;
-    }
-    GNUNET_OS_process_wait (proc);
-    GNUNET_OS_process_destroy (proc);
-
-    proc = GNUNET_OS_start_process (GNUNET_NO,
-                                   GNUNET_OS_INHERIT_STD_ALL,
-                                   NULL, NULL, NULL,
-                                   "taler-exchange-dbinit",
-                                   "taler-exchange-dbinit",
-                                   "-r",
-                                   "-c", config_file,
-                                   NULL);
-    if (NULL == proc)
-    {
-      fprintf (stderr,
-              "Failed to run taler-exchange-dbinit. Check your PATH.\n");
-      return 77;
-    }
-    GNUNET_OS_process_wait (proc);
-    GNUNET_OS_process_destroy (proc);
-
-    exchanged = GNUNET_OS_start_process (GNUNET_NO,
-                                        GNUNET_OS_INHERIT_STD_ALL,
-                                        NULL, NULL, NULL,
-                                        "taler-exchange-httpd",
-                                        "taler-exchange-httpd",
-                                        "-c", config_file,
-                                        NULL);
-    if (NULL == exchanged)
-    {
-      fprintf (stderr,
-              "Failed to run taler-exchange-httpd. Check your PATH.\n");
-      return 77;
-    }
+  TALER_LOG_INFO ("Executed W=%u, D=%u, R=%u, operations in %s\n",
+                  howmany_coins,
+                  howmany_coins,
+                  howmany_refreshes,
+                  GNUNET_STRINGS_relative_time_to_string
+                    (duration,
+                     GNUNET_YES));
 
-    GNUNET_asprintf (&wget,
-                    "wget -q -t 1 -T 1 %s%skeys -o /dev/null -O /dev/null",
-                    exchange_url,
-                    (exchange_url[strlen (exchange_url)-1] == '/') ? "" : "/");
-    cnt = 0;
-    do {
-      fprintf (stderr, ".");
-      sleep (1);
-      cnt++;
-      if (cnt > 60)
-      {
-        fprintf (stderr,
-                 "\nFailed to start taler-exchange-httpd\n");
-        GNUNET_OS_process_kill (exchanged,
-                                SIGKILL);
-        GNUNET_OS_process_wait (exchanged);
-        GNUNET_OS_process_destroy (exchanged);
-        return 77;
-      }
-    }
-    while (0 != system (wget));
-    GNUNET_free (wget);
-    fprintf (stderr, "\n");
-  }
-  sigpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_NO);
-  GNUNET_assert (NULL != sigpipe);
-  shc_chld = GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD,
-                                            &sighandler_child_death);
-  GNUNET_SCHEDULER_run (&run,
-                        NULL);
-  GNUNET_SIGNAL_handler_uninstall (shc_chld);
-  shc_chld = NULL;
-  GNUNET_DISK_pipe_close (sigpipe);
-  if (run_exchange)
-  {
-    GNUNET_OS_process_kill (exchanged,
-                            SIGTERM);
-    GNUNET_OS_process_wait (exchanged);
-    GNUNET_OS_process_destroy (exchanged);
-  }
-  return 0;
+  return (GNUNET_OK == result) ? 0 : result;
 }
-
-/* end of taler-exchange-benchmark.c */

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



reply via email to

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