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(+) 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(-) 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(-) 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(-) 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: Tue, 14 Jun 2016 16:52:03 +0200 Subject: Minor fixes and adding some FIXMEs about the auditor --- doc/paper/taler.tex | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/doc/paper/taler.tex b/doc/paper/taler.tex index a5a1a0354..d93cbf9cc 100644 --- a/doc/paper/taler.tex +++ b/doc/paper/taler.tex @@ -583,6 +583,11 @@ protocol messages; denomination keys are used for blind-signing coins. The exchange's long-term offline key is assumed to be known to both customers and merchants and is certified by the auditors. +We avoid asking either customers or merchants to make trust desissions +about individual exchanges. Instead, they need only select the auditors. +Auditors must sign all the exchange's keys including, the individual +denomination keys. + As we are dealing with financial transactions, we explicitly describe whenever entities need to safely commit data to persistent storage. As long as those commitments persist, the protocol can be safely @@ -597,14 +602,20 @@ Merchants may discard information once payments from the exchange have been received, assuming the records are also no longer needed for tax purposes. The exchange's bank transfers dealing in traditional currency are expected to be recorded for tax authorities to ensure taxability. +% FIXME: Auditor? + +We use RSA for denomination keys and EdDSA over some eliptic curve +$\mathbb{E}$ for all other keys. Let $G$ denote the generator of +our elliptic curve $\mathbb{E}$. + \subsection{Withdrawal} -Let $G$ be the generator of an elliptic curve. To withdraw anonymous -digital coins, the customer first identifies a exchange with a -denomination public-private key pair $K := (K_s, K_p)$ corresponding -to a denomination the customer would like to withdraw, and then -performs the following interaction with the exchange: +To withdraw anonymous digital coins, the customer first selects an +exchange and one of its public denomination public keys $K_p$ whose +value $K_v$ corresponds to an amount the customer wishes to withdraw. +We let $K_s$ denote the exchange's private key corresponding to $K_p$. +Now the customer carries out the following interaction with the exchange: % FIXME: We say withdrawal key in this document, but say reserve key in % others, so probably withdrawal key should be renamed to reserve key. @@ -621,7 +632,7 @@ performs the following interaction with the exchange: \item coin key $C := (c_s,C_p)$ with private key $c_s$ and public key $C_p := c_s G$, \item blinding factor $b$, and commits $\langle W, C, b \rangle$ to disk. \end{itemize} - \item The customer transfers an amount of money corresponding to at least $K_p$ to the exchange, with $W_p$ in the subject line of the transaction. + \item The customer transfers an amount of money corresponding to at least $K_v$ to the exchange, with $W_p$ in the subject line of the transaction. \item The exchange receives the transaction and credits the $W_p$ reserve with the respective amount in its database. \item The customer sends $S_W(B_b(C_p))$ to the exchange to request withdrawal of $C$; here, $B_b$ denotes Chaum-style blinding with blinding factor $b$. \item The exchange checks if the same withdrawal request was issued before; in this case, it sends $S_{K}(B_b(C_p))$ to the customer.\footnote{$S_K$ @@ -636,6 +647,7 @@ performs the following interaction with the exchange: If the guards for the transaction fail, the exchange sends a descriptive error back to the customer, with proof that it operated correctly. Assuming the signature was valid, this would involve showing the transaction history for the reserve. + % FIXME: Is it really the whole history? \item The customer computes and verifies the unblinded signature $S_K(C_p) = U_b(S_K(B_b(C_p)))$. The customer saves the coin $\langle S_K(C_p), c_s \rangle$ to local wallet on disk. \end{enumerate} @@ -644,9 +656,12 @@ performs the following interaction with the exchange: \subsection{Exact and partial spending} A customer can spend coins at a merchant, under the condition that the -merchant trusts the specific exchange that issued the coin. Merchants are -identified by their key $M := (m_s, M_p)$ where the public key $M_p$ -must be known to the customer a priori. +merchant trusts the exchange that issued the coin. +% FIXME: Auditor here? +Merchants are identified by their public key $M_p = m_s G$ which the +customer's wallet learns through the merchant's webpage, which itself +must be authenticated with X.509c. +% FIXME: Is this correct? We now describe the protocol between the customer, merchant, and exchange for a transaction in which the customer spends a coin $C := (c_s, C_p)$ @@ -676,8 +691,8 @@ with signature $\widetilde{C} := S_K(C_p)$ S_c(\widetilde{C}, m, f, H(a), H(p,r), M_p)$ and sends $\langle \mathcal{D}, D_j\rangle$ to the merchant, where $D_j$ is the exchange which signed $K$. -\item The merchant gives $(\mathcal{D}, p, r)$ to the exchange, revealing $p$ - only to the exchange. +\item The merchant gives $(\mathcal{D}, p, r)$ to the exchange, thereby + revealing $p$ only to the exchange. \item The exchange validates $\mathcal{D}$ and checks for double spending. If the coin has been involved in previous transactions and the new one would exceed its remaining value, it sends an error -- cgit v1.2.3 From c32cc081ee8ddb5b0e6538264781e8d3ba2f5798 Mon Sep 17 00:00:00 2001 From: Christian Grothoff 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 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(-) 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(-) 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(-) 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(-) 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 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(-) 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(-) 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(-) 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(-) 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(-) 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(-) 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(-) 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