summaryrefslogtreecommitdiff
path: root/src/lib/testing_api_cmd_refresh.c
diff options
context:
space:
mode:
authorFlorian Dold <florian.dold@gmail.com>2020-01-19 15:23:19 +0100
committerFlorian Dold <florian.dold@gmail.com>2020-01-19 15:23:33 +0100
commit72a629a8be1ed2adc7402285e0f19f8f06816a26 (patch)
tree499468c12eaf06e8ad514db7b1ff684462c99ac2 /src/lib/testing_api_cmd_refresh.c
parentdbf85bbc0d23b044aa47be67ceae4e6ecd709298 (diff)
downloadexchange-72a629a8be1ed2adc7402285e0f19f8f06816a26.tar.gz
exchange-72a629a8be1ed2adc7402285e0f19f8f06816a26.tar.bz2
exchange-72a629a8be1ed2adc7402285e0f19f8f06816a26.zip
move testing logic and integration tests into separate directory
Diffstat (limited to 'src/lib/testing_api_cmd_refresh.c')
-rw-r--r--src/lib/testing_api_cmd_refresh.c1411
1 files changed, 0 insertions, 1411 deletions
diff --git a/src/lib/testing_api_cmd_refresh.c b/src/lib/testing_api_cmd_refresh.c
deleted file mode 100644
index 575f1a0c6..000000000
--- a/src/lib/testing_api_cmd_refresh.c
+++ /dev/null
@@ -1,1411 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2018 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3, or (at your
- option) any later version.
-
- TALER is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public
- License along with TALER; see the file COPYING. If not, see
- <http://www.gnu.org/licenses/>
-*/
-/**
- * @file lib/testing_api_cmd_refresh.c
- * @brief commands for testing all "refresh" features.
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "exchange_api_handle.h"
-#include "taler_testing_lib.h"
-#include "taler_signatures.h"
-#include "backoff.h"
-
-
-/**
- * Information about a fresh coin generated by the refresh
- * operation.
- */
-struct TALER_TESTING_FreshCoinData
-{
-
- /**
- * 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
- * coin's public key.
- */
- struct TALER_DenominationSignature sig;
-
- /**
- * Set (by the interpreter) to the coin's private key.
- */
- struct TALER_CoinSpendPrivateKeyP coin_priv;
-
- /**
- * The blinding key (needed for recoup operations).
- */
- struct TALER_DenominationBlindingKeyP blinding_key;
-
-};
-
-
-/**
- * State for a "refresh melt" command.
- */
-struct RefreshMeltState
-{
-
- /**
- * Reference to reserve_withdraw operations for coin to
- * be used for the /refresh/melt operation.
- */
- const char *coin_reference;
-
- /**
- * "Crypto data" used in the refresh operation.
- */
- char *refresh_data;
-
- /**
- * Reference to a previous melt command.
- */
- const char *melt_reference;
-
- /**
- * Melt handle while operation is running.
- */
- struct TALER_EXCHANGE_RefreshMeltHandle *rmh;
-
- /**
- * Interpreter state.
- */
- struct TALER_TESTING_Interpreter *is;
-
- /**
- * Array of the denomination public keys
- * corresponding to the @e num_fresh_coins;
- */
- struct TALER_EXCHANGE_DenomPublicKey *fresh_pks;
-
- /**
- * Private key of the dirty coin being melted.
- */
- const struct TALER_CoinSpendPrivateKeyP *melt_priv;
-
- /**
- * Task scheduled to try later.
- */
- struct GNUNET_SCHEDULER_Task *retry_task;
-
- /**
- * How long do we wait until we retry?
- */
- struct GNUNET_TIME_Relative backoff;
-
- /**
- * Number of bytes in @e refresh_data.
- */
- size_t refresh_data_length;
-
- /**
- * Amounts to be generated during melt.
- */
- const char **melt_fresh_amounts;
-
- /**
- * Number of fresh coins generated by the melt.
- */
- unsigned int num_fresh_coins;
-
- /**
- * Expected HTTP response code.
- */
- unsigned int expected_response_code;
-
- /**
- * if set to #GNUNET_YES, then two /refresh/melt operations
- * will be performed. This is needed to trigger the logic
- * that manages those already-made requests. Note: it
- * is not possible to just copy-and-paste a test refresh melt
- * CMD to have the same effect, because every data preparation
- * generates new planchets that (in turn) make the whole "hash"
- * different from any previous one, therefore NOT allowing the
- * exchange to pick any previous /rerfesh/melt operation from
- * the database.
- */
- unsigned int double_melt;
-
- /**
- * Should we retry on (transient) failures?
- */
- int do_retry;
-
- /**
- * Set by the melt callback as it comes from the exchange.
- */
- uint16_t noreveal_index;
-};
-
-
-/**
- * State for a "refresh reveal" CMD.
- */
-struct RefreshRevealState
-{
- /**
- * Link to a "refresh melt" command.
- */
- const char *melt_reference;
-
- /**
- * Reveal handle while operation is running.
- */
- struct TALER_EXCHANGE_RefreshRevealHandle *rrh;
-
- /**
- * Convenience struct to keep in one place all the
- * data related to one fresh coin, set by the reveal callback
- * as it comes from the exchange.
- */
- struct TALER_TESTING_FreshCoinData *fresh_coins;
-
- /**
- * Interpreter state.
- */
- struct TALER_TESTING_Interpreter *is;
-
- /**
- * Task scheduled to try later.
- */
- struct GNUNET_SCHEDULER_Task *retry_task;
-
- /**
- * How long do we wait until we retry?
- */
- struct GNUNET_TIME_Relative backoff;
-
- /**
- * Number of fresh coins withdrawn, set by the
- * reveal callback as it comes from the exchange,
- * it is the length of the @e fresh_coins array.
- */
- unsigned int num_fresh_coins;
-
- /**
- * Expected HTTP response code.
- */
- unsigned int expected_response_code;
-
- /**
- * Should we retry on (transient) failures?
- */
- int do_retry;
-
-};
-
-
-/**
- * State for a "refresh link" CMD.
- */
-struct RefreshLinkState
-{
- /**
- * Link to a "refresh reveal" command.
- */
- const char *reveal_reference;
-
- /**
- * Handle to the ongoing operation.
- */
- struct TALER_EXCHANGE_RefreshLinkHandle *rlh;
-
- /**
- * Interpreter state.
- */
- struct TALER_TESTING_Interpreter *is;
-
- /**
- * Task scheduled to try later.
- */
- struct GNUNET_SCHEDULER_Task *retry_task;
-
- /**
- * How long do we wait until we retry?
- */
- struct GNUNET_TIME_Relative backoff;
-
- /**
- * Expected HTTP response code.
- */
- unsigned int expected_response_code;
-
- /**
- * Should we retry on (transient) failures?
- */
- int do_retry;
-
-};
-
-
-/**
- * Run the command.
- *
- * @param cls closure.
- * @param cmd the command to execute.
- * @param is the interpreter state.
- */
-static void
-refresh_reveal_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is);
-
-
-/**
- * Task scheduled to re-try #refresh_reveal_run.
- *
- * @param cls a `struct RefreshRevealState`
- */
-static void
-do_reveal_retry (void *cls)
-{
- struct RefreshRevealState *rrs = cls;
-
- rrs->retry_task = NULL;
- refresh_reveal_run (rrs,
- NULL,
- rrs->is);
-}
-
-
-/**
- * "refresh reveal" request callback; it checks that the response
- * code is expected and copies into its command's state the data
- * coming from the exchange, namely the fresh coins.
- *
- * @param cls closure.
- * @param http_status HTTP response code.
- * @param ec taler-specific error code.
- * @param num_coins number of fresh coins created, length of the
- * @a sigs and @a coin_privs arrays, 0 if the operation
- * failed.
- * @param coin_privs array of @a num_coins private keys for the
- * coins that were created, NULL on error.
- * @param sigs array of signature over @a num_coins coins,
- * NULL on error.
- * @param full_response raw exchange response.
- */
-static void
-reveal_cb (void *cls,
- unsigned int http_status,
- enum TALER_ErrorCode ec,
- unsigned int num_coins,
- const struct TALER_PlanchetSecretsP *coin_privs,
- const struct TALER_DenominationSignature *sigs,
- const json_t *full_response)
-{
- struct RefreshRevealState *rrs = cls;
- const struct TALER_TESTING_Command *melt_cmd;
-
- rrs->rrh = NULL;
- if (rrs->expected_response_code != http_status)
- {
- if (GNUNET_YES == rrs->do_retry)
- {
- if ( (0 == http_status) ||
- (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) ||
- (MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) )
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Retrying refresh reveal failed with %u/%d\n",
- http_status,
- (int) ec);
- /* on DB conflicts, do not use backoff */
- if (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec)
- rrs->backoff = GNUNET_TIME_UNIT_ZERO;
- else
- rrs->backoff = EXCHANGE_LIB_BACKOFF (rrs->backoff);
- rrs->retry_task = GNUNET_SCHEDULER_add_delayed (rrs->backoff,
- &do_reveal_retry,
- rrs);
- return;
- }
- }
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u/%d to command %s in %s:%u\n",
- http_status,
- (int) ec,
- rrs->is->commands[rrs->is->ip].label,
- __FILE__,
- __LINE__);
- json_dumpf (full_response, stderr, 0);
- TALER_TESTING_interpreter_fail (rrs->is);
- return;
- }
- melt_cmd = TALER_TESTING_interpreter_lookup_command
- (rrs->is, rrs->melt_reference);
- if (NULL == melt_cmd)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (rrs->is);
- return;
- }
- rrs->num_fresh_coins = num_coins;
- switch (http_status)
- {
- case MHD_HTTP_OK:
- rrs->fresh_coins = GNUNET_new_array (num_coins,
- struct TALER_TESTING_FreshCoinData);
- for (unsigned int i = 0; i<num_coins; i++)
- {
- struct TALER_TESTING_FreshCoinData *fc = &rrs->fresh_coins[i];
-
- if (GNUNET_OK !=
- TALER_TESTING_get_trait_denom_pub (melt_cmd,
- i,
- &fc->pk))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (rrs->is);
- return;
- }
- fc->coin_priv = coin_privs[i].coin_priv;
- fc->blinding_key = coin_privs[i].blinding_key;
- fc->sig.rsa_signature = GNUNET_CRYPTO_rsa_signature_dup
- (sigs[i].rsa_signature);
- }
- break;
- default:
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Unknown HTTP status %d\n",
- http_status);
- }
- TALER_TESTING_interpreter_next (rrs->is);
-}
-
-
-/**
- * Run the command.
- *
- * @param cls closure.
- * @param cmd the command to execute.
- * @param is the interpreter state.
- */
-static void
-refresh_reveal_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is)
-{
- struct RefreshRevealState *rrs = cls;
- struct RefreshMeltState *rms;
- const struct TALER_TESTING_Command *melt_cmd;
-
- rrs->is = is;
- melt_cmd = TALER_TESTING_interpreter_lookup_command
- (is, rrs->melt_reference);
-
- if (NULL == melt_cmd)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (rrs->is);
- return;
- }
- rms = melt_cmd->cls;
- rrs->rrh = TALER_EXCHANGE_refresh_reveal
- (is->exchange,
- rms->refresh_data_length,
- rms->refresh_data,
- rms->noreveal_index,
- &reveal_cb, rrs);
-
- if (NULL == rrs->rrh)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
-}
-
-
-/**
- * Free the state from a "refresh reveal" CMD, and possibly
- * cancel a pending operation thereof.
- *
- * @param cls closure.
- * @param cmd the command which is being cleaned up.
- */
-static void
-refresh_reveal_cleanup (void *cls,
- const struct TALER_TESTING_Command *cmd)
-{
- struct RefreshRevealState *rrs = cls;
-
- if (NULL != rrs->rrh)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Command %u (%s) did not complete\n",
- rrs->is->ip,
- cmd->label);
-
- TALER_EXCHANGE_refresh_reveal_cancel (rrs->rrh);
- rrs->rrh = NULL;
- }
- if (NULL != rrs->retry_task)
- {
- GNUNET_SCHEDULER_cancel (rrs->retry_task);
- rrs->retry_task = NULL;
- }
-
- for (unsigned int j = 0; j < rrs->num_fresh_coins; j++)
- GNUNET_CRYPTO_rsa_signature_free (rrs->fresh_coins[j].sig.rsa_signature);
-
- GNUNET_free_non_null (rrs->fresh_coins);
- rrs->fresh_coins = NULL;
- rrs->num_fresh_coins = 0;
- GNUNET_free (rrs);
-}
-
-
-/**
- * Run the command.
- *
- * @param cls closure.
- * @param cmd the command to execute.
- * @param is the interpreter state.
- */
-static void
-refresh_link_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is);
-
-
-/**
- * Task scheduled to re-try #refresh_link_run.
- *
- * @param cls a `struct RefreshLinkState`
- */
-static void
-do_link_retry (void *cls)
-{
- struct RefreshLinkState *rls = cls;
-
- rls->retry_task = NULL;
- refresh_link_run (rls,
- NULL,
- rls->is);
-}
-
-
-/**
- * "refresh link" operation callback, checks that HTTP response
- * code is expected _and_ that all the linked coins were actually
- * withdrawn by the "refresh reveal" CMD.
- *
- * @param cls closure.
- * @param http_status HTTP response code.
- * @param ec taler-specific error code
- * @param num_coins number of fresh coins created, length of the
- * @a sigs and @a coin_privs arrays, 0 if the operation
- * failed.
- * @param coin_privs array of @a num_coins private keys for the
- * coins that were created, NULL on error.
- * @param sigs array of signature over @a num_coins coins, NULL on
- * error.
- * @param pubs array of public keys for the @a sigs,
- * NULL on error.
- * @param full_response raw response from the exchange.
- */
-static void
-link_cb (void *cls,
- unsigned int http_status,
- enum TALER_ErrorCode ec,
- unsigned int num_coins,
- const struct TALER_CoinSpendPrivateKeyP *coin_privs,
- const struct TALER_DenominationSignature *sigs,
- const struct TALER_DenominationPublicKey *pubs,
- const json_t *full_response)
-{
-
- struct RefreshLinkState *rls = cls;
- const struct TALER_TESTING_Command *reveal_cmd;
- struct TALER_TESTING_Command *link_cmd
- = &rls->is->commands[rls->is->ip];
- unsigned int found;
- const unsigned int *num_fresh_coins;
-
- rls->rlh = NULL;
- if (rls->expected_response_code != http_status)
- {
- if (GNUNET_YES == rls->do_retry)
- {
- if ( (0 == http_status) ||
- (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) ||
- (MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) )
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Retrying refresh link failed with %u/%d\n",
- http_status,
- (int) ec);
- /* on DB conflicts, do not use backoff */
- if (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec)
- rls->backoff = GNUNET_TIME_UNIT_ZERO;
- else
- rls->backoff = EXCHANGE_LIB_BACKOFF (rls->backoff);
- rls->retry_task = GNUNET_SCHEDULER_add_delayed (rls->backoff,
- &do_link_retry,
- rls);
- return;
- }
- }
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u/%d to command %s in %s:%u\n",
- http_status,
- (int) ec,
- link_cmd->label,
- __FILE__,
- __LINE__);
- json_dumpf (full_response, stderr, 0);
- TALER_TESTING_interpreter_fail (rls->is);
- return;
- }
- reveal_cmd = TALER_TESTING_interpreter_lookup_command
- (rls->is, rls->reveal_reference);
-
- if (NULL == reveal_cmd)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (rls->is);
- return;
- }
-
- switch (http_status)
- {
- case MHD_HTTP_OK:
- /* check that number of coins returned matches */
- if (GNUNET_OK != TALER_TESTING_get_trait_uint
- (reveal_cmd, 0, &num_fresh_coins))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (rls->is);
- return;
- }
- if (num_coins != *num_fresh_coins)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected number of fresh coins: %d vs %d in %s:%u\n",
- num_coins,
- *num_fresh_coins,
- __FILE__,
- __LINE__);
- TALER_TESTING_interpreter_fail (rls->is);
- return;
- }
- /* check that the coins match */
- for (unsigned int i = 0; i<num_coins; i++)
- for (unsigned int j = i + 1; j<num_coins; j++)
- if (0 == GNUNET_memcmp
- (&coin_privs[i], &coin_privs[j]))
- GNUNET_break (0);
- /* Note: coins might be legitimately permutated in here... */
- found = 0;
-
- /* Will point to the pointer inside the cmd state. */
- const struct TALER_TESTING_FreshCoinData *fc = NULL;
-
- if (GNUNET_OK != TALER_TESTING_get_trait_fresh_coins
- (reveal_cmd, 0, &fc))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (rls->is);
- return;
- }
-
- for (unsigned int i = 0; i<num_coins; i++)
- for (unsigned int j = 0; j<num_coins; j++)
- {
- if ( (0 == GNUNET_memcmp
- (&coin_privs[i], &fc[j].coin_priv)) &&
- (0 == GNUNET_CRYPTO_rsa_signature_cmp
- (fc[i].sig.rsa_signature,
- sigs[j].rsa_signature)) &&
- (0 == GNUNET_CRYPTO_rsa_public_key_cmp
- (fc[i].pk->key.rsa_public_key,
- pubs[j].rsa_public_key)) )
- {
- found++;
- break;
- }
- }
- if (found != num_coins)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Only %u/%u coins match expectations\n",
- found, num_coins);
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (rls->is);
- return;
- }
- break;
- default:
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unknown HTTP response code %u.\n",
- http_status);
- }
- TALER_TESTING_interpreter_next (rls->is);
-}
-
-
-/**
- * Run the command.
- *
- * @param cls closure.
- * @param cmd the command to execute.
- * @param is the interpreter state.
- */
-static void
-refresh_link_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is)
-{
- struct RefreshLinkState *rls = cls;
- struct RefreshRevealState *rrs;
- struct RefreshMeltState *rms;
- const struct TALER_TESTING_Command *reveal_cmd;
- const struct TALER_TESTING_Command *melt_cmd;
- const struct TALER_TESTING_Command *coin_cmd;
-
- rls->is = is;
- reveal_cmd = TALER_TESTING_interpreter_lookup_command
- (rls->is, rls->reveal_reference);
-
- if (NULL == reveal_cmd)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (rls->is);
- return;
- }
- rrs = reveal_cmd->cls;
- melt_cmd = TALER_TESTING_interpreter_lookup_command
- (rls->is, rrs->melt_reference);
-
- if (NULL == melt_cmd)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (rls->is);
- return;
- }
-
- /* find reserve_withdraw command */
- {
- rms = melt_cmd->cls;
- coin_cmd = TALER_TESTING_interpreter_lookup_command
- (rls->is, rms->coin_reference);
- if (NULL == coin_cmd)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (rls->is);
- return;
- }
- }
-
- const struct TALER_CoinSpendPrivateKeyP *coin_priv;
- if (GNUNET_OK != TALER_TESTING_get_trait_coin_priv
- (coin_cmd, 0, &coin_priv))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (rls->is);
- return;
- }
-
- /* finally, use private key from withdraw sign command */
- rls->rlh = TALER_EXCHANGE_refresh_link
- (is->exchange, coin_priv, &link_cb, rls);
-
- if (NULL == rls->rlh)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (rls->is);
- return;
- }
-}
-
-
-/**
- * Free the state of the "refresh link" CMD, and possibly
- * cancel a operation thereof.
- *
- * @param cls closure
- * @param cmd the command which is being cleaned up.
- */
-static void
-refresh_link_cleanup (void *cls,
- const struct TALER_TESTING_Command *cmd)
-{
- struct RefreshLinkState *rls = cls;
-
- if (NULL != rls->rlh)
- {
-
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Command %u (%s) did not complete\n",
- rls->is->ip,
- cmd->label);
- TALER_EXCHANGE_refresh_link_cancel (rls->rlh);
- rls->rlh = NULL;
- }
- if (NULL != rls->retry_task)
- {
- GNUNET_SCHEDULER_cancel (rls->retry_task);
- rls->retry_task = NULL;
- }
- GNUNET_free (rls);
-}
-
-
-/**
- * Run the command.
- *
- * @param cls closure.
- * @param cmd the command to execute.
- * @param is the interpreter state.
- */
-static void
-refresh_melt_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is);
-
-
-/**
- * Task scheduled to re-try #refresh_melt_run.
- *
- * @param cls a `struct RefreshMeltState`
- */
-static void
-do_melt_retry (void *cls)
-{
- struct RefreshMeltState *rms = cls;
-
- rms->retry_task = NULL;
- refresh_melt_run (rms,
- NULL,
- rms->is);
-}
-
-
-/**
- * Callback for a "refresh melt" operation; checks if the HTTP
- * response code is okay and re-run the melt operation if the
- * CMD was set to do so.
- *
- * @param cls closure.
- * @param http_status HTTP response code.
- * @param ec taler-specific error code.
- * @param noreveal_index choice by the exchange in the
- * cut-and-choose protocol, UINT16_MAX on error.
- * @param exchange_pub public key the exchange used for signing.
- * @param full_response raw response body from the exchange.
- */
-static void
-melt_cb (void *cls,
- unsigned int http_status,
- enum TALER_ErrorCode ec,
- uint32_t noreveal_index,
- const struct TALER_ExchangePublicKeyP *exchange_pub,
- const json_t *full_response)
-{
- struct RefreshMeltState *rms = cls;
-
- rms->rmh = NULL;
- if (rms->expected_response_code != http_status)
- {
- if (GNUNET_YES == rms->do_retry)
- {
- if ( (0 == http_status) ||
- (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) ||
- (MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) )
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Retrying refresh melt failed with %u/%d\n",
- http_status,
- (int) ec);
- /* on DB conflicts, do not use backoff */
- if (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec)
- rms->backoff = GNUNET_TIME_UNIT_ZERO;
- else
- rms->backoff = EXCHANGE_LIB_BACKOFF (rms->backoff);
- rms->retry_task = GNUNET_SCHEDULER_add_delayed
- (rms->backoff,
- &do_melt_retry,
- rms);
- return;
- }
- }
- GNUNET_log
- (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u/%d to command %s in %s:%u\n",
- http_status,
- (int) ec,
- rms->is->commands[rms->is->ip].label,
- __FILE__,
- __LINE__);
- json_dumpf (full_response, stderr, 0);
- TALER_TESTING_interpreter_fail (rms->is);
- return;
- }
- rms->noreveal_index = noreveal_index;
-
- if (GNUNET_YES == rms->double_melt)
- {
- TALER_LOG_DEBUG ("Doubling the melt (%s)\n",
- rms->is->commands[rms->is->ip].label);
- rms->rmh = TALER_EXCHANGE_refresh_melt
- (rms->is->exchange, rms->refresh_data_length,
- rms->refresh_data, &melt_cb, rms);
- rms->double_melt = GNUNET_NO;
- return;
- }
- TALER_TESTING_interpreter_next (rms->is);
-}
-
-
-/**
- * Run the command.
- *
- * @param cls closure.
- * @param cmd the command to execute.
- * @param is the interpreter state.
- */
-static void
-refresh_melt_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is)
-{
- struct RefreshMeltState *rms = cls;
- unsigned int num_fresh_coins;
- const char *default_melt_fresh_amounts[] = {
- "EUR:1", "EUR:1", "EUR:1", "EUR:0.1",
- NULL
- };
- const char **melt_fresh_amounts;
-
- if (NULL == (melt_fresh_amounts = rms->melt_fresh_amounts))
- melt_fresh_amounts = default_melt_fresh_amounts;
- rms->is = is;
- rms->noreveal_index = UINT16_MAX;
- for (num_fresh_coins = 0;
- NULL != melt_fresh_amounts[num_fresh_coins];
- num_fresh_coins++)
- ;
- rms->num_fresh_coins = num_fresh_coins;
- rms->fresh_pks = GNUNET_new_array
- (num_fresh_coins,
- struct TALER_EXCHANGE_DenomPublicKey);
- {
- struct TALER_Amount melt_amount;
- struct TALER_Amount fresh_amount;
- const struct TALER_DenominationSignature *melt_sig;
- const struct TALER_EXCHANGE_DenomPublicKey *melt_denom_pub;
- const struct TALER_TESTING_Command *coin_command;
-
- if (NULL == (coin_command
- = TALER_TESTING_interpreter_lookup_command
- (is, rms->coin_reference)))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (rms->is);
- return;
- }
-
- if (GNUNET_OK != TALER_TESTING_get_trait_coin_priv
- (coin_command, 0, &rms->melt_priv))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (rms->is);
- return;
- }
-
- if (GNUNET_OK !=
- TALER_TESTING_get_trait_denom_sig (coin_command,
- 0,
- &melt_sig))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (rms->is);
- return;
- }
- if (GNUNET_OK != TALER_TESTING_get_trait_denom_pub
- (coin_command, 0, &melt_denom_pub))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (rms->is);
- return;
- }
- /* Melt amount starts with the melt fee of the old coin; we'll add the
- values and withdraw fees of the fresh coins next */
- melt_amount = melt_denom_pub->fee_refresh;
- for (unsigned int i = 0; i<num_fresh_coins; i++)
- {
- const struct TALER_EXCHANGE_DenomPublicKey *fresh_pk;
-
- if (GNUNET_OK != TALER_string_to_amount
- (melt_fresh_amounts[i], &fresh_amount))
- {
- GNUNET_break (0);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to parse amount `%s' at index %u\n",
- melt_fresh_amounts[i], i);
- TALER_TESTING_interpreter_fail (rms->is);
- return;
- }
- fresh_pk = TALER_TESTING_find_pk
- (TALER_EXCHANGE_get_keys (is->exchange), &fresh_amount);
- if (NULL == fresh_pk)
- {
- GNUNET_break (0);
- /* Subroutine logs specific error */
- TALER_TESTING_interpreter_fail (rms->is);
- return;
- }
- GNUNET_assert (GNUNET_OK ==
- TALER_amount_add (&melt_amount,
- &melt_amount,
- &fresh_amount));
- GNUNET_assert (GNUNET_OK ==
- TALER_amount_add (&melt_amount,
- &melt_amount,
- &fresh_pk->fee_withdraw));
- rms->fresh_pks[i] = *fresh_pk;
- /* Make a deep copy of the RSA key */
- rms->fresh_pks[i].key.rsa_public_key
- = GNUNET_CRYPTO_rsa_public_key_dup (fresh_pk->key.rsa_public_key);
- }
- rms->refresh_data
- = TALER_EXCHANGE_refresh_prepare (rms->melt_priv,
- &melt_amount,
- melt_sig,
- melt_denom_pub,
- num_fresh_coins,
- rms->fresh_pks,
- &rms->refresh_data_length);
-
- if (NULL == rms->refresh_data)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (rms->is);
- return;
- }
- rms->rmh = TALER_EXCHANGE_refresh_melt (is->exchange,
- rms->refresh_data_length,
- rms->refresh_data,
- &melt_cb,
- rms);
-
- if (NULL == rms->rmh)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (rms->is);
- return;
- }
- }
-}
-
-
-/**
- * Free the "refresh melt" CMD state, and possibly cancel a
- * pending operation thereof.
- *
- * @param cls closure, must be a `struct RefreshMeltState`.
- * @param cmd the command which is being cleaned up.
- */
-static void
-refresh_melt_cleanup (void *cls,
- const struct TALER_TESTING_Command *cmd)
-{
- struct RefreshMeltState *rms = cls;
-
- if (NULL != rms->rmh)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Command %u (%s) did not complete\n",
- rms->is->ip, rms->is->commands[rms->is->ip].label);
- TALER_EXCHANGE_refresh_melt_cancel (rms->rmh);
- rms->rmh = NULL;
- }
- if (NULL != rms->retry_task)
- {
- GNUNET_SCHEDULER_cancel (rms->retry_task);
- rms->retry_task = NULL;
- }
- if (NULL != rms->fresh_pks)
- {
- for (unsigned int i = 0; i < rms->num_fresh_coins; i++)
- GNUNET_CRYPTO_rsa_public_key_free (rms->fresh_pks[i].key.rsa_public_key);
- }
- GNUNET_free_non_null (rms->fresh_pks);
- rms->fresh_pks = NULL;
- GNUNET_free_non_null (rms->refresh_data);
- rms->refresh_data = NULL;
- rms->refresh_data_length = 0;
- GNUNET_free_non_null (rms->melt_fresh_amounts);
- GNUNET_free (rms);
-}
-
-
-/**
- * Offer internal data to the "refresh melt" CMD.
- *
- * @param cls closure.
- * @param[out] ret result (could be anything).
- * @param trait name of the trait.
- * @param index index number of the object to offer.
- * @return #GNUNET_OK on success.
- */
-static int
-refresh_melt_traits (void *cls,
- const void **ret,
- const char *trait,
- unsigned int index)
-{
- struct RefreshMeltState *rms = cls;
-
- if (index >= rms->num_fresh_coins)
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- {
- struct TALER_TESTING_Trait traits[] = {
- TALER_TESTING_make_trait_denom_pub (index, &rms->fresh_pks[index]),
- TALER_TESTING_make_trait_coin_priv (0, rms->melt_priv),
- TALER_TESTING_trait_end ()
- };
-
- return TALER_TESTING_get_trait (traits,
- ret,
- trait,
- index);
- }
-}
-
-
-/**
- * Parse list of amounts for melt operation.
- *
- * @param[in,out] rms where to store the list
- * @param ap NULL-termianted list of amounts to be melted (one per fresh coin)
- * @return #GNUNET_OK on success
- */
-static int
-parse_amounts (struct RefreshMeltState *rms,
- va_list ap)
-{
- unsigned int len;
- unsigned int off;
- const char *amount;
-
- len = 0;
- off = 0;
- while (NULL != (amount = va_arg (ap, const char *)))
- {
- if (len == off)
- {
- struct TALER_Amount a;
-
- GNUNET_array_grow (rms->melt_fresh_amounts,
- len,
- off + 16);
- if (GNUNET_OK !=
- TALER_string_to_amount (amount, &a))
- {
- GNUNET_break (0);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to parse amount `%s' at index %u\n",
- amount, off);
- GNUNET_free (rms->melt_fresh_amounts);
- rms->melt_fresh_amounts = NULL;
- return GNUNET_SYSERR;
- }
- rms->melt_fresh_amounts[off++] = amount;
- }
- }
- if (0 == off)
- return GNUNET_OK; /* no amounts given == use defaults! */
- /* ensure NULL-termination */
- GNUNET_array_grow (rms->melt_fresh_amounts,
- len,
- off + 1);
- return GNUNET_OK;
-}
-
-
-/**
- * Create a "refresh melt" command.
- *
- * @param label command label.
- * @param coin_reference reference to a command
- * that will provide a coin to refresh.
- * @param expected_response_code expected HTTP code.
- * @param ... NULL-terminated list of amounts to be melted
- * @return the command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_refresh_melt (const char *label,
- const char *coin_reference,
- unsigned int expected_response_code,
- ...)
-{
- struct RefreshMeltState *rms;
- va_list ap;
-
- rms = GNUNET_new (struct RefreshMeltState);
- rms->coin_reference = coin_reference;
- rms->expected_response_code = expected_response_code;
- va_start (ap, expected_response_code);
- GNUNET_assert (GNUNET_OK ==
- parse_amounts (rms, ap));
- va_end (ap);
- {
- struct TALER_TESTING_Command cmd = {
- .label = label,
- .cls = rms,
- .run = &refresh_melt_run,
- .cleanup = &refresh_melt_cleanup,
- .traits = &refresh_melt_traits
- };
-
- return cmd;
- }
-}
-
-
-/**
- * Create a "refresh melt" CMD that does TWO /refresh/melt
- * requests. This was needed to test the replay of a valid melt
- * request, see #5312.
- *
- * @param label command label
- * @param coin_reference reference to a command that will provide
- * a coin to refresh
- * @param expected_response_code expected HTTP code
- * @param ... NULL-terminated list of amounts to be melted
- * @return the command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_refresh_melt_double (const char *label,
- const char *coin_reference,
- unsigned int expected_response_code,
- ...)
-{
- struct RefreshMeltState *rms;
- va_list ap;
-
- rms = GNUNET_new (struct RefreshMeltState);
- rms->coin_reference = coin_reference;
- rms->expected_response_code = expected_response_code;
- rms->double_melt = GNUNET_YES;
- va_start (ap, expected_response_code);
- GNUNET_assert (GNUNET_OK ==
- parse_amounts (rms, ap));
- va_end (ap);
- {
- struct TALER_TESTING_Command cmd = {
- .label = label,
- .cls = rms,
- .run = &refresh_melt_run,
- .cleanup = &refresh_melt_cleanup,
- .traits = &refresh_melt_traits
- };
-
- return cmd;
- }
-}
-
-
-/**
- * Modify a "refresh melt" command to enable retries.
- *
- * @param cmd command
- * @return modified command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_refresh_melt_with_retry (struct TALER_TESTING_Command cmd)
-{
- struct RefreshMeltState *rms;
-
- GNUNET_assert (&refresh_melt_run == cmd.run);
- rms = cmd.cls;
- rms->do_retry = GNUNET_YES;
- return cmd;
-}
-
-
-/**
- * Offer internal data from a "refresh reveal" CMD.
- *
- * @param cls closure.
- * @param[out] ret result (could be anything).
- * @param trait name of the trait.
- * @param index index number of the object to offer.
- * @return #GNUNET_OK on success.
- */
-static int
-refresh_reveal_traits (void *cls,
- const void **ret,
- const char *trait,
- unsigned int index)
-{
- struct RefreshRevealState *rrs = cls;
- unsigned int num_coins = rrs->num_fresh_coins;
-#define NUM_TRAITS ((num_coins * 4) + 3)
- struct TALER_TESTING_Trait traits[NUM_TRAITS];
-
- /* Making coin privs traits */
- for (unsigned int i = 0; i<num_coins; i++)
- traits[i] = TALER_TESTING_make_trait_coin_priv
- (i, &rrs->fresh_coins[i].coin_priv);
-
- /* Making denom pubs traits */
- for (unsigned int i = 0; i<num_coins; i++)
- traits[num_coins + i]
- = TALER_TESTING_make_trait_denom_pub
- (i, rrs->fresh_coins[i].pk);
-
- /* Making denom sigs traits */
- for (unsigned int i = 0; i<num_coins; i++)
- traits[(num_coins * 2) + i]
- = TALER_TESTING_make_trait_denom_sig
- (i, &rrs->fresh_coins[i].sig);
- /* blinding key traits */
- for (unsigned int i = 0; i<num_coins; i++)
- traits[(num_coins * 3) + i]
- = TALER_TESTING_make_trait_blinding_key (i,
- &rrs->fresh_coins[i].blinding_key),
-
- /* number of fresh coins */
- traits[(num_coins * 4)] = TALER_TESTING_make_trait_uint
- (0, &rrs->num_fresh_coins);
-
- /* whole array of fresh coins */
- traits[(num_coins * 4) + 1]
- = TALER_TESTING_make_trait_fresh_coins (0, rrs->fresh_coins),
-
- /* end of traits */
- traits[(num_coins * 4) + 2] = TALER_TESTING_trait_end ();
-
- return TALER_TESTING_get_trait (traits,
- ret,
- trait,
- index);
-}
-
-
-/**
- * Create a "refresh reveal" command.
- *
- * @param label command label.
- * @param melt_reference reference to a "refresh melt" command.
- * @param expected_response_code expected HTTP response code.
- * @return the command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_refresh_reveal (const char *label,
- const char *melt_reference,
- unsigned int expected_response_code)
-{
- struct RefreshRevealState *rrs;
-
- rrs = GNUNET_new (struct RefreshRevealState);
- rrs->melt_reference = melt_reference;
- rrs->expected_response_code = expected_response_code;
- {
- struct TALER_TESTING_Command cmd = {
- .cls = rrs,
- .label = label,
- .run = &refresh_reveal_run,
- .cleanup = &refresh_reveal_cleanup,
- .traits = &refresh_reveal_traits
- };
-
- return cmd;
- }
-}
-
-
-/**
- * Modify a "refresh reveal" command to enable retries.
- *
- * @param cmd command
- * @return modified command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_refresh_reveal_with_retry (struct TALER_TESTING_Command cmd)
-{
- struct RefreshRevealState *rrs;
-
- GNUNET_assert (&refresh_reveal_run == cmd.run);
- rrs = cmd.cls;
- rrs->do_retry = GNUNET_YES;
- return cmd;
-}
-
-
-/**
- * Create a "refresh link" command.
- *
- * @param label command label.
- * @param reveal_reference reference to a "refresh reveal" CMD.
- * @param expected_response_code expected HTTP response code
- * @return the "refresh link" command
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_refresh_link (const char *label,
- const char *reveal_reference,
- unsigned int expected_response_code)
-{
- struct RefreshLinkState *rrs;
-
- rrs = GNUNET_new (struct RefreshLinkState);
- rrs->reveal_reference = reveal_reference;
- rrs->expected_response_code = expected_response_code;
- {
- struct TALER_TESTING_Command cmd = {
- .cls = rrs,
- .label = label,
- .run = &refresh_link_run,
- .cleanup = &refresh_link_cleanup
- };
-
- return cmd;
- }
-}
-
-
-/**
- * Modify a "refresh link" command to enable retries.
- *
- * @param cmd command
- * @return modified command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_refresh_link_with_retry (struct TALER_TESTING_Command cmd)
-{
- struct RefreshLinkState *rls;
-
- GNUNET_assert (&refresh_link_run == cmd.run);
- rls = cmd.cls;
- rls->do_retry = GNUNET_YES;
- return cmd;
-}