summaryrefslogtreecommitdiff
path: root/src/mint-lib/test_mint_api.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mint-lib/test_mint_api.c')
-rw-r--r--src/mint-lib/test_mint_api.c2599
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 (&timestamp);
- {
- 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 */