From 18c22e3e2e97111c9e3717cfe4ac67d397b0456c Mon Sep 17 00:00:00 2001 From: Marcello Stanisci Date: Mon, 13 Jun 2016 23:40:00 +0200 Subject: fixing corrupted DLL (resulting from double call to json_decref()) --- src/benchmark/taler-exchange-benchmark.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src') diff --git a/src/benchmark/taler-exchange-benchmark.c b/src/benchmark/taler-exchange-benchmark.c index f2274e606..02b91f87a 100644 --- a/src/benchmark/taler-exchange-benchmark.c +++ b/src/benchmark/taler-exchange-benchmark.c @@ -167,6 +167,12 @@ struct Coin { */ unsigned int refresh; + /** + * If the coin has to be refreshed, this value indicates + * how much is left on this coin + */ + struct TALER_Amount left; + /** * Refresh melt handle */ @@ -838,6 +844,9 @@ benchmark_run (void *cls) json_decref (transfer_details); } json_decref (sender_details); + sender_details = NULL; + transfer_details = NULL; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "benchmark_run() returns\n"); } -- cgit v1.2.3 From a34a2873caf245b47388004a2734f590dd15bd22 Mon Sep 17 00:00:00 2001 From: Marcello Stanisci Date: Tue, 14 Jun 2016 15:51:58 +0200 Subject: reconstructing array of denominations for coins gotten by melting dynamically; as reported in msg (0010890) of #4576' --- src/benchmark/taler-exchange-benchmark.c | 112 +++++++++++++++++-------------- 1 file changed, 61 insertions(+), 51 deletions(-) (limited to 'src') diff --git a/src/benchmark/taler-exchange-benchmark.c b/src/benchmark/taler-exchange-benchmark.c index 02b91f87a..a02f62f05 100644 --- a/src/benchmark/taler-exchange-benchmark.c +++ b/src/benchmark/taler-exchange-benchmark.c @@ -87,6 +87,11 @@ struct RefreshRevealCls { * Which coin in the list are we melting */ unsigned int coin_index; + + /** + * Array of denominations expected to get from melt + */ + struct TALER_Amount *denoms; }; /** @@ -221,16 +226,6 @@ static struct Reserve *reserves; */ static struct Coin *coins; -/** - * Indices of spent coins - */ -static unsigned int *spent_coins; - -/** - * Current number of spent coins - */ -static unsigned int spent_coins_size = 0; - /** * Transaction id counter, used in /deposit's */ @@ -425,22 +420,20 @@ reveal_cb (void *cls, for (i=0; idenoms[i]); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "revealing %s " + "# of coins after refresh: %d\n", + revealed_str, + ncoins); + + GNUNET_free (revealed_str); fresh_coin.reserve_index = coins[rrcls->coin_index].reserve_index; - TALER_string_to_amount (refresh_denom, &amount); - GNUNET_free (refresh_denom); - fresh_coin.pk = find_pk (keys, &amount); + fresh_coin.pk = find_pk (keys, &rrcls->denoms[i]); fresh_coin.sig = sigs[i]; GNUNET_array_append (coins, ncoins, fresh_coin); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "# of coins after refresh: %d\n", - ncoins); } GNUNET_free (rrcls); } @@ -463,8 +456,8 @@ melt_cb (void *cls, const struct TALER_ExchangePublicKeyP *exchange_pub, const json_t *full_response) { + /* free'd in `reveal_cb` */ struct RefreshRevealCls *rrcls = cls; - /* FIXME to be freed */ coins[rrcls->coin_index].rmh = NULL; if (MHD_HTTP_OK != http_status) @@ -473,12 +466,13 @@ melt_cb (void *cls, fail ("Coin not correctly melted!\n"); return; } + coins[rrcls->coin_index].rrh = TALER_EXCHANGE_refresh_reveal (exchange, rrcls->blob_size, rrcls->blob, noreveal_index, - reveal_cb, + &reveal_cb, rrcls); } @@ -525,30 +519,52 @@ deposit_cb (void *cls, fail ("At least one coin has not been deposited, status: %d\n"); return; } - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Coin #%d correctly spent!\n", coin_index); - GNUNET_array_append (spent_coins, spent_coins_size, coin_index); - spent_coins_size++; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Coin #%d correctly spent!\n", + coin_index); if (GNUNET_YES == coins[coin_index].refresh) { - struct TALER_Amount melt_amount; struct RefreshRevealCls *rrcls; - - TALER_amount_get_zero (currency, &melt_amount); - melt_amount.value = 7; char *blob; size_t blob_size; - + const struct TALER_EXCHANGE_Keys *keys; + struct TALER_Amount *denoms = NULL; + struct TALER_EXCHANGE_DenomPublicKey *dpks = NULL; + const struct TALER_EXCHANGE_DenomPublicKey *curr_dpk; + struct TALER_Amount curr; + unsigned int ndenoms = 0; + unsigned int ndenoms2 = 0; + unsigned long long acc_value; + + TALER_amount_get_zero (currency, &curr); + curr.value = COIN_VALUE >> 1; + acc_value = 0; + + keys = TALER_EXCHANGE_get_keys (exchange); + for (; curr.value > 0; curr.value = curr.value >> 1) + { + if (acc_value + curr.value <= coins[coin_index].left.value) + { + GNUNET_array_append (denoms, ndenoms, curr); + GNUNET_assert (NULL != (curr_dpk = find_pk (keys, &curr))); + GNUNET_array_append (dpks, ndenoms2, *curr_dpk); + acc_value += curr.value; + } + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "# of coins to get in melt: %d\n", + ndenoms2); blob = TALER_EXCHANGE_refresh_prepare (&coins[coin_index].coin_priv, - &melt_amount, + &coins[coin_index].left, &coins[coin_index].sig, coins[coin_index].pk, GNUNET_YES, - refresh_pk_len, - refresh_pk, + ndenoms2, + dpks, &blob_size); if (NULL == blob) { - fail ("Failed to prepare refresh"); + fail ("Failed to prepare refresh\n"); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, @@ -556,14 +572,11 @@ deposit_cb (void *cls, (unsigned int) blob_size); refreshed_once = GNUNET_YES; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "# of coins to get in melt: %d\n", - refresh_pk_len); rrcls = GNUNET_new (struct RefreshRevealCls); rrcls->blob = blob; rrcls->blob_size = blob_size; rrcls->coin_index = coin_index; - + rrcls->denoms = denoms; coins[coin_index].rmh = TALER_EXCHANGE_refresh_melt (exchange, blob_size, blob, @@ -619,7 +632,7 @@ reserve_withdraw_cb (void *cls, fail ("At least one coin has not correctly been withdrawn\n"); return; } - GNUNET_log (GNUNET_ERROR_TYPE_INFO, + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%d-th coin withdrawn\n", coin_index); coins[coin_index].sig.rsa_signature = @@ -652,18 +665,20 @@ reserve_withdraw_cb (void *cls, if (GNUNET_YES == eval_probability (REFRESH_PROBABILITY) && GNUNET_NO == refreshed_once) { + /** + * Always spending 1 out of 8 KUDOS. To be improved by randomly + * picking the spent amount + */ struct TALER_Amount one; TALER_amount_get_zero (currency, &one); one.value = 1; - /** - * If the coin is going to be refreshed, only 1 unit - * of currency will be spent, since 4 units are going - * to be refreshed - */ TALER_amount_subtract (&amount, &one, &coins[coin_index].pk->fee_deposit); + TALER_amount_subtract (&coins[coin_index].left, + &coins[coin_index].pk->value, + &one); coins[coin_index].refresh = GNUNET_YES; refreshed_once = GNUNET_YES; } @@ -1004,7 +1019,6 @@ do_shutdown (void *cls) GNUNET_free_non_null (reserves); GNUNET_free_non_null (coins); - GNUNET_free_non_null (spent_coins); GNUNET_free_non_null (currency); if (NULL != exchange) @@ -1095,10 +1109,6 @@ run (void *cls) NULL); GNUNET_CONFIGURATION_destroy (cfg); - GNUNET_array_append (spent_coins, - spent_coins_size, - 1); - spent_coins_size++; reserves = NULL; coins = NULL; ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule, -- cgit v1.2.3 From 1a7619d54e0337939cef1b323af985e0f5ede515 Mon Sep 17 00:00:00 2001 From: Marcello Stanisci Date: Tue, 14 Jun 2016 15:53:48 +0200 Subject: comments --- src/benchmark/taler-exchange-benchmark.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/benchmark/taler-exchange-benchmark.c b/src/benchmark/taler-exchange-benchmark.c index a02f62f05..83f201889 100644 --- a/src/benchmark/taler-exchange-benchmark.c +++ b/src/benchmark/taler-exchange-benchmark.c @@ -608,7 +608,8 @@ deposit_cb (void *cls, /** * Function called upon completion of our /reserve/withdraw request. - * This is merely the function which spends withdrawn coins + * This is merely the function which spends withdrawn coins. For each + * spent coin, ti either refresh it or re-withdraw it. * * @param cls closure with the interpreter state * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request -- cgit v1.2.3 From 7b9272d3e8cb4c540c876bc4e10875d45971214b Mon Sep 17 00:00:00 2001 From: Marcello Stanisci Date: Tue, 14 Jun 2016 15:58:25 +0200 Subject: left=0 after successful reveal --- src/benchmark/taler-exchange-benchmark.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/benchmark/taler-exchange-benchmark.c b/src/benchmark/taler-exchange-benchmark.c index 83f201889..93df0ae0d 100644 --- a/src/benchmark/taler-exchange-benchmark.c +++ b/src/benchmark/taler-exchange-benchmark.c @@ -57,7 +57,6 @@ static unsigned int nreserves; */ unsigned int ncoins; - /** * Bank details of who creates reserves */ @@ -190,7 +189,6 @@ struct Coin { }; - /** * Handle to the exchange's process */ @@ -413,9 +411,13 @@ reveal_cb (void *cls, return; } else + { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Coin #%d revealed!\n", rrcls->coin_index); + coins[rrcls->coin_index].left.value = 0; + } + keys = TALER_EXCHANGE_get_keys (exchange); for (i=0; i Date: Wed, 15 Jun 2016 15:09:57 +0200 Subject: misc minor stylistic fixes to benchmark tool: --- src/benchmark/Makefile.am | 5 + src/benchmark/bank_details.json | 1 + src/benchmark/sender_details.json | 1 - src/benchmark/taler-exchange-benchmark.c | 402 +++++++++++++++------------- src/benchmark/taler-exchange-benchmark.conf | 4 +- 5 files changed, 231 insertions(+), 182 deletions(-) create mode 100644 src/benchmark/bank_details.json delete mode 100644 src/benchmark/sender_details.json (limited to 'src') diff --git a/src/benchmark/Makefile.am b/src/benchmark/Makefile.am index e92a13944..a5aef47e3 100644 --- a/src/benchmark/Makefile.am +++ b/src/benchmark/Makefile.am @@ -20,3 +20,8 @@ taler_exchange_benchmark_LDADD = \ -lgnunetcurl \ -lgnunetutil \ -ljansson + +EXTRA_DIST = \ + taler-exchange-benchmark.conf \ + bank-details.json \ + merchant-details.json diff --git a/src/benchmark/bank_details.json b/src/benchmark/bank_details.json new file mode 100644 index 000000000..d6f60005b --- /dev/null +++ b/src/benchmark/bank_details.json @@ -0,0 +1 @@ +{"type":"test", "bank_uri":"https://bank.test.taler.net/", "account_number":63} diff --git a/src/benchmark/sender_details.json b/src/benchmark/sender_details.json deleted file mode 100644 index d6f60005b..000000000 --- a/src/benchmark/sender_details.json +++ /dev/null @@ -1 +0,0 @@ -{"type":"test", "bank_uri":"https://bank.test.taler.net/", "account_number":63} diff --git a/src/benchmark/taler-exchange-benchmark.c b/src/benchmark/taler-exchange-benchmark.c index 93df0ae0d..6996a4fa2 100644 --- a/src/benchmark/taler-exchange-benchmark.c +++ b/src/benchmark/taler-exchange-benchmark.c @@ -28,7 +28,11 @@ #include #include -#define RUNXCG +/** + * Should we initialize and start the exchange, if #GNUNET_NO, + * we expect one to be already up and running. + */ +static int run_exchange; /** * How many coins the benchmark should operate on @@ -43,7 +47,7 @@ static char *config_file; /** * Configuation object (used to get BANK_URI) */ -struct GNUNET_CONFIGURATION_Handle *cfg; +static struct GNUNET_CONFIGURATION_Handle *cfg; /** * How many reserves ought to be created given the pool size @@ -51,34 +55,36 @@ struct GNUNET_CONFIGURATION_Handle *cfg; static unsigned int nreserves; /** - * How many coins are in `coins` array. This is needed - * as the number of coins is not always nreserves * COINS_PER_RESERVE + * 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 */ -unsigned int ncoins; +static unsigned int ncoins; /** * Bank details of who creates reserves */ -json_t *sender_details; +static json_t *bank_details; /** * Bank details of who deposits coins */ -json_t *merchant_details; +static json_t *merchant_details; + /** * Information needed by the /refresh/melt's callback */ -struct RefreshRevealCls { +struct RefreshRevealCls +{ /** - * The result of a `TALER_EXCHANGE_refresh_prepare()` call + * The result of a #TALER_EXCHANGE_refresh_prepare() call */ const char *blob; /** - * Size of `blob` + * Size of @e blob */ size_t blob_size; @@ -93,10 +99,12 @@ struct RefreshRevealCls { struct TALER_Amount *denoms; }; + /** * Needed information for a reserve. Other values are the same for all reserves, therefore defined in global variables */ -struct Reserve { +struct Reserve +{ /** * Set (by the interpreter) to the reserve's private key * we used to fill the reserve. @@ -110,26 +118,28 @@ struct Reserve { }; + /** * Array of denomination keys needed to perform the 4 KUDOS * refresh operation */ -struct TALER_EXCHANGE_DenomPublicKey *refresh_pk; +static struct TALER_EXCHANGE_DenomPublicKey *refresh_pk; /** - * Size of `refresh_pk` + * Size of #refresh_pk */ -unsigned int refresh_pk_len; +static unsigned int refresh_pk_len; /** * Same blinding key for all coins */ -struct TALER_DenominationBlindingKeyP blinding_key; +static struct TALER_DenominationBlindingKeyP blinding_key; /** * Information regarding a coin */ -struct Coin { +struct Coin +{ /** * Index in the reserve's global array indicating which * reserve this coin is to be retrieved. If the coin comes @@ -202,7 +212,7 @@ static struct GNUNET_CURL_RescheduleContext *rc; /** * Benchmark's task */ -struct GNUNET_SCHEDULER_Task *benchmark_task; +static struct GNUNET_SCHEDULER_Task *benchmark_task; /** * Main execution context for the main loop of the exchange. @@ -227,7 +237,7 @@ static struct Coin *coins; /** * Transaction id counter, used in /deposit's */ -static unsigned int transaction_id = 0; +static unsigned int transaction_id; /** * This key (usually provided by merchants) is needed when depositing coins, @@ -276,7 +286,7 @@ static char *currency; * Refreshed once. For each batch of deposits, only one * coin will be refreshed, according to #REFRESH_PROBABILITY */ -static unsigned int refreshed_once = GNUNET_NO; +static unsigned int refreshed_once; /** * List of coins to get in return to a melt operation. Just a @@ -286,29 +296,32 @@ static unsigned int refreshed_once = GNUNET_NO; * TALER_Amount structs, as every time it's needed it requires * too many operations before getting the desired TALER_Amount. */ -static char *refresh_denoms[] = { +static const char *refresh_denoms[] = { "4", "2", "1", NULL }; + +/** + * Throw a weighted coin with @a probability. + * + * @reurn #GNUNET_OK with @a probability, #GNUNET_NO with 1 - @a probability + */ static unsigned int eval_probability (float probability) { - unsigned int random; + uint64_t random; float random_01; - random = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX); - random_01 = (float) random / UINT32_MAX; - return random_01 <= probability ? GNUNET_OK : GNUNET_NO; + 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; } -static void -do_shutdown (void *cls); - - /** * Shutdown benchmark in case of errors * @@ -322,7 +335,6 @@ fail (const char *msg) "%s\n", msg); GNUNET_SCHEDULER_shutdown (); - return; } @@ -407,7 +419,7 @@ reveal_cb (void *cls, { GNUNET_free (rrcls); json_dumpf (full_response, stderr, 0); - fail ("Not all coins correctly revealed\n"); + fail ("Not all coins correctly revealed"); return; } else @@ -440,6 +452,7 @@ reveal_cb (void *cls, GNUNET_free (rrcls); } + /** * Function called with the result of the /refresh/melt operation. * @@ -465,7 +478,7 @@ melt_cb (void *cls, if (MHD_HTTP_OK != http_status) { json_dumpf (full_response, stderr, 0); - fail ("Coin not correctly melted!\n"); + fail ("Coin not correctly melted!"); return; } @@ -518,7 +531,7 @@ deposit_cb (void *cls, if (MHD_HTTP_OK != http_status) { json_dumpf (obj, stderr, 0); - fail ("At least one coin has not been deposited, status: %d\n"); + fail ("At least one coin has not been deposited, status: %d"); return; } GNUNET_log (GNUNET_ERROR_TYPE_INFO, @@ -566,7 +579,7 @@ deposit_cb (void *cls, &blob_size); if (NULL == blob) { - fail ("Failed to prepare refresh\n"); + fail ("Failed to prepare refresh"); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, @@ -586,7 +599,7 @@ deposit_cb (void *cls, rrcls); if (NULL == coins[coin_index].rmh) { - fail ("Impossible to issue a melt request to the exchange\n"); + fail ("Impossible to issue a melt request to the exchange"); return; } } @@ -632,7 +645,7 @@ reserve_withdraw_cb (void *cls, if (MHD_HTTP_OK != http_status) { json_dumpf (full_response, stderr, 0); - fail ("At least one coin has not correctly been withdrawn\n"); + fail ("At least one coin has not correctly been withdrawn"); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, @@ -734,7 +747,7 @@ reserve_withdraw_cb (void *cls, if (NULL == coins[coin_index].dh) { json_decref (merchant_details); - fail ("An error occurred while calling deposit API\n"); + fail ("An error occurred while calling deposit API"); return; } transaction_id++; @@ -742,7 +755,6 @@ reserve_withdraw_cb (void *cls, } - /** * Function called upon completion of our /admin/add/incoming request. * Its duty is withdrawing coins on the freshly created reserve. @@ -772,7 +784,8 @@ add_incoming_cb (void *cls, if (MHD_HTTP_OK != http_status) { json_dumpf (full_response, stderr, 0); - fail ("At least one reserve failed in being created\n"); + fail ("At least one reserve failed in being created"); + return; } for (i=0; i < COINS_PER_RESERVE; i++) @@ -798,9 +811,9 @@ add_incoming_cb (void *cls, /** - * Benchmark runner. + * Main task for the benchmark. * - * @param cls closure for benchmark_run() + * @param cls NULL */ static void benchmark_run (void *cls) @@ -813,6 +826,7 @@ benchmark_run (void *cls) struct GNUNET_TIME_Absolute execution_date; struct TALER_Amount reserve_amount; + benchmark_task = NULL; priv = GNUNET_CRYPTO_eddsa_key_create (); merchant_priv.eddsa_priv = *priv; GNUNET_free (priv); @@ -824,12 +838,9 @@ benchmark_run (void *cls) reserve_amount.value = RESERVE_VALUE; execution_date = GNUNET_TIME_absolute_get (); GNUNET_TIME_round_abs (&execution_date); - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "benchmark_run() invoked\n"); nreserves = pool_size / COINS_PER_RESERVE; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "creating %d reserves\n", + "Creating %d reserves\n", nreserves); reserves = GNUNET_new_array (nreserves, @@ -838,11 +849,12 @@ benchmark_run (void *cls) coins = GNUNET_new_array (ncoins, struct Coin); - for (i=0;i < nreserves && 0 < nreserves;i++) + for (i=0;i < nreserves;i++) { priv = GNUNET_CRYPTO_eddsa_key_create (); reserves[i].reserve_priv.eddsa_priv = *priv; GNUNET_free (priv); + // FIXME: avoid use of JSON parser GNUNET_asprintf (&uuid, "{ \"uuid\":%d}", i); transfer_details = json_loads (uuid, JSON_REJECT_DUPLICATES, NULL); GNUNET_free (uuid); @@ -854,24 +866,22 @@ benchmark_run (void *cls) &reserve_pub, &reserve_amount, execution_date, - sender_details, + bank_details, transfer_details, &add_incoming_cb, (void *) (long) i); GNUNET_assert (NULL != reserves[i].aih); json_decref (transfer_details); } - json_decref (sender_details); - sender_details = NULL; + json_decref (bank_details); + bank_details = NULL; transfer_details = NULL; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "benchmark_run() returns\n"); } + /** * Populates the global array of denominations which will - * be withdrawn in a refresh operation. It sums up 4 KUDOS, + * be withdrawn in a refresh operation. It sums up 4 #currency units, * since that is the only amount refreshed so far by the benchmark * * @param NULL-terminated array of value.fraction pairs @@ -879,7 +889,7 @@ benchmark_run (void *cls) * otherwise */ static unsigned int -build_refresh (char **list) +build_refresh (const char *const*list) { char *amount_str; struct TALER_Amount amount; @@ -888,21 +898,28 @@ build_refresh (char **list) const struct TALER_EXCHANGE_Keys *keys; keys = TALER_EXCHANGE_get_keys (exchange); - for (i=0; list[i] != NULL; i++) + for (i=0; NULL != list[i]; i++) { - unsigned int size; - GNUNET_asprintf (&amount_str, "%s:%s", currency, list[i]); - TALER_string_to_amount (amount_str, &amount); - picked_denom = find_pk (keys, &amount); + GNUNET_asprintf (&amount_str, + "%s:%s", + currency, + list[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; } - size = i; - GNUNET_array_append (refresh_pk, size, *picked_denom); + GNUNET_array_append (refresh_pk, + refresh_pk_len, + *picked_denom); GNUNET_free (amount_str); } - refresh_pk_len = i; return GNUNET_OK; } @@ -920,30 +937,34 @@ cert_cb (void *cls, const struct TALER_EXCHANGE_Keys *_keys) { /* check that keys is OK */ -#define ERR(cond) do { if(!(cond)) break; GNUNET_break (0); GNUNET_SCHEDULER_shutdown(); return; } while (0) - ERR (NULL == _keys); - ERR (0 == _keys->num_sign_keys); + 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\n", + "Read %u signing keys and %u denomination keys\n", _keys->num_sign_keys); - ERR (0 == _keys->num_denom_keys); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Read %u denomination keys\n", _keys->num_denom_keys); -#undef ERR - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Certificate callback invoked, invoking benchmark_run()\n"); + if (NULL != currency) + return; /* we've been here before... */ currency = GNUNET_strdup (_keys->denom_keys[0].value.currency); GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Using currency: %s\n", currency); - - if (GNUNET_SYSERR == build_refresh (refresh_denoms)) + "Using currency: %s\n", + currency); + if (GNUNET_SYSERR == + build_refresh (refresh_denoms)) { - fail(NULL); + fail ("Initializing denominations failed"); return; } - benchmark_task = GNUNET_SCHEDULER_add_now (&benchmark_run, NULL); } @@ -960,14 +981,21 @@ do_shutdown (void *cls) { unsigned int i; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "shutting down..\n"); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Shutting down...\n"); + if (NULL != benchmark_task) + { + GNUNET_SCHEDULER_cancel (benchmark_task); + benchmark_task = NULL; + } + /** * WARNING: all the non NULL handles must correspond to non completed * calls (AKA calls for which the callback function has not been called). * If not, it segfaults */ - for (i=0; i Date: Wed, 15 Jun 2016 15:41:17 +0200 Subject: make exchange URI a command-line option --- src/benchmark/taler-exchange-benchmark.c | 105 ++++++++++++++++--------------- 1 file changed, 56 insertions(+), 49 deletions(-) (limited to 'src') diff --git a/src/benchmark/taler-exchange-benchmark.c b/src/benchmark/taler-exchange-benchmark.c index 6996a4fa2..9b410ab5f 100644 --- a/src/benchmark/taler-exchange-benchmark.c +++ b/src/benchmark/taler-exchange-benchmark.c @@ -120,8 +120,7 @@ struct Reserve /** - * Array of denomination keys needed to perform the 4 KUDOS - * refresh operation + * Array of denomination keys needed to perform the refresh operation */ static struct TALER_EXCHANGE_DenomPublicKey *refresh_pk; @@ -140,20 +139,6 @@ static struct TALER_DenominationBlindingKeyP blinding_key; */ struct Coin { - /** - * 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; - - /** - * If @e amount is NULL, this specifies the denomination key to - * use. Otherwise, this will be set (by the interpreter) to the - * denomination PK matching @e amount. - */ - const struct TALER_EXCHANGE_DenomPublicKey *pk; /** * Set (by the interpreter) to the exchange's signature over the @@ -162,15 +147,30 @@ struct Coin struct TALER_DenominationSignature sig; /** - * Set (by the interpreter) to the coin's private key. + * 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). */ @@ -182,20 +182,18 @@ struct Coin unsigned int refresh; /** - * If the coin has to be refreshed, this value indicates - * how much is left on this coin - */ - struct TALER_Amount left; - - /** - * Refresh melt handle + * 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 */ - struct TALER_EXCHANGE_RefreshMeltHandle *rmh; + unsigned int reserve_index; /** - * Refresh reveal handle + * If the coin has to be refreshed, this value indicates + * how much is left on this coin */ - struct TALER_EXCHANGE_RefreshRevealHandle *rrh; + struct TALER_Amount left; }; @@ -225,12 +223,12 @@ static struct GNUNET_CURL_Context *ctx; static struct TALER_EXCHANGE_Handle *exchange; /** - * The array of all reserves + * The array of all reserves, of length #nreserves. */ static struct Reserve *reserves; /** - * The array of all coins + * The array of all coins, of length #ncoins. */ static struct Coin *coins; @@ -248,7 +246,7 @@ static struct TALER_MerchantPrivateKeyP merchant_priv; /** * URI under which the exchange is reachable during the benchmark. */ -#define EXCHANGE_URI "http://localhost:8081/" +static char *exchange_uri; /** * How many coins (AKA withdraw operations) per reserve should be withdrawn @@ -951,7 +949,7 @@ cert_cb (void *cls, } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Read %u signing keys and %u denomination keys\n", - _keys->num_sign_keys); + _keys->num_sign_keys, _keys->num_denom_keys); if (NULL != currency) return; /* we've been here before... */ @@ -1161,7 +1159,7 @@ run (void *cls) rc = GNUNET_CURL_gnunet_rc_create (ctx); GNUNET_assert (NULL != rc); exchange = TALER_EXCHANGE_connect (ctx, - EXCHANGE_URI, + exchange_uri, &cert_cb, NULL, TALER_EXCHANGE_OPTION_END); if (NULL == exchange) @@ -1178,27 +1176,32 @@ main (int argc, { struct GNUNET_OS_Process *proc; unsigned int cnt; - - GNUNET_log_setup ("taler-exchange-benchmark", - "WARNING", - NULL); const struct GNUNET_GETOPT_CommandLineOption options[] = { - {'s', "pool-size", NULL, + {'a', "automate", NULL, + "Initialize and start the bank and exchange", GNUNET_NO, + &GNUNET_GETOPT_set_one, &run_exchange}, + GNUNET_GETOPT_OPTION_CFG_FILE (&config_file), + GNUNET_GETOPT_OPTION_HELP ("tool to benchmark the Taler exchange"), + {'s', "pool-size", "SIZE", "How many coins this benchmark should instantiate", GNUNET_YES, &GNUNET_GETOPT_set_uint, &pool_size}, - {'e', "exchange", NULL, - "Initialize and start the exchange", GNUNET_NO, - &GNUNET_GETOPT_set_one, &run_exchange}, - {'c', "config", NULL, - "Configuration file", GNUNET_YES, - &GNUNET_GETOPT_set_string, &config_file} + {'e', "exchange-uri", "URI", + "URI of the exchange", GNUNET_YES, + &GNUNET_GETOPT_set_string, &exchange_uri} }; + GNUNET_log_setup ("taler-exchange-benchmark", + "WARNING", + NULL); GNUNET_assert (GNUNET_SYSERR != - GNUNET_GETOPT_run ("taler-exchange-benchmark", - options, argc, argv)); + GNUNET_GETOPT_run ("taler-exchange-benchmark", + options, argc, argv)); + if (NULL == exchange_uri) + exchange_uri = GNUNET_strdup ("http://localhost:8081/"); if (run_exchange) { + char *wget; + proc = GNUNET_OS_start_process (GNUNET_NO, GNUNET_OS_INHERIT_STD_ALL, NULL, NULL, NULL, @@ -1242,7 +1245,10 @@ main (int argc, "Failed to run taler-exchange-httpd. Check your PATH.\n"); return 77; } - + + GNUNET_asprintf (&wget, + "wget -q -t 1 -T 1 %s keys -o /dev/null -O /dev/null", + exchange_uri); cnt = 0; do { fprintf (stderr, "."); @@ -1259,10 +1265,10 @@ main (int argc, return 77; } } - while (0 != system ("wget -q -t 1 -T 1 " EXCHANGE_URI "keys -o /dev/null -O /dev/null")); + while (0 != system (wget)); + GNUNET_free (wget); fprintf (stderr, "\n"); } - GNUNET_SCHEDULER_run (&run, NULL); if (run_exchange) { @@ -1271,6 +1277,7 @@ main (int argc, GNUNET_OS_process_wait (exchanged); GNUNET_OS_process_destroy (exchanged); } - return 0; } + +/* end of taler-exchange-benchmark.c */ -- cgit v1.2.3 From b31c62039dd342455b678b921ab16156e625af51 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Wed, 15 Jun 2016 16:04:29 +0200 Subject: avoid passing int's as void*'s in benchmark logic --- src/benchmark/taler-exchange-benchmark.c | 265 ++++++++++++++++++------------- src/exchange-lib/exchange_api_refund.c | 3 +- 2 files changed, 157 insertions(+), 111 deletions(-) (limited to 'src') diff --git a/src/benchmark/taler-exchange-benchmark.c b/src/benchmark/taler-exchange-benchmark.c index 9b410ab5f..4d6531347 100644 --- a/src/benchmark/taler-exchange-benchmark.c +++ b/src/benchmark/taler-exchange-benchmark.c @@ -17,6 +17,7 @@ * @file src/benchmark/taler-exchange-benchmark.c * @brief exchange's benchmark * @author Marcello Stanisci + * @author Christian Grothoff */ #include "platform.h" #include "taler_util.h" @@ -116,6 +117,11 @@ struct Reserve */ struct TALER_EXCHANGE_AdminAddIncomingHandle *aih; + /** + * Index of this reserve in the #reserves array. + */ + unsigned int reserve_index; + }; @@ -189,6 +195,11 @@ struct Coin */ 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 @@ -237,6 +248,11 @@ static struct Coin *coins; */ static unsigned int transaction_id; +/** + * Transfer UUID counter, used in /admin/add/incoming + */ +static unsigned int transfer_uuid; + /** * This key (usually provided by merchants) is needed when depositing coins, * even though there is no merchant acting in the benchmark @@ -248,6 +264,12 @@ static struct TALER_MerchantPrivateKeyP merchant_priv; */ static char *exchange_uri; +/** + * URI under which the administrative exchange is reachable during the + * benchmark. + */ +static char *exchange_admin_uri; + /** * How many coins (AKA withdraw operations) per reserve should be withdrawn */ @@ -389,10 +411,11 @@ find_pk (const struct TALER_EXCHANGE_Keys *keys, return NULL; } + /** * Function called with the result of the /refresh/reveal operation. * - * @param cls closure with the interpreter state + * @param cls closure with the `struct RefreshRevealCls *` * @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 num_coins number of fresh coins created, length of the @a sigs and @a coin_privs arrays, 0 if the operation failed @@ -409,10 +432,12 @@ reveal_cb (void *cls, const json_t *full_response) { struct RefreshRevealCls *rrcls = cls; + struct Coin *coin; unsigned int i; const struct TALER_EXCHANGE_Keys *keys; - coins[rrcls->coin_index].rrh = NULL; + coin = &coins[rrcls->coin_index]; + coin->rrh = NULL; if (MHD_HTTP_OK != http_status) { GNUNET_free (rrcls); @@ -425,7 +450,7 @@ reveal_cb (void *cls, GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Coin #%d revealed!\n", rrcls->coin_index); - coins[rrcls->coin_index].left.value = 0; + coin->left.value = 0; } keys = TALER_EXCHANGE_get_keys (exchange); @@ -440,12 +465,14 @@ reveal_cb (void *cls, "# of coins after refresh: %d\n", revealed_str, ncoins); - GNUNET_free (revealed_str); - fresh_coin.reserve_index = coins[rrcls->coin_index].reserve_index; + + fresh_coin.reserve_index = coin->reserve_index; fresh_coin.pk = find_pk (keys, &rrcls->denoms[i]); fresh_coin.sig = sigs[i]; - GNUNET_array_append (coins, ncoins, fresh_coin); + GNUNET_array_append (coins, + ncoins, + fresh_coin); } GNUNET_free (rrcls); } @@ -454,7 +481,7 @@ reveal_cb (void *cls, /** * Function called with the result of the /refresh/melt operation. * - * @param cls closure with the interpreter state + * @param cls closure with the `struct RefreshRevealCls *` * @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 noreveal_index choice by the exchange in the cut-and-choose protocol, @@ -471,8 +498,10 @@ melt_cb (void *cls, { /* free'd in `reveal_cb` */ struct RefreshRevealCls *rrcls = cls; + struct Coin *coin; - coins[rrcls->coin_index].rmh = NULL; + coin = &coins[rrcls->coin_index]; + coin->rmh = NULL; if (MHD_HTTP_OK != http_status) { json_dumpf (full_response, stderr, 0); @@ -480,7 +509,7 @@ melt_cb (void *cls, return; } - coins[rrcls->coin_index].rrh + coin->rrh = TALER_EXCHANGE_refresh_reveal (exchange, rrcls->blob_size, rrcls->blob, @@ -494,7 +523,7 @@ melt_cb (void *cls, * Function called upon completion of our /reserve/withdraw request. * This is merely the function which spends withdrawn coins * - * @param cls closure with the interpreter state + * @param cls closure with the `struct Coin` we are withdrawing * @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 sig signature over the coin, NULL on error @@ -510,7 +539,7 @@ reserve_withdraw_cb (void *cls, /** * Function called with the result of a /deposit operation. * - * @param cls closure with the interpreter state + * @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 exchange_pub public key used by the exchange for signing @@ -523,9 +552,9 @@ deposit_cb (void *cls, const struct TALER_ExchangePublicKeyP *exchange_pub, const json_t *obj) { - unsigned int coin_index = (unsigned int) (long) cls; + struct Coin *coin = cls; - coins[coin_index].dh = NULL; + coin->dh = NULL; if (MHD_HTTP_OK != http_status) { json_dumpf (obj, stderr, 0); @@ -534,8 +563,8 @@ deposit_cb (void *cls, } GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Coin #%d correctly spent!\n", - coin_index); - if (GNUNET_YES == coins[coin_index].refresh) + coin->coin_index); + if (GNUNET_YES == coin->refresh) { struct RefreshRevealCls *rrcls; char *blob; @@ -550,15 +579,15 @@ deposit_cb (void *cls, unsigned long long acc_value; TALER_amount_get_zero (currency, &curr); - curr.value = COIN_VALUE >> 1; acc_value = 0; - keys = TALER_EXCHANGE_get_keys (exchange); - for (; curr.value > 0; curr.value = curr.value >> 1) + for (curr.value = COIN_VALUE >> 1; curr.value > 0; curr.value = curr.value >> 1) { - if (acc_value + curr.value <= coins[coin_index].left.value) + if (acc_value + curr.value <= coin->left.value) { - GNUNET_array_append (denoms, ndenoms, curr); + GNUNET_array_append (denoms, + ndenoms, + curr); GNUNET_assert (NULL != (curr_dpk = find_pk (keys, &curr))); GNUNET_array_append (dpks, ndenoms2, *curr_dpk); acc_value += curr.value; @@ -567,10 +596,10 @@ deposit_cb (void *cls, GNUNET_log (GNUNET_ERROR_TYPE_INFO, "# of coins to get in melt: %d\n", ndenoms2); - blob = TALER_EXCHANGE_refresh_prepare (&coins[coin_index].coin_priv, - &coins[coin_index].left, - &coins[coin_index].sig, - coins[coin_index].pk, + blob = TALER_EXCHANGE_refresh_prepare (&coin->coin_priv, + &coin->left, + &coin->sig, + coin->pk, GNUNET_YES, ndenoms2, dpks, @@ -588,14 +617,14 @@ deposit_cb (void *cls, rrcls = GNUNET_new (struct RefreshRevealCls); rrcls->blob = blob; rrcls->blob_size = blob_size; - rrcls->coin_index = coin_index; + rrcls->coin_index = coin->coin_index; rrcls->denoms = denoms; - coins[coin_index].rmh = TALER_EXCHANGE_refresh_melt (exchange, - blob_size, - blob, - &melt_cb, - rrcls); - if (NULL == coins[coin_index].rmh) + coin->rmh = TALER_EXCHANGE_refresh_melt (exchange, + blob_size, + blob, + &melt_cb, + rrcls); + if (NULL == coin->rmh) { fail ("Impossible to issue a melt request to the exchange"); return; @@ -604,17 +633,18 @@ deposit_cb (void *cls, else { /* re-withdraw */ struct GNUNET_CRYPTO_EddsaPrivateKey *coin_priv; + coin_priv = GNUNET_CRYPTO_eddsa_key_create (); - coins[coin_index].coin_priv.eddsa_priv = *coin_priv; + coin->coin_priv.eddsa_priv = *coin_priv; GNUNET_free (coin_priv); - coins[coin_index].wsh = + coin->wsh = TALER_EXCHANGE_reserve_withdraw (exchange, - coins[coin_index].pk, - &reserves[coins[coin_index].reserve_index].reserve_priv, - &coins[coin_index].coin_priv, + coin->pk, + &reserves[coin->reserve_index].reserve_priv, + &coin->coin_priv, &blinding_key, - reserve_withdraw_cb, - (void *) (long) coin_index); + &reserve_withdraw_cb, + coin); } } @@ -624,7 +654,7 @@ deposit_cb (void *cls, * This is merely the function which spends withdrawn coins. For each * spent coin, ti either refresh it or re-withdraw it. * - * @param cls closure with the interpreter state + * @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 sig signature over the coin, NULL on error @@ -636,10 +666,9 @@ reserve_withdraw_cb (void *cls, const struct TALER_DenominationSignature *sig, const json_t *full_response) { + struct Coin *coin = cls; - unsigned int coin_index = (unsigned int) (long) cls; - - coins[coin_index].wsh = NULL; + coin->wsh = NULL; if (MHD_HTTP_OK != http_status) { json_dumpf (full_response, stderr, 0); @@ -648,8 +677,8 @@ reserve_withdraw_cb (void *cls, } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%d-th coin withdrawn\n", - coin_index); - coins[coin_index].sig.rsa_signature = + coin->coin_index); + coin->sig.rsa_signature = GNUNET_CRYPTO_rsa_signature_dup (sig->rsa_signature); if (GNUNET_OK == eval_probability (SPEND_PROBABILITY)) { @@ -663,44 +692,49 @@ reserve_withdraw_cb (void *cls, struct TALER_MerchantPublicKeyP merchant_pub; struct TALER_CoinSpendSignatureP coin_sig; - GNUNET_CRYPTO_eddsa_key_get_public (&coins[coin_index].coin_priv.eddsa_priv, + 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, sizeof (h_contract)); 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); + 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 (×tamp); GNUNET_TIME_round_abs (&wire_deadline); GNUNET_TIME_round_abs (&refund_deadline); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Spending %d-th coin\n", coin_index); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Spending %d-th coin\n", + coin->coin_index); - if (GNUNET_YES == eval_probability (REFRESH_PROBABILITY) - && GNUNET_NO == refreshed_once) + if ( (GNUNET_YES == eval_probability (REFRESH_PROBABILITY)) && + (GNUNET_NO == refreshed_once) ) { /** * Always spending 1 out of 8 KUDOS. To be improved by randomly * picking the spent amount */ struct TALER_Amount one; + TALER_amount_get_zero (currency, &one); one.value = 1; TALER_amount_subtract (&amount, &one, - &coins[coin_index].pk->fee_deposit); - TALER_amount_subtract (&coins[coin_index].left, - &coins[coin_index].pk->value, + &coin->pk->fee_deposit); + TALER_amount_subtract (&coin->left, + &coin->pk->value, &one); - coins[coin_index].refresh = GNUNET_YES; + coin->refresh = GNUNET_YES; refreshed_once = GNUNET_YES; } else { TALER_amount_subtract (&amount, - &coins[coin_index].pk->value, - &coins[coin_index].pk->fee_deposit); + &coin->pk->value, + &coin->pk->fee_deposit); } memset (&dr, 0, sizeof (dr)); dr.purpose.size = htonl (sizeof (struct TALER_DepositRequestPS)); @@ -716,33 +750,33 @@ reserve_withdraw_cb (void *cls, TALER_amount_hton (&dr.amount_with_fee, &amount); TALER_amount_hton (&dr.deposit_fee, - &coins[coin_index].pk->fee_deposit); + &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 (&coins[coin_index].coin_priv.eddsa_priv, + GNUNET_CRYPTO_eddsa_sign (&coin->coin_priv.eddsa_priv, &dr.purpose, &coin_sig.eddsa_signature)); - coins[coin_index].dh = TALER_EXCHANGE_deposit (exchange, - &amount, - wire_deadline, - merchant_details, - &h_contract, - &coin_pub, - &coins[coin_index].sig, - &coins[coin_index].pk->key, - timestamp, - transaction_id, - &merchant_pub, - refund_deadline, - &coin_sig, - &deposit_cb, - (void *) (long) coin_index); - if (NULL == coins[coin_index].dh) + coin->dh = TALER_EXCHANGE_deposit (exchange, + &amount, + wire_deadline, + merchant_details, + &h_contract, + &coin_pub, + &coin->sig, + &coin->pk->key, + timestamp, + transaction_id, + &merchant_pub, + refund_deadline, + &coin_sig, + &deposit_cb, + coin); + if (NULL == coin->dh) { json_decref (merchant_details); fail ("An error occurred while calling deposit API"); @@ -757,7 +791,7 @@ reserve_withdraw_cb (void *cls, * 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 interpreter state + * @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 full_response full response from the exchange (for logging, in case of errors) @@ -767,18 +801,17 @@ add_incoming_cb (void *cls, unsigned int http_status, const json_t *full_response) { - unsigned int reserve_index = (unsigned int) (long) cls; + struct Reserve *r = cls; struct GNUNET_CRYPTO_EddsaPrivateKey *coin_priv; unsigned int i; unsigned int coin_index; struct TALER_Amount amount; const struct TALER_EXCHANGE_Keys *keys; - keys = TALER_EXCHANGE_get_keys (exchange); + r->aih = NULL; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "/admin/add/incoming callback called on %d-th reserve\n", - reserve_index); - reserves[reserve_index].aih = NULL; + r->reserve_index); if (MHD_HTTP_OK != http_status) { json_dumpf (full_response, stderr, 0); @@ -786,24 +819,30 @@ add_incoming_cb (void *cls, return; } + keys = TALER_EXCHANGE_get_keys (exchange); for (i=0; i < COINS_PER_RESERVE; i++) { + struct Coin *coin; + + coin_index = r->reserve_index * COINS_PER_RESERVE + i; + coin = &coins[coin_index]; + coin->coin_index = coin_index; coin_priv = GNUNET_CRYPTO_eddsa_key_create (); - coin_index = reserve_index * COINS_PER_RESERVE + i; - coins[coin_index].coin_priv.eddsa_priv = *coin_priv; - coins[coin_index].reserve_index = reserve_index; - TALER_amount_get_zero (currency, &amount); - amount.value = COIN_VALUE; - GNUNET_assert (NULL != (coins[coin_index].pk = find_pk (keys, &amount))); + coin->coin_priv.eddsa_priv = *coin_priv; GNUNET_free (coin_priv); - coins[coin_index].wsh = + coin->reserve_index = r->reserve_index; + TALER_amount_get_zero (currency, + &amount); + amount.value = COIN_VALUE; + GNUNET_assert (NULL != (coin->pk = find_pk (keys, &amount))); + coin->wsh = TALER_EXCHANGE_reserve_withdraw (exchange, - coins[coin_index].pk, - &reserves[reserve_index].reserve_priv, - &coins[coin_index].coin_priv, + coin->pk, + &r->reserve_priv, + &coin->coin_priv, &blinding_key, - reserve_withdraw_cb, - (void *) (long) coin_index); + &reserve_withdraw_cb, + coin); } } @@ -819,7 +858,6 @@ benchmark_run (void *cls) unsigned int i; struct GNUNET_CRYPTO_EddsaPrivateKey *priv; json_t *transfer_details; - char *uuid; struct TALER_ReservePublicKeyP reserve_pub; struct GNUNET_TIME_Absolute execution_date; struct TALER_Amount reserve_amount; @@ -849,26 +887,27 @@ benchmark_run (void *cls) for (i=0;i < nreserves;i++) { + struct Reserve *r = &reserves[i]; + priv = GNUNET_CRYPTO_eddsa_key_create (); - reserves[i].reserve_priv.eddsa_priv = *priv; + r->reserve_priv.eddsa_priv = *priv; GNUNET_free (priv); - // FIXME: avoid use of JSON parser - GNUNET_asprintf (&uuid, "{ \"uuid\":%d}", i); - transfer_details = json_loads (uuid, JSON_REJECT_DUPLICATES, NULL); - GNUNET_free (uuid); - GNUNET_CRYPTO_eddsa_key_get_public (&reserves[i].reserve_priv.eddsa_priv, + r->reserve_index = i; + transfer_details = json_pack ("{s:I}", + "uuid", (json_int_t) transfer_uuid++); + GNUNET_assert (NULL != transfer_details); + GNUNET_CRYPTO_eddsa_key_get_public (&r->reserve_priv.eddsa_priv, &reserve_pub.eddsa_pub); - - reserves[i].aih = TALER_EXCHANGE_admin_add_incoming (exchange, - "http://localhost:18080/", - &reserve_pub, - &reserve_amount, - execution_date, - bank_details, - transfer_details, - &add_incoming_cb, - (void *) (long) i); - GNUNET_assert (NULL != reserves[i].aih); + r->aih = TALER_EXCHANGE_admin_add_incoming (exchange, + exchange_admin_uri, + &reserve_pub, + &reserve_amount, + execution_date, + bank_details, + transfer_details, + &add_incoming_cb, + r); + GNUNET_assert (NULL != r->aih); json_decref (transfer_details); } json_decref (bank_details); @@ -1187,7 +1226,11 @@ main (int argc, &GNUNET_GETOPT_set_uint, &pool_size}, {'e', "exchange-uri", "URI", "URI of the exchange", GNUNET_YES, - &GNUNET_GETOPT_set_string, &exchange_uri} + &GNUNET_GETOPT_set_string, &exchange_uri}, + {'E', "exchange-admin-uri", "URI", + "URI of the administrative interface of the exchange", GNUNET_YES, + &GNUNET_GETOPT_set_string, &exchange_admin_uri}, + GNUNET_GETOPT_OPTION_END }; GNUNET_log_setup ("taler-exchange-benchmark", @@ -1198,6 +1241,8 @@ main (int argc, options, argc, argv)); if (NULL == exchange_uri) exchange_uri = GNUNET_strdup ("http://localhost:8081/"); + if (NULL == exchange_admin_uri) + exchange_admin_uri = GNUNET_strdup ("http://localhost:18080/"); if (run_exchange) { char *wget; diff --git a/src/exchange-lib/exchange_api_refund.c b/src/exchange-lib/exchange_api_refund.c index fff03acf9..26b960703 100644 --- a/src/exchange-lib/exchange_api_refund.c +++ b/src/exchange-lib/exchange_api_refund.c @@ -283,7 +283,8 @@ TALER_EXCHANGE_refund (struct TALER_EXCHANGE_Handle *exchange, "merchant_pub", GNUNET_JSON_from_data_auto (&rr.merchant), "merchant_sig", GNUNET_JSON_from_data_auto (&merchant_sig) ); - + GNUNET_assert (NULL != refund_obj); + rh = GNUNET_new (struct TALER_EXCHANGE_RefundHandle); rh->exchange = exchange; rh->cb = cb; -- cgit v1.2.3 From e4b9a151a697948559c056c4497e5d9d203e6649 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Wed, 15 Jun 2016 16:36:17 +0200 Subject: restructure benchmark logic so that we can schedule each operation independently --- src/benchmark/taler-exchange-benchmark.c | 747 +++++++++++++++++-------------- 1 file changed, 401 insertions(+), 346 deletions(-) (limited to 'src') diff --git a/src/benchmark/taler-exchange-benchmark.c b/src/benchmark/taler-exchange-benchmark.c index 4d6531347..c8e4c0341 100644 --- a/src/benchmark/taler-exchange-benchmark.c +++ b/src/benchmark/taler-exchange-benchmark.c @@ -29,49 +29,6 @@ #include #include -/** - * Should we initialize and start the exchange, if #GNUNET_NO, - * we expect one to be already up and running. - */ -static int run_exchange; - -/** - * 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_URI) - */ -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; - /** * Information needed by the /refresh/melt's callback @@ -125,21 +82,6 @@ struct Reserve }; -/** - * 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; - /** * Information regarding a coin */ @@ -208,6 +150,65 @@ struct Coin }; + +/** + * Should we initialize and start the exchange, if #GNUNET_NO, + * we expect one to be already up and running. + */ +static int run_exchange; + +/** + * 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_URI) + */ +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; + /** * Handle to the exchange's process */ @@ -302,11 +303,6 @@ static char *currency; */ #define REFRESH_PROBABILITY 0.4 -/** - * Refreshed once. For each batch of deposits, only one - * coin will be refreshed, according to #REFRESH_PROBABILITY - */ -static unsigned int refreshed_once; /** * List of coins to get in return to a melt operation. Just a @@ -358,6 +354,26 @@ fail (const char *msg) } +/** + * 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. * @@ -461,8 +477,7 @@ reveal_cb (void *cls, revealed_str = TALER_amount_to_string (&rrcls->denoms[i]); GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "revealing %s " - "# of coins after refresh: %d\n", + "revealing %s # of coins after refresh: %d\n", revealed_str, ncoins); GNUNET_free (revealed_str); @@ -475,6 +490,7 @@ reveal_cb (void *cls, fresh_coin); } GNUNET_free (rrcls); + continue_master_task (); } @@ -536,6 +552,81 @@ reserve_withdraw_cb (void *cls, const json_t *full_response); +/** + * Refresh the given @a coin + * + * @param coin coin to refresh + */ +static void +refresh_coin (struct Coin *coin) +{ + struct RefreshRevealCls *rrcls; + char *blob; + size_t blob_size; + const struct TALER_EXCHANGE_Keys *keys; + struct TALER_Amount *denoms = NULL; + struct TALER_EXCHANGE_DenomPublicKey *dpks = NULL; + const struct TALER_EXCHANGE_DenomPublicKey *curr_dpk; + struct TALER_Amount curr; + unsigned int ndenoms = 0; + unsigned int ndenoms2 = 0; + unsigned long long acc_value; + + TALER_amount_get_zero (currency, &curr); + acc_value = 0; + keys = TALER_EXCHANGE_get_keys (exchange); + for (curr.value = COIN_VALUE >> 1; curr.value > 0; curr.value = curr.value >> 1) + { + if (acc_value + curr.value <= coin->left.value) + { + GNUNET_array_append (denoms, + ndenoms, + curr); + GNUNET_assert (NULL != (curr_dpk = find_pk (keys, &curr))); + GNUNET_array_append (dpks, + ndenoms2, + *curr_dpk); + acc_value += curr.value; + } + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "# of coins to get in melt: %d\n", + ndenoms2); + blob = TALER_EXCHANGE_refresh_prepare (&coin->coin_priv, + &coin->left, + &coin->sig, + coin->pk, + GNUNET_YES, + ndenoms2, + dpks, + &blob_size); + 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); + + rrcls = GNUNET_new (struct RefreshRevealCls); + rrcls->blob = blob; + rrcls->blob_size = blob_size; + rrcls->coin_index = coin->coin_index; + rrcls->denoms = denoms; + coin->rmh = TALER_EXCHANGE_refresh_melt (exchange, + blob_size, + blob, + &melt_cb, + rrcls); + if (NULL == coin->rmh) + { + fail ("Impossible to issue a melt request to the exchange"); + return; + } +} + + /** * Function called with the result of a /deposit operation. * @@ -565,86 +656,119 @@ deposit_cb (void *cls, "Coin #%d correctly spent!\n", coin->coin_index); if (GNUNET_YES == coin->refresh) + refresh_coin (coin); + else + 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; + 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, + sizeof (h_contract)); + 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 (×tamp); + 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) { - struct RefreshRevealCls *rrcls; - char *blob; - size_t blob_size; - const struct TALER_EXCHANGE_Keys *keys; - struct TALER_Amount *denoms = NULL; - struct TALER_EXCHANGE_DenomPublicKey *dpks = NULL; - const struct TALER_EXCHANGE_DenomPublicKey *curr_dpk; - struct TALER_Amount curr; - unsigned int ndenoms = 0; - unsigned int ndenoms2 = 0; - unsigned long long acc_value; - - TALER_amount_get_zero (currency, &curr); - acc_value = 0; - keys = TALER_EXCHANGE_get_keys (exchange); - for (curr.value = COIN_VALUE >> 1; curr.value > 0; curr.value = curr.value >> 1) - { - if (acc_value + curr.value <= coin->left.value) - { - GNUNET_array_append (denoms, - ndenoms, - curr); - GNUNET_assert (NULL != (curr_dpk = find_pk (keys, &curr))); - GNUNET_array_append (dpks, ndenoms2, *curr_dpk); - acc_value += curr.value; - } - } - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "# of coins to get in melt: %d\n", - ndenoms2); - blob = TALER_EXCHANGE_refresh_prepare (&coin->coin_priv, - &coin->left, - &coin->sig, - coin->pk, - GNUNET_YES, - ndenoms2, - dpks, - &blob_size); - if (NULL == blob) - { - fail ("Failed to prepare refresh"); - return; - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "prepared blob %d\n", - (unsigned int) blob_size); - refreshed_once = GNUNET_YES; - - rrcls = GNUNET_new (struct RefreshRevealCls); - rrcls->blob = blob; - rrcls->blob_size = blob_size; - rrcls->coin_index = coin->coin_index; - rrcls->denoms = denoms; - coin->rmh = TALER_EXCHANGE_refresh_melt (exchange, - blob_size, - blob, - &melt_cb, - rrcls); - if (NULL == coin->rmh) - { - fail ("Impossible to issue a melt request to the exchange"); - return; - } + /** + * Always spending 1 out of 8 KUDOS. To be improved by randomly + * picking the spent amount + */ + struct TALER_Amount one; + + TALER_amount_get_zero (currency, &one); + one.value = 1; + + TALER_amount_subtract (&amount, + &one, + &coin->pk->fee_deposit); + TALER_amount_subtract (&coin->left, + &coin->pk->value, + &one); + coin->refresh = GNUNET_YES; } else - { /* re-withdraw */ - struct GNUNET_CRYPTO_EddsaPrivateKey *coin_priv; - - coin_priv = GNUNET_CRYPTO_eddsa_key_create (); - coin->coin_priv.eddsa_priv = *coin_priv; - GNUNET_free (coin_priv); - coin->wsh = - TALER_EXCHANGE_reserve_withdraw (exchange, - coin->pk, - &reserves[coin->reserve_index].reserve_priv, - &coin->coin_priv, - &blinding_key, - &reserve_withdraw_cb, - coin); + { + TALER_amount_subtract (&amount, + &coin->pk->value, + &coin->pk->fee_deposit); + } + 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 = h_contract; + TALER_JSON_hash (merchant_details, + &dr.h_wire); + + dr.timestamp = GNUNET_TIME_absolute_hton (timestamp); + dr.refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline); + dr.transaction_id = GNUNET_htonll (transaction_id); + + 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)); + + coin->dh = TALER_EXCHANGE_deposit (exchange, + &amount, + wire_deadline, + merchant_details, + &h_contract, + &coin_pub, + &coin->sig, + &coin->pk->key, + timestamp, + transaction_id++, + &merchant_pub, + refund_deadline, + &coin_sig, + &deposit_cb, + coin); + if (NULL == coin->dh) + { + fail ("An error occurred while calling deposit API"); + return; } } @@ -680,110 +804,40 @@ reserve_withdraw_cb (void *cls, coin->coin_index); coin->sig.rsa_signature = GNUNET_CRYPTO_rsa_signature_dup (sig->rsa_signature); - if (GNUNET_OK == eval_probability (SPEND_PROBABILITY)) - { - 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; - 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, - sizeof (h_contract)); - 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 (×tamp); - 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 ( (GNUNET_YES == eval_probability (REFRESH_PROBABILITY)) && - (GNUNET_NO == refreshed_once) ) - { - /** - * Always spending 1 out of 8 KUDOS. To be improved by randomly - * picking the spent amount - */ - struct TALER_Amount one; - - TALER_amount_get_zero (currency, &one); - one.value = 1; - - TALER_amount_subtract (&amount, - &one, - &coin->pk->fee_deposit); - TALER_amount_subtract (&coin->left, - &coin->pk->value, - &one); - coin->refresh = GNUNET_YES; - refreshed_once = GNUNET_YES; - } - else - { - TALER_amount_subtract (&amount, - &coin->pk->value, - &coin->pk->fee_deposit); - } - 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 = h_contract; - TALER_JSON_hash (merchant_details, - &dr.h_wire); - - dr.timestamp = GNUNET_TIME_absolute_hton (timestamp); - dr.refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline); - dr.transaction_id = GNUNET_htonll (transaction_id); - - 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)); - - coin->dh = TALER_EXCHANGE_deposit (exchange, - &amount, - wire_deadline, - merchant_details, - &h_contract, - &coin_pub, - &coin->sig, - &coin->pk->key, - timestamp, - transaction_id, - &merchant_pub, - refund_deadline, - &coin_sig, - &deposit_cb, - coin); - if (NULL == coin->dh) - { - json_decref (merchant_details); - fail ("An error occurred while calling deposit API"); - return; - } - transaction_id++; - } + continue_master_task (); +} + + +/** + * Withdraw the given coin from the respective reserve. + * + * @param coin coin to withdraw + */ +static void +withdraw_coin (struct Coin *coin) +{ + struct GNUNET_CRYPTO_EddsaPrivateKey *coin_priv; + struct TALER_Amount amount; + const struct TALER_EXCHANGE_Keys *keys; + struct Reserve *r; + + 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); + TALER_amount_get_zero (currency, + &amount); + amount.value = COIN_VALUE; + GNUNET_assert (NULL != (coin->pk = find_pk (keys, &amount))); + coin->wsh = + TALER_EXCHANGE_reserve_withdraw (exchange, + coin->pk, + &r->reserve_priv, + &coin->coin_priv, + &blinding_key, + &reserve_withdraw_cb, + coin); } @@ -802,11 +856,6 @@ add_incoming_cb (void *cls, const json_t *full_response) { struct Reserve *r = cls; - struct GNUNET_CRYPTO_EddsaPrivateKey *coin_priv; - unsigned int i; - unsigned int coin_index; - struct TALER_Amount amount; - const struct TALER_EXCHANGE_Keys *keys; r->aih = NULL; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, @@ -818,101 +867,94 @@ add_incoming_cb (void *cls, fail ("At least one reserve failed in being created"); return; } - - keys = TALER_EXCHANGE_get_keys (exchange); - for (i=0; i < COINS_PER_RESERVE; i++) - { - struct Coin *coin; - - coin_index = r->reserve_index * COINS_PER_RESERVE + i; - coin = &coins[coin_index]; - coin->coin_index = coin_index; - coin_priv = GNUNET_CRYPTO_eddsa_key_create (); - coin->coin_priv.eddsa_priv = *coin_priv; - GNUNET_free (coin_priv); - coin->reserve_index = r->reserve_index; - TALER_amount_get_zero (currency, - &amount); - amount.value = COIN_VALUE; - GNUNET_assert (NULL != (coin->pk = find_pk (keys, &amount))); - coin->wsh = - TALER_EXCHANGE_reserve_withdraw (exchange, - coin->pk, - &r->reserve_priv, - &coin->coin_priv, - &blinding_key, - &reserve_withdraw_cb, - coin); - } + continue_master_task (); } /** - * Main task for the benchmark. + * Fill a reserve using /admin/add/incoming * - * @param cls NULL + * @param r reserve to fill */ static void -benchmark_run (void *cls) +fill_reserve (struct Reserve *r) { - unsigned int i; struct GNUNET_CRYPTO_EddsaPrivateKey *priv; - json_t *transfer_details; struct TALER_ReservePublicKeyP reserve_pub; struct GNUNET_TIME_Absolute execution_date; struct TALER_Amount reserve_amount; + json_t *transfer_details; - benchmark_task = NULL; - 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)); - TALER_amount_get_zero (currency, &reserve_amount); + TALER_amount_get_zero (currency, + &reserve_amount); reserve_amount.value = RESERVE_VALUE; execution_date = GNUNET_TIME_absolute_get (); GNUNET_TIME_round_abs (&execution_date); - nreserves = pool_size / COINS_PER_RESERVE; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Creating %d reserves\n", - nreserves); + + priv = GNUNET_CRYPTO_eddsa_key_create (); + r->reserve_priv.eddsa_priv = *priv; + GNUNET_free (priv); + transfer_details = json_pack ("{s:I}", + "uuid", (json_int_t) transfer_uuid++); + GNUNET_assert (NULL != transfer_details); + GNUNET_CRYPTO_eddsa_key_get_public (&r->reserve_priv.eddsa_priv, + &reserve_pub.eddsa_pub); + r->aih = TALER_EXCHANGE_admin_add_incoming (exchange, + exchange_admin_uri, + &reserve_pub, + &reserve_amount, + execution_date, + bank_details, + transfer_details, + &add_incoming_cb, + r); + GNUNET_assert (NULL != r->aih); + json_decref (transfer_details); +} - reserves = GNUNET_new_array (nreserves, - struct Reserve); - ncoins = COINS_PER_RESERVE * nreserves; - coins = GNUNET_new_array (ncoins, - struct Coin); +/** + * Main task for the benchmark. + * + * @param cls NULL + */ +static void +benchmark_run (void *cls) +{ + unsigned int i; + + benchmark_task = NULL; + /* FIXME: Note that this function cannot work as-is, it's + just a placeholder for the final logic we want here. */ for (i=0;i < nreserves;i++) { struct Reserve *r = &reserves[i]; - priv = GNUNET_CRYPTO_eddsa_key_create (); - r->reserve_priv.eddsa_priv = *priv; - GNUNET_free (priv); r->reserve_index = i; - transfer_details = json_pack ("{s:I}", - "uuid", (json_int_t) transfer_uuid++); - GNUNET_assert (NULL != transfer_details); - GNUNET_CRYPTO_eddsa_key_get_public (&r->reserve_priv.eddsa_priv, - &reserve_pub.eddsa_pub); - r->aih = TALER_EXCHANGE_admin_add_incoming (exchange, - exchange_admin_uri, - &reserve_pub, - &reserve_amount, - execution_date, - bank_details, - transfer_details, - &add_incoming_cb, - r); - GNUNET_assert (NULL != r->aih); - json_decref (transfer_details); + fill_reserve (r); + + + for (i=0; i < COINS_PER_RESERVE; i++) + { + struct Coin *coin; + unsigned int coin_index; + + coin_index = r->reserve_index * COINS_PER_RESERVE + i; + coin = &coins[coin_index]; + coin->coin_index = coin_index; + coin->reserve_index = r->reserve_index; + withdraw_coin (coin); + } } - json_decref (bank_details); - bank_details = NULL; - transfer_details = NULL; + + if (GNUNET_OK == eval_probability (SPEND_PROBABILITY)) + { + struct Coin *coin; + + i = 0; // FIXME... + coin = &coins[i]; + spend_coin (coin, + (GNUNET_YES == eval_probability (REFRESH_PROBABILITY))); } } @@ -993,7 +1035,7 @@ cert_cb (void *cls, if (NULL != currency) return; /* we've been here before... */ currency = GNUNET_strdup (_keys->denom_keys[0].value.currency); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Using currency: %s\n", currency); if (GNUNET_SYSERR == @@ -1002,8 +1044,7 @@ cert_cb (void *cls, fail ("Initializing denominations failed"); return; } - benchmark_task = GNUNET_SCHEDULER_add_now (&benchmark_run, - NULL); + continue_master_task (); } @@ -1020,18 +1061,11 @@ do_shutdown (void *cls) GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Shutting down...\n"); - if (NULL != benchmark_task) { GNUNET_SCHEDULER_cancel (benchmark_task); benchmark_task = NULL; } - - /** - * WARNING: all the non NULL handles must correspond to non completed - * calls (AKA calls for which the callback function has not been called). - * If not, it segfaults - */ for (i=0; iwsh) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Cancelling %d-th coin withdraw handle\n", i); - TALER_EXCHANGE_reserve_withdraw_cancel(coins[i].wsh); - coins[i].wsh = NULL; + TALER_EXCHANGE_reserve_withdraw_cancel (coin->wsh); + coin->wsh = NULL; } - if (NULL != coins[i].dh) + if (NULL != coin->dh) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Cancelling %d-th coin deposit handle\n", i); - TALER_EXCHANGE_deposit_cancel(coins[i].dh); - coins[i].dh = NULL; + TALER_EXCHANGE_deposit_cancel(coin->dh); + coin->dh = NULL; } - if (NULL != coins[i].rmh) + if (NULL != coin->rmh) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Cancelling %d-th coin melt handle\n", i); - TALER_EXCHANGE_refresh_melt_cancel(coins[i].rmh); - coins[i].rmh = NULL; + TALER_EXCHANGE_refresh_melt_cancel (coin->rmh); + coin->rmh = NULL; } - if (NULL != coins[i].rrh) + if (NULL != coin->rrh) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Cancelling %d-th coin reveal handle\n", i); - TALER_EXCHANGE_refresh_reveal_cancel(coins[i].rrh); - coins[i].rmh = NULL; + TALER_EXCHANGE_refresh_reveal_cancel (coin->rrh); + coin->rmh = NULL; } } if (NULL != bank_details) @@ -1089,8 +1125,11 @@ do_shutdown (void *cls) 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) { @@ -1120,6 +1159,7 @@ do_shutdown (void *cls) /** * Main function that will be run by the scheduler. + * Prepares everything for the benchmark. * * @param cls closure */ @@ -1128,6 +1168,7 @@ run (void *cls) { char *bank_details_filename; char *merchant_details_filename; + struct GNUNET_CRYPTO_EddsaPrivateKey *priv; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "running run()\n"); @@ -1190,8 +1231,22 @@ run (void *cls) fail ("Failed to parse file with MERCHANT_DETAILS"); return; } - reserves = NULL; - coins = NULL; + + 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; + reserves = GNUNET_new_array (nreserves, + struct Reserve); + ncoins = COINS_PER_RESERVE * nreserves; + coins = GNUNET_new_array (ncoins, + struct Coin); + ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule, &rc); GNUNET_assert (NULL != ctx); -- cgit v1.2.3 From 3876b70eb4daeaa04050fdaf5a2f9f625a879ff6 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Wed, 15 Jun 2016 16:42:43 +0200 Subject: merge refresh closure into struct Coin --- src/benchmark/taler-exchange-benchmark.c | 88 +++++++++++++------------------- 1 file changed, 36 insertions(+), 52 deletions(-) (limited to 'src') diff --git a/src/benchmark/taler-exchange-benchmark.c b/src/benchmark/taler-exchange-benchmark.c index c8e4c0341..392504efc 100644 --- a/src/benchmark/taler-exchange-benchmark.c +++ b/src/benchmark/taler-exchange-benchmark.c @@ -18,6 +18,12 @@ * @brief exchange's benchmark * @author Marcello Stanisci * @author Christian Grothoff + * + * TODO: + * - track state of reserve/coin with its struct + * - have global work-lists with available slots for + * admin, deposit and withdraw operations (and stats!) + * - implement the main loop of the benchmark */ #include "platform.h" #include "taler_util.h" @@ -30,34 +36,6 @@ #include -/** - * Information needed by the /refresh/melt's callback - */ -struct RefreshRevealCls -{ - - /** - * The result of a #TALER_EXCHANGE_refresh_prepare() call - */ - const char *blob; - - /** - * Size of @e blob - */ - size_t blob_size; - - /** - * Which coin in the list are we melting - */ - unsigned int coin_index; - - /** - * Array of denominations expected to get from melt - */ - struct TALER_Amount *denoms; -}; - - /** * Needed information for a reserve. Other values are the same for all reserves, therefore defined in global variables */ @@ -123,6 +101,21 @@ struct Coin * Deposit handle (while operation is running). */ struct TALER_EXCHANGE_DepositHandle *dh; + + /** + * The result of a #TALER_EXCHANGE_refresh_prepare() call + */ + const char *blob; + + /** + * Size of @e blob + */ + size_t blob_size; + + /** + * Array of denominations expected to get from melt + */ + struct TALER_Amount *denoms; /** * Flag indicating if the coin is going to be refreshed @@ -431,7 +424,7 @@ find_pk (const struct TALER_EXCHANGE_Keys *keys, /** * Function called with the result of the /refresh/reveal operation. * - * @param cls closure with the `struct RefreshRevealCls *` + * @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 num_coins number of fresh coins created, length of the @a sigs and @a coin_privs arrays, 0 if the operation failed @@ -447,16 +440,13 @@ reveal_cb (void *cls, const struct TALER_DenominationSignature *sigs, const json_t *full_response) { - struct RefreshRevealCls *rrcls = cls; - struct Coin *coin; + struct Coin *coin = cls; unsigned int i; const struct TALER_EXCHANGE_Keys *keys; - coin = &coins[rrcls->coin_index]; coin->rrh = NULL; if (MHD_HTTP_OK != http_status) { - GNUNET_free (rrcls); json_dumpf (full_response, stderr, 0); fail ("Not all coins correctly revealed"); return; @@ -465,7 +455,7 @@ reveal_cb (void *cls, { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Coin #%d revealed!\n", - rrcls->coin_index); + coin->coin_index); coin->left.value = 0; } @@ -475,7 +465,7 @@ reveal_cb (void *cls, struct Coin fresh_coin; char *revealed_str; - revealed_str = TALER_amount_to_string (&rrcls->denoms[i]); + 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, @@ -483,13 +473,13 @@ reveal_cb (void *cls, GNUNET_free (revealed_str); fresh_coin.reserve_index = coin->reserve_index; - fresh_coin.pk = find_pk (keys, &rrcls->denoms[i]); + fresh_coin.pk = find_pk (keys, &coin->denoms[i]); fresh_coin.sig = sigs[i]; + // FIXME: yuck! GNUNET_array_append (coins, ncoins, fresh_coin); } - GNUNET_free (rrcls); continue_master_task (); } @@ -497,7 +487,7 @@ reveal_cb (void *cls, /** * Function called with the result of the /refresh/melt operation. * - * @param cls closure with the `struct RefreshRevealCls *` + * @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 noreveal_index choice by the exchange in the cut-and-choose protocol, @@ -512,11 +502,8 @@ melt_cb (void *cls, const struct TALER_ExchangePublicKeyP *exchange_pub, const json_t *full_response) { - /* free'd in `reveal_cb` */ - struct RefreshRevealCls *rrcls = cls; - struct Coin *coin; + struct Coin *coin = cls; - coin = &coins[rrcls->coin_index]; coin->rmh = NULL; if (MHD_HTTP_OK != http_status) { @@ -527,11 +514,11 @@ melt_cb (void *cls, coin->rrh = TALER_EXCHANGE_refresh_reveal (exchange, - rrcls->blob_size, - rrcls->blob, + coin->blob_size, + coin->blob, noreveal_index, &reveal_cb, - rrcls); + coin); } @@ -560,7 +547,6 @@ reserve_withdraw_cb (void *cls, static void refresh_coin (struct Coin *coin) { - struct RefreshRevealCls *rrcls; char *blob; size_t blob_size; const struct TALER_EXCHANGE_Keys *keys; @@ -609,16 +595,14 @@ refresh_coin (struct Coin *coin) "Prepared blob of size %d for refresh\n", (unsigned int) blob_size); - rrcls = GNUNET_new (struct RefreshRevealCls); - rrcls->blob = blob; - rrcls->blob_size = blob_size; - rrcls->coin_index = coin->coin_index; - rrcls->denoms = denoms; + coin->blob = blob; + coin->blob_size = blob_size; + coin->denoms = denoms; coin->rmh = TALER_EXCHANGE_refresh_melt (exchange, blob_size, blob, &melt_cb, - rrcls); + coin); if (NULL == coin->rmh) { fail ("Impossible to issue a melt request to the exchange"); -- cgit v1.2.3 From f59246e763cce70819f3ea8cc9b2f20732506912 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Wed, 15 Jun 2016 16:45:29 +0200 Subject: clean up blobs clean up blobs clean up blobs clean up blobs pass -c option to taler services, ship with reasonable config exclude live-keys from config --- src/benchmark/Makefile.am | 5 +- src/benchmark/taler-exchange-benchmark.c | 245 ++++++++++++++++----- src/benchmark/taler-exchange-benchmark.conf | 88 ++++++++ .../test_benchmark_home/.config/taler/sepa.json | 9 + .../test_benchmark_home/.config/taler/test.json | 8 + .../share/taler/exchange/offline-keys/master.priv | 1 + src/exchange-lib/test_exchange_api.conf | 2 +- 7 files changed, 307 insertions(+), 51 deletions(-) create mode 100644 src/benchmark/test_benchmark_home/.config/taler/sepa.json create mode 100644 src/benchmark/test_benchmark_home/.config/taler/test.json create mode 100644 src/benchmark/test_benchmark_home/.local/share/taler/exchange/offline-keys/master.priv (limited to 'src') diff --git a/src/benchmark/Makefile.am b/src/benchmark/Makefile.am index a5aef47e3..f2c299b64 100644 --- a/src/benchmark/Makefile.am +++ b/src/benchmark/Makefile.am @@ -24,4 +24,7 @@ taler_exchange_benchmark_LDADD = \ EXTRA_DIST = \ taler-exchange-benchmark.conf \ bank-details.json \ - merchant-details.json + merchant-details.json \ + test_benchmark_home/.local/share/taler/exchange/offline-keys/master.priv \ + test_benchmark_home/.config/taler/test.json \ + test_benchmark_home/.config/taler/sepa.json diff --git a/src/benchmark/taler-exchange-benchmark.c b/src/benchmark/taler-exchange-benchmark.c index 392504efc..430f44f0f 100644 --- a/src/benchmark/taler-exchange-benchmark.c +++ b/src/benchmark/taler-exchange-benchmark.c @@ -20,10 +20,9 @@ * @author Christian Grothoff * * TODO: - * - track state of reserve/coin with its struct - * - have global work-lists with available slots for - * admin, deposit and withdraw operations (and stats!) - * - implement the main loop of the benchmark + * - test + * - add instrumentation + * - add support for automatic termination */ #include "platform.h" #include "taler_util.h" @@ -35,13 +34,28 @@ #include #include +/** + * How much slack do we leave in terms of coins that are invalid (and + * thus available for refresh)? + */ +#define INVALID_COIN_SLACK 10 /** * 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. */ @@ -51,6 +65,11 @@ struct Reserve * Set to the API's handle during the operation. */ struct TALER_EXCHANGE_AdminAddIncomingHandle *aih; + + /** + * How much is left in this reserve. + */ + struct TALER_Amount left; /** * Index of this reserve in the #reserves array. @@ -66,6 +85,16 @@ struct Reserve 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. @@ -101,27 +130,32 @@ struct Coin * Deposit handle (while operation is running). */ struct TALER_EXCHANGE_DepositHandle *dh; + + /** + * Array of denominations expected to get from melt + */ + struct TALER_Amount *denoms; /** * The result of a #TALER_EXCHANGE_refresh_prepare() call */ - const char *blob; - + char *blob; + /** * Size of @e blob */ size_t blob_size; - /** - * Array of denominations expected to get from melt - */ - struct TALER_Amount *denoms; - /** * 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 @@ -144,6 +178,31 @@ struct Coin }; +/** + * 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. @@ -462,7 +521,7 @@ reveal_cb (void *cls, keys = TALER_EXCHANGE_get_keys (exchange); for (i=0; idenoms[i]); @@ -472,13 +531,22 @@ reveal_cb (void *cls, ncoins); GNUNET_free (revealed_str); - fresh_coin.reserve_index = coin->reserve_index; - fresh_coin.pk = find_pk (keys, &coin->denoms[i]); - fresh_coin.sig = sigs[i]; - // FIXME: yuck! - GNUNET_array_append (coins, - ncoins, - fresh_coin); + fresh_coin = invalid_coins_head; + if (NULL == fresh_coin) + { + /* #INVALID_COIN_SLACK 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]); + fresh_coin->sig = sigs[i]; + fresh_coin->coin_priv = coin_privs[i]; + fresh_coin->left = coin->denoms[i]; } continue_master_task (); } @@ -519,6 +587,13 @@ melt_cb (void *cls, noreveal_index, &reveal_cb, coin); + GNUNET_free (coin->blob); + coin->blob = NULL; + if (NULL == coin->rrh) + { + fail ("Failed on reveal during refresh!"); + return; + } } @@ -708,6 +783,7 @@ spend_coin (struct Coin *coin, 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)); @@ -754,6 +830,11 @@ spend_coin (struct Coin *coin, fail ("An error occurred while calling deposit API"); return; } + GNUNET_CONTAINER_DLL_insert (invalid_coins_head, + invalid_coins_tail, + coin); + num_invalid_coins++; + coin->invalid = GNUNET_YES; } @@ -788,6 +869,11 @@ reserve_withdraw_cb (void *cls, 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 (); } @@ -802,11 +888,14 @@ withdraw_coin (struct Coin *coin) { struct GNUNET_CRYPTO_EddsaPrivateKey *coin_priv; struct TALER_Amount amount; + struct TALER_Amount left; const struct TALER_EXCHANGE_Keys *keys; struct Reserve *r; keys = TALER_EXCHANGE_get_keys (exchange); r = &reserves[coin->reserve_index]; + GNUNET_assert (-1 != TALER_amount_cmp (&r->left, + &amount)); coin_priv = GNUNET_CRYPTO_eddsa_key_create (); coin->coin_priv.eddsa_priv = *coin_priv; GNUNET_free (coin_priv); @@ -822,6 +911,20 @@ withdraw_coin (struct Coin *coin) &blinding_key, &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); + } } @@ -851,6 +954,9 @@ add_incoming_cb (void *cls, fail ("At least one reserve failed in being created"); return; } + GNUNET_CONTAINER_DLL_remove (empty_reserve_head, + empty_reserve_tail, + r); continue_master_task (); } @@ -883,6 +989,7 @@ fill_reserve (struct Reserve *r) GNUNET_assert (NULL != transfer_details); GNUNET_CRYPTO_eddsa_key_get_public (&r->reserve_priv.eddsa_priv, &reserve_pub.eddsa_pub); + r->left = reserve_amount; r->aih = TALER_EXCHANGE_admin_add_incoming (exchange, exchange_admin_uri, &reserve_pub, @@ -906,39 +1013,40 @@ static void benchmark_run (void *cls) { unsigned int i; + int refresh; + struct Coin *coin; benchmark_task = NULL; - /* FIXME: Note that this function cannot work as-is, it's - just a placeholder for the final logic we want here. */ - for (i=0;i < nreserves;i++) + /* First, always make sure all reserves are full */ + if (NULL != empty_reserve_head) { - struct Reserve *r = &reserves[i]; - - r->reserve_index = i; - fill_reserve (r); - - - for (i=0; i < COINS_PER_RESERVE; i++) - { - struct Coin *coin; - unsigned int coin_index; - - coin_index = r->reserve_index * COINS_PER_RESERVE + i; - coin = &coins[coin_index]; - coin->coin_index = coin_index; - coin->reserve_index = r->reserve_index; - withdraw_coin (coin); - } + fill_reserve (empty_reserve_head); + return; } - - if (GNUNET_OK == eval_probability (SPEND_PROBABILITY)) + /* Second, withdraw until #num_invalid_coins is less than + #INVALID_COIN_SLACK */ + if (num_invalid_coins > INVALID_COIN_SLACK) { - struct Coin *coin; + withdraw_coin (invalid_coins_head); + return; + } - i = 0; // FIXME... - coin = &coins[i]; + /* By default, pick a random valid coin to spend */ + for (i=0;i<1000;i++) + { + coin = &coins[GNUNET_CRYPTO_random_u32 (ncoins, + GNUNET_CRYPTO_QUALITY_WEAK)]; + 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); spend_coin (coin, - (GNUNET_YES == eval_probability (REFRESH_PROBABILITY))); } + refresh); + return; + } + fail ("Too many invalid coins, is your INVALID_COIN_SLACK too high?"); } @@ -1097,6 +1205,11 @@ do_shutdown (void *cls) TALER_EXCHANGE_refresh_reveal_cancel (coin->rrh); coin->rmh = NULL; } + if (NULL != coin->blob) + { + GNUNET_free (coin->blob); + coin->blob = NULL; + } } if (NULL != bank_details) { @@ -1153,6 +1266,8 @@ run (void *cls) char *bank_details_filename; char *merchant_details_filename; struct GNUNET_CRYPTO_EddsaPrivateKey *priv; + unsigned int i; + unsigned int j; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "running run()\n"); @@ -1230,7 +1345,31 @@ run (void *cls) ncoins = COINS_PER_RESERVE * nreserves; coins = GNUNET_new_array (ncoins, struct Coin); + for (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 (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; + coin->invalid = GNUNET_YES; + GNUNET_CONTAINER_DLL_insert (invalid_coins_head, + invalid_coins_tail, + coin); + num_invalid_coins++; + } + } + ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule, &rc); GNUNET_assert (NULL != ctx); @@ -1278,8 +1417,12 @@ main (int argc, GNUNET_assert (GNUNET_SYSERR != GNUNET_GETOPT_run ("taler-exchange-benchmark", options, argc, argv)); - if (NULL == exchange_uri) + if ( (NULL == exchange_uri) || + (0 == strlen (exchange_uri) )) + { + GNUNET_free_non_null (exchange_uri); exchange_uri = GNUNET_strdup ("http://localhost:8081/"); + } if (NULL == exchange_admin_uri) exchange_admin_uri = GNUNET_strdup ("http://localhost:18080/"); if (run_exchange) @@ -1291,6 +1434,7 @@ main (int argc, NULL, NULL, NULL, "taler-exchange-keyup", "taler-exchange-keyup", + "-c", config_file, NULL); if (NULL == proc) { @@ -1307,6 +1451,7 @@ main (int argc, "taler-exchange-dbinit", "taler-exchange-dbinit", "-r", + "-c", config_file, NULL); if (NULL == proc) { @@ -1322,6 +1467,7 @@ main (int argc, NULL, NULL, NULL, "taler-exchange-httpd", "taler-exchange-httpd", + "-c", config_file, NULL); if (NULL == exchanged) { @@ -1331,8 +1477,9 @@ main (int argc, } GNUNET_asprintf (&wget, - "wget -q -t 1 -T 1 %s keys -o /dev/null -O /dev/null", - exchange_uri); + "wget -q -t 1 -T 1 %s%skeys -o /dev/null -O /dev/null", + exchange_uri, + (exchange_uri[strlen (exchange_uri)-1] == '/') ? "" : "/"); cnt = 0; do { fprintf (stderr, "."); diff --git a/src/benchmark/taler-exchange-benchmark.conf b/src/benchmark/taler-exchange-benchmark.conf index 6197bb3a9..16a26d8ae 100644 --- a/src/benchmark/taler-exchange-benchmark.conf +++ b/src/benchmark/taler-exchange-benchmark.conf @@ -1,3 +1,91 @@ [benchmark] BANK_DETAILS = bank_details.json MERCHANT_DETAILS = merchant_details.json + +[PATHS] +# Persistant data storage for the testcase +TALER_TEST_HOME = test_benchmark_home/ + +[taler] +CURRENCY = KUDOS + +[exchange] + +# Wire format supported by the exchange +# We use 'test' for testing of the actual +# coin operations, and 'sepa' to test SEPA-specific routines. +WIREFORMAT = test + +# HTTP port the exchange listens to +PORT = 8081 +# How to access our database +DB = postgres + +# Master public key used to sign the exchange's various keys +MASTER_PUBLIC_KEY = 98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG + +[exchangedb-postgres] +DB_CONN_STR = "postgres:///talercheck" + + +[exchange-wire-outgoing-test] +# What is the main website of the bank? +# (Not used unless the aggregator is run.) +BANK_URI = "http://localhost:8082/" +# From which account at the 'bank' should outgoing wire transfers be made? +BANK_ACCOUNT_NUMBER = 2 + +[exchange-wire-incoming-test] +# This is the response we give out for the /wire request. It provides +# wallets with the bank information for transfers to the exchange. +TEST_RESPONSE_FILE = ${TALER_CONFIG_HOME}/test.json + + +[coin_kudos_1] +value = KUDOS:1 +duration_overlap = 5 minutes +duration_withdraw = 7 days +duration_spend = 2 years +duration_legal = 3 years +fee_withdraw = KUDOS:0.00 +fee_deposit = KUDOS:0.00 +fee_refresh = KUDOS:0.00 +fee_refund = KUDOS:0.00 +rsa_keysize = 1024 + +[coin_kudos_2] +value = KUDOS:2 +duration_overlap = 5 minutes +duration_withdraw = 7 days +duration_spend = 2 years +duration_legal = 3 years +fee_withdraw = KUDOS:0.00 +fee_deposit = KUDOS:0.00 +fee_refresh = KUDOS:0.00 +fee_refund = KUDOS:0.00 +rsa_keysize = 1024 + +[coin_kudos_4] +value = KUDOS:4 +duration_overlap = 5 minutes +duration_withdraw = 7 days +duration_spend = 2 years +duration_legal = 3 years +fee_withdraw = KUDOS:0.00 +fee_deposit = KUDOS:0.00 +fee_refresh = KUDOS:0.00 +fee_refund = KUDOS:0.00 +rsa_keysize = 1024 + +[coin_kudos_8] +value = KUDOS:8 +duration_overlap = 5 minutes +duration_withdraw = 7 days +duration_spend = 2 years +duration_legal = 3 years +fee_withdraw = KUDOS:0.00 +fee_deposit = KUDOS:0.00 +fee_refresh = KUDOS:0.00 +fee_refund = KUDOS:0.00 +rsa_keysize = 1024 + diff --git a/src/benchmark/test_benchmark_home/.config/taler/sepa.json b/src/benchmark/test_benchmark_home/.config/taler/sepa.json new file mode 100644 index 000000000..b435ce86b --- /dev/null +++ b/src/benchmark/test_benchmark_home/.config/taler/sepa.json @@ -0,0 +1,9 @@ +{ + "name": "Max Musterman", + "bic": "COBADEFF370", + "type": "sepa", + "sig": "4EVRC2MCJPXQC8MC00831DNWEXMZAP4JQDDE1A7R6KR3MANG24RC1VQ55AX5A2E35S58VW1VSTENFTPHG5MWG9BSN8B8WXSV21KKW20", + "address": "Musterstadt", + "salt": "3KTM1ZRMWGEQPQ254S4R5R4Q8XM0ZYWTCTE01TZ76MVBSQ6RX7A5DR08WXVH1DCHR1R7ACRB7X0EVC2XDW1CBZM9WFSD9TRMZ90BR98", + "iban": "DE89370400440532013000" +} \ No newline at end of file diff --git a/src/benchmark/test_benchmark_home/.config/taler/test.json b/src/benchmark/test_benchmark_home/.config/taler/test.json new file mode 100644 index 000000000..be5e92c11 --- /dev/null +++ b/src/benchmark/test_benchmark_home/.config/taler/test.json @@ -0,0 +1,8 @@ +{ + "salt": "AZPRFVJ58NM6M7J5CZQPJAH3EW5DYM52AEZ9Y1C1ER3W94QV8D8TQKF6CK8MYQRA9QMSKDQTGZ306ZS9GQ0M6R01CJ20KPP49WFDZK8", + "name": "The exchange", + "account_number": 3, + "bank_uri": "http://localhost:8082/", + "type": "test", + "sig": "RPQXP9S4P8PQP7HEZQNRSZCT0ATNEP8GW0P5TPM34V5RX86FCD670V44R9NETSYDDKB8SZV7TKY9PAJYTY51D3VDWY9XXQ5BPFRXR28" +} \ No newline at end of file diff --git a/src/benchmark/test_benchmark_home/.local/share/taler/exchange/offline-keys/master.priv b/src/benchmark/test_benchmark_home/.local/share/taler/exchange/offline-keys/master.priv new file mode 100644 index 000000000..394926938 --- /dev/null +++ b/src/benchmark/test_benchmark_home/.local/share/taler/exchange/offline-keys/master.priv @@ -0,0 +1 @@ +p^-33XX!\0qmU_ \ No newline at end of file diff --git a/src/exchange-lib/test_exchange_api.conf b/src/exchange-lib/test_exchange_api.conf index a8c690786..03dd6f992 100644 --- a/src/exchange-lib/test_exchange_api.conf +++ b/src/exchange-lib/test_exchange_api.conf @@ -43,7 +43,7 @@ TEST_RESPONSE_FILE = ${TALER_CONFIG_HOME}/test.json [exchange-wire-outgoing-test] # What is the main website of the bank? BANK_URI = "http://localhost:8082/" -# Into which account at the 'bank' should (incoming) wire transfers be made? +# From which account at the 'bank' should outgoing wire transfers be made? BANK_ACCOUNT_NUMBER = 2 [coin_eur_ct_1] -- cgit v1.2.3 From c2bb85ffdd243a61deda23557ee5173d5a117308 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Wed, 15 Jun 2016 17:54:36 +0200 Subject: first working version of benchmark logic --- .gitignore | 1 + src/benchmark/bank_details.json | 2 +- src/benchmark/merchant_details.json | 2 +- src/benchmark/taler-exchange-benchmark.c | 119 +++++++++++++++++-------------- 4 files changed, 68 insertions(+), 56 deletions(-) (limited to 'src') diff --git a/.gitignore b/.gitignore index a928bb4bc..ace3f1375 100644 --- a/.gitignore +++ b/.gitignore @@ -44,6 +44,7 @@ src/exchange-tools/taler-exchange-reservemod src/exchange-tools/taler-exchange-wire src/exchangedb/perf-exchangedb src/benchmark/taler-exchange-benchmark +src/benchmark/test_benchmark_home/.local/share/taler/exchange/live-keys/ src/json/test_json src/wire/test_sepa_wireformat src/wire/test_wire_plugin diff --git a/src/benchmark/bank_details.json b/src/benchmark/bank_details.json index d6f60005b..bc46c48f3 100644 --- a/src/benchmark/bank_details.json +++ b/src/benchmark/bank_details.json @@ -1 +1 @@ -{"type":"test", "bank_uri":"https://bank.test.taler.net/", "account_number":63} +{"type":"test", "bank_uri":"http://localhost:8082/", "account_number":63} diff --git a/src/benchmark/merchant_details.json b/src/benchmark/merchant_details.json index bda6e6cc0..c3869161d 100644 --- a/src/benchmark/merchant_details.json +++ b/src/benchmark/merchant_details.json @@ -1 +1 @@ -{"type":"test", "bank_uri":"https://bank.test.taler.net/", "account_number":64} +{"type":"test", "bank_uri":"http://localhost:8082/", "account_number":64} diff --git a/src/benchmark/taler-exchange-benchmark.c b/src/benchmark/taler-exchange-benchmark.c index 430f44f0f..cd406dbd7 100644 --- a/src/benchmark/taler-exchange-benchmark.c +++ b/src/benchmark/taler-exchange-benchmark.c @@ -40,6 +40,34 @@ */ #define INVALID_COIN_SLACK 10 +/** + * The benchmark withdraws always the same denomination, since the calculation + * for refreshing is statically done (at least in its very first version). + */ +#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 + +/** + * Large enough value to allow having 12 coins per reserve without parsing + * /keys in the first place + */ +#define RESERVE_VALUE 1000 + +/** + * How many coins (AKA withdraw operations) per reserve should be withdrawn at the same time. + */ +#define COINS_PER_RESERVE 12 + + + /** * Needed information for a reserve. Other values are the same for all reserves, therefore defined in global variables */ @@ -323,39 +351,11 @@ static char *exchange_uri; */ static char *exchange_admin_uri; -/** - * How many coins (AKA withdraw operations) per reserve should be withdrawn - */ -#define COINS_PER_RESERVE 12 - /** * Used currency (read from /keys' output) */ static char *currency; -/** - * Large enough value to allow having 12 coins per reserve without parsing - * /keys in the first place - */ -#define RESERVE_VALUE 1000 - -/** - * The benchmark withdraws always the same denomination, since the calculation - * for refreshing is statically done (at least in its very first version). - */ -#define COIN_VALUE 8 - -/** - * Probability a coin can be spent - */ -#define SPEND_PROBABILITY 0.1 - -/** - * Probability a coin can be refreshed - */ -#define REFRESH_PROBABILITY 0.4 - - /** * List of coins to get in return to a melt operation. Just a * static list for now as every melt operation is carried out @@ -544,7 +544,9 @@ reveal_cb (void *cls, num_invalid_coins--; fresh_coin->invalid = GNUNET_NO; fresh_coin->pk = find_pk (keys, &coin->denoms[i]); - fresh_coin->sig = sigs[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]; } @@ -598,20 +600,24 @@ melt_cb (void *cls, /** - * Function called upon completion of our /reserve/withdraw request. - * This is merely the function which spends withdrawn coins + * Mark coin as invalid. * - * @param cls closure with the `struct Coin` we are withdrawing - * @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 sig signature over the coin, NULL on error - * @param full_response full response from the exchange (for logging, in case of errors) + * @param coin coin to mark invalid */ static void -reserve_withdraw_cb (void *cls, - unsigned int http_status, - const struct TALER_DenominationSignature *sig, - const json_t *full_response); +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; + } +} /** @@ -661,6 +667,10 @@ refresh_coin (struct Coin *coin) ndenoms2, dpks, &blob_size); + invalidate_coin (coin); + GNUNET_array_grow (dpks, + ndenoms2, + 0); if (NULL == blob) { fail ("Failed to prepare refresh"); @@ -715,9 +725,14 @@ deposit_cb (void *cls, "Coin #%d correctly spent!\n", coin->coin_index); if (GNUNET_YES == coin->refresh) + { refresh_coin (coin); + } else + { + invalidate_coin (coin); continue_master_task (); + } } @@ -830,11 +845,6 @@ spend_coin (struct Coin *coin, fail ("An error occurred while calling deposit API"); return; } - GNUNET_CONTAINER_DLL_insert (invalid_coins_head, - invalid_coins_tail, - coin); - num_invalid_coins++; - coin->invalid = GNUNET_YES; } @@ -894,14 +904,14 @@ withdraw_coin (struct Coin *coin) keys = TALER_EXCHANGE_get_keys (exchange); r = &reserves[coin->reserve_index]; - GNUNET_assert (-1 != TALER_amount_cmp (&r->left, - &amount)); coin_priv = GNUNET_CRYPTO_eddsa_key_create (); coin->coin_priv.eddsa_priv = *coin_priv; GNUNET_free (coin_priv); 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))); coin->wsh = TALER_EXCHANGE_reserve_withdraw (exchange, @@ -1034,8 +1044,8 @@ benchmark_run (void *cls) /* By default, pick a random valid coin to spend */ for (i=0;i<1000;i++) { - coin = &coins[GNUNET_CRYPTO_random_u32 (ncoins, - GNUNET_CRYPTO_QUALITY_WEAK)]; + 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) @@ -1210,6 +1220,11 @@ do_shutdown (void *cls) 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 != bank_details) { @@ -1362,11 +1377,7 @@ run (void *cls) coin = &coins[coin_index]; coin->coin_index = coin_index; coin->reserve_index = i; - coin->invalid = GNUNET_YES; - GNUNET_CONTAINER_DLL_insert (invalid_coins_head, - invalid_coins_tail, - coin); - num_invalid_coins++; + invalidate_coin (coin); } } -- cgit v1.2.3 From 0c3f6dde252500f55bc3f4154a0c103666251594 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Wed, 15 Jun 2016 18:19:40 +0200 Subject: add support to collect basic metrics and to terminate automatically --- src/benchmark/taler-exchange-benchmark.c | 145 +++++++++++++++++++++++++------ 1 file changed, 119 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/benchmark/taler-exchange-benchmark.c b/src/benchmark/taler-exchange-benchmark.c index cd406dbd7..a92087b4f 100644 --- a/src/benchmark/taler-exchange-benchmark.c +++ b/src/benchmark/taler-exchange-benchmark.c @@ -18,11 +18,6 @@ * @brief exchange's benchmark * @author Marcello Stanisci * @author Christian Grothoff - * - * TODO: - * - test - * - add instrumentation - * - add support for automatic termination */ #include "platform.h" #include "taler_util.h" @@ -66,6 +61,26 @@ */ #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. Just a + * static list for now as every melt operation is carried out + * on a 8 KUDOS coin whose only 1 KUDOS has been spent, thus + * 7 KUDOS melted. This structure must be changed with one holding + * TALER_Amount structs, as every time it's needed it requires + * too many operations before getting the desired TALER_Amount. + */ +static const char *refresh_denoms[] = { + "4", + "2", + "1", + NULL +}; /** @@ -237,6 +252,11 @@ static unsigned int num_invalid_coins; */ static int run_exchange; +/** + * Enables printing of "-" and "." to indicate progress. + */ +static int be_verbose; + /** * How many coins the benchmark should operate on */ @@ -357,19 +377,41 @@ static char *exchange_admin_uri; static char *currency; /** - * List of coins to get in return to a melt operation. Just a - * static list for now as every melt operation is carried out - * on a 8 KUDOS coin whose only 1 KUDOS has been spent, thus - * 7 KUDOS melted. This structure must be changed with one holding - * TALER_Amount structs, as every time it's needed it requires - * too many operations before getting the desired TALER_Amount. + * What time did we start to really measure performance? */ -static const char *refresh_denoms[] = { - "4", - "2", - "1", - NULL -}; +static struct GNUNET_TIME_Absolute start_time; + +/** + * Number of times #bennchmark_run has executed. Used + * to indicate when we consider us warm. + */ +static unsigned long long warm; + +/** + * Number of times #bennchmark_run should execute + * before we shut down. + */ +static unsigned int num_iterations; + +/** + * Number of /deposit operations we have executed since #start_time. + */ +static unsigned long long num_deposit; + +/** + * Number of /withdraw operations we have executed since #start_time. + */ +static unsigned long long num_withdraw; + +/** + * Number of /refresh operations we have executed since #start_time. + */ +static unsigned long long num_refresh; + +/** + * Number of /admin operations we have executed since #start_time. + */ +static unsigned long long num_admin; /** @@ -683,6 +725,8 @@ refresh_coin (struct Coin *coin) 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, @@ -824,7 +868,8 @@ spend_coin (struct Coin *coin, 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, @@ -913,6 +958,8 @@ withdraw_coin (struct Coin *coin) GNUNET_assert (-1 != TALER_amount_cmp (&r->left, &amount)); GNUNET_assert (NULL != (coin->pk = find_pk (keys, &amount))); + if (warm >= WARM_THRESHOLD) + num_withdraw++; coin->wsh = TALER_EXCHANGE_reserve_withdraw (exchange, coin->pk, @@ -1000,6 +1047,8 @@ fill_reserve (struct Reserve *r) 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++; r->aih = TALER_EXCHANGE_admin_add_incoming (exchange, exchange_admin_uri, &reserve_pub, @@ -1025,7 +1074,7 @@ benchmark_run (void *cls) unsigned int i; int refresh; struct Coin *coin; - + benchmark_task = NULL; /* First, always make sure all reserves are full */ if (NULL != empty_reserve_head) @@ -1040,6 +1089,24 @@ benchmark_run (void *cls) withdraw_coin (invalid_coins_head); return; } + warm++; + if ( be_verbose && + (0 == (warm % 10)) ) + fprintf (stderr, + "%s", + WARM_THRESHOLD < warm ? "." : "-"); + 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; + } /* By default, pick a random valid coin to spend */ for (i=0;i<1000;i++) @@ -1160,7 +1227,10 @@ static void do_shutdown (void *cls) { unsigned int i; + struct GNUNET_TIME_Relative duration; + 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) @@ -1266,6 +1336,22 @@ do_shutdown (void *cls) } 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_NO)); + } + else + { + fprintf (stdout, + "Sorry, no results, benchmark did not get warm!\n"); + } } @@ -1409,25 +1495,32 @@ main (int argc, "Initialize and start the bank and exchange", GNUNET_NO, &GNUNET_GETOPT_set_one, &run_exchange}, GNUNET_GETOPT_OPTION_CFG_FILE (&config_file), - GNUNET_GETOPT_OPTION_HELP ("tool to benchmark the Taler exchange"), - {'s', "pool-size", "SIZE", - "How many coins this benchmark should instantiate", GNUNET_YES, - &GNUNET_GETOPT_set_uint, &pool_size}, {'e', "exchange-uri", "URI", "URI of the exchange", GNUNET_YES, &GNUNET_GETOPT_set_string, &exchange_uri}, {'E', "exchange-admin-uri", "URI", "URI of the administrative interface of the exchange", GNUNET_YES, &GNUNET_GETOPT_set_string, &exchange_admin_uri}, + GNUNET_GETOPT_OPTION_HELP ("tool to benchmark the Taler exchange"), + {'s', "pool-size", "SIZE", + "How many coins this benchmark should instantiate", GNUNET_YES, + &GNUNET_GETOPT_set_uint, &pool_size}, + {'l', "limit", "LIMIT", + "Terminatet the benchmark after LIMIT operations", GNUNET_YES, + &GNUNET_GETOPT_set_uint, &num_iterations}, + GNUNET_GETOPT_OPTION_VERBOSE (&be_verbose), GNUNET_GETOPT_OPTION_END }; + int ret; GNUNET_log_setup ("taler-exchange-benchmark", "WARNING", NULL); - GNUNET_assert (GNUNET_SYSERR != - GNUNET_GETOPT_run ("taler-exchange-benchmark", - options, argc, argv)); + ret = GNUNET_GETOPT_run ("taler-exchange-benchmark", + options, argc, argv); + GNUNET_assert (GNUNET_SYSERR != ret); + if (GNUNET_NO == ret) + return 0; if ( (NULL == exchange_uri) || (0 == strlen (exchange_uri) )) { -- cgit v1.2.3 From 754c4ef24c7758755136309661dbbb38fd75cd8d Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Wed, 15 Jun 2016 18:42:00 +0200 Subject: nicer reports -fix leak -fix leaks --- src/benchmark/taler-exchange-benchmark.c | 31 +++++++++++++++++++++++++------ src/exchange-tools/taler-exchange-keyup.c | 6 +++++- 2 files changed, 30 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/benchmark/taler-exchange-benchmark.c b/src/benchmark/taler-exchange-benchmark.c index a92087b4f..9c4b8cbf7 100644 --- a/src/benchmark/taler-exchange-benchmark.c +++ b/src/benchmark/taler-exchange-benchmark.c @@ -253,7 +253,9 @@ static unsigned int num_invalid_coins; static int run_exchange; /** - * Enables printing of "-" and "." to indicate progress. + * 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 int be_verbose; @@ -686,7 +688,7 @@ refresh_coin (struct Coin *coin) keys = TALER_EXCHANGE_get_keys (exchange); for (curr.value = COIN_VALUE >> 1; curr.value > 0; curr.value = curr.value >> 1) { - if (acc_value + curr.value <= coin->left.value) + while (acc_value + curr.value <= coin->left.value) { GNUNET_array_append (denoms, ndenoms, @@ -710,6 +712,9 @@ refresh_coin (struct Coin *coin) dpks, &blob_size); invalidate_coin (coin); + GNUNET_array_grow (denoms, + ndenoms, + 0); GNUNET_array_grow (dpks, ndenoms2, 0); @@ -1091,10 +1096,22 @@ benchmark_run (void *cls) } warm++; if ( be_verbose && - (0 == (warm % 10)) ) + (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", - WARM_THRESHOLD < warm ? "." : "-"); + "%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, @@ -1345,7 +1362,7 @@ do_shutdown (void *cls) num_deposit, num_refresh, GNUNET_STRINGS_relative_time_to_string (duration, - GNUNET_NO)); + GNUNET_YES)); } else { @@ -1406,6 +1423,7 @@ run (void *cls) 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"); @@ -1426,6 +1444,7 @@ run (void *cls) 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"); diff --git a/src/exchange-tools/taler-exchange-keyup.c b/src/exchange-tools/taler-exchange-keyup.c index 69d28361f..21024ffca 100644 --- a/src/exchange-tools/taler-exchange-keyup.c +++ b/src/exchange-tools/taler-exchange-keyup.c @@ -807,13 +807,14 @@ exchange_keys_update_cointype (void *cls, &denomkey_issue); if (GNUNET_OK != TALER_EXCHANGEDB_denomination_key_write (dkf, - &denomkey_issue)) + &denomkey_issue)) { fprintf (stderr, "Failed to write denomination key information to file `%s'.\n", dkf); *ret = GNUNET_SYSERR; GNUNET_CRYPTO_rsa_private_key_free (denomkey_issue.denom_priv.rsa_private_key); + GNUNET_CRYPTO_rsa_public_key_free (denomkey_issue.denom_pub.rsa_public_key); return; } if ( (NULL != auditor_output_file) && @@ -828,9 +829,12 @@ exchange_keys_update_cointype (void *cls, auditorrequestfile, STRERROR (errno)); *ret = GNUNET_SYSERR; + GNUNET_CRYPTO_rsa_private_key_free (denomkey_issue.denom_priv.rsa_private_key); + GNUNET_CRYPTO_rsa_public_key_free (denomkey_issue.denom_pub.rsa_public_key); return; } GNUNET_CRYPTO_rsa_private_key_free (denomkey_issue.denom_priv.rsa_private_key); + GNUNET_CRYPTO_rsa_public_key_free (denomkey_issue.denom_pub.rsa_public_key); p.anchor = GNUNET_TIME_absolute_add (p.anchor, p.duration_spend); p.anchor = GNUNET_TIME_absolute_subtract (p.anchor, -- cgit v1.2.3 From c38a7c5518418caefd1c6725a29cfa577d40e7a4 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Wed, 15 Jun 2016 19:24:48 +0200 Subject: more sanity checks, better clean up --- src/benchmark/taler-exchange-benchmark.c | 125 +++++++++++++++++++++---------- 1 file changed, 85 insertions(+), 40 deletions(-) (limited to 'src') diff --git a/src/benchmark/taler-exchange-benchmark.c b/src/benchmark/taler-exchange-benchmark.c index 9c4b8cbf7..4b50033da 100644 --- a/src/benchmark/taler-exchange-benchmark.c +++ b/src/benchmark/taler-exchange-benchmark.c @@ -31,13 +31,24 @@ /** * How much slack do we leave in terms of coins that are invalid (and - * thus available for refresh)? + * thus available for refresh)? Should be significantly larger + * than #REFRESH_SLOTS_NEEDED, and must be below #pool_size. */ -#define INVALID_COIN_SLACK 10 +#define INVALID_COIN_SLACK 20 /** - * The benchmark withdraws always the same denomination, since the calculation - * for refreshing is statically done (at least in its very first version). + * 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 @@ -51,13 +62,15 @@ #define REFRESH_PROBABILITY 0.1 /** - * Large enough value to allow having 12 coins per reserve without parsing - * /keys in the first place + * 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 /** - * How many coins (AKA withdraw operations) per reserve should be withdrawn at the same time. + * 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 @@ -68,17 +81,15 @@ #define WARM_THRESHOLD 1000LL /** - * List of coins to get in return to a melt operation. Just a - * static list for now as every melt operation is carried out - * on a 8 KUDOS coin whose only 1 KUDOS has been spent, thus - * 7 KUDOS melted. This structure must be changed with one holding - * TALER_Amount structs, as every time it's needed it requires - * too many operations before getting the desired TALER_Amount. + * 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", - "2", - "1", + "4.00", + "2.00", + "1.00", NULL }; @@ -578,7 +589,7 @@ reveal_cb (void *cls, fresh_coin = invalid_coins_head; if (NULL == fresh_coin) { - /* #INVALID_COIN_SLACK too low? */ + /* #REFRESH_SLOTS_NEEDED too low? */ GNUNET_break (0); continue; } @@ -594,6 +605,8 @@ reveal_cb (void *cls, fresh_coin->coin_priv = coin_privs[i]; fresh_coin->left = coin->denoms[i]; } + GNUNET_free (coin->denoms); + coin->denoms = NULL; continue_master_task (); } @@ -674,35 +687,45 @@ refresh_coin (struct Coin *coin) { char *blob; size_t blob_size; - const struct TALER_EXCHANGE_Keys *keys; struct TALER_Amount *denoms = NULL; struct TALER_EXCHANGE_DenomPublicKey *dpks = NULL; const struct TALER_EXCHANGE_DenomPublicKey *curr_dpk; struct TALER_Amount curr; unsigned int ndenoms = 0; unsigned int ndenoms2 = 0; - unsigned long long acc_value; + unsigned int off; TALER_amount_get_zero (currency, &curr); - acc_value = 0; - keys = TALER_EXCHANGE_get_keys (exchange); - for (curr.value = COIN_VALUE >> 1; curr.value > 0; curr.value = curr.value >> 1) + off = 0; + while (0 != TALER_amount_cmp (&curr, + &coin->left)) { - while (acc_value + curr.value <= coin->left.value) + 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 (&coin->left, + &curr_dpk->value)) { GNUNET_array_append (denoms, ndenoms, - curr); - GNUNET_assert (NULL != (curr_dpk = find_pk (keys, &curr))); + curr_dpk->value); GNUNET_array_append (dpks, ndenoms2, *curr_dpk); - acc_value += curr.value; + TALER_amount_subtract (&coin->left, + &coin->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, @@ -712,9 +735,6 @@ refresh_coin (struct Coin *coin) dpks, &blob_size); invalidate_coin (coin); - GNUNET_array_grow (denoms, - ndenoms, - 0); GNUNET_array_grow (dpks, ndenoms2, 0); @@ -1136,6 +1156,8 @@ benchmark_run (void *cls) 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; @@ -1149,12 +1171,11 @@ benchmark_run (void *cls) * be withdrawn in a refresh operation. It sums up 4 #currency units, * since that is the only amount refreshed so far by the benchmark * - * @param NULL-terminated array of value.fraction pairs * @return #GNUNET_OK if the array is correctly built, #GNUNET_SYSERR * otherwise */ static unsigned int -build_refresh (const char *const*list) +build_refresh () { char *amount_str; struct TALER_Amount amount; @@ -1162,13 +1183,16 @@ build_refresh (const char *const*list) 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 (i=0; NULL != list[i]; i++) + for (i=0; NULL != refresh_denoms[i]; i++) { GNUNET_asprintf (&amount_str, "%s:%s", currency, - list[i]); + refresh_denoms[i]); GNUNET_assert (GNUNET_OK == TALER_string_to_amount (amount_str, &amount)); @@ -1219,17 +1243,26 @@ cert_cb (void *cls, _keys->num_sign_keys, _keys->num_denom_keys); if (NULL != currency) - return; /* we've been here before... */ + { + /* 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); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Using currency: %s\n", - currency); if (GNUNET_SYSERR == - build_refresh (refresh_denoms)) + build_refresh ()) { fail ("Initializing denominations failed"); return; } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Using currency: %s\n", + currency); continue_master_task (); } @@ -1312,6 +1345,11 @@ do_shutdown (void *cls) 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 != bank_details) { @@ -1387,8 +1425,6 @@ run (void *cls) unsigned int i; unsigned int j; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "running run()\n"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "gotten pool_size of %d\n", pool_size); @@ -1407,6 +1443,11 @@ run (void *cls) fail ("Failed to parse configuration file"); return; } + if (pool_size < INVALID_COIN_SLACK) + { + fail ("Pool size given too small."); + return; + } if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_filename (cfg, "benchmark", @@ -1460,6 +1501,8 @@ run (void *cls) 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; @@ -1535,6 +1578,8 @@ main (int argc, 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); GNUNET_assert (GNUNET_SYSERR != ret); -- cgit v1.2.3 From 8c7406cb42c6c9cc8967ab8cbfd901809c8b3c2e Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Wed, 15 Jun 2016 20:09:09 +0200 Subject: check refresh amounts add up correctly, fix linker issue --- src/bank-lib/Makefile.am | 1 + src/benchmark/taler-exchange-benchmark.c | 23 ++++++++++++++------- src/exchange-lib/exchange_api_refresh.c | 35 ++++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/bank-lib/Makefile.am b/src/bank-lib/Makefile.am index 289135023..a87a2c467 100644 --- a/src/bank-lib/Makefile.am +++ b/src/bank-lib/Makefile.am @@ -38,6 +38,7 @@ libtalerfakebank_la_LIBADD = \ -lgnunetjson \ -lgnunetutil \ -ljansson \ + -lmicrohttpd \ $(XLIB) diff --git a/src/benchmark/taler-exchange-benchmark.c b/src/benchmark/taler-exchange-benchmark.c index 4b50033da..66b0c6f5e 100644 --- a/src/benchmark/taler-exchange-benchmark.c +++ b/src/benchmark/taler-exchange-benchmark.c @@ -186,7 +186,7 @@ struct Coin struct TALER_EXCHANGE_DepositHandle *dh; /** - * Array of denominations expected to get from melt + * Array of denominations we expect to get from melt. */ struct TALER_Amount *denoms; @@ -691,14 +691,17 @@ refresh_coin (struct Coin *coin) 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); TALER_amount_get_zero (currency, &curr); + left = coin->left; off = 0; while (0 != TALER_amount_cmp (&curr, - &coin->left)) + &left)) { if (off >= refresh_pk_len) { @@ -707,7 +710,7 @@ refresh_coin (struct Coin *coin) break; } curr_dpk = &refresh_pk[off]; - while (-1 != TALER_amount_cmp (&coin->left, + while (-1 != TALER_amount_cmp (&left, &curr_dpk->value)) { GNUNET_array_append (denoms, @@ -716,9 +719,10 @@ refresh_coin (struct Coin *coin) GNUNET_array_append (dpks, ndenoms2, *curr_dpk); - TALER_amount_subtract (&coin->left, - &coin->left, - &curr_dpk->value); + GNUNET_assert (GNUNET_SYSERR != + TALER_amount_subtract (&left, + &left, + &curr_dpk->value)); } off++; } @@ -1585,6 +1589,11 @@ main (int argc, GNUNET_assert (GNUNET_SYSERR != ret); 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_uri) || (0 == strlen (exchange_uri) )) { diff --git a/src/exchange-lib/exchange_api_refresh.c b/src/exchange-lib/exchange_api_refresh.c index 9a9c6b7eb..e32f73e21 100644 --- a/src/exchange-lib/exchange_api_refresh.c +++ b/src/exchange-lib/exchange_api_refresh.c @@ -764,6 +764,7 @@ TALER_EXCHANGE_refresh_prepare (const struct TALER_CoinSpendPrivateKeyP *melt_pr unsigned int i; unsigned int j; struct GNUNET_HashContext *hash_context; + struct TALER_Amount total; /* build up melt data structure */ for (i=0;icurrency, + &total)); + for (j=0;j Date: Thu, 16 Jun 2016 00:22:20 +0200 Subject: typo --- src/benchmark/taler-exchange-benchmark.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/benchmark/taler-exchange-benchmark.c b/src/benchmark/taler-exchange-benchmark.c index 66b0c6f5e..4b6465ac6 100644 --- a/src/benchmark/taler-exchange-benchmark.c +++ b/src/benchmark/taler-exchange-benchmark.c @@ -925,7 +925,7 @@ spend_coin (struct Coin *coin, /** * Function called upon completion of our /reserve/withdraw request. * This is merely the function which spends withdrawn coins. For each - * spent coin, ti either refresh it or re-withdraw it. + * 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 -- cgit v1.2.3 From 17c8741e2049cde4099af3d1d132da3b48e427c5 Mon Sep 17 00:00:00 2001 From: Marcello Stanisci Date: Thu, 16 Jun 2016 11:22:07 +0200 Subject: typo --- src/benchmark/taler-exchange-benchmark.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/benchmark/taler-exchange-benchmark.c b/src/benchmark/taler-exchange-benchmark.c index 4b6465ac6..45ed28521 100644 --- a/src/benchmark/taler-exchange-benchmark.c +++ b/src/benchmark/taler-exchange-benchmark.c @@ -1572,7 +1572,7 @@ main (int argc, "How many coins this benchmark should instantiate", GNUNET_YES, &GNUNET_GETOPT_set_uint, &pool_size}, {'l', "limit", "LIMIT", - "Terminatet the benchmark after LIMIT operations", GNUNET_YES, + "Terminate the benchmark after LIMIT operations", GNUNET_YES, &GNUNET_GETOPT_set_uint, &num_iterations}, GNUNET_GETOPT_OPTION_VERBOSE (&be_verbose), GNUNET_GETOPT_OPTION_END -- cgit v1.2.3