diff options
Diffstat (limited to 'src/mint-lib/test_mint_api.c')
-rw-r--r-- | src/mint-lib/test_mint_api.c | 2599 |
1 files changed, 0 insertions, 2599 deletions
diff --git a/src/mint-lib/test_mint_api.c b/src/mint-lib/test_mint_api.c deleted file mode 100644 index b243cc2cf..000000000 --- a/src/mint-lib/test_mint_api.c +++ /dev/null @@ -1,2599 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015, 2016 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - 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, If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file mint/test_mint_api.c - * @brief testcase to test mint's HTTP API interface - * @author Sree Harsha Totakura <sreeharsha@totakura.in> - * @author Christian Grothoff - */ -#include "platform.h" -#include "taler_util.h" -#include "taler_signatures.h" -#include "taler_mint_service.h" -#include <gnunet/gnunet_util_lib.h> -#include <microhttpd.h> - -/** - * Is the configuration file is set to include wire format 'test'? - */ -#define WIRE_TEST 1 - -/** - * Is the configuration file is set to include wire format 'sepa'? - */ -#define WIRE_SEPA 1 - -/** - * Main execution context for the main loop. - */ -static struct TALER_MINT_Context *ctx; - -/** - * Handle to access the mint. - */ -static struct TALER_MINT_Handle *mint; - -/** - * Task run on shutdown. - */ -static struct GNUNET_SCHEDULER_Task *shutdown_task; - -/** - * Task that runs the main event loop. - */ -static struct GNUNET_SCHEDULER_Task *ctx_task; - -/** - * Result of the testcases, #GNUNET_OK on success - */ -static int result; - - -/** - * Opcodes for the interpreter. - */ -enum OpCode -{ - /** - * Termination code, stops the interpreter loop (with success). - */ - OC_END = 0, - - /** - * Add funds to a reserve by (faking) incoming wire transfer. - */ - OC_ADMIN_ADD_INCOMING, - - /** - * Check status of a reserve. - */ - OC_WITHDRAW_STATUS, - - /** - * Withdraw a coin from a reserve. - */ - OC_WITHDRAW_SIGN, - - /** - * Deposit a coin (pay with it). - */ - OC_DEPOSIT, - - /** - * Melt a (set of) coins. - */ - OC_REFRESH_MELT, - - /** - * Complete melting session by withdrawing melted coins. - */ - OC_REFRESH_REVEAL, - - /** - * Verify mint's /refresh/link by linking original private key to - * results from #OC_REFRESH_REVEAL step. - */ - OC_REFRESH_LINK, - - /** - * Verify the mint's /wire-method. - */ - OC_WIRE, - - /** - * Verify mint's /wire/deposits method. - */ - OC_WIRE_DEPOSITS, - - /** - * Verify mint's /deposit/wtid method. - */ - OC_DEPOSIT_WTID - -}; - - -/** - * Structure specifying details about a coin to be melted. - * Used in a NULL-terminated array as part of command - * specification. - */ -struct MeltDetails -{ - - /** - * Amount to melt (including fee). - */ - const char *amount; - - /** - * Reference to reserve_withdraw operations for coin to - * be used for the /refresh/melt operation. - */ - const char *coin_ref; - -}; - - -/** - * Information about a fresh coin generated by the refresh operation. - */ -struct FreshCoin -{ - - /** - * 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_MINT_DenomPublicKey *pk; - - /** - * Set (by the interpreter) to the mint'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; - -}; - - -/** - * Details for a mint operation to execute. - */ -struct Command -{ - /** - * Opcode of the command. - */ - enum OpCode oc; - - /** - * Label for the command, can be NULL. - */ - const char *label; - - /** - * Which response code do we expect for this command? - */ - unsigned int expected_response_code; - - /** - * Details about the command. - */ - union - { - - /** - * Information for a #OC_ADMIN_ADD_INCOMING command. - */ - struct - { - - /** - * Label to another admin_add_incoming command if we - * should deposit into an existing reserve, NULL if - * a fresh reserve should be created. - */ - const char *reserve_reference; - - /** - * String describing the amount to add to the reserve. - */ - const char *amount; - - /** - * Wire details (JSON). - */ - const char *wire; - - /** - * Set (by the interpreter) to the reserve's private key - * we used to fill the reserve. - */ - struct TALER_ReservePrivateKeyP reserve_priv; - - /** - * Set to the API's handle during the operation. - */ - struct TALER_MINT_AdminAddIncomingHandle *aih; - - } admin_add_incoming; - - /** - * Information for a #OC_WITHDRAW_STATUS command. - */ - struct - { - - /** - * Label to the #OC_ADMIN_ADD_INCOMING command which - * created the reserve. - */ - const char *reserve_reference; - - /** - * Set to the API's handle during the operation. - */ - struct TALER_MINT_ReserveStatusHandle *wsh; - - /** - * Expected reserve balance. - */ - const char *expected_balance; - - } reserve_status; - - /** - * Information for a #OC_WITHDRAW_SIGN command. - */ - struct - { - - /** - * Which reserve should we withdraw from? - */ - const char *reserve_reference; - - /** - * String describing the denomination value we should withdraw. - * A corresponding denomination key must exist in the mint's - * offerings. Can be NULL if @e pk is set instead. - */ - const char *amount; - - /** - * 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_MINT_DenomPublicKey *pk; - - /** - * Set (by the interpreter) to the mint'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; - - /** - * Blinding key used for the operation. - */ - struct TALER_DenominationBlindingKey blinding_key; - - /** - * Withdraw handle (while operation is running). - */ - struct TALER_MINT_ReserveWithdrawHandle *wsh; - - } reserve_withdraw; - - /** - * Information for a #OC_DEPOSIT command. - */ - struct - { - - /** - * Amount to deposit. - */ - const char *amount; - - /** - * Reference to a reserve_withdraw operation for a coin to - * be used for the /deposit operation. - */ - const char *coin_ref; - - /** - * If this @e coin_ref refers to an operation that generated - * an array of coins, this value determines which coin to use. - */ - unsigned int coin_idx; - - /** - * JSON string describing the merchant's "wire details". - */ - const char *wire_details; - - /** - * JSON string describing the contract between the two parties. - */ - const char *contract; - - /** - * Transaction ID to use. - */ - uint64_t transaction_id; - - /** - * Relative time (to add to 'now') to compute the refund deadline. - * Zero for no refunds. - */ - struct GNUNET_TIME_Relative refund_deadline; - - /** - * Set (by the interpreter) to a fresh private key of the merchant, - * if @e refund_deadline is non-zero. - */ - struct TALER_MerchantPrivateKeyP merchant_priv; - - /** - * Deposit handle while operation is running. - */ - struct TALER_MINT_DepositHandle *dh; - - } deposit; - - /** - * Information for a #OC_REFRESH_MELT command. - */ - struct - { - - /** - * Information about coins to be melted. - */ - struct MeltDetails *melted_coins; - - /** - * Denominations of the fresh coins to withdraw. - */ - const char **fresh_amounts; - - /** - * Array of the public keys corresponding to - * the @e fresh_amounts, set by the interpreter. - */ - const struct TALER_MINT_DenomPublicKey **fresh_pks; - - /** - * Melt handle while operation is running. - */ - struct TALER_MINT_RefreshMeltHandle *rmh; - - /** - * Data used in the refresh operation, set by the interpreter. - */ - char *refresh_data; - - /** - * Number of bytes in @e refresh_data, set by the interpreter. - */ - size_t refresh_data_length; - - /** - * Set by the interpreter (upon completion) to the noreveal - * index selected by the mint. - */ - uint16_t noreveal_index; - - } refresh_melt; - - /** - * Information for a #OC_REFRESH_REVEAL command. - */ - struct - { - - /** - * Melt operation this is the matching reveal for. - */ - const char *melt_ref; - - /** - * Reveal handle while operation is running. - */ - struct TALER_MINT_RefreshRevealHandle *rrh; - - /** - * Number of fresh coins withdrawn, set by the interpreter. - * Length of the @e fresh_coins array. - */ - unsigned int num_fresh_coins; - - /** - * Information about coins withdrawn, set by the interpreter. - */ - struct FreshCoin *fresh_coins; - - } refresh_reveal; - - /** - * Information for a #OC_REFRESH_LINK command. - */ - struct - { - - /** - * Reveal operation this is the matching link for. - */ - const char *reveal_ref; - - /** - * Link handle while operation is running. - */ - struct TALER_MINT_RefreshLinkHandle *rlh; - - /** - * Which of the melted coins should be used for the linkage? - */ - unsigned int coin_idx; - - } refresh_link; - - /** - * Information for the /wire command. - */ - struct { - - /** - * Handle to the wire request. - */ - struct TALER_MINT_WireHandle *wh; - - /** - * Format we expect to see, others will be *ignored*. - */ - const char *format; - - } wire; - - /** - * Information for the /wire/deposits's command. - */ - struct { - - /** - * Handle to the wire deposits request. - */ - struct TALER_MINT_WireDepositsHandle *wdh; - - /** - * Reference to a /deposit/wtid command. If set, we use the - * WTID from that command. - */ - const char *wtid_ref; - - /** - * WTID to use (used if @e wtid_ref is NULL). - */ - struct TALER_WireTransferIdentifierRawP wtid; - - /* TODO: may want to add list of deposits we expected - to see aggregated here in the future. */ - - } wire_deposits; - - /** - * Information for the /deposit/wtid command. - */ - struct { - - /** - * Handle to the deposit wtid request. - */ - struct TALER_MINT_DepositWtidHandle *dwh; - - /** - * Which /deposit operation should we obtain WTID data for? - */ - const char *deposit_ref; - - /** - * What is the expected total amount? Only used if - * @e expected_response_code was #MHD_HTTP_OK. - */ - struct TALER_Amount total_amount_expected; - - /** - * Wire transfer identifier, set if #MHD_HTTP_OK was the response code. - */ - struct TALER_WireTransferIdentifierRawP wtid; - - } deposit_wtid; - - } details; - -}; - - -/** - * State of the interpreter loop. - */ -struct InterpreterState -{ - /** - * Keys from the mint. - */ - const struct TALER_MINT_Keys *keys; - - /** - * Commands the interpreter will run. - */ - struct Command *commands; - - /** - * Interpreter task (if one is scheduled). - */ - struct GNUNET_SCHEDULER_Task *task; - - /** - * Instruction pointer. Tells #interpreter_run() which - * instruction to run next. - */ - unsigned int ip; - -}; - - -/** - * Task that runs the context's event loop with the GNUnet scheduler. - * - * @param cls unused - * @param tc scheduler context (unused) - */ -static void -context_task (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc); - - -/** - * Run the context task, the working set has changed. - */ -static void -trigger_context_task () -{ - GNUNET_SCHEDULER_cancel (ctx_task); - ctx_task = GNUNET_SCHEDULER_add_now (&context_task, - NULL); -} - - -/** - * The testcase failed, return with an error code. - * - * @param is interpreter state to clean up - */ -static void -fail (struct InterpreterState *is) -{ - result = GNUNET_SYSERR; - GNUNET_SCHEDULER_shutdown (); -} - - -/** - * Find a command by label. - * - * @param is interpreter state to search - * @param label label to look for - * @return NULL if command was not found - */ -static const struct Command * -find_command (const struct InterpreterState *is, - const char *label) -{ - unsigned int i; - const struct Command *cmd; - - if (NULL == label) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Attempt to lookup command for empty label\n"); - return NULL; - } - for (i=0;OC_END != (cmd = &is->commands[i])->oc;i++) - if ( (NULL != cmd->label) && - (0 == strcmp (cmd->label, - label)) ) - return cmd; - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command not found: %s\n", - label); - return NULL; -} - - -/** - * Run the main interpreter loop that performs mint operations. - * - * @param cls contains the `struct InterpreterState` - * @param tc scheduler context - */ -static void -interpreter_run (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc); - - -/** - * Function called upon completion of our /admin/add/incoming request. - * - * @param cls closure with the interpreter state - * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request - * 0 if the mint's reply is bogus (fails to follow the protocol) - * @param full_response full response from the mint (for logging, in case of errors) - */ -static void -add_incoming_cb (void *cls, - unsigned int http_status, - json_t *full_response) -{ - struct InterpreterState *is = cls; - struct Command *cmd = &is->commands[is->ip]; - - cmd->details.admin_add_incoming.aih = NULL; - if (MHD_HTTP_OK != http_status) - { - GNUNET_break (0); - fail (is); - return; - } - is->ip++; - is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, - is); -} - - -/** - * Check if the given historic event @a h corresponds to the given - * command @a cmd. - * - * @param h event in history - * @param cmd an #OC_ADMIN_ADD_INCOMING command - * @return #GNUNET_OK if they match, #GNUNET_SYSERR if not - */ -static int -compare_admin_add_incoming_history (const struct TALER_MINT_ReserveHistory *h, - const struct Command *cmd) -{ - struct TALER_Amount amount; - - if (TALER_MINT_RTT_DEPOSIT != h->type) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - GNUNET_assert (GNUNET_OK == - TALER_string_to_amount (cmd->details.admin_add_incoming.amount, - &amount)); - if (0 != TALER_amount_cmp (&amount, - &h->amount)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/** - * Check if the given historic event @a h corresponds to the given - * command @a cmd. - * - * @param h event in history - * @param cmd an #OC_WITHDRAW_SIGN command - * @return #GNUNET_OK if they match, #GNUNET_SYSERR if not - */ -static int -compare_reserve_withdraw_history (const struct TALER_MINT_ReserveHistory *h, - const struct Command *cmd) -{ - struct TALER_Amount amount; - struct TALER_Amount amount_with_fee; - - if (TALER_MINT_RTT_WITHDRAWAL != h->type) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - GNUNET_assert (GNUNET_OK == - TALER_string_to_amount (cmd->details.reserve_withdraw.amount, - &amount)); - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&amount_with_fee, - &amount, - &cmd->details.reserve_withdraw.pk->fee_withdraw)); - if (0 != TALER_amount_cmp (&amount_with_fee, - &h->amount)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/** - * Function called with the result of a /reserve/status request. - * - * @param cls closure with the interpreter state - * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request - * 0 if the mint's reply is bogus (fails to follow the protocol) - * @param[in] json original response in JSON format (useful only for diagnostics) - * @param balance current balance in the reserve, NULL on error - * @param history_length number of entries in the transaction history, 0 on error - * @param history detailed transaction history, NULL on error - */ -static void -reserve_status_cb (void *cls, - unsigned int http_status, - json_t *json, - const struct TALER_Amount *balance, - unsigned int history_length, - const struct TALER_MINT_ReserveHistory *history) -{ - struct InterpreterState *is = cls; - struct Command *cmd = &is->commands[is->ip]; - struct Command *rel; - unsigned int i; - unsigned int j; - struct TALER_Amount amount; - - cmd->details.reserve_status.wsh = NULL; - if (cmd->expected_response_code != http_status) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u to command %s\n", - http_status, - cmd->label); - GNUNET_break (0); - json_dumpf (json, stderr, 0); - fail (is); - return; - } - switch (http_status) - { - case MHD_HTTP_OK: - /* FIXME: note that history events may come in a different - order than the commands. However, for now this works... */ - j = 0; - for (i=0;i<is->ip;i++) - { - switch ((rel = &is->commands[i])->oc) - { - case OC_ADMIN_ADD_INCOMING: - if ( ( (NULL != rel->label) && - (0 == strcmp (cmd->details.reserve_status.reserve_reference, - rel->label) ) ) || - ( (NULL != rel->details.admin_add_incoming.reserve_reference) && - (0 == strcmp (cmd->details.reserve_status.reserve_reference, - rel->details.admin_add_incoming.reserve_reference) ) ) ) - { - if (GNUNET_OK != - compare_admin_add_incoming_history (&history[j], - rel)) - { - GNUNET_break (0); - fail (is); - return; - } - j++; - } - break; - case OC_WITHDRAW_SIGN: - if (0 == strcmp (cmd->details.reserve_status.reserve_reference, - rel->details.reserve_withdraw.reserve_reference)) - { - if (GNUNET_OK != - compare_reserve_withdraw_history (&history[j], - rel)) - { - GNUNET_break (0); - fail (is); - return; - } - j++; - } - break; - default: - /* unreleated, just skip */ - break; - } - } - if (j != history_length) - { - GNUNET_break (0); - fail (is); - return; - } - if (NULL != cmd->details.reserve_status.expected_balance) - { - GNUNET_assert (GNUNET_OK == - TALER_string_to_amount (cmd->details.reserve_status.expected_balance, - &amount)); - if (0 != TALER_amount_cmp (&amount, - balance)) - { - GNUNET_break (0); - fail (is); - return; - } - } - break; - default: - /* Unsupported status code (by test harness) */ - GNUNET_break (0); - break; - } - is->ip++; - is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, - is); -} - - -/** - * Function called upon completion of our /reserve/withdraw request. - * - * @param cls closure with the interpreter state - * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request - * 0 if the mint'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 mint (for logging, in case of errors) - */ -static void -reserve_withdraw_cb (void *cls, - unsigned int http_status, - const struct TALER_DenominationSignature *sig, - json_t *full_response) -{ - struct InterpreterState *is = cls; - struct Command *cmd = &is->commands[is->ip]; - - cmd->details.reserve_withdraw.wsh = NULL; - if (cmd->expected_response_code != http_status) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u to command %s\n", - http_status, - cmd->label); - json_dumpf (full_response, stderr, 0); - GNUNET_break (0); - fail (is); - return; - } - switch (http_status) - { - case MHD_HTTP_OK: - if (NULL == sig) - { - GNUNET_break (0); - fail (is); - return; - } - cmd->details.reserve_withdraw.sig.rsa_signature - = GNUNET_CRYPTO_rsa_signature_dup (sig->rsa_signature); - break; - case MHD_HTTP_PAYMENT_REQUIRED: - /* nothing to check */ - break; - default: - /* Unsupported status code (by test harness) */ - GNUNET_break (0); - break; - } - is->ip++; - is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, - is); -} - - -/** - * Function called with the result of a /deposit operation. - * - * @param cls closure with the interpreter state - * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful deposit; - * 0 if the mint's reply is bogus (fails to follow the protocol) - * @param obj the received JSON reply, should be kept as proof (and, in case of errors, - * be forwarded to the customer) - */ -static void -deposit_cb (void *cls, - unsigned int http_status, - json_t *obj) -{ - struct InterpreterState *is = cls; - struct Command *cmd = &is->commands[is->ip]; - - cmd->details.deposit.dh = NULL; - if (cmd->expected_response_code != http_status) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u to command %s\n", - http_status, - cmd->label); - json_dumpf (obj, stderr, 0); - fail (is); - return; - } - is->ip++; - is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, - is); -} - - -/** - * Function called with the result of the /refresh/melt operation. - * - * @param cls closure with the interpreter state - * @param http_status HTTP response code, never #MHD_HTTP_OK (200) as for successful intermediate response this callback is skipped. - * 0 if the mint's reply is bogus (fails to follow the protocol) - * @param noreveal_index choice by the mint in the cut-and-choose protocol, - * UINT16_MAX on error - * @param full_response full response from the mint (for logging, in case of errors) - */ -static void -melt_cb (void *cls, - unsigned int http_status, - uint16_t noreveal_index, - json_t *full_response) -{ - struct InterpreterState *is = cls; - struct Command *cmd = &is->commands[is->ip]; - - cmd->details.refresh_melt.rmh = NULL; - if (cmd->expected_response_code != http_status) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u to command %s\n", - http_status, - cmd->label); - json_dumpf (full_response, stderr, 0); - fail (is); - return; - } - cmd->details.refresh_melt.noreveal_index = noreveal_index; - is->ip++; - is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, - is); -} - - -/** - * Function called with the result of the /refresh/reveal operation. - * - * @param cls closure with the interpreter state - * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request - * 0 if the mint'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 - * @param coin_privs array of @a num_coins private keys for the coins that were created, NULL on error - * @param sigs array of signature over @a num_coins coins, NULL on error - * @param full_response full response from the mint (for logging, in case of errors) - */ -static void -reveal_cb (void *cls, - unsigned int http_status, - unsigned int num_coins, - const struct TALER_CoinSpendPrivateKeyP *coin_privs, - const struct TALER_DenominationSignature *sigs, - json_t *full_response) -{ - struct InterpreterState *is = cls; - struct Command *cmd = &is->commands[is->ip]; - const struct Command *ref; - unsigned int i; - - cmd->details.refresh_reveal.rrh = NULL; - if (cmd->expected_response_code != http_status) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u to command %s\n", - http_status, - cmd->label); - json_dumpf (full_response, stderr, 0); - fail (is); - return; - } - ref = find_command (is, - cmd->details.refresh_reveal.melt_ref); - cmd->details.refresh_reveal.num_fresh_coins = num_coins; - switch (http_status) - { - case MHD_HTTP_OK: - cmd->details.refresh_reveal.fresh_coins - = GNUNET_new_array (num_coins, - struct FreshCoin); - for (i=0;i<num_coins;i++) - { - struct FreshCoin *fc = &cmd->details.refresh_reveal.fresh_coins[i]; - - fc->pk = ref->details.refresh_melt.fresh_pks[i]; - fc->coin_priv = coin_privs[i]; - fc->sig.rsa_signature - = GNUNET_CRYPTO_rsa_signature_dup (sigs[i].rsa_signature); - } - break; - default: - break; - } - - is->ip++; - is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, - is); -} - - -/** - * Function called with the result of a /refresh/link operation. - * - * @param cls closure with the interpreter state - * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request - * 0 if the mint'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 - * @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 full response from the mint (for logging, in case of errors) - */ -static void -link_cb (void *cls, - unsigned int http_status, - unsigned int num_coins, - const struct TALER_CoinSpendPrivateKeyP *coin_privs, - const struct TALER_DenominationSignature *sigs, - const struct TALER_DenominationPublicKey *pubs, - json_t *full_response) -{ - struct InterpreterState *is = cls; - struct Command *cmd = &is->commands[is->ip]; - const struct Command *ref; - unsigned int i; - unsigned int j; - unsigned int found; - - cmd->details.refresh_link.rlh = NULL; - if (cmd->expected_response_code != http_status) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u to command %s\n", - http_status, - cmd->label); - json_dumpf (full_response, stderr, 0); - fail (is); - return; - } - ref = find_command (is, - cmd->details.refresh_link.reveal_ref); - switch (http_status) - { - case MHD_HTTP_OK: - /* check that number of coins returned matches */ - if (num_coins != ref->details.refresh_reveal.num_fresh_coins) - { - GNUNET_break (0); - fail (is); - return; - } - /* check that the coins match */ - for (i=0;i<num_coins;i++) - for (j=i+1;j<num_coins;j++) - if (0 == memcmp (&coin_privs[i], - &coin_privs[j], - sizeof (struct TALER_CoinSpendPrivateKeyP))) - GNUNET_break (0); - /* Note: coins might be legitimately permutated in here... */ - found = 0; - for (i=0;i<num_coins;i++) - for (j=0;j<num_coins;j++) - { - const struct FreshCoin *fc; - - fc = &ref->details.refresh_reveal.fresh_coins[j]; - if ( (0 == memcmp (&coin_privs[i], - &fc->coin_priv, - sizeof (struct TALER_CoinSpendPrivateKeyP))) && - (0 == GNUNET_CRYPTO_rsa_signature_cmp (fc->sig.rsa_signature, - sigs[i].rsa_signature)) && - (0 == GNUNET_CRYPTO_rsa_public_key_cmp (fc->pk->key.rsa_public_key, - pubs[i].rsa_public_key)) ) - { - found++; - break; - } - } - if (found != num_coins) - { - fprintf (stderr, - "Only %u/%u coins match expectations\n", - found, - num_coins); - GNUNET_break (0); - fail (is); - return; - } - break; - default: - break; - } - is->ip++; - is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, - is); -} - - -/** - * Find denomination key matching the given amount. - * - * @param keys array of keys to search - * @param amount coin value to look for - * @return NULL if no matching key was found - */ -static const struct TALER_MINT_DenomPublicKey * -find_pk (const struct TALER_MINT_Keys *keys, - const struct TALER_Amount *amount) -{ - unsigned int i; - struct GNUNET_TIME_Absolute now; - struct TALER_MINT_DenomPublicKey *pk; - char *str; - - now = GNUNET_TIME_absolute_get (); - for (i=0;i<keys->num_denom_keys;i++) - { - pk = &keys->denom_keys[i]; - if ( (0 == TALER_amount_cmp (amount, - &pk->value)) && - (now.abs_value_us >= pk->valid_from.abs_value_us) && - (now.abs_value_us < pk->withdraw_valid_until.abs_value_us) ) - return pk; - } - /* do 2nd pass to check if expiration times are to blame for failure */ - str = TALER_amount_to_string (amount); - for (i=0;i<keys->num_denom_keys;i++) - { - pk = &keys->denom_keys[i]; - if ( (0 == TALER_amount_cmp (amount, - &pk->value)) && - ( (now.abs_value_us < pk->valid_from.abs_value_us) || - (now.abs_value_us > pk->withdraw_valid_until.abs_value_us) ) ) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Have denomination key for `%s', but with wrong expiration range %llu vs [%llu,%llu)\n", - str, - now.abs_value_us, - pk->valid_from.abs_value_us, - pk->withdraw_valid_until.abs_value_us); - GNUNET_free (str); - return NULL; - } - } - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "No denomination key for amount %s found\n", - str); - GNUNET_free (str); - return NULL; -} - - -/** - * Callbacks called with the result(s) of a - * wire format inquiry request to the mint. - * - * The callback is invoked multiple times, once for each supported @a - * method. Finally, it is invoked one more time with cls/0/NULL/NULL - * to indicate the end of the iteration. If any request fails to - * generate a valid response from the mint, @a http_status will also - * be zero and the iteration will also end. Thus, the iteration - * always ends with a final call with an @a http_status of 0. If the - * @a http_status is already 0 on the first call, then the response to - * the /wire request was invalid. Later, clients can tell the - * difference between @a http_status of 0 indicating a failed - * /wire/method request and a regular end of the iteration by @a - * method being non-NULL. If the mint simply correctly asserts that - * it does not support any methods, @a method will be NULL but the @a - * http_status will be #MHD_HTTP_OK for the first call (followed by a - * cls/0/NULL/NULL call to signal the end of the iteration). - * - * @param cls closure with the interpreter state - * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful request; - * 0 if the mint's reply is bogus (fails to follow the protocol) - * @param method wire format method supported, i.e. "test" or "sepa", or NULL - * if already the /wire request failed. - * @param obj the received JSON reply, if successful this should be the wire - * format details as provided by /wire/METHOD/, or NULL if the - * reply was not in JSON format (in this case, the client might - * want to do an HTTP request to /wire/METHOD/ with a browser to - * provide more information to the user about the @a method). - */ -static void -wire_cb (void *cls, - unsigned int http_status, - const char *method, - json_t *obj) -{ - struct InterpreterState *is = cls; - struct Command *cmd = &is->commands[is->ip]; - - if (0 == http_status) - { - /* 0 always signals the end of the iteration */ - cmd->details.wire.wh = NULL; - } - else if ( (NULL != method) && - (0 != strcasecmp (method, - cmd->details.wire.format)) ) - { - /* not the method we care about, skip */ - return; - } - if (cmd->expected_response_code != http_status) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u to command %s/%s\n", - http_status, - cmd->label, - method); - json_dumpf (obj, stderr, 0); - fail (is); - return; - } - if (0 == http_status) - { - /* end of iteration, move to next command */ - is->ip++; - is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, - is); - return; - } - /* For now, we only support to be called only once - with a "positive" result; so we switch to an - expected value of 0 for the 2nd iteration */ - cmd->expected_response_code = 0; -} - - -/** - * Function called with detailed wire transfer data, including all - * of the coin transactions that were combined into the wire transfer. - * - * @param cls closure - * @param http_status HTTP status code we got, 0 on mint protocol violation - * @param json original json reply (may include signatures, those have then been - * validated already) - * @param wtid extracted wire transfer identifier, or NULL if the mint could - * not provide any (set only if @a http_status is #MHD_HTTP_OK) - * @param total_amount total amount of the wire transfer, or NULL if the mint could - * not provide any @a wtid (set only if @a http_status is #MHD_HTTP_OK) - * @param details_length length of the @a details array - * @param details array with details about the combined transactions - */ -static void -wire_deposits_cb (void *cls, - unsigned int http_status, - json_t *json, - const struct GNUNET_HashCode *h_wire, - const struct TALER_Amount *total_amount, - unsigned int details_length, - const struct TALER_WireDepositDetails *details) -{ - struct InterpreterState *is = cls; - struct Command *cmd = &is->commands[is->ip]; - const struct Command *ref; - - cmd->details.wire_deposits.wdh = NULL; - ref = find_command (is, - cmd->details.wire_deposits.wtid_ref); - if (cmd->expected_response_code != http_status) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u to command %s\n", - http_status, - cmd->label); - json_dumpf (json, stderr, 0); - fail (is); - return; - } - switch (http_status) - { - case MHD_HTTP_OK: - if (0 != TALER_amount_cmp (total_amount, - &ref->details.deposit_wtid.total_amount_expected)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Total amount missmatch to command %s\n", - http_status, - cmd->label); - json_dumpf (json, stderr, 0); - fail (is); - return; - } - if (NULL != ref->details.deposit_wtid.deposit_ref) - { - const struct Command *dep; - struct GNUNET_HashCode hw; - - dep = find_command (is, - ref->details.deposit_wtid.deposit_ref); - GNUNET_CRYPTO_hash (dep->details.deposit.wire_details, - strlen (dep->details.deposit.wire_details), - &hw); - if (0 != memcmp (&hw, - h_wire, - sizeof (struct GNUNET_HashCode))) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Wire hash missmatch to command %s\n", - cmd->label); - json_dumpf (json, stderr, 0); - fail (is); - return; - } - } - break; - default: - break; - } - - /* move to next command */ - is->ip++; - is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, - is); -} - - -/** - * Function called with detailed wire transfer data. - * - * @param cls closure - * @param http_status HTTP status code we got, 0 on mint protocol violation - * @param json original json reply (may include signatures, those have then been - * validated already) - * @param wtid wire transfer identifier used by the mint, NULL if mint did not - * yet execute the transaction - * @param execution_time actual or planned execution time for the wire transfer - * @param coin_contribution contribution to the @a total_amount of the deposited coin (may be NULL) - * @param total_amount total amount of the wire transfer, or NULL if the mint could - * not provide any @a wtid (set only if @a http_status is #MHD_HTTP_OK) - */ -static void -deposit_wtid_cb (void *cls, - unsigned int http_status, - json_t *json, - const struct TALER_WireTransferIdentifierRawP *wtid, - struct GNUNET_TIME_Absolute execution_time, - const struct TALER_Amount *coin_contribution) -{ - struct InterpreterState *is = cls; - struct Command *cmd = &is->commands[is->ip]; - - cmd->details.deposit_wtid.dwh = NULL; - if (cmd->expected_response_code != http_status) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u to command %s\n", - http_status, - cmd->label); - json_dumpf (json, stderr, 0); - fail (is); - return; - } - switch (http_status) - { - case MHD_HTTP_OK: - cmd->details.deposit_wtid.wtid = *wtid; - break; - default: - break; - } - - /* move to next command */ - is->ip++; - is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, - is); -} - - -/** - * Run the main interpreter loop that performs mint operations. - * - * @param cls contains the `struct InterpreterState` - * @param tc scheduler context - */ -static void -interpreter_run (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct InterpreterState *is = cls; - struct Command *cmd = &is->commands[is->ip]; - const struct Command *ref; - struct TALER_ReservePublicKeyP reserve_pub; - struct TALER_CoinSpendPublicKeyP coin_pub; - struct TALER_Amount amount; - struct GNUNET_TIME_Absolute execution_date; - json_t *wire; - - is->task = NULL; - if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) - { - fprintf (stderr, - "Test aborted by shutdown request\n"); - fail (is); - return; - } - switch (cmd->oc) - { - case OC_END: - result = GNUNET_OK; - GNUNET_SCHEDULER_shutdown (); - return; - case OC_ADMIN_ADD_INCOMING: - if (NULL != - cmd->details.admin_add_incoming.reserve_reference) - { - ref = find_command (is, - cmd->details.admin_add_incoming.reserve_reference); - GNUNET_assert (NULL != ref); - GNUNET_assert (OC_ADMIN_ADD_INCOMING == ref->oc); - cmd->details.admin_add_incoming.reserve_priv - = ref->details.admin_add_incoming.reserve_priv; - } - else - { - struct GNUNET_CRYPTO_EddsaPrivateKey *priv; - - priv = GNUNET_CRYPTO_eddsa_key_create (); - cmd->details.admin_add_incoming.reserve_priv.eddsa_priv = *priv; - GNUNET_free (priv); - } - GNUNET_CRYPTO_eddsa_key_get_public (&cmd->details.admin_add_incoming.reserve_priv.eddsa_priv, - &reserve_pub.eddsa_pub); - if (GNUNET_OK != - TALER_string_to_amount (cmd->details.admin_add_incoming.amount, - &amount)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to parse amount `%s' at %u\n", - cmd->details.admin_add_incoming.amount, - is->ip); - fail (is); - return; - } - wire = json_loads (cmd->details.admin_add_incoming.wire, - JSON_REJECT_DUPLICATES, - NULL); - if (NULL == wire) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to parse wire details `%s' at %u\n", - cmd->details.admin_add_incoming.wire, - is->ip); - fail (is); - return; - } - execution_date = GNUNET_TIME_absolute_get (); - TALER_round_abs_time (&execution_date); - cmd->details.admin_add_incoming.aih - = TALER_MINT_admin_add_incoming (mint, - &reserve_pub, - &amount, - execution_date, - wire, - &add_incoming_cb, - is); - if (NULL == cmd->details.admin_add_incoming.aih) - { - GNUNET_break (0); - fail (is); - return; - } - trigger_context_task (); - return; - case OC_WITHDRAW_STATUS: - GNUNET_assert (NULL != - cmd->details.reserve_status.reserve_reference); - ref = find_command (is, - cmd->details.reserve_status.reserve_reference); - GNUNET_assert (NULL != ref); - GNUNET_assert (OC_ADMIN_ADD_INCOMING == ref->oc); - GNUNET_CRYPTO_eddsa_key_get_public (&ref->details.admin_add_incoming.reserve_priv.eddsa_priv, - &reserve_pub.eddsa_pub); - cmd->details.reserve_status.wsh - = TALER_MINT_reserve_status (mint, - &reserve_pub, - &reserve_status_cb, - is); - trigger_context_task (); - return; - case OC_WITHDRAW_SIGN: - GNUNET_assert (NULL != - cmd->details.reserve_withdraw.reserve_reference); - ref = find_command (is, - cmd->details.reserve_withdraw.reserve_reference); - GNUNET_assert (NULL != ref); - GNUNET_assert (OC_ADMIN_ADD_INCOMING == ref->oc); - if (NULL != cmd->details.reserve_withdraw.amount) - { - if (GNUNET_OK != - TALER_string_to_amount (cmd->details.reserve_withdraw.amount, - &amount)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to parse amount `%s' at %u\n", - cmd->details.reserve_withdraw.amount, - is->ip); - fail (is); - return; - } - cmd->details.reserve_withdraw.pk = find_pk (is->keys, - &amount); - } - if (NULL == cmd->details.reserve_withdraw.pk) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to determine denomination key at %u\n", - is->ip); - fail (is); - return; - } - - /* create coin's private key */ - { - struct GNUNET_CRYPTO_EddsaPrivateKey *priv; - - priv = GNUNET_CRYPTO_eddsa_key_create (); - cmd->details.reserve_withdraw.coin_priv.eddsa_priv = *priv; - GNUNET_free (priv); - } - GNUNET_CRYPTO_eddsa_key_get_public (&cmd->details.reserve_withdraw.coin_priv.eddsa_priv, - &coin_pub.eddsa_pub); - cmd->details.reserve_withdraw.blinding_key.rsa_blinding_key - = GNUNET_CRYPTO_rsa_blinding_key_create (GNUNET_CRYPTO_rsa_public_key_len (cmd->details.reserve_withdraw.pk->key.rsa_public_key)); - cmd->details.reserve_withdraw.wsh - = TALER_MINT_reserve_withdraw (mint, - cmd->details.reserve_withdraw.pk, - &ref->details.admin_add_incoming.reserve_priv, - &cmd->details.reserve_withdraw.coin_priv, - &cmd->details.reserve_withdraw.blinding_key, - &reserve_withdraw_cb, - is); - if (NULL == cmd->details.reserve_withdraw.wsh) - { - GNUNET_break (0); - fail (is); - return; - } - trigger_context_task (); - return; - case OC_DEPOSIT: - { - struct GNUNET_HashCode h_contract; - const struct TALER_CoinSpendPrivateKeyP *coin_priv; - const struct TALER_MINT_DenomPublicKey *coin_pk; - const struct TALER_DenominationSignature *coin_pk_sig; - struct TALER_CoinSpendPublicKeyP coin_pub; - struct TALER_CoinSpendSignatureP coin_sig; - struct GNUNET_TIME_Absolute refund_deadline; - struct GNUNET_TIME_Absolute wire_deadline; - struct GNUNET_TIME_Absolute timestamp; - struct GNUNET_CRYPTO_EddsaPrivateKey *priv; - struct TALER_MerchantPublicKeyP merchant_pub; - json_t *contract; - json_t *wire; - - GNUNET_assert (NULL != - cmd->details.deposit.coin_ref); - ref = find_command (is, - cmd->details.deposit.coin_ref); - GNUNET_assert (NULL != ref); - switch (ref->oc) - { - case OC_WITHDRAW_SIGN: - coin_priv = &ref->details.reserve_withdraw.coin_priv; - coin_pk = ref->details.reserve_withdraw.pk; - coin_pk_sig = &ref->details.reserve_withdraw.sig; - break; - case OC_REFRESH_REVEAL: - { - const struct FreshCoin *fc; - unsigned int idx; - - idx = cmd->details.deposit.coin_idx; - GNUNET_assert (idx < ref->details.refresh_reveal.num_fresh_coins); - fc = &ref->details.refresh_reveal.fresh_coins[idx]; - - coin_priv = &fc->coin_priv; - coin_pk = fc->pk; - coin_pk_sig = &fc->sig; - } - break; - default: - GNUNET_assert (0); - } - if (GNUNET_OK != - TALER_string_to_amount (cmd->details.deposit.amount, - &amount)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to parse amount `%s' at %u\n", - cmd->details.deposit.amount, - is->ip); - fail (is); - return; - } - contract = json_loads (cmd->details.deposit.contract, - JSON_REJECT_DUPLICATES, - NULL); - if (NULL == contract) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to parse contract details `%s' at %u/%s\n", - cmd->details.deposit.contract, - is->ip, - cmd->label); - fail (is); - return; - } - TALER_hash_json (contract, - &h_contract); - wire = json_loads (cmd->details.deposit.wire_details, - JSON_REJECT_DUPLICATES, - NULL); - if (NULL == wire) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to parse wire details `%s' at %u/%s\n", - cmd->details.deposit.wire_details, - is->ip, - cmd->label); - fail (is); - return; - } - GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv, - &coin_pub.eddsa_pub); - - priv = GNUNET_CRYPTO_eddsa_key_create (); - cmd->details.deposit.merchant_priv.eddsa_priv = *priv; - GNUNET_free (priv); - if (0 != cmd->details.deposit.refund_deadline.rel_value_us) - { - refund_deadline = GNUNET_TIME_relative_to_absolute (cmd->details.deposit.refund_deadline); - } - else - { - refund_deadline = GNUNET_TIME_UNIT_ZERO_ABS; - } - GNUNET_CRYPTO_eddsa_key_get_public (&cmd->details.deposit.merchant_priv.eddsa_priv, - &merchant_pub.eddsa_pub); - - wire_deadline = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_DAYS); - timestamp = GNUNET_TIME_absolute_get (); - TALER_round_abs_time (×tamp); - { - struct TALER_DepositRequestPS dr; - - 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_hash_json (wire, - &dr.h_wire); - dr.timestamp = GNUNET_TIME_absolute_hton (timestamp); - dr.refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline); - dr.transaction_id = GNUNET_htonll (cmd->details.deposit.transaction_id); - TALER_amount_hton (&dr.amount_with_fee, - &amount); - TALER_amount_hton (&dr.deposit_fee, - &coin_pk->fee_deposit); - dr.merchant = merchant_pub; - dr.coin_pub = coin_pub; - GNUNET_assert (GNUNET_OK == - GNUNET_CRYPTO_eddsa_sign (&coin_priv->eddsa_priv, - &dr.purpose, - &coin_sig.eddsa_signature)); - } - cmd->details.deposit.dh - = TALER_MINT_deposit (mint, - &amount, - wire_deadline, - wire, - &h_contract, - &coin_pub, - coin_pk_sig, - &coin_pk->key, - timestamp, - cmd->details.deposit.transaction_id, - &merchant_pub, - refund_deadline, - &coin_sig, - &deposit_cb, - is); - if (NULL == cmd->details.deposit.dh) - { - GNUNET_break (0); - json_decref (wire); - fail (is); - return; - } - json_decref (wire); - trigger_context_task (); - return; - } - case OC_REFRESH_MELT: - { - unsigned int num_melted_coins; - unsigned int num_fresh_coins; - - cmd->details.refresh_melt.noreveal_index = UINT16_MAX; - for (num_melted_coins=0; - NULL != cmd->details.refresh_melt.melted_coins[num_melted_coins].amount; - num_melted_coins++) ; - for (num_fresh_coins=0; - NULL != cmd->details.refresh_melt.fresh_amounts[num_fresh_coins]; - num_fresh_coins++) ; - - cmd->details.refresh_melt.fresh_pks - = GNUNET_new_array (num_fresh_coins, - const struct TALER_MINT_DenomPublicKey *); - { - struct TALER_CoinSpendPrivateKeyP melt_privs[num_melted_coins]; - struct TALER_Amount melt_amounts[num_melted_coins]; - struct TALER_DenominationSignature melt_sigs[num_melted_coins]; - struct TALER_MINT_DenomPublicKey melt_pks[num_melted_coins]; - struct TALER_MINT_DenomPublicKey fresh_pks[num_fresh_coins]; - unsigned int i; - - for (i=0;i<num_melted_coins;i++) - { - const struct MeltDetails *md = &cmd->details.refresh_melt.melted_coins[i]; - ref = find_command (is, - md->coin_ref); - GNUNET_assert (NULL != ref); - GNUNET_assert (OC_WITHDRAW_SIGN == ref->oc); - - melt_privs[i] = ref->details.reserve_withdraw.coin_priv; - if (GNUNET_OK != - TALER_string_to_amount (md->amount, - &melt_amounts[i])) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to parse amount `%s' at %u\n", - md->amount, - is->ip); - fail (is); - return; - } - melt_sigs[i] = ref->details.reserve_withdraw.sig; - melt_pks[i] = *ref->details.reserve_withdraw.pk; - } - for (i=0;i<num_fresh_coins;i++) - { - if (GNUNET_OK != - TALER_string_to_amount (cmd->details.refresh_melt.fresh_amounts[i], - &amount)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to parse amount `%s' at %u\n", - cmd->details.reserve_withdraw.amount, - is->ip); - fail (is); - return; - } - cmd->details.refresh_melt.fresh_pks[i] - = find_pk (is->keys, - &amount); - fresh_pks[i] = *cmd->details.refresh_melt.fresh_pks[i]; - } - cmd->details.refresh_melt.refresh_data - = TALER_MINT_refresh_prepare (num_melted_coins, - melt_privs, - melt_amounts, - melt_sigs, - melt_pks, - GNUNET_YES, - num_fresh_coins, - fresh_pks, - &cmd->details.refresh_melt.refresh_data_length); - if (NULL == cmd->details.refresh_melt.refresh_data) - { - GNUNET_break (0); - fail (is); - return; - } - cmd->details.refresh_melt.rmh - = TALER_MINT_refresh_melt (mint, - cmd->details.refresh_melt.refresh_data_length, - cmd->details.refresh_melt.refresh_data, - &melt_cb, - is); - if (NULL == cmd->details.refresh_melt.rmh) - { - GNUNET_break (0); - fail (is); - return; - } - } - } - trigger_context_task (); - return; - case OC_REFRESH_REVEAL: - ref = find_command (is, - cmd->details.refresh_reveal.melt_ref); - cmd->details.refresh_reveal.rrh - = TALER_MINT_refresh_reveal (mint, - ref->details.refresh_melt.refresh_data_length, - ref->details.refresh_melt.refresh_data, - ref->details.refresh_melt.noreveal_index, - &reveal_cb, - is); - if (NULL == cmd->details.refresh_reveal.rrh) - { - GNUNET_break (0); - fail (is); - return; - } - trigger_context_task (); - return; - case OC_REFRESH_LINK: - /* find reveal command */ - ref = find_command (is, - cmd->details.refresh_link.reveal_ref); - /* find melt command */ - ref = find_command (is, - ref->details.refresh_reveal.melt_ref); - /* find reserve_withdraw command */ - { - unsigned int idx; - const struct MeltDetails *md; - unsigned int num_melted_coins; - - for (num_melted_coins=0; - NULL != ref->details.refresh_melt.melted_coins[num_melted_coins].amount; - num_melted_coins++) ; - idx = cmd->details.refresh_link.coin_idx; - GNUNET_assert (idx < num_melted_coins); - md = &ref->details.refresh_melt.melted_coins[idx]; - ref = find_command (is, - md->coin_ref); - } - GNUNET_assert (OC_WITHDRAW_SIGN == ref->oc); - /* finally, use private key from withdraw sign command */ - cmd->details.refresh_link.rlh - = TALER_MINT_refresh_link (mint, - &ref->details.reserve_withdraw.coin_priv, - &link_cb, - is); - if (NULL == cmd->details.refresh_link.rlh) - { - GNUNET_break (0); - fail (is); - return; - } - trigger_context_task (); - return; - case OC_WIRE: - cmd->details.wire.wh = TALER_MINT_wire (mint, - &wire_cb, - is); - trigger_context_task (); - return; - case OC_WIRE_DEPOSITS: - if (NULL != cmd->details.wire_deposits.wtid_ref) - { - ref = find_command (is, - cmd->details.wire_deposits.wtid_ref); - GNUNET_assert (NULL != ref); - cmd->details.wire_deposits.wtid = ref->details.deposit_wtid.wtid; - } - cmd->details.wire_deposits.wdh - = TALER_MINT_wire_deposits (mint, - &cmd->details.wire_deposits.wtid, - &wire_deposits_cb, - is); - trigger_context_task (); - return; - case OC_DEPOSIT_WTID: - { - struct GNUNET_HashCode h_wire; - struct GNUNET_HashCode h_contract; - json_t *wire; - json_t *contract; - const struct Command *coin; - struct TALER_CoinSpendPublicKeyP coin_pub; - - ref = find_command (is, - cmd->details.deposit_wtid.deposit_ref); - GNUNET_assert (NULL != ref); - coin = find_command (is, - ref->details.deposit.coin_ref); - GNUNET_assert (NULL != coin); - switch (coin->oc) - { - case OC_WITHDRAW_SIGN: - GNUNET_CRYPTO_eddsa_key_get_public (&coin->details.reserve_withdraw.coin_priv.eddsa_priv, - &coin_pub.eddsa_pub); - break; - case OC_REFRESH_REVEAL: - { - const struct FreshCoin *fc; - unsigned int idx; - - idx = ref->details.deposit.coin_idx; - GNUNET_assert (idx < coin->details.refresh_reveal.num_fresh_coins); - fc = &coin->details.refresh_reveal.fresh_coins[idx]; - - GNUNET_CRYPTO_eddsa_key_get_public (&fc->coin_priv.eddsa_priv, - &coin_pub.eddsa_pub); - } - break; - default: - GNUNET_assert (0); - } - - wire = json_loads (ref->details.deposit.wire_details, - JSON_REJECT_DUPLICATES, - NULL); - GNUNET_assert (NULL != wire); - TALER_hash_json (wire, - &h_wire); - json_decref (wire); - contract = json_loads (ref->details.deposit.contract, - JSON_REJECT_DUPLICATES, - NULL); - GNUNET_assert (NULL != contract); - TALER_hash_json (contract, - &h_contract); - json_decref (contract); - cmd->details.deposit_wtid.dwh - = TALER_MINT_deposit_wtid (mint, - &ref->details.deposit.merchant_priv, - &h_wire, - &h_contract, - &coin_pub, - ref->details.deposit.transaction_id, - &deposit_wtid_cb, - is); - trigger_context_task (); - } - return; - default: - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unknown instruction %d at %u (%s)\n", - cmd->oc, - is->ip, - cmd->label); - fail (is); - return; - } -} - - -/** - * Function run when the test terminates (good or bad). - * Cleans up our state. - * - * @param cls the interpreter state. - * @param tc unused - */ -static void -do_shutdown (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct InterpreterState *is = cls; - struct Command *cmd; - unsigned int i; - - shutdown_task = NULL; - for (i=0;OC_END != (cmd = &is->commands[i])->oc;i++) - { - switch (cmd->oc) - { - case OC_END: - GNUNET_assert (0); - break; - case OC_ADMIN_ADD_INCOMING: - if (NULL != cmd->details.admin_add_incoming.aih) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - i, - cmd->label); - TALER_MINT_admin_add_incoming_cancel (cmd->details.admin_add_incoming.aih); - cmd->details.admin_add_incoming.aih = NULL; - } - break; - case OC_WITHDRAW_STATUS: - if (NULL != cmd->details.reserve_status.wsh) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - i, - cmd->label); - TALER_MINT_reserve_status_cancel (cmd->details.reserve_status.wsh); - cmd->details.reserve_status.wsh = NULL; - } - break; - case OC_WITHDRAW_SIGN: - if (NULL != cmd->details.reserve_withdraw.wsh) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - i, - cmd->label); - TALER_MINT_reserve_withdraw_cancel (cmd->details.reserve_withdraw.wsh); - cmd->details.reserve_withdraw.wsh = NULL; - } - if (NULL != cmd->details.reserve_withdraw.sig.rsa_signature) - { - GNUNET_CRYPTO_rsa_signature_free (cmd->details.reserve_withdraw.sig.rsa_signature); - cmd->details.reserve_withdraw.sig.rsa_signature = NULL; - } - if (NULL != cmd->details.reserve_withdraw.blinding_key.rsa_blinding_key) - { - GNUNET_CRYPTO_rsa_blinding_key_free (cmd->details.reserve_withdraw.blinding_key.rsa_blinding_key); - cmd->details.reserve_withdraw.blinding_key.rsa_blinding_key = NULL; - } - break; - case OC_DEPOSIT: - if (NULL != cmd->details.deposit.dh) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - i, - cmd->label); - TALER_MINT_deposit_cancel (cmd->details.deposit.dh); - cmd->details.deposit.dh = NULL; - } - break; - case OC_REFRESH_MELT: - if (NULL != cmd->details.refresh_melt.rmh) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - i, - cmd->label); - TALER_MINT_refresh_melt_cancel (cmd->details.refresh_melt.rmh); - cmd->details.refresh_melt.rmh = NULL; - } - GNUNET_free_non_null (cmd->details.refresh_melt.fresh_pks); - cmd->details.refresh_melt.fresh_pks = NULL; - GNUNET_free_non_null (cmd->details.refresh_melt.refresh_data); - cmd->details.refresh_melt.refresh_data = NULL; - cmd->details.refresh_melt.refresh_data_length = 0; - break; - case OC_REFRESH_REVEAL: - if (NULL != cmd->details.refresh_reveal.rrh) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - i, - cmd->label); - TALER_MINT_refresh_reveal_cancel (cmd->details.refresh_reveal.rrh); - cmd->details.refresh_reveal.rrh = NULL; - } - { - unsigned int j; - struct FreshCoin *fresh_coins; - - fresh_coins = cmd->details.refresh_reveal.fresh_coins; - for (j=0;j<cmd->details.refresh_reveal.num_fresh_coins;j++) - GNUNET_CRYPTO_rsa_signature_free (fresh_coins[j].sig.rsa_signature); - } - GNUNET_free_non_null (cmd->details.refresh_reveal.fresh_coins); - cmd->details.refresh_reveal.fresh_coins = NULL; - cmd->details.refresh_reveal.num_fresh_coins = 0; - break; - case OC_REFRESH_LINK: - if (NULL != cmd->details.refresh_link.rlh) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - i, - cmd->label); - TALER_MINT_refresh_link_cancel (cmd->details.refresh_link.rlh); - cmd->details.refresh_link.rlh = NULL; - } - break; - case OC_WIRE: - if (NULL != cmd->details.wire.wh) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - i, - cmd->label); - TALER_MINT_wire_cancel (cmd->details.wire.wh); - cmd->details.wire.wh = NULL; - } - break; - case OC_WIRE_DEPOSITS: - if (NULL != cmd->details.wire_deposits.wdh) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - i, - cmd->label); - TALER_MINT_wire_deposits_cancel (cmd->details.wire_deposits.wdh); - cmd->details.wire_deposits.wdh = NULL; - } - break; - case OC_DEPOSIT_WTID: - if (NULL != cmd->details.deposit_wtid.dwh) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - i, - cmd->label); - TALER_MINT_deposit_wtid_cancel (cmd->details.deposit_wtid.dwh); - cmd->details.deposit_wtid.dwh = NULL; - } - break; - default: - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unknown instruction %d at %u (%s)\n", - cmd->oc, - i, - cmd->label); - break; - } - } - if (NULL != is->task) - { - GNUNET_SCHEDULER_cancel (is->task); - is->task = NULL; - } - GNUNET_free (is); - if (NULL != ctx_task) - { - GNUNET_SCHEDULER_cancel (ctx_task); - ctx_task = NULL; - } - if (NULL != mint) - { - TALER_MINT_disconnect (mint); - mint = NULL; - } - if (NULL != ctx) - { - TALER_MINT_fini (ctx); - ctx = NULL; - } -} - - -/** - * Functions of this type are called to provide the retrieved signing and - * denomination keys of the mint. No TALER_MINT_*() functions should be called - * in this callback. - * - * @param cls closure - * @param keys information about keys of the mint - */ -static void -cert_cb (void *cls, - const struct TALER_MINT_Keys *keys) -{ - struct InterpreterState *is = cls; - - /* 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); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Read %u signing 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 - - /* run actual tests via interpreter-loop */ - is->keys = keys; - is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, - is); -} - - -/** - * Task that runs the context's event loop with the GNUnet scheduler. - * - * @param cls unused - * @param tc scheduler context (unused) - */ -static void -context_task (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - long timeout; - int max_fd; - fd_set read_fd_set; - fd_set write_fd_set; - fd_set except_fd_set; - struct GNUNET_NETWORK_FDSet *rs; - struct GNUNET_NETWORK_FDSet *ws; - struct GNUNET_TIME_Relative delay; - - ctx_task = NULL; - TALER_MINT_perform (ctx); - max_fd = -1; - timeout = -1; - FD_ZERO (&read_fd_set); - FD_ZERO (&write_fd_set); - FD_ZERO (&except_fd_set); - TALER_MINT_get_select_info (ctx, - &read_fd_set, - &write_fd_set, - &except_fd_set, - &max_fd, - &timeout); - if (timeout >= 0) - delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, - timeout); - else - delay = GNUNET_TIME_UNIT_FOREVER_REL; - rs = GNUNET_NETWORK_fdset_create (); - GNUNET_NETWORK_fdset_copy_native (rs, - &read_fd_set, - max_fd + 1); - ws = GNUNET_NETWORK_fdset_create (); - GNUNET_NETWORK_fdset_copy_native (ws, - &write_fd_set, - max_fd + 1); - ctx_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, - delay, - rs, - ws, - &context_task, - cls); - GNUNET_NETWORK_fdset_destroy (rs); - GNUNET_NETWORK_fdset_destroy (ws); -} - - -/** - * Main function that will be run by the scheduler. - * - * @param cls closure - * @param args remaining command-line arguments - * @param cfgfile name of the configuration file used (for saving, can be NULL!) - * @param config configuration - */ -static void -run (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct InterpreterState *is; - static struct MeltDetails melt_coins_1[] = { - { .amount = "EUR:4", - .coin_ref = "refresh-withdraw-coin-1" }, - { NULL, NULL } - }; - static const char *melt_fresh_amounts_1[] = { - "EUR:1", - "EUR:1", - "EUR:1", - "EUR:0.1", - "EUR:0.1", - "EUR:0.1", - "EUR:0.1", - "EUR:0.1", - "EUR:0.1", - "EUR:0.1", - "EUR:0.1", - "EUR:0.01", - "EUR:0.01", - "EUR:0.01", - "EUR:0.01", - "EUR:0.01", - "EUR:0.01", - /* with 0.01 withdraw fees (except for 1ct coins), - this totals up to exactly EUR:3.97, and with - the 0.03 refresh fee, to EUR:4.0*/ - NULL - }; - static struct Command commands[] = - { - /* *************** start of /wire testing ************** */ - -#if WIRE_TEST - { .oc = OC_WIRE, - .label = "wire-test", - /* /wire/test replies with a 302 redirect */ - .expected_response_code = MHD_HTTP_FOUND, - .details.wire.format = "test" }, -#endif -#if WIRE_SEPA - { .oc = OC_WIRE, - .label = "wire-sepa", - /* /wire/sepa replies with a 200 redirect */ - .expected_response_code = MHD_HTTP_OK, - .details.wire.format = "sepa" }, -#endif - /* *************** end of /wire testing ************** */ - -#if WIRE_TEST - /* None of this works if 'test' is not allowed as we do - /admin/add/incoming with format 'test' */ - - /* Fill reserve with EUR:5.01, as withdraw fee is 1 ct per config */ - { .oc = OC_ADMIN_ADD_INCOMING, - .label = "create-reserve-1", - .expected_response_code = MHD_HTTP_OK, - .details.admin_add_incoming.wire = "{ \"type\":\"TEST\", \"bank\":\"source bank\", \"account\":42 }", - .details.admin_add_incoming.amount = "EUR:5.01" }, - /* Withdraw a 5 EUR coin, at fee of 1 ct */ - { .oc = OC_WITHDRAW_SIGN, - .label = "withdraw-coin-1", - .expected_response_code = MHD_HTTP_OK, - .details.reserve_withdraw.reserve_reference = "create-reserve-1", - .details.reserve_withdraw.amount = "EUR:5" }, - /* Check that deposit and withdraw operation are in history, and - that the balance is now at zero */ - { .oc = OC_WITHDRAW_STATUS, - .label = "withdraw-status-1", - .expected_response_code = MHD_HTTP_OK, - .details.reserve_status.reserve_reference = "create-reserve-1", - .details.reserve_status.expected_balance = "EUR:0" }, - /* Try to deposit the 5 EUR coin (in full) */ - { .oc = OC_DEPOSIT, - .label = "deposit-simple", - .expected_response_code = MHD_HTTP_OK, - .details.deposit.amount = "EUR:5", - .details.deposit.coin_ref = "withdraw-coin-1", - .details.deposit.wire_details = "{ \"type\":\"TEST\", \"bank\":\"dest bank\", \"account\":42 }", - .details.deposit.contract = "{ \"items\": [ { \"name\":\"ice cream\", \"value\":1 } ] }", - .details.deposit.transaction_id = 1 }, - - /* Try to overdraw funds ... */ - { .oc = OC_WITHDRAW_SIGN, - .label = "withdraw-coin-2", - .expected_response_code = MHD_HTTP_PAYMENT_REQUIRED, - .details.reserve_withdraw.reserve_reference = "create-reserve-1", - .details.reserve_withdraw.amount = "EUR:5" }, - - /* Try to double-spend the 5 EUR coin with different wire details */ - { .oc = OC_DEPOSIT, - .label = "deposit-double-1", - .expected_response_code = MHD_HTTP_FORBIDDEN, - .details.deposit.amount = "EUR:5", - .details.deposit.coin_ref = "withdraw-coin-1", - .details.deposit.wire_details = "{ \"type\":\"TEST\", \"bank\":\"dest bank\", \"account\":43 }", - .details.deposit.contract = "{ \"items\": [ { \"name\":\"ice cream\", \"value\":1 } ] }", - .details.deposit.transaction_id = 1 }, - /* Try to double-spend the 5 EUR coin at the same merchant (but different - transaction ID) */ - { .oc = OC_DEPOSIT, - .label = "deposit-double-2", - .expected_response_code = MHD_HTTP_FORBIDDEN, - .details.deposit.amount = "EUR:5", - .details.deposit.coin_ref = "withdraw-coin-1", - .details.deposit.wire_details = "{ \"type\":\"TEST\", \"bank\":\"dest bank\", \"account\":42 }", - .details.deposit.contract = "{ \"items\": [ { \"name\":\"ice cream\", \"value\":1 } ] }", - .details.deposit.transaction_id = 2 }, - /* Try to double-spend the 5 EUR coin at the same merchant (but different - contract) */ - { .oc = OC_DEPOSIT, - .label = "deposit-double-3", - .expected_response_code = MHD_HTTP_FORBIDDEN, - .details.deposit.amount = "EUR:5", - .details.deposit.coin_ref = "withdraw-coin-1", - .details.deposit.wire_details = "{ \"type\":\"TEST\", \"bank\":\"dest bank\", \"account\":42 }", - .details.deposit.contract = "{ \"items\":[{ \"name\":\"ice cream\", \"value\":2 } ] }", - .details.deposit.transaction_id = 1 }, - - /* ***************** /refresh testing ******************** */ - - /* Fill reserve with EUR:5.01, as withdraw fee is 1 ct */ - { .oc = OC_ADMIN_ADD_INCOMING, - .label = "refresh-create-reserve-1", - .expected_response_code = MHD_HTTP_OK, - .details.admin_add_incoming.wire = "{ \"type\":\"TEST\", \"bank\":\"source bank\", \"account\":424 }", - .details.admin_add_incoming.amount = "EUR:5.01" }, - /* Withdraw a 5 EUR coin, at fee of 1 ct */ - { .oc = OC_WITHDRAW_SIGN, - .label = "refresh-withdraw-coin-1", - .expected_response_code = MHD_HTTP_OK, - .details.reserve_withdraw.reserve_reference = "refresh-create-reserve-1", - .details.reserve_withdraw.amount = "EUR:5" }, - /* Try to partially spend (deposit) 1 EUR of the 5 EUR coin (in full) - (merchant would receive EUR:0.99 due to 1 ct deposit fee) */ - { .oc = OC_DEPOSIT, - .label = "refresh-deposit-partial", - .expected_response_code = MHD_HTTP_OK, - .details.deposit.amount = "EUR:1", - .details.deposit.coin_ref = "refresh-withdraw-coin-1", - .details.deposit.wire_details = "{ \"type\":\"TEST\", \"bank\":\"dest bank\", \"account\":42 }", - .details.deposit.contract = "{ \"items\" : [ { \"name\":\"ice cream\", \"value\":\"EUR:1\" } ] }", - .details.deposit.transaction_id = 42421 }, - - /* Melt the rest of the coin's value (EUR:4.00 = 3x EUR:1.03 + 7x EUR:0.13) */ - - { .oc = OC_REFRESH_MELT, - .label = "refresh-melt-1", - .expected_response_code = MHD_HTTP_OK, - .details.refresh_melt.melted_coins = melt_coins_1, - .details.refresh_melt.fresh_amounts = melt_fresh_amounts_1 }, - - - /* Complete (successful) melt operation, and withdraw the coins */ - { .oc = OC_REFRESH_REVEAL, - .label = "refresh-reveal-1", - .expected_response_code = MHD_HTTP_OK, - .details.refresh_reveal.melt_ref = "refresh-melt-1" }, - - /* Test that /refresh/link works */ - { .oc = OC_REFRESH_LINK, - .label = "refresh-link-1", - .expected_response_code = MHD_HTTP_OK, - .details.refresh_link.reveal_ref = "refresh-reveal-1" }, - - - /* Test successfully spending coins from the refresh operation: - first EUR:1 */ - { .oc = OC_DEPOSIT, - .label = "refresh-deposit-refreshed-1a", - .expected_response_code = MHD_HTTP_OK, - .details.deposit.amount = "EUR:1", - .details.deposit.coin_ref = "refresh-reveal-1", - .details.deposit.coin_idx = 0, - .details.deposit.wire_details = "{ \"type\":\"TEST\", \"bank\":\"dest bank\", \"account\":42 }", - .details.deposit.contract = "{ \"items\": [ { \"name\":\"ice cream\", \"value\":3 } ] }", - .details.deposit.transaction_id = 2 }, - - /* Test successfully spending coins from the refresh operation: - finally EUR:0.1 */ - { .oc = OC_DEPOSIT, - .label = "refresh-deposit-refreshed-1b", - .expected_response_code = MHD_HTTP_OK, - .details.deposit.amount = "EUR:0.1", - .details.deposit.coin_ref = "refresh-reveal-1", - .details.deposit.coin_idx = 4, - .details.deposit.wire_details = "{ \"type\":\"TEST\", \"bank\":\"dest bank\", \"account\":42 }", - .details.deposit.contract = "{ \"items\": [ { \"name\":\"ice cream\", \"value\":3 } ] }", - .details.deposit.transaction_id = 2 }, - - /* Test running a failing melt operation (same operation again must fail) */ - { .oc = OC_REFRESH_MELT, - .label = "refresh-melt-failing", - .expected_response_code = MHD_HTTP_FORBIDDEN, - .details.refresh_melt.melted_coins = melt_coins_1, - .details.refresh_melt.fresh_amounts = melt_fresh_amounts_1 }, - - // FIXME: also test with coin that was already melted - // (signature differs from coin that was deposited...) - /* *************** end of /refresh testing ************** */ - - /* ************** Test tracking API ******************** */ - /* Try resolving a deposit's WTID, as we never triggered - execution of transactions, the answer should be that - the mint knows about the deposit, but has no WTID yet. */ - { .oc = OC_DEPOSIT_WTID, - .label = "deposit-wtid-found", - .expected_response_code = MHD_HTTP_ACCEPTED, - .details.deposit_wtid.deposit_ref = "deposit-simple" }, - /* Try resolving a deposit's WTID for a failed deposit. - As the deposit failed, the answer should be that - the mint does NOT know about the deposit. */ - { .oc = OC_DEPOSIT_WTID, - .label = "deposit-wtid-failing", - .expected_response_code = MHD_HTTP_NOT_FOUND, - .details.deposit_wtid.deposit_ref = "deposit-double-2" }, - /* Try resolving an undefined (all zeros) WTID; this - should fail as obviously the mint didn't use that - WTID value for any transaction. */ - { .oc = OC_WIRE_DEPOSITS, - .label = "wire-deposit-failing", - .expected_response_code = MHD_HTTP_NOT_FOUND }, - - /* TODO: trigger aggregation logic and then check the - cases where tracking succeeds! */ - - /* ************** End of tracking API testing************* */ - - -#endif - - { .oc = OC_END } - }; - - is = GNUNET_new (struct InterpreterState); - is->commands = commands; - - ctx = TALER_MINT_init (); - GNUNET_assert (NULL != ctx); - ctx_task = GNUNET_SCHEDULER_add_now (&context_task, - ctx); - mint = TALER_MINT_connect (ctx, - "http://localhost:8081", - &cert_cb, is, - TALER_MINT_OPTION_END); - GNUNET_assert (NULL != mint); - shutdown_task - = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_SECONDS, 150), - &do_shutdown, is); -} - - -/** - * Main function for the testcase for the mint API. - * - * @param argc expected to be 1 - * @param argv expected to only contain the program name - */ -int -main (int argc, - char * const *argv) -{ - struct GNUNET_OS_Process *proc; - struct GNUNET_OS_Process *mintd; - - GNUNET_log_setup ("test-mint-api", - "WARNING", - NULL); - proc = GNUNET_OS_start_process (GNUNET_NO, - GNUNET_OS_INHERIT_STD_ALL, - NULL, NULL, NULL, - "taler-mint-keyup", - "taler-mint-keyup", - "-d", "test-mint-home", - "-m", "test-mint-home/master.priv", - NULL); - GNUNET_OS_process_wait (proc); - GNUNET_OS_process_destroy (proc); - mintd = GNUNET_OS_start_process (GNUNET_NO, - GNUNET_OS_INHERIT_STD_ALL, - NULL, NULL, NULL, - "taler-mint-httpd", - "taler-mint-httpd", - "-d", "test-mint-home", - NULL); - /* give child time to start and bind against the socket */ - fprintf (stderr, "Waiting for taler-mint-httpd to be ready"); - do - { - fprintf (stderr, "."); - sleep (1); - } - while (0 != system ("wget -q -t 1 -T 1 http://127.0.0.1:8081/keys -o /dev/null -O /dev/null")); - fprintf (stderr, "\n"); - result = GNUNET_SYSERR; - GNUNET_SCHEDULER_run (&run, NULL); - GNUNET_OS_process_kill (mintd, - SIGTERM); - GNUNET_OS_process_wait (mintd); - GNUNET_OS_process_destroy (mintd); - return (GNUNET_OK == result) ? 0 : 1; -} - -/* end of test_mint_api.c */ |