summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2018-09-15 22:20:07 +0200
committerChristian Grothoff <christian@grothoff.org>2018-09-15 22:20:07 +0200
commit528faeab81ba240329140eb1587ccc542736c1dc (patch)
tree639283b45f05dcd7ad9e2e5c89a28cf3f9dbefd8
parent46e4ea696cdba772ad5d6f8d79cf2e6586ef9979 (diff)
downloadexchange-528faeab81ba240329140eb1587ccc542736c1dc.tar.gz
exchange-528faeab81ba240329140eb1587ccc542736c1dc.tar.bz2
exchange-528faeab81ba240329140eb1587ccc542736c1dc.zip
fix #5315, including more testing
-rw-r--r--src/exchange-lib/Makefile.am29
-rw-r--r--src/exchange-lib/exchange_api_handle.c52
-rw-r--r--src/exchange-lib/test_exchange_api.c4035
-rw-r--r--src/exchange-lib/test_exchange_api_keys_cherry_picking.c803
-rw-r--r--src/exchange-lib/test_exchange_api_keys_cherry_picking.conf12
-rw-r--r--src/exchange-lib/test_exchange_api_keys_cherry_picking_new.c25
-rw-r--r--src/exchange-lib/testing_api_cmd_check_keys.c11
-rw-r--r--src/exchange-tools/taler-exchange-keyup.c14
-rw-r--r--src/exchange/taler-exchange-httpd_keystate.c9
-rw-r--r--src/include/taler_exchange_service.h15
10 files changed, 83 insertions, 4922 deletions
diff --git a/src/exchange-lib/Makefile.am b/src/exchange-lib/Makefile.am
index 9dbd2256c..8ac43ea8c 100644
--- a/src/exchange-lib/Makefile.am
+++ b/src/exchange-lib/Makefile.am
@@ -48,6 +48,7 @@ libtalertesting_la_SOURCES = \
testing_api_cmd_refund.c \
testing_api_cmd_status.c \
testing_api_cmd_deposit.c \
+ testing_api_cmd_sleep.c \
testing_api_cmd_refresh.c \
testing_api_cmd_track.c \
testing_api_cmd_bank_check.c \
@@ -95,9 +96,7 @@ endif
check_PROGRAMS = \
test_exchange_api_keys_cherry_picking_new \
- test_exchange_api_new \
- test_exchange_api_keys_cherry_picking \
- test_exchange_api
+ test_exchange_api_new
if HAVE_TWISTER
check_PROGRAMS += \
@@ -126,19 +125,6 @@ AM_TESTS_ENVIRONMENT=export TALER_PREFIX=$${TALER_PREFIX:-@libdir@};export PATH=
TESTS = \
$(check_PROGRAMS)
-test_exchange_api_SOURCES = \
- test_exchange_api.c
-test_exchange_api_LDADD = \
- libtalerexchange.la \
- $(LIBGCRYPT_LIBS) \
- $(top_builddir)/src/bank-lib/libtalerfakebank.la \
- $(top_builddir)/src/bank-lib/libtalerbank.la \
- $(top_builddir)/src/json/libtalerjson.la \
- $(top_builddir)/src/util/libtalerutil.la \
- -lgnunetcurl \
- -lgnunetutil \
- -ljansson
-
test_exchange_api_new_SOURCES = \
test_exchange_api_new.c
test_exchange_api_new_LDADD = \
@@ -166,17 +152,6 @@ test_exchange_api_keys_cherry_picking_new_LDADD = \
-lgnunetutil \
-ljansson
-test_exchange_api_keys_cherry_picking_SOURCES = \
- test_exchange_api_keys_cherry_picking.c
-test_exchange_api_keys_cherry_picking_LDADD = \
- libtalerexchange.la \
- $(LIBGCRYPT_LIBS) \
- $(top_builddir)/src/json/libtalerjson.la \
- $(top_builddir)/src/util/libtalerutil.la \
- -lgnunetcurl \
- -lgnunetutil \
- -ljansson
-
EXTRA_DIST = \
test_exchange_api_home/.local/share/taler/exchange/offline-keys/master.priv \
test_exchange_api_home/.config/taler/test.json \
diff --git a/src/exchange-lib/exchange_api_handle.c b/src/exchange-lib/exchange_api_handle.c
index ba1f8c217..83dda20f6 100644
--- a/src/exchange-lib/exchange_api_handle.c
+++ b/src/exchange-lib/exchange_api_handle.c
@@ -426,14 +426,15 @@ parse_json_auditor (struct TALER_EXCHANGE_AuditorInformation *auditor,
&kv.auditor_url_hash);
kv.master = key_data->master_pub;
len = json_array_size (keys);
- auditor->denom_keys = GNUNET_new_array (len,
- const struct TALER_EXCHANGE_DenomPublicKey *);
+ auditor->denom_key_offsets = GNUNET_new_array (len,
+ unsigned int);
i = 0;
off = 0;
json_array_foreach (keys, i, key) {
struct TALER_AuditorSignatureP auditor_sig;
struct GNUNET_HashCode denom_h;
const struct TALER_EXCHANGE_DenomPublicKey *dk;
+ unsigned int dk_off;
struct GNUNET_JSON_Specification kspec[] = {
GNUNET_JSON_spec_fixed_auto ("denom_pub_h",
&denom_h),
@@ -451,6 +452,7 @@ parse_json_auditor (struct TALER_EXCHANGE_AuditorInformation *auditor,
continue;
}
dk = NULL;
+ dk_off = UINT_MAX;
for (unsigned int j=0;j<key_data->num_denom_keys;j++)
{
if (0 == memcmp (&denom_h,
@@ -458,6 +460,7 @@ parse_json_auditor (struct TALER_EXCHANGE_AuditorInformation *auditor,
sizeof (struct GNUNET_HashCode)))
{
dk = &key_data->denom_keys[j];
+ dk_off = j;
break;
}
}
@@ -492,7 +495,7 @@ parse_json_auditor (struct TALER_EXCHANGE_AuditorInformation *auditor,
GNUNET_JSON_parse_free (spec);
return GNUNET_SYSERR;
}
- auditor->denom_keys[off] = dk;
+ auditor->denom_key_offsets[off] = dk_off;
off++;
}
auditor->num_denom_keys = off;
@@ -628,7 +631,8 @@ decode_keys_json (const json_t *resp_obj,
unsigned int index;
EXITIF (NULL == (denom_keys_array =
- json_object_get (resp_obj, "denoms")));
+ json_object_get (resp_obj,
+ "denoms")));
EXITIF (JSON_ARRAY != json_typeof (denom_keys_array));
index = 0;
@@ -694,6 +698,7 @@ decode_keys_json (const json_t *resp_obj,
for (unsigned int j=0;j<key_data->num_auditors;j++)
{
struct TALER_EXCHANGE_AuditorInformation *aix = &key_data->auditors[j];
+
if (0 == memcmp (&ai.auditor_pub,
&aix->auditor_pub,
sizeof (struct TALER_AuditorPublicKeyP)))
@@ -701,12 +706,12 @@ decode_keys_json (const json_t *resp_obj,
found = true;
/* Merge denomination key signatures of downloaded /keys into existing
auditor information 'aix'. */
- GNUNET_array_grow (aix->denom_keys,
+ GNUNET_array_grow (aix->denom_key_offsets,
aix->num_denom_keys,
aix->num_denom_keys + ai.num_denom_keys);
- memcpy (&aix->denom_keys[aix->num_denom_keys - ai.num_denom_keys],
- ai.denom_keys,
- ai.num_denom_keys * sizeof (struct TALER_EXCHANGE_DenomPublicKey *));
+ memcpy (&aix->denom_key_offsets[aix->num_denom_keys - ai.num_denom_keys],
+ ai.denom_key_offsets,
+ ai.num_denom_keys * sizeof (unsigned int));
break;
}
}
@@ -762,7 +767,7 @@ free_key_data (struct TALER_EXCHANGE_Keys *key_data)
0);
for (unsigned int i=0;i<key_data->num_auditors;i++)
{
- GNUNET_array_grow (key_data->auditors[i].denom_keys,
+ GNUNET_array_grow (key_data->auditors[i].denom_key_offsets,
key_data->auditors[i].num_denom_keys,
0);
GNUNET_free (key_data->auditors[i].auditor_url);
@@ -827,10 +832,11 @@ keys_completed_cb (void *cls,
struct TALER_EXCHANGE_Keys kd_old;
enum TALER_EXCHANGE_VersionCompatibility vc;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Received keys from URL `%s' with status %ld.\n",
kr->url,
response_code);
+ json_dumpf (resp_obj, stderr, 0);
kd_old = exchange->key_data;
memset (&kd,
0,
@@ -878,17 +884,12 @@ keys_completed_cb (void *cls,
anew->auditor_pub = aold->auditor_pub;
anew->auditor_url = GNUNET_strdup (aold->auditor_url);
- GNUNET_array_grow (anew->denom_keys,
+ GNUNET_array_grow (anew->denom_key_offsets,
anew->num_denom_keys,
aold->num_denom_keys);
- for (unsigned int j=0;j<aold->num_denom_keys;j++)
- {
- /* offsets will map 1:1 */
- unsigned int off = aold->denom_keys[j] - kd_old.denom_keys;
- /* FIXME(#5315): this should not be an assert! */
- GNUNET_assert (off < kd_old.num_denom_keys);
- anew->denom_keys[j] = &kd.denom_keys[off];
- }
+ memcpy (anew->denom_key_offsets,
+ aold->denom_key_offsets,
+ aold->num_denom_keys * sizeof (unsigned int));
}
if (GNUNET_OK !=
@@ -921,10 +922,10 @@ keys_completed_cb (void *cls,
NULL,
vc);
if (NULL != exchange->key_data_raw)
- {
- json_decref (exchange->key_data_raw);
- exchange->key_data_raw = NULL;
- }
+ {
+ json_decref (exchange->key_data_raw);
+ exchange->key_data_raw = NULL;
+ }
free_key_data (&kd_old);
return;
}
@@ -1157,13 +1158,10 @@ request_keys (void *cls)
kr = GNUNET_new (struct KeysRequest);
kr->exchange = exchange;
if (GNUNET_YES ==
- MAH_handle_is_ready (exchange) && !TALER_EXCHANGE_API_DISABLE_CHERRYPICKING)
+ MAH_handle_is_ready (exchange))
{
char *arg;
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Doing cherry-picking\n");
-
GNUNET_asprintf (&arg,
"/keys?last_issue_date=%llu",
(unsigned long long) exchange->key_data.last_denom_issue_date.abs_value_us / 1000000LLU);
diff --git a/src/exchange-lib/test_exchange_api.c b/src/exchange-lib/test_exchange_api.c
deleted file mode 100644
index a96e49963..000000000
--- a/src/exchange-lib/test_exchange_api.c
+++ /dev/null
@@ -1,4035 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014-2017 GNUnet e.V. and Inria
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file exchange/test_exchange_api.c
- * @brief testcase to test exchange'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_exchange_service.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_util_lib.h>
-#include <microhttpd.h>
-#include "taler_bank_service.h"
-#include "taler_fakebank_lib.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 'ebics'?
- * Requires that EBICS /history function is implemented, which it
- * is currently not. Once it is, set ENABLE_CREDIT to YES in the
- * configuration and then set this option to 1.
- */
-#define WIRE_EBICS 0
-
-/**
- * Account number of the exchange at the bank.
- */
-#define EXCHANGE_ACCOUNT_NO 2
-
-/**
- * Main execution context for the main loop.
- */
-static struct GNUNET_CURL_Context *ctx;
-
-/**
- * Handle to access the exchange.
- */
-static struct TALER_EXCHANGE_Handle *exchange;
-
-/**
- * Context for running the CURL event loop.
- */
-static struct GNUNET_CURL_RescheduleContext *rc;
-
-/**
- * Handle to the exchange process.
- */
-static struct GNUNET_OS_Process *exchanged;
-
-/**
- * Task run on timeout.
- */
-static struct GNUNET_SCHEDULER_Task *timeout_task;
-
-/**
- * Handle to our fakebank.
- */
-static struct TALER_FAKEBANK_Handle *fakebank;
-
-/**
- * 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 exchange's /refresh/link by linking original private key to
- * results from #OC_REFRESH_REVEAL step.
- */
- OC_REFRESH_LINK,
-
- /**
- * Verify the exchange's /wire-method.
- */
- OC_WIRE,
-
- /**
- * Verify exchange's /track/transfer method.
- */
- OC_WIRE_DEPOSITS,
-
- /**
- * Verify exchange's /track/transaction method.
- */
- OC_DEPOSIT_WTID,
-
- /**
- * Run the aggregator to execute deposits.
- */
- OC_RUN_AGGREGATOR,
-
- /**
- * Run the wirewatcher to check for incoming transactions.
- */
- OC_RUN_WIREWATCH,
-
- /**
- * Check that the fakebank has received a certain transaction.
- */
- OC_CHECK_BANK_TRANSFER,
-
- /**
- * Check that the fakebank has not received any other transactions.
- */
- OC_CHECK_BANK_TRANSFERS_EMPTY,
-
- /**
- * Refund some deposit.
- */
- OC_REFUND,
-
- /**
- * Revoke some denomination key.
- */
- OC_REVOKE,
-
- /**
- * Payback some coin.
- */
- OC_PAYBACK
-
-};
-
-
-/**
- * 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_EXCHANGE_DenomPublicKey *pk;
-
- /**
- * Set (by the interpreter) to the exchange's signature over the
- * coin's public key.
- */
- struct TALER_DenominationSignature sig;
-
- /**
- * Set (by the interpreter) to the coin's private key.
- */
- struct TALER_CoinSpendPrivateKeyP coin_priv;
-
-};
-
-
-/**
- * Details for a exchange 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 transfer subject. NULL to use public key corresponding
- * to @e reserve_priv or @e reserve_reference. Should only be
- * set manually to test invalid wire transfer subjects.
- */
- const char *subject;
-
- /**
- * Sender (debit) account number.
- */
- uint64_t debit_account_no;
-
- /**
- * Receiver (credit) account number.
- */
- uint64_t credit_account_no;
-
- /**
- * Username to use for authentication.
- */
- const char *auth_username;
-
- /**
- * Password to use for authentication.
- */
- const char *auth_password;
-
- /**
- * 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_BANK_AdminAddIncomingHandle *aih;
-
- /**
- * Set to the wire transfer's unique ID.
- */
- uint64_t serial_id;
-
- } 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_EXCHANGE_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 exchange'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_EXCHANGE_DenomPublicKey *pk;
-
- /**
- * Set (by the interpreter) to the exchange's signature over the
- * coin's public key.
- */
- struct TALER_DenominationSignature sig;
-
- /**
- * Private key material of the coin, set by the interpreter.
- */
- struct TALER_PlanchetSecretsP ps;
-
- /**
- * Withdraw handle (while operation is running).
- */
- struct TALER_EXCHANGE_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 what a proposal is about.
- */
- const char *contract_terms;
-
- /**
- * 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_EXCHANGE_DepositHandle *dh;
-
- } deposit;
-
- /**
- * Information for a #OC_REFRESH_MELT command.
- */
- struct
- {
-
- /**
- * Information about coins to be melted.
- */
- struct MeltDetails melted_coin;
-
- /**
- * 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_EXCHANGE_DenomPublicKey **fresh_pks;
-
- /**
- * Melt handle while operation is running.
- */
- struct TALER_EXCHANGE_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 exchange.
- */
- 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_EXCHANGE_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_EXCHANGE_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_EXCHANGE_WireHandle *wh;
-
- /**
- * Format we expect to see, others will be *ignored*.
- */
- const char *format;
-
- /**
- * Expected wire fee.
- */
- const char *expected_fee;
-
- } wire;
-
- /**
- * Information for the /track/transfer's command.
- */
- struct {
-
- /**
- * Handle to the wire deposits request.
- */
- struct TALER_EXCHANGE_TrackTransferHandle *wdh;
-
- /**
- * Reference to a command providing a WTID. If set, we use the
- * WTID from that command. The command can be either an
- * #OC_DEPOSIT_WTID or an #OC_CHECK_BANK_TRANSFER. In the
- * case of the bank transfer, we check that the total amount
- * claimed by the exchange matches the total amount transferred
- * by the bank. In the case of a /track/transaction, we check
- * that the wire details match.
- */
- const char *wtid_ref;
-
- /**
- * WTID to use (used if @e wtid_ref is NULL).
- */
- struct TALER_WireTransferIdentifierRawP wtid;
-
- /**
- * What is the expected total amount? Only used if
- * @e expected_response_code was #MHD_HTTP_OK.
- */
- const char *total_amount_expected;
-
- /**
- * What is the expected wire fee? Only used if
- * @e expected_response_code was #MHD_HTTP_OK.
- */
- const char *wire_fee_expected;
-
-
- /* TODO: may want to add list of deposits we expected
- to see aggregated here in the future. */
-
- } wire_deposits;
-
- /**
- * Information for the /track/transaction command.
- */
- struct {
-
- /**
- * Handle to the deposit wtid request.
- */
- struct TALER_EXCHANGE_TrackTransactionHandle *dwh;
-
- /**
- * Which /deposit operation should we obtain WTID data for?
- */
- const char *deposit_ref;
-
- /**
- * Which #OC_CHECK_BANK_TRANSFER wtid should this match? NULL for none.
- */
- const char *bank_transfer_ref;
-
- /**
- * Wire transfer identifier, set if #MHD_HTTP_OK was the response code.
- */
- struct TALER_WireTransferIdentifierRawP wtid;
-
- } deposit_wtid;
-
- struct {
-
- /**
- * Process for the aggregator.
- */
- struct GNUNET_OS_Process *aggregator_proc;
-
- /**
- * ID of task called whenever we get a SIGCHILD.
- */
- struct GNUNET_SCHEDULER_Task *child_death_task;
-
- } run_aggregator;
-
- struct {
-
- /**
- * Process for the wirewatcher.
- */
- struct GNUNET_OS_Process *wirewatch_proc;
-
- /**
- * ID of task called whenever we get a SIGCHILD.
- */
- struct GNUNET_SCHEDULER_Task *child_death_task;
-
- } run_wirewatch;
-
- struct {
-
- /**
- * Which amount do we expect to see transferred?
- */
- const char *amount;
-
- /**
- * Which account do we expect to be debited?
- */
- uint64_t account_debit;
-
- /**
- * Which account do we expect to be credited?
- */
- uint64_t account_credit;
-
- /**
- * Which exchange base URL is expected?
- */
- const char *exchange_base_url;
-
- /**
- * Set (!) to the wire transfer subject observed.
- */
- char *subject;
-
- } check_bank_transfer;
-
- struct {
-
- /**
- * Amount that should be refunded.
- */
- const char *amount;
-
- /**
- * Expected refund fee.
- */
- const char *fee;
-
- /**
- * Reference to the corresponding deposit operation.
- * Used to obtain proposal details, merchant keys,
- * fee structure, etc.
- */
- const char *deposit_ref;
-
- /**
- * Refund transaction identifier.
- */
- uint64_t rtransaction_id;
-
- /**
- * Handle to the refund operation (while it is ongoing).
- */
- struct TALER_EXCHANGE_RefundHandle *rh;
-
- } refund;
-
- struct {
-
- /**
- * Reference to a _coin's_ withdraw operation where the coin's denomination key
- * is the denomination key to be revoked.
- */
- const char *ref;
-
- /**
- * Process for the revocation process.
- */
- struct GNUNET_OS_Process *revoke_proc;
-
- /**
- * ID of task called whenever we get a SIGCHILD.
- */
- struct GNUNET_SCHEDULER_Task *child_death_task;
-
- } revoke;
-
- struct {
-
- /**
- * Reference to the _coin's_ withdraw operation.
- */
- const char *ref;
-
- /**
- * Amount that should be paid back.
- */
- const char *amount;
-
- /**
- * Handle to the ongoing /payback operation.
- */
- struct TALER_EXCHANGE_PaybackHandle *ph;
-
- } payback;
-
-
- } details;
-
-};
-
-
-/**
- * State of the interpreter loop.
- */
-struct InterpreterState
-{
- /**
- * Keys from the exchange.
- */
- const struct TALER_EXCHANGE_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;
-
-};
-
-
-/**
- * Pipe used to communicate child death via signal.
- */
-static struct GNUNET_DISK_PipeHandle *sigpipe;
-
-
-/**
- * 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 exchange operations.
- *
- * @param cls contains the `struct InterpreterState`
- */
-static void
-interpreter_run (void *cls);
-
-
-/**
- * Run the next command with the interpreter.
- *
- * @param is current interpeter state.
- */
-static void
-next_command (struct InterpreterState *is)
-{
- if (GNUNET_SYSERR == result)
- return; /* ignore, we already failed! */
- is->ip++;
- is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
- is);
-}
-
-
-/**
- * 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 exchange's reply is bogus (fails to follow the protocol)
- * @param ec taler-specific error code, #TALER_EC_NONE on success
- * @param serial_id unique ID of the wire transfer
- * @param full_response full response from the exchange (for logging, in case of errors)
- */
-static void
-add_incoming_cb (void *cls,
- unsigned int http_status,
- enum TALER_ErrorCode ec,
- uint64_t serial_id,
- const json_t *full_response)
-{
- struct InterpreterState *is = cls;
- struct Command *cmd = &is->commands[is->ip];
-
- cmd->details.admin_add_incoming.aih = NULL;
- cmd->details.admin_add_incoming.serial_id = serial_id;
- if (MHD_HTTP_OK != http_status)
- {
- GNUNET_break (0);
- fail (is);
- return;
- }
- next_command (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_EXCHANGE_ReserveHistory *h,
- const struct Command *cmd)
-{
- struct TALER_Amount amount;
-
- if (TALER_EXCHANGE_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_EXCHANGE_ReserveHistory *h,
- const struct Command *cmd)
-{
- struct TALER_Amount amount;
- struct TALER_Amount amount_with_fee;
-
- if (TALER_EXCHANGE_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;
-}
-
-
-/**
- * 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_payback_history (const struct TALER_EXCHANGE_ReserveHistory *h,
- const struct Command *cmd)
-{
- struct TALER_Amount amount;
-
- if (TALER_EXCHANGE_RTT_PAYBACK != h->type)
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- GNUNET_assert (GNUNET_OK ==
- TALER_string_to_amount (cmd->details.payback.amount,
- &amount));
- if (0 != TALER_amount_cmp (&amount,
- &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 exchange's reply is bogus (fails to follow the protocol)
- * @param ec taler-specific error code, #TALER_EC_NONE on success
- * @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,
- enum TALER_ErrorCode ec,
- const json_t *json,
- const struct TALER_Amount *balance,
- unsigned int history_length,
- const struct TALER_EXCHANGE_ReserveHistory *history)
-{
- struct InterpreterState *is = cls;
- struct Command *cmd = &is->commands[is->ip];
- struct Command *rel;
- const struct Command *xrel;
- 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 ( (j >= history_length) ||
- (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 ( (j >= history_length) ||
- (GNUNET_OK !=
- compare_reserve_withdraw_history (&history[j],
- rel)) )
- {
- GNUNET_break (0);
- fail (is);
- return;
- }
- j++;
- }
- break;
- case OC_PAYBACK:
- xrel = find_command (is,
- rel->details.payback.ref);
- GNUNET_assert (NULL != xrel);
- if (0 == strcmp (cmd->details.reserve_status.reserve_reference,
- xrel->details.reserve_withdraw.reserve_reference))
- {
- if ( (j >= history_length) ||
- (GNUNET_OK !=
- compare_reserve_payback_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;
- }
- next_command (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 exchange's reply is bogus (fails to follow the protocol)
- * @param ec taler-specific error code, #TALER_EC_NONE on success
- * @param sig signature over the coin, NULL on error
- * @param full_response full response from the exchange (for logging, in case of errors)
- */
-static void
-reserve_withdraw_cb (void *cls,
- unsigned int http_status,
- enum TALER_ErrorCode ec,
- const struct TALER_DenominationSignature *sig,
- const 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_FORBIDDEN:
- /* nothing to check */
- break;
- case MHD_HTTP_NOT_FOUND:
- /* nothing to check */
- break;
- default:
- /* Unsupported status code (by test harness) */
- GNUNET_break (0);
- break;
- }
- next_command (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 exchange's reply is bogus (fails to follow the protocol)
- * @param ec taler-specific error code, #TALER_EC_NONE on success
- * @param exchange_pub public key the exchange used for signing
- * @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,
- enum TALER_ErrorCode ec,
- const struct TALER_ExchangePublicKeyP *exchange_pub,
- const 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;
- }
- next_command (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 exchange's reply is bogus (fails to follow the protocol)
- * @param ec taler-specific error code, #TALER_EC_NONE on success
- * @param noreveal_index choice by the exchange in the cut-and-choose protocol,
- * UINT16_MAX on error
- * @param exchange_pub public key the exchange used for signing
- * @param full_response full response from the exchange (for logging, in case of errors)
- */
-static void
-melt_cb (void *cls,
- unsigned int http_status,
- enum TALER_ErrorCode ec,
- uint32_t noreveal_index,
- const struct TALER_ExchangePublicKeyP *exchange_pub,
- const json_t *full_response)
-{
- struct 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;
- next_command (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 exchange's reply is bogus (fails to follow the protocol)
- * @param ec taler-specific error code, #TALER_EC_NONE on success
- * @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 exchange (for logging, in case of errors)
- */
-static void
-reveal_cb (void *cls,
- unsigned int http_status,
- enum TALER_ErrorCode ec,
- unsigned int num_coins,
- const struct TALER_CoinSpendPrivateKeyP *coin_privs,
- const struct TALER_DenominationSignature *sigs,
- const 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);
- GNUNET_assert (NULL != 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;
- }
- next_command (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 exchange's reply is bogus (fails to follow the protocol)
- * @param ec taler-specific error code, #TALER_EC_NONE on success
- * @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 exchange (for logging, in case of errors)
- */
-static void
-link_cb (void *cls,
- unsigned int http_status,
- enum TALER_ErrorCode ec,
- unsigned int num_coins,
- const struct TALER_CoinSpendPrivateKeyP *coin_privs,
- const struct TALER_DenominationSignature *sigs,
- const struct TALER_DenominationPublicKey *pubs,
- const json_t *full_response)
-{
- struct InterpreterState *is = cls;
- struct Command *cmd = &is->commands[is->ip];
- const struct Command *ref;
- 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);
- GNUNET_assert (NULL != 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 (unsigned int i=0;i<num_coins;i++)
- for (unsigned int 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 (unsigned int i=0;i<num_coins;i++)
- for (unsigned int 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;
- }
- next_command (is);
-}
-
-
-/**
- * Task triggered whenever we receive a SIGCHLD (child
- * process died).
- *
- * @param cls closure, NULL if we need to self-restart
- */
-static void
-maint_child_death (void *cls)
-{
- struct InterpreterState *is = cls;
- struct Command *cmd = &is->commands[is->ip];
- const struct GNUNET_DISK_FileHandle *pr;
- char c[16];
-
- switch (cmd->oc) {
- case OC_RUN_AGGREGATOR:
- cmd->details.run_aggregator.child_death_task = NULL;
- pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ);
- GNUNET_break (0 < GNUNET_DISK_file_read (pr, &c, sizeof (c)));
- GNUNET_OS_process_wait (cmd->details.run_aggregator.aggregator_proc);
- GNUNET_OS_process_destroy (cmd->details.run_aggregator.aggregator_proc);
- cmd->details.run_aggregator.aggregator_proc = NULL;
- break;
- case OC_RUN_WIREWATCH:
- cmd->details.run_wirewatch.child_death_task = NULL;
- pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ);
- GNUNET_break (0 < GNUNET_DISK_file_read (pr, &c, sizeof (c)));
- GNUNET_OS_process_wait (cmd->details.run_wirewatch.wirewatch_proc);
- GNUNET_OS_process_destroy (cmd->details.run_wirewatch.wirewatch_proc);
- cmd->details.run_wirewatch.wirewatch_proc = NULL;
- break;
- case OC_REVOKE:
- cmd->details.revoke.child_death_task = NULL;
- pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ);
- GNUNET_break (0 < GNUNET_DISK_file_read (pr, &c, sizeof (c)));
- GNUNET_OS_process_wait (cmd->details.revoke.revoke_proc);
- GNUNET_OS_process_destroy (cmd->details.revoke.revoke_proc);
- cmd->details.revoke.revoke_proc = NULL;
- /* trigger reload of denomination key information */
- GNUNET_break (0 ==
- GNUNET_OS_process_kill (exchanged,
- SIGUSR1));
- sleep (5); /* make sure signal was received and processed */
- break;
- default:
- GNUNET_break (0);
- fail (is);
- return;
- }
- next_command (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_EXCHANGE_DenomPublicKey *
-find_pk (const struct TALER_EXCHANGE_Keys *keys,
- const struct TALER_Amount *amount)
-{
- struct GNUNET_TIME_Absolute now;
- struct TALER_EXCHANGE_DenomPublicKey *pk;
- char *str;
-
- now = GNUNET_TIME_absolute_get ();
- for (unsigned int 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 (unsigned int 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,
- (unsigned long long) now.abs_value_us,
- (unsigned long long) pk->valid_from.abs_value_us,
- (unsigned long long) 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;
-}
-
-
-#if LEGACY
-/* Tests the *old* /wire API, the _modern_ testcase was adapted,
- but little point in right now adapting the old testcase */
-/**
- * Function called with information about the wire fees
- * for each wire method.
- *
- * @param cls closure
- * @param wire_method name of the wire method (i.e. "ebics")
- * @param fees fee structure for this method
- */
-static void
-check_fee_cb (void *cls,
- const char *wire_method,
- const struct TALER_EXCHANGE_WireAggregateFees *fees)
-{
- struct InterpreterState *is = cls;
- struct Command *cmd = &is->commands[is->ip];
- struct TALER_Amount expected_amount;
-
- GNUNET_break ( (0 == strcasecmp ("x-taler-bank",
- wire_method)) ||
- (0 == strcasecmp ("ebics",
- wire_method)) );
- if (GNUNET_OK !=
- TALER_string_to_amount (cmd->details.wire.expected_fee,
- &expected_amount))
- {
- GNUNET_break (0);
- fail (is);
- return;
- }
- while (NULL != fees)
- {
- if (0 != TALER_amount_cmp (&fees->wire_fee,
- &expected_amount))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Wire fee missmatch to command %s\n",
- cmd->label);
- fail (is);
- return;
- }
- fees = fees->next;
- }
-}
-#endif
-
-
-/**
- * Callbacks called with the result(s) of a
- * wire format inquiry request to the exchange.
- *
- * @param cls closure with the interpreter state
- * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful request;
- * 0 if the exchange's reply is bogus (fails to follow the protocol)
- * @param ec taler-specific error code, #TALER_EC_NONE on success
- * @param accounts_len length of the @a accounts array
- * @param accounts list of wire accounts of the exchange, NULL on error
- */
-static void
-wire_cb (void *cls,
- unsigned int http_status,
- enum TALER_ErrorCode ec,
- unsigned int accounts_len,
- const struct TALER_EXCHANGE_WireAccount *accounts)
-{
- struct InterpreterState *is = cls;
- struct Command *cmd = &is->commands[is->ip];
-
- cmd->details.wire.wh = 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);
-#if LEGACY
- json_dumpf (obj, stderr, 0);
-#endif
- fail (is);
- return;
- }
- switch (http_status)
- {
- case MHD_HTTP_OK:
- {
-#if LEGACY
- json_t *method;
-
- method = json_object_get (obj,
- cmd->details.wire.format);
- if (NULL == method)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Expected method `%s' not included in response to command %s\n",
- cmd->details.wire.format,
- cmd->label);
- json_dumpf (obj, stderr, 0);
- fail (is);
- return;
- }
- if (GNUNET_OK !=
- TALER_EXCHANGE_wire_get_fees (&TALER_EXCHANGE_get_keys (exchange)->master_pub,
- obj,
- &check_fee_cb,
- is))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Wire fee extraction in command %s failed\n",
- cmd->label);
- json_dumpf (obj, stderr, 0);
- fail (is);
- return;
- }
-#endif
- }
- break;
- default:
- break;
- }
- next_command (is);
-}
-
-
-/**
- * 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 exchange protocol violation
- * @param ec taler-specific error code, #TALER_EC_NONE on success
- * @param exchange_pub public key the exchange used for signing
- * @param json original json reply (may include signatures, those have then been
- * validated already)
- * @param h_wire hash of the wire transfer address the transfer went to, or NULL on error
- * @param execution_time time when the exchange claims to have performed the wire transfer
- * @param total_amount total amount of the wire transfer, or NULL if the exchange could
- * not provide any @a wtid (set only if @a http_status is #MHD_HTTP_OK)
- * @param wire_fee wire fee that was charged by the exchange
- * @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,
- enum TALER_ErrorCode ec,
- const struct TALER_ExchangePublicKeyP *exchange_pub,
- const json_t *json,
- const struct GNUNET_HashCode *h_wire,
- struct GNUNET_TIME_Absolute execution_time,
- const struct TALER_Amount *total_amount,
- const struct TALER_Amount *wire_fee,
- unsigned int details_length,
- const struct TALER_TrackTransferDetails *details)
-{
- struct InterpreterState *is = cls;
- struct Command *cmd = &is->commands[is->ip];
- const struct Command *ref;
- struct TALER_Amount expected_amount;
-
- cmd->details.wire_deposits.wdh = 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:
- if (GNUNET_OK !=
- TALER_string_to_amount (cmd->details.wire_deposits.total_amount_expected,
- &expected_amount))
- {
- GNUNET_break (0);
- fail (is);
- return;
- }
- if (0 != TALER_amount_cmp (total_amount,
- &expected_amount))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Total amount missmatch to command %s\n",
- cmd->label);
- json_dumpf (json, stderr, 0);
- fail (is);
- return;
- }
- if (GNUNET_OK !=
- TALER_string_to_amount (cmd->details.wire_deposits.wire_fee_expected,
- &expected_amount))
- {
- GNUNET_break (0);
- fail (is);
- return;
- }
- if (0 != TALER_amount_cmp (wire_fee,
- &expected_amount))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Wire fee missmatch to command %s\n",
- cmd->label);
- json_dumpf (json, stderr, 0);
- fail (is);
- return;
- }
- ref = find_command (is,
- cmd->details.wire_deposits.wtid_ref);
- GNUNET_assert (NULL != ref);
- switch (ref->oc)
- {
- case OC_DEPOSIT_WTID:
- if (NULL != ref->details.deposit_wtid.deposit_ref)
- {
- const struct Command *dep;
- struct GNUNET_HashCode hw;
- json_t *wire;
-
- dep = find_command (is,
- ref->details.deposit_wtid.deposit_ref);
- GNUNET_assert (NULL != dep);
- wire = json_loads (dep->details.deposit.wire_details,
- JSON_REJECT_DUPLICATES,
- NULL);
- GNUNET_assert (GNUNET_OK ==
- TALER_JSON_wire_signature_hash (wire,
- &hw));
- json_decref (wire);
- 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;
- case OC_CHECK_BANK_TRANSFER:
- if (GNUNET_OK !=
- TALER_string_to_amount (ref->details.check_bank_transfer.amount,
- &expected_amount))
- {
- GNUNET_break (0);
- fail (is);
- return;
- }
- if (0 != TALER_amount_cmp (total_amount,
- &expected_amount))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Total amount missmatch to command %s\n",
- cmd->label);
- json_dumpf (json, stderr, 0);
- fail (is);
- return;
- }
- break;
- default:
- GNUNET_break (0);
- fail (is);
- return;
- }
- break;
- default:
- break;
- }
- next_command (is);
-}
-
-
-/**
- * Function called with detailed wire transfer data.
- *
- * @param cls closure
- * @param http_status HTTP status code we got, 0 on exchange protocol violation
- * @param ec taler-specific error code, #TALER_EC_NONE on success
- * @param exchange_pub public key the exchange used for signing
- * @param json original json reply (may include signatures, those have then been
- * validated already)
- * @param wtid wire transfer identifier used by the exchange, NULL if exchange 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 exchange 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,
- enum TALER_ErrorCode ec,
- const struct TALER_ExchangePublicKeyP *exchange_pub,
- const 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;
- if (NULL != cmd->details.deposit_wtid.bank_transfer_ref)
- {
- const struct Command *ref;
- char *ws;
-
- ws = GNUNET_STRINGS_data_to_string_alloc (wtid,
- sizeof (*wtid));
-
-
- ref = find_command (is,
- cmd->details.deposit_wtid.bank_transfer_ref);
- GNUNET_assert (NULL != ref);
- if (0 != strcmp (ws,
- ref->details.check_bank_transfer.subject))
- {
- GNUNET_break (0);
- GNUNET_free (ws);
- fail (is);
- return;
- }
- GNUNET_free (ws);
- }
- break;
- case MHD_HTTP_ACCEPTED:
- /* allowed, nothing to check here */
- break;
- case MHD_HTTP_NOT_FOUND:
- /* allowed, nothing to check here */
- break;
- default:
- GNUNET_break (0);
- break;
- }
- next_command (is);
-}
-
-
-/**
- * Check the result for the refund request.
- *
- * @param cls closure
- * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful deposit;
- * 0 if the exchange's reply is bogus (fails to follow the protocol)
- * @param ec taler-specific error code, #TALER_EC_NONE on success
- * @param exchange_pub public key the exchange used for signing @a obj
- * @param obj the received JSON reply, should be kept as proof (and, in particular,
- * be forwarded to the customer)
- */
-static void
-refund_cb (void *cls,
- unsigned int http_status,
- enum TALER_ErrorCode ec,
- const struct TALER_ExchangePublicKeyP *exchange_pub,
- const json_t *obj)
-{
- struct InterpreterState *is = cls;
- struct Command *cmd = &is->commands[is->ip];
-
- cmd->details.refund.rh = 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;
- }
- switch (http_status)
- {
- case MHD_HTTP_OK:
- break;
- default:
- break;
- }
- next_command (is);
-}
-
-
-
-/**
- * Check the result of the payback request.
- *
- * @param cls closure
- * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
- * 0 if the exchange's reply is bogus (fails to follow the protocol)
- * @param ec taler-specific error code, #TALER_EC_NONE on success
- * @param amount amount the exchange will wire back for this coin
- * @param timestamp what time did the exchange receive the /payback request
- * @param reserve_pub public key of the reserve receiving the payback
- * @param full_response full response from the exchange (for logging, in case of errors)
- */
-static void
-payback_cb (void *cls,
- unsigned int http_status,
- enum TALER_ErrorCode ec,
- const struct TALER_Amount *amount,
- struct GNUNET_TIME_Absolute timestamp,
- const struct TALER_ReservePublicKeyP *reserve_pub,
- const json_t *full_response)
-{
- struct InterpreterState *is = cls;
- struct Command *cmd = &is->commands[is->ip];
- const struct Command *withdraw;
- const struct Command *reserve;
- struct TALER_Amount expected_amount;
- struct TALER_ReservePublicKeyP rp;
-
- cmd->details.payback.ph = 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;
- }
- withdraw = find_command (is,
- cmd->details.payback.ref);
- GNUNET_assert (NULL != withdraw);
- reserve = find_command (is,
- withdraw->details.reserve_withdraw.reserve_reference);
- GNUNET_assert (NULL != reserve);
- GNUNET_CRYPTO_eddsa_key_get_public (&reserve->details.admin_add_incoming.reserve_priv.eddsa_priv,
- &rp.eddsa_pub);
- switch (http_status)
- {
- case MHD_HTTP_OK:
- if (GNUNET_OK !=
- TALER_string_to_amount (cmd->details.payback.amount,
- &expected_amount))
- {
- GNUNET_break (0);
- fail (is);
- return;
- }
- if (0 != TALER_amount_cmp (amount,
- &expected_amount))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Total amount missmatch to command %s\n",
- cmd->label);
- json_dumpf (full_response, stderr, 0);
- fail (is);
- return;
- }
- if (0 != memcmp (reserve_pub,
- &rp,
- sizeof (rp)))
- {
- GNUNET_break (0);
- fail (is);
- return;
- }
- break;
- default:
- break;
- }
- next_command (is);
-}
-
-
-/**
- * Given a command that is used to withdraw coins,
- * extract the corresponding public key of the coin.
- *
- * @param coin command relating to coin withdrawal or refresh
- * @param idx index to use if we got multiple coins from the @a coin command
- * @param[out] coin_pub where to store the public key of the coin
- */
-static void
-get_public_key_from_coin_command (const struct Command *coin,
- unsigned int idx,
- struct TALER_CoinSpendPublicKeyP *coin_pub)
-{
- switch (coin->oc)
- {
- case OC_WITHDRAW_SIGN:
- GNUNET_CRYPTO_eddsa_key_get_public (&coin->details.reserve_withdraw.ps.coin_priv.eddsa_priv,
- &coin_pub->eddsa_pub);
- break;
- case OC_REFRESH_REVEAL:
- {
- const struct FreshCoin *fc;
-
- 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);
- }
-}
-
-
-/**
- * Run the main interpreter loop that performs exchange operations.
- *
- * @param cls contains the `struct InterpreterState`
- */
-static void
-interpreter_run (void *cls)
-{
- struct InterpreterState *is = cls;
- struct Command *cmd = &is->commands[is->ip];
- const struct Command *ref;
- struct TALER_ReservePublicKeyP reserve_pub;
- struct TALER_Amount amount;
- const struct GNUNET_SCHEDULER_TaskContext *tc;
-
- is->task = NULL;
- tc = GNUNET_SCHEDULER_get_task_context ();
- if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
- {
- fprintf (stderr,
- "Test aborted by shutdown request\n");
- fail (is);
- return;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Running command `%s'\n",
- cmd->label);
- switch (cmd->oc)
- {
- case OC_END:
- result = GNUNET_OK;
- GNUNET_SCHEDULER_shutdown ();
- return;
- case OC_ADMIN_ADD_INCOMING:
- {
- char *subject;
- struct TALER_BANK_AuthenticationData auth;
-
- if (NULL !=
- cmd->details.admin_add_incoming.subject)
- {
- subject = GNUNET_strdup (cmd->details.admin_add_incoming.subject);
- }
- else
- {
- /* Use reserve public key as subject */
- 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);
- subject = GNUNET_STRINGS_data_to_string_alloc (&reserve_pub,
- sizeof (reserve_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;
- }
- auth.method = TALER_BANK_AUTH_BASIC;
- auth.details.basic.username = (char *) cmd->details.admin_add_incoming.auth_username;
- auth.details.basic.password = (char *) cmd->details.admin_add_incoming.auth_password;
- cmd->details.admin_add_incoming.aih
- = TALER_BANK_admin_add_incoming (ctx,
- "http://localhost:8082/", /* bank URL */
- &auth,
- "http://localhost:8081/", /* exchange URL */
- subject,
- &amount,
- cmd->details.admin_add_incoming.debit_account_no,
- cmd->details.admin_add_incoming.credit_account_no,
- &add_incoming_cb,
- is);
- GNUNET_free (subject);
- if (NULL == cmd->details.admin_add_incoming.aih)
- {
- GNUNET_break (0);
- fail (is);
- return;
- }
- }
- 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_EXCHANGE_reserve_status (exchange,
- &reserve_pub,
- &reserve_status_cb,
- is);
- 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;
- }
-
- TALER_planchet_setup_random (&cmd->details.reserve_withdraw.ps);
- cmd->details.reserve_withdraw.wsh
- = TALER_EXCHANGE_reserve_withdraw (exchange,
- cmd->details.reserve_withdraw.pk,
- &ref->details.admin_add_incoming.reserve_priv,
- &cmd->details.reserve_withdraw.ps,
- &reserve_withdraw_cb,
- is);
- if (NULL == cmd->details.reserve_withdraw.wsh)
- {
- GNUNET_break (0);
- fail (is);
- return;
- }
- return;
- case OC_DEPOSIT:
- {
- struct GNUNET_HashCode h_contract_terms;
- const struct TALER_CoinSpendPrivateKeyP *coin_priv;
- const struct TALER_EXCHANGE_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_terms;
- 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.ps.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_terms = json_loads (cmd->details.deposit.contract_terms,
- JSON_REJECT_DUPLICATES,
- NULL);
- if (NULL == contract_terms)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to parse proposal data `%s' at %u/%s\n",
- cmd->details.deposit.contract_terms,
- is->ip,
- cmd->label);
- fail (is);
- return;
- }
- GNUNET_assert (GNUNET_OK ==
- TALER_JSON_hash (contract_terms,
- &h_contract_terms));
- json_decref (contract_terms);
- 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);
- wire_deadline = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_multiply (cmd->details.deposit.refund_deadline, 2));
- }
- else
- {
- refund_deadline = GNUNET_TIME_UNIT_ZERO_ABS;
- wire_deadline = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_ZERO);
- }
- GNUNET_CRYPTO_eddsa_key_get_public (&cmd->details.deposit.merchant_priv.eddsa_priv,
- &merchant_pub.eddsa_pub);
-
- timestamp = GNUNET_TIME_absolute_get ();
- GNUNET_TIME_round_abs (&timestamp);
- GNUNET_TIME_round_abs (&refund_deadline);
- GNUNET_TIME_round_abs (&wire_deadline);
- {
- 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_terms = h_contract_terms;
- GNUNET_assert (GNUNET_OK ==
- TALER_JSON_wire_signature_hash (wire,
- &dr.h_wire));
- dr.timestamp = GNUNET_TIME_absolute_hton (timestamp);
- dr.refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline);
- 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_EXCHANGE_deposit (exchange,
- &amount,
- wire_deadline,
- wire,
- &h_contract_terms,
- &coin_pub,
- coin_pk_sig,
- &coin_pk->key,
- timestamp,
- &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);
- return;
- }
- case OC_REFRESH_MELT:
- {
- unsigned int num_fresh_coins;
-
- cmd->details.refresh_melt.noreveal_index = UINT16_MAX;
- 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_EXCHANGE_DenomPublicKey *);
- {
- struct TALER_CoinSpendPrivateKeyP melt_priv;
- struct TALER_Amount melt_amount;
- struct TALER_DenominationSignature melt_sig;
- struct TALER_EXCHANGE_DenomPublicKey melt_pk;
- struct TALER_EXCHANGE_DenomPublicKey fresh_pks[num_fresh_coins];
- unsigned int i;
-
- const struct MeltDetails *md = &cmd->details.refresh_melt.melted_coin;
- ref = find_command (is,
- md->coin_ref);
- GNUNET_assert (NULL != ref);
- GNUNET_assert (OC_WITHDRAW_SIGN == ref->oc);
-
- melt_priv = ref->details.reserve_withdraw.ps.coin_priv;
- if (GNUNET_OK !=
- TALER_string_to_amount (md->amount,
- &melt_amount))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to parse amount `%s' at %u\n",
- md->amount,
- is->ip);
- fail (is);
- return;
- }
- melt_sig = ref->details.reserve_withdraw.sig;
- melt_pk = *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;
- }
- if (NULL ==
- (cmd->details.refresh_melt.fresh_pks[i]
- = find_pk (is->keys,
- &amount)))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to find denomination key for amount `%s' at %u\n",
- cmd->details.reserve_withdraw.amount,
- is->ip);
- fail (is);
- return;
- }
- fresh_pks[i] = *cmd->details.refresh_melt.fresh_pks[i];
- }
- cmd->details.refresh_melt.refresh_data
- = TALER_EXCHANGE_refresh_prepare (&melt_priv,
- &melt_amount,
- &melt_sig,
- &melt_pk,
- 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_EXCHANGE_refresh_melt (exchange,
- 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;
- }
- }
- }
- return;
- case OC_REFRESH_REVEAL:
- ref = find_command (is,
- cmd->details.refresh_reveal.melt_ref);
- GNUNET_assert (NULL != ref);
- cmd->details.refresh_reveal.rrh
- = TALER_EXCHANGE_refresh_reveal (exchange,
- 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;
- }
- return;
- case OC_REFRESH_LINK:
- /* find reveal command */
- ref = find_command (is,
- cmd->details.refresh_link.reveal_ref);
- GNUNET_assert (NULL != ref);
- /* find melt command */
- ref = find_command (is,
- ref->details.refresh_reveal.melt_ref);
- GNUNET_assert (NULL != ref);
- /* find reserve_withdraw command */
- {
- const struct MeltDetails *md;
-
- md = &ref->details.refresh_melt.melted_coin;
- ref = find_command (is,
- md->coin_ref);
- GNUNET_assert (NULL != ref);
- }
- GNUNET_assert (OC_WITHDRAW_SIGN == ref->oc);
- /* finally, use private key from withdraw sign command */
- cmd->details.refresh_link.rlh
- = TALER_EXCHANGE_refresh_link (exchange,
- &ref->details.reserve_withdraw.ps.coin_priv,
- &link_cb,
- is);
- if (NULL == cmd->details.refresh_link.rlh)
- {
- GNUNET_break (0);
- fail (is);
- return;
- }
- return;
- case OC_WIRE:
- cmd->details.wire.wh = TALER_EXCHANGE_wire (exchange,
- &wire_cb,
- is);
- 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);
- switch (ref->oc)
- {
- case OC_DEPOSIT_WTID:
- cmd->details.wire_deposits.wtid = ref->details.deposit_wtid.wtid;
- break;
- case OC_CHECK_BANK_TRANSFER:
- GNUNET_assert (GNUNET_OK ==
- GNUNET_STRINGS_string_to_data (ref->details.check_bank_transfer.subject,
- strlen (ref->details.check_bank_transfer.subject),
- &cmd->details.wire_deposits.wtid,
- sizeof (cmd->details.wire_deposits.wtid)));
- break;
- default:
- GNUNET_break (0);
- fail (is);
- return;
- }
- }
- cmd->details.wire_deposits.wdh
- = TALER_EXCHANGE_track_transfer (exchange,
- &cmd->details.wire_deposits.wtid,
- &wire_deposits_cb,
- is);
- return;
- case OC_DEPOSIT_WTID:
- {
- struct GNUNET_HashCode h_wire;
- struct GNUNET_HashCode h_contract_terms;
- json_t *wire;
- json_t *contract_terms;
- 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);
- get_public_key_from_coin_command (coin,
- ref->details.deposit.coin_idx,
- &coin_pub);
- wire = json_loads (ref->details.deposit.wire_details,
- JSON_REJECT_DUPLICATES,
- NULL);
- GNUNET_assert (NULL != wire);
- GNUNET_assert (GNUNET_OK ==
- TALER_JSON_wire_signature_hash (wire,
- &h_wire));
- json_decref (wire);
- contract_terms = json_loads (ref->details.deposit.contract_terms,
- JSON_REJECT_DUPLICATES,
- NULL);
- GNUNET_assert (NULL != contract_terms);
- GNUNET_assert (GNUNET_OK ==
- TALER_JSON_hash (contract_terms,
- &h_contract_terms));
- json_decref (contract_terms);
- cmd->details.deposit_wtid.dwh
- = TALER_EXCHANGE_track_transaction (exchange,
- &ref->details.deposit.merchant_priv,
- &h_wire,
- &h_contract_terms,
- &coin_pub,
- &deposit_wtid_cb,
- is);
- }
- return;
- case OC_RUN_AGGREGATOR:
- {
- const struct GNUNET_DISK_FileHandle *pr;
-
- cmd->details.run_aggregator.aggregator_proc
- = GNUNET_OS_start_process (GNUNET_NO,
- GNUNET_OS_INHERIT_STD_ALL,
- NULL, NULL, NULL,
- "taler-exchange-aggregator",
- "taler-exchange-aggregator",
- "-c", "test_exchange_api.conf",
- "-t", /* exit when done */
- NULL);
- if (NULL == cmd->details.run_aggregator.aggregator_proc)
- {
- GNUNET_break (0);
- fail (is);
- return;
- }
- pr = GNUNET_DISK_pipe_handle (sigpipe,
- GNUNET_DISK_PIPE_END_READ);
- cmd->details.run_aggregator.child_death_task
- = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
- pr,
- &maint_child_death, is);
- return;
- }
- case OC_RUN_WIREWATCH:
- {
- const struct GNUNET_DISK_FileHandle *pr;
-
- cmd->details.run_wirewatch.wirewatch_proc
- = GNUNET_OS_start_process (GNUNET_NO,
- GNUNET_OS_INHERIT_STD_ALL,
- NULL, NULL, NULL,
- "taler-exchange-wirewatch",
- "taler-exchange-wirewatch",
- "-c", "test_exchange_api.conf",
- "-T", /* exit when done */
- NULL);
- if (NULL == cmd->details.run_wirewatch.wirewatch_proc)
- {
- GNUNET_break (0);
- fail (is);
- return;
- }
- pr = GNUNET_DISK_pipe_handle (sigpipe,
- GNUNET_DISK_PIPE_END_READ);
- cmd->details.run_wirewatch.child_death_task
- = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
- pr,
- &maint_child_death, is);
- return;
- }
- case OC_CHECK_BANK_TRANSFER:
- {
- if (GNUNET_OK !=
- TALER_string_to_amount (cmd->details.check_bank_transfer.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;
- }
- if (GNUNET_OK !=
- TALER_FAKEBANK_check (fakebank,
- &amount,
- cmd->details.check_bank_transfer.account_debit,
- cmd->details.check_bank_transfer.account_credit,
- cmd->details.check_bank_transfer.exchange_base_url,
- &cmd->details.check_bank_transfer.subject))
- {
- GNUNET_break (0);
- fail (is);
- return;
- }
- next_command (is);
- return;
- }
- case OC_CHECK_BANK_TRANSFERS_EMPTY:
- {
- if (GNUNET_OK !=
- TALER_FAKEBANK_check_empty (fakebank))
- {
- GNUNET_break (0);
- fail (is);
- return;
- }
- next_command (is);
- return;
- }
- case OC_REFUND:
- {
- const struct Command *coin;
- struct GNUNET_HashCode h_contract_terms;
- json_t *contract_terms;
- struct TALER_CoinSpendPublicKeyP coin_pub;
- struct TALER_Amount refund_fee;
-
- if (GNUNET_OK !=
- TALER_string_to_amount (cmd->details.refund.amount,
- &amount))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to parse amount `%s' at %u\n",
- cmd->details.refund.amount,
- is->ip);
- fail (is);
- return;
- }
- if (GNUNET_OK !=
- TALER_string_to_amount (cmd->details.refund.fee,
- &refund_fee))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to parse amount `%s' at %u\n",
- cmd->details.refund.fee,
- is->ip);
- fail (is);
- return;
- }
- ref = find_command (is,
- cmd->details.refund.deposit_ref);
- GNUNET_assert (NULL != ref);
- contract_terms = json_loads (ref->details.deposit.contract_terms,
- JSON_REJECT_DUPLICATES,
- NULL);
- GNUNET_assert (NULL != contract_terms);
- GNUNET_assert (GNUNET_OK ==
- TALER_JSON_hash (contract_terms,
- &h_contract_terms));
- json_decref (contract_terms);
-
- coin = find_command (is,
- ref->details.deposit.coin_ref);
- GNUNET_assert (NULL != coin);
- get_public_key_from_coin_command (coin,
- ref->details.deposit.coin_idx,
- &coin_pub);
- cmd->details.refund.rh
- = TALER_EXCHANGE_refund (exchange,
- &amount,
- &refund_fee,
- &h_contract_terms,
- &coin_pub,
- cmd->details.refund.rtransaction_id,
- &ref->details.deposit.merchant_priv,
- &refund_cb,
- is);
- if (NULL == cmd->details.refund.rh)
- {
- GNUNET_break (0);
- fail (is);
- return;
- }
- return;
- }
- case OC_REVOKE:
- {
- const struct GNUNET_DISK_FileHandle *pr;
- char *dhks;
- const struct Command *ref;
-
- ref = find_command (is,
- cmd->details.revoke.ref);
- GNUNET_assert (NULL != ref);
- dhks = GNUNET_STRINGS_data_to_string_alloc (&ref->details.reserve_withdraw.pk->h_key,
- sizeof (struct GNUNET_HashCode));
- cmd->details.revoke.revoke_proc
- = GNUNET_OS_start_process (GNUNET_NO,
- GNUNET_OS_INHERIT_STD_ALL,
- NULL, NULL, NULL,
- "taler-exchange-keyup",
- "taler-exchange-keyup",
- "-c", "test_exchange_api.conf",
- "-r", dhks,
- NULL);
- GNUNET_free (dhks);
- if (NULL == cmd->details.revoke.revoke_proc)
- {
- GNUNET_break (0);
- fail (is);
- return;
- }
- pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ);
- cmd->details.revoke.child_death_task
- = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
- pr,
- &maint_child_death,
- is);
- return;
- }
- case OC_PAYBACK:
- {
- const struct Command *ref;
-
- ref = find_command (is,
- cmd->details.payback.ref);
- GNUNET_assert (NULL != ref);
- cmd->details.payback.ph
- = TALER_EXCHANGE_payback (exchange,
- ref->details.reserve_withdraw.pk,
- &ref->details.reserve_withdraw.sig,
- &ref->details.reserve_withdraw.ps,
- &payback_cb,
- is);
- return;
- }
-
- default:
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unknown instruction %d at %u (%s)\n",
- cmd->oc,
- is->ip,
- cmd->label);
- fail (is);
- return;
- }
-}
-
-
-/**
- * Signal handler called for SIGCHLD. Triggers the
- * respective handler by writing to the trigger pipe.
- */
-static void
-sighandler_child_death ()
-{
- static char c;
- int old_errno = errno; /* back-up errno */
-
- GNUNET_break (1 ==
- GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle
- (sigpipe, GNUNET_DISK_PIPE_END_WRITE),
- &c, sizeof (c)));
- errno = old_errno; /* restore errno */
-}
-
-
-/**
- * Function run when the test terminates (good or bad) with timeout.
- *
- * @param cls NULL
- */
-static void
-do_timeout (void *cls)
-{
- timeout_task = NULL;
- GNUNET_SCHEDULER_shutdown ();
-}
-
-
-/**
- * Function run when the test terminates (good or bad).
- * Cleans up our state.
- *
- * @param cls the interpreter state.
- */
-static void
-do_shutdown (void *cls)
-{
- struct InterpreterState *is = cls;
- struct Command *cmd;
-
- fprintf (stderr,
- "Executing shutdown at `%s'\n",
- is->commands[is->ip].label);
-
- for (unsigned int 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_BANK_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_EXCHANGE_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_EXCHANGE_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;
- }
- 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_EXCHANGE_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_EXCHANGE_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_EXCHANGE_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_EXCHANGE_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_EXCHANGE_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_EXCHANGE_track_transfer_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_EXCHANGE_track_transaction_cancel (cmd->details.deposit_wtid.dwh);
- cmd->details.deposit_wtid.dwh = NULL;
- }
- break;
- case OC_RUN_AGGREGATOR:
- if (NULL != cmd->details.run_aggregator.aggregator_proc)
- {
- GNUNET_break (0 ==
- GNUNET_OS_process_kill (cmd->details.run_aggregator.aggregator_proc,
- SIGKILL));
- GNUNET_OS_process_wait (cmd->details.run_aggregator.aggregator_proc);
- GNUNET_OS_process_destroy (cmd->details.run_aggregator.aggregator_proc);
- cmd->details.run_aggregator.aggregator_proc = NULL;
- }
- if (NULL != cmd->details.run_aggregator.child_death_task)
- {
- GNUNET_SCHEDULER_cancel (cmd->details.run_aggregator.child_death_task);
- cmd->details.run_aggregator.child_death_task = NULL;
- }
- break;
- case OC_RUN_WIREWATCH:
- if (NULL != cmd->details.run_wirewatch.wirewatch_proc)
- {
- GNUNET_break (0 ==
- GNUNET_OS_process_kill (cmd->details.run_wirewatch.wirewatch_proc,
- SIGKILL));
- GNUNET_OS_process_wait (cmd->details.run_wirewatch.wirewatch_proc);
- GNUNET_OS_process_destroy (cmd->details.run_wirewatch.wirewatch_proc);
- cmd->details.run_wirewatch.wirewatch_proc = NULL;
- }
- if (NULL != cmd->details.run_wirewatch.child_death_task)
- {
- GNUNET_SCHEDULER_cancel (cmd->details.run_wirewatch.child_death_task);
- cmd->details.run_wirewatch.child_death_task = NULL;
- }
- break;
- case OC_CHECK_BANK_TRANSFER:
- GNUNET_free_non_null (cmd->details.check_bank_transfer.subject);
- cmd->details.check_bank_transfer.subject = NULL;
- break;
- case OC_CHECK_BANK_TRANSFERS_EMPTY:
- break;
- case OC_REFUND:
- if (NULL != cmd->details.refund.rh)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Command %u (%s) did not complete\n",
- i,
- cmd->label);
- TALER_EXCHANGE_refund_cancel (cmd->details.refund.rh);
- cmd->details.refund.rh = NULL;
- }
- break;
- case OC_REVOKE:
- if (NULL != cmd->details.revoke.revoke_proc)
- {
- GNUNET_break (0 ==
- GNUNET_OS_process_kill (cmd->details.revoke.revoke_proc,
- SIGKILL));
- GNUNET_OS_process_wait (cmd->details.revoke.revoke_proc);
- GNUNET_OS_process_destroy (cmd->details.revoke.revoke_proc);
- cmd->details.revoke.revoke_proc = NULL;
- }
- if (NULL != cmd->details.revoke.child_death_task)
- {
- GNUNET_SCHEDULER_cancel (cmd->details.revoke.child_death_task);
- cmd->details.revoke.child_death_task = NULL;
- }
- break;
- case OC_PAYBACK:
- if (NULL != cmd->details.payback.ph)
- {
- TALER_EXCHANGE_payback_cancel (cmd->details.payback.ph);
- cmd->details.payback.ph = 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 != fakebank)
- {
- TALER_FAKEBANK_stop (fakebank);
- fakebank = NULL;
- }
- if (NULL != exchange)
- {
- TALER_EXCHANGE_disconnect (exchange);
- exchange = NULL;
- }
- if (NULL != ctx)
- {
- GNUNET_CURL_fini (ctx);
- ctx = NULL;
- }
- if (NULL != rc)
- {
- GNUNET_CURL_gnunet_rc_destroy (rc);
- rc = NULL;
- }
- if (NULL != timeout_task)
- {
- GNUNET_SCHEDULER_cancel (timeout_task);
- timeout_task = NULL;
- }
-}
-
-
-/**
- * Functions of this type are called to provide the retrieved signing and
- * denomination keys of the exchange. No TALER_EXCHANGE_*() functions should be called
- * in this callback.
- *
- * @param cls closure
- * @param keys information about keys of the exchange
- * @param vc version compatibility
- */
-static void
-cert_cb (void *cls,
- const struct TALER_EXCHANGE_Keys *keys,
- enum TALER_EXCHANGE_VersionCompatibility vc)
-{
- 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);
-}
-
-
-/**
- * Main function that will be run by the scheduler.
- *
- * @param cls closure
- */
-static void
-run (void *cls)
-{
- struct InterpreterState *is;
- 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",
- /* expecting 'test' method in response */
- .expected_response_code = MHD_HTTP_OK,
- .details.wire.format = "x-taler-bank",
- .details.wire.expected_fee = "EUR:0.01" },
-#endif
-#if WIRE_EBICS
- { .oc = OC_WIRE,
- .label = "wire-sepa",
- /* expecting 'ebics' method in response */
- .expected_response_code = MHD_HTTP_OK,
- .details.wire.format = "ebics",
- .details.wire.expected_fee = "EUR:0.01" },
-#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.debit_account_no = 42,
- .details.admin_add_incoming.credit_account_no = EXCHANGE_ACCOUNT_NO,
- .details.admin_add_incoming.auth_username = "user42",
- .details.admin_add_incoming.auth_password = "pass42",
- .details.admin_add_incoming.amount = "EUR:5.01" },
- /* Run wirewatch to observe /admin/add/incoming */
- { .oc = OC_RUN_WIREWATCH,
- .label = "wirewatch-1" },
- /* 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 = "{ \"url\":\"payto://x-taler-bank/localhost:8082/42\", \"salt\":\"my salt\" }",
- .details.deposit.contract_terms = "{ \"items\": [ { \"name\":\"ice cream\", \"value\":1 } ] }" },
-
- /* Try to overdraw funds ... */
- { .oc = OC_WITHDRAW_SIGN,
- .label = "withdraw-coin-2",
- .expected_response_code = MHD_HTTP_FORBIDDEN,
- .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 = "{ \"url\":\"payto://x-taler-bank/localhost:8082/43\", \"salt\":\"my salt\" }",
- .details.deposit.contract_terms = "{ \"items\": [ { \"name\":\"ice cream\", \"value\":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 = "{ \"url\":\"payto://x-taler-bank/localhost:8082/42\", \"salt\":\"my salt\" }",
- .details.deposit.contract_terms = "{ \"items\": [ { \"name\":\"ice cream\", \"value\":1 } ] }" },
- /* Try to double-spend the 5 EUR coin at the same merchant (but different
- proposal) */
- { .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 = "{ \"url\":\"payto://x-taler-bank/localhost:8082/42\", \"salt\":\"my salt\" }",
- .details.deposit.contract_terms = "{ \"items\":[{ \"name\":\"ice cream\", \"value\":2 } ] }" },
-
- /* ***************** /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.debit_account_no = 424,
- .details.admin_add_incoming.credit_account_no = EXCHANGE_ACCOUNT_NO,
- .details.admin_add_incoming.auth_username = "user424",
- .details.admin_add_incoming.auth_password = "pass424",
- .details.admin_add_incoming.amount = "EUR:5.01" },
- /* Run wirewatch to observe /admin/add/incoming */
- { .oc = OC_RUN_WIREWATCH,
- .label = "wirewatch-2" },
- /* 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 = "{ \"url\":\"payto://x-taler-bank/localhost:8082/42\", \"salt\":\"my salt\" }",
- .details.deposit.contract_terms = "{ \"items\" : [ { \"name\":\"ice cream\", \"value\":\"EUR:1\" } ] }" },
-
- /* 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_coin = {
- .amount = "EUR:4",
- .coin_ref = "refresh-withdraw-coin-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" },
-
- /* do it again to check idempotency */
- { .oc = OC_REFRESH_REVEAL,
- .label = "refresh-reveal-1-idempotency",
- .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-idempotency",
- .details.deposit.coin_idx = 0,
- .details.deposit.wire_details = "{ \"url\":\"payto://x-taler-bank/localhost:8082/42\", \"salt\":\"my salt\" }",
- .details.deposit.contract_terms = "{ \"items\": [ { \"name\":\"ice cream\", \"value\":3 } ] }" },
-
- /* 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 = "{ \"url\":\"payto://x-taler-bank/localhost:8082/43\", \"salt\":\"my salt\" }",
- .details.deposit.contract_terms = "{ \"items\": [ { \"name\":\"ice cream\", \"value\":3 } ] }" },
-
- /* 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_coin = {
- .amount = "EUR:4",
- .coin_ref = "refresh-withdraw-coin-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 exchange 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 exchange 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 exchange didn't use that
- WTID value for any transaction. */
- { .oc = OC_WIRE_DEPOSITS,
- .label = "wire-deposit-failing",
- .expected_response_code = MHD_HTTP_NOT_FOUND },
-
- /* Run transfers. Note that _actual_ aggregation will NOT
- happen here, as each deposit operation is run with a
- fresh merchant public key! */
- { .oc = OC_RUN_AGGREGATOR,
- .label = "run-aggregator" },
-
- { .oc = OC_CHECK_BANK_TRANSFER,
- .label = "check_bank_transfer-499c",
- .details.check_bank_transfer.exchange_base_url = "http://localhost:8081/",
- .details.check_bank_transfer.amount = "EUR:4.98",
- .details.check_bank_transfer.account_debit = 2,
- .details.check_bank_transfer.account_credit = 42
- },
- { .oc = OC_CHECK_BANK_TRANSFER,
- .label = "check_bank_transfer-99c1",
- .details.check_bank_transfer.exchange_base_url = "http://localhost:8081/",
- .details.check_bank_transfer.amount = "EUR:0.98",
- .details.check_bank_transfer.account_debit = 2,
- .details.check_bank_transfer.account_credit = 42
- },
- { .oc = OC_CHECK_BANK_TRANSFER,
- .label = "check_bank_transfer-99c2",
- .details.check_bank_transfer.exchange_base_url = "http://localhost:8081/",
- .details.check_bank_transfer.amount = "EUR:0.98",
- .details.check_bank_transfer.account_debit = 2,
- .details.check_bank_transfer.account_credit = 42
- },
- { .oc = OC_CHECK_BANK_TRANSFER,
- .label = "check_bank_transfer-9c",
- .details.check_bank_transfer.exchange_base_url = "http://localhost:8081/",
- .details.check_bank_transfer.amount = "EUR:0.08",
- .details.check_bank_transfer.account_debit = 2,
- .details.check_bank_transfer.account_credit = 43
- },
- { .oc = OC_CHECK_BANK_TRANSFER,
- .label = "check_bank_transfer-aai-1",
- .details.check_bank_transfer.exchange_base_url = "http://localhost:8081/",
- .details.check_bank_transfer.amount = "EUR:5.01",
- .details.check_bank_transfer.account_debit = 42,
- .details.check_bank_transfer.account_credit = 2
- },
- { .oc = OC_CHECK_BANK_TRANSFER,
- .label = "check_bank_transfer-aai-2",
- .details.check_bank_transfer.exchange_base_url = "http://localhost:8081/",
- .details.check_bank_transfer.amount = "EUR:5.01",
- .details.check_bank_transfer.account_debit = 424,
- .details.check_bank_transfer.account_credit = 2
- },
-
- { .oc = OC_CHECK_BANK_TRANSFERS_EMPTY,
- .label = "check_bank_empty" },
- { .oc = OC_DEPOSIT_WTID,
- .label = "deposit-wtid-ok",
- .expected_response_code = MHD_HTTP_OK,
- .details.deposit_wtid.deposit_ref = "deposit-simple",
- .details.deposit_wtid.bank_transfer_ref = "check_bank_transfer-499c" },
-
- { .oc = OC_WIRE_DEPOSITS,
- .label = "wire-deposits-success-bank",
- .expected_response_code = MHD_HTTP_OK,
- .details.wire_deposits.wtid_ref = "check_bank_transfer-99c1",
- .details.wire_deposits.total_amount_expected = "EUR:0.98",
- .details.wire_deposits.wire_fee_expected = "EUR:0.01" },
-
- { .oc = OC_WIRE_DEPOSITS,
- .label = "wire-deposits-success-wtid",
- .expected_response_code = MHD_HTTP_OK,
- .details.wire_deposits.wtid_ref = "deposit-wtid-ok",
- .details.wire_deposits.total_amount_expected = "EUR:4.98",
- .details.wire_deposits.wire_fee_expected = "EUR:0.01" },
-
- /* ************** End of tracking API testing************* */
-
- /* ************** Test /refund API ************* */
-
-
- /* Fill reserve with EUR:5.01, as withdraw fee is 1 ct per config */
- { .oc = OC_ADMIN_ADD_INCOMING,
- .label = "create-reserve-r1",
- .expected_response_code = MHD_HTTP_OK,
- .details.admin_add_incoming.debit_account_no = 42,
- .details.admin_add_incoming.credit_account_no = EXCHANGE_ACCOUNT_NO,
- .details.admin_add_incoming.auth_username = "user42",
- .details.admin_add_incoming.auth_password = "pass42",
- .details.admin_add_incoming.amount = "EUR:5.01" },
- /* Run wirewatch to observe /admin/add/incoming */
- { .oc = OC_RUN_WIREWATCH,
- .label = "wirewatch-3" },
- /* Withdraw a 5 EUR coin, at fee of 1 ct */
- { .oc = OC_WITHDRAW_SIGN,
- .label = "withdraw-coin-r1",
- .expected_response_code = MHD_HTTP_OK,
- .details.reserve_withdraw.reserve_reference = "create-reserve-r1",
- .details.reserve_withdraw.amount = "EUR:5" },
- /* Spend 5 EUR of the 5 EUR coin (in full)
- (merchant would receive EUR:4.99 due to 1 ct deposit fee) */
- { .oc = OC_DEPOSIT,
- .label = "deposit-refund-1",
- .expected_response_code = MHD_HTTP_OK,
- .details.deposit.amount = "EUR:5",
- .details.deposit.coin_ref = "withdraw-coin-r1",
- .details.deposit.wire_details = "{ \"url\":\"payto://x-taler-bank/localhost:8082/42\", \"salt\":\"my salt\" }",
- .details.deposit.contract_terms = "{ \"items\" : [ { \"name\":\"ice cream\", \"value\":\"EUR:5\" } ] }",
- .details.deposit.refund_deadline = { 60LL * 1000 * 1000 } /* 60 s */,
- },
- /* Run transfers. Should do nothing as refund deadline blocks it */
- { .oc = OC_RUN_AGGREGATOR,
- .label = "run-aggregator-refund" },
- { .oc = OC_CHECK_BANK_TRANSFER,
- .label = "check_bank_transfer-aai-3",
- .details.check_bank_transfer.exchange_base_url = "http://localhost:8081/",
- .details.check_bank_transfer.amount = "EUR:5.01",
- .details.check_bank_transfer.account_debit = 42,
- .details.check_bank_transfer.account_credit = 2
- },
- /* check that aggregator didn't do anything, as expected */
- { .oc = OC_CHECK_BANK_TRANSFERS_EMPTY,
- .label = "check-refund-not-run" },
- /* Trigger refund */
- { .oc = OC_REFUND,
- .label = "refund-ok",
- .expected_response_code = MHD_HTTP_OK,
- .details.refund.amount = "EUR:5",
- .details.refund.fee = "EUR:0.01",
- .details.refund.deposit_ref = "deposit-refund-1",
- },
- /* Spend 4.99 EUR of the refunded 4.99 EUR coin (1ct gone due to refund)
- (merchant would receive EUR:4.98 due to 1 ct deposit fee) */
- { .oc = OC_DEPOSIT,
- .label = "deposit-refund-2",
- .expected_response_code = MHD_HTTP_OK,
- .details.deposit.amount = "EUR:4.99",
- .details.deposit.coin_ref = "withdraw-coin-r1",
- .details.deposit.wire_details = "{ \"url\":\"payto://x-taler-bank/localhost:8082/42\", \"salt\":\"my salt\" }",
- .details.deposit.contract_terms = "{ \"items\" : [ { \"name\":\"more ice cream\", \"value\":\"EUR:5\" } ] }",
- },
- /* Run transfers. This will do the transfer as refund deadline was 0 */
- { .oc = OC_RUN_AGGREGATOR,
- .label = "run-aggregator-3" },
- /* Check that deposit did run */
- { .oc = OC_CHECK_BANK_TRANSFER,
- .label = "check_bank_transfer-pre-refund",
- .details.check_bank_transfer.exchange_base_url = "http://localhost:8081/",
- .details.check_bank_transfer.amount = "EUR:4.97",
- .details.check_bank_transfer.account_debit = 2,
- .details.check_bank_transfer.account_credit = 42
- },
- /* Run failing refund, as past deadline & aggregation */
- { .oc = OC_REFUND,
- .label = "refund-fail",
- .expected_response_code = MHD_HTTP_GONE,
- .details.refund.amount = "EUR:4.99",
- .details.refund.fee = "EUR:0.01",
- .details.refund.deposit_ref = "deposit-refund-2",
- },
- { .oc = OC_CHECK_BANK_TRANSFERS_EMPTY,
- .label = "check-empty-after-refund" },
-
-
- /* Test refunded coins are never executed, even past
- refund deadline */
- { .oc = OC_ADMIN_ADD_INCOMING,
- .label = "create-reserve-rb",
- .expected_response_code = MHD_HTTP_OK,
- .details.admin_add_incoming.debit_account_no = 42,
- .details.admin_add_incoming.credit_account_no = EXCHANGE_ACCOUNT_NO,
- .details.admin_add_incoming.auth_username = "user42",
- .details.admin_add_incoming.auth_password = "pass42",
- .details.admin_add_incoming.amount = "EUR:5.01" },
- /* Run wirewatch to observe /admin/add/incoming */
- { .oc = OC_RUN_WIREWATCH,
- .label = "wirewatch-3b" },
- /* Withdraw a 5 EUR coin, at fee of 1 ct */
- { .oc = OC_WITHDRAW_SIGN,
- .label = "withdraw-coin-rb",
- .expected_response_code = MHD_HTTP_OK,
- .details.reserve_withdraw.reserve_reference = "create-reserve-rb",
- .details.reserve_withdraw.amount = "EUR:5" },
- /* Spend 5 EUR of the 5 EUR coin (in full)
- (merchant would receive EUR:4.99 due to 1 ct deposit fee) */
- { .oc = OC_DEPOSIT,
- .label = "deposit-refund-1b",
- .expected_response_code = MHD_HTTP_OK,
- .details.deposit.amount = "EUR:5",
- .details.deposit.coin_ref = "withdraw-coin-rb",
- .details.deposit.contract_terms = "{ \"items\" : [ { \"name\":\"ice cream\", \"value\":\"EUR:5\" } ] }",
- .details.deposit.refund_deadline = { 0 },
- .details.deposit.wire_details = "{ \"url\":\"payto://x-taler-bank/localhost:8082/42\", \"salt\":\"my salt\" }"
- },
- { .oc = OC_CHECK_BANK_TRANSFER,
- .label = "check_bank_transfer-aai-3b",
- .details.check_bank_transfer.exchange_base_url = "http://localhost:8081/",
- .details.check_bank_transfer.amount = "EUR:5.01",
- .details.check_bank_transfer.account_debit = 42,
- .details.check_bank_transfer.account_credit = 2
- },
- /* Trigger refund (before aggregator had a chance to execute
- deposit, even though refund deadline was zero) */
- { .oc = OC_REFUND,
- .label = "refund-ok-fast",
- .expected_response_code = MHD_HTTP_OK,
- .details.refund.amount = "EUR:5",
- .details.refund.fee = "EUR:0.01",
- .details.refund.deposit_ref = "deposit-refund-1b",
- },
- /* Run transfers. This will do the transfer as refund deadline
- was 0, except of course because the refund succeeded, the
- transfer should no longer be done. */
- { .oc = OC_RUN_AGGREGATOR,
- .label = "run-aggregator-3b" },
- /* check that aggregator didn't do anything, as expected */
- { .oc = OC_CHECK_BANK_TRANSFERS_EMPTY,
- .label = "check-refund-fast-not-run" },
-
-
- /* ************** End of refund API testing************* */
-
- /* ************** Test /payback API ************* */
-
- /* Fill reserve with EUR:5.01, as withdraw fee is 1 ct per config,
- then withdraw a coin and then have it be paid back. */
- { .oc = OC_ADMIN_ADD_INCOMING,
- .label = "payback-create-reserve-1",
- .expected_response_code = MHD_HTTP_OK,
- .details.admin_add_incoming.debit_account_no = 42,
- .details.admin_add_incoming.credit_account_no = EXCHANGE_ACCOUNT_NO,
- .details.admin_add_incoming.auth_username = "user42",
- .details.admin_add_incoming.auth_password = "pass42",
- .details.admin_add_incoming.amount = "EUR:5.01" },
- /* Run wirewatch to observe /admin/add/incoming */
- { .oc = OC_RUN_WIREWATCH,
- .label = "wirewatch-4" },
- /* Withdraw a 5 EUR coin, at fee of 1 ct */
- { .oc = OC_WITHDRAW_SIGN,
- .label = "payback-withdraw-coin-1",
- .expected_response_code = MHD_HTTP_OK,
- .details.reserve_withdraw.reserve_reference = "payback-create-reserve-1",
- .details.reserve_withdraw.amount = "EUR:5" },
- { .oc = OC_REVOKE,
- .label = "revoke-1",
- .expected_response_code = MHD_HTTP_OK,
- .details.revoke.ref = "payback-withdraw-coin-1" },
- { .oc = OC_PAYBACK,
- .label = "payback-1",
- .expected_response_code = MHD_HTTP_OK,
- .details.payback.ref = "payback-withdraw-coin-1",
- .details.payback.amount = "EUR:5" },
- /* Check the money is back with the reserve */
- { .oc = OC_WITHDRAW_STATUS,
- .label = "payback-reserve-status-1",
- .expected_response_code = MHD_HTTP_OK,
- .details.reserve_status.reserve_reference = "payback-create-reserve-1",
- .details.reserve_status.expected_balance = "EUR:5.00" },
-
-
- /* Fill reserve with EUR:2.02, as withdraw fee is 1 ct per config,
- then withdraw two coin, partially spend one, and then have the rest paid back.
- Check deposit of other coin fails.
- (Do not use EUR:5 here as the EUR:5 coin was revoked and we did not
- bother to create a new one...) */
- { .oc = OC_ADMIN_ADD_INCOMING,
- .label = "payback-create-reserve-2",
- .expected_response_code = MHD_HTTP_OK,
- .details.admin_add_incoming.debit_account_no = 42,
- .details.admin_add_incoming.credit_account_no = EXCHANGE_ACCOUNT_NO,
- .details.admin_add_incoming.auth_username = "user42",
- .details.admin_add_incoming.auth_password = "pass42",
- .details.admin_add_incoming.amount = "EUR:2.02" },
- /* Run wirewatch to observe /admin/add/incoming */
- { .oc = OC_RUN_WIREWATCH,
- .label = "wirewatch-5" },
- /* Withdraw a 1 EUR coin, at fee of 1 ct */
- { .oc = OC_WITHDRAW_SIGN,
- .label = "payback-withdraw-coin-2a",
- .expected_response_code = MHD_HTTP_OK,
- .details.reserve_withdraw.reserve_reference = "payback-create-reserve-2",
- .details.reserve_withdraw.amount = "EUR:1" },
- /* Withdraw a 1 EUR coin, at fee of 1 ct */
- { .oc = OC_WITHDRAW_SIGN,
- .label = "payback-withdraw-coin-2b",
- .expected_response_code = MHD_HTTP_OK,
- .details.reserve_withdraw.reserve_reference = "payback-create-reserve-2",
- .details.reserve_withdraw.amount = "EUR:1" },
-
- { .oc = OC_DEPOSIT,
- .label = "payback-deposit-partial",
- .expected_response_code = MHD_HTTP_OK,
- .details.deposit.amount = "EUR:0.5",
- .details.deposit.coin_ref = "payback-withdraw-coin-2a",
- .details.deposit.wire_details = "{ \"url\":\"payto://x-taler-bank/localhost:8082/42\", \"salt\":\"my salt\" }",
- .details.deposit.contract_terms = "{ \"items\": [ { \"name\":\"more ice cream\", \"value\":1 } ] }" },
- { .oc = OC_REVOKE,
- .label = "revoke-2",
- .expected_response_code = MHD_HTTP_OK,
- .details.revoke.ref = "payback-withdraw-coin-2a" },
- { .oc = OC_PAYBACK,
- .label = "payback-2",
- .expected_response_code = MHD_HTTP_OK,
- .details.payback.ref = "payback-withdraw-coin-2a",
- .details.payback.amount = "EUR:0.5" },
- { .oc = OC_PAYBACK,
- .label = "payback-2b",
- .expected_response_code = MHD_HTTP_FORBIDDEN,
- .details.payback.ref = "payback-withdraw-coin-2a",
- .details.payback.amount = "EUR:0.5" },
- { .oc = OC_DEPOSIT,
- .label = "payback-deposit-revoked",
- .expected_response_code = MHD_HTTP_NOT_FOUND,
- .details.deposit.amount = "EUR:1",
- .details.deposit.coin_ref = "payback-withdraw-coin-2b",
- .details.deposit.wire_details = "{ \"url\":\"payto://x-taler-bank/localhost:8082/42\", \"salt\":\"my salt\" }",
- .details.deposit.contract_terms = "{ \"items\": [ { \"name\":\"more ice cream\", \"value\":1 } ] }" },
-
- /* Test deposit fails after payback, with proof in payback */
- /* FIXME: #3887: right now, the exchange will never return the
- coin's transaction history with payback data, as we get a 404 on the DK! */
- { .oc = OC_DEPOSIT,
- .label = "payback-deposit-partial-after-payback",
- .expected_response_code = MHD_HTTP_NOT_FOUND,
- .details.deposit.amount = "EUR:0.5",
- .details.deposit.coin_ref = "payback-withdraw-coin-2a",
- .details.deposit.wire_details = "{ \"url\":\"payto://x-taler-bank/localhost:8082/42\", \"salt\":\"my salt\" }",
- .details.deposit.contract_terms = "{ \"items\": [ { \"name\":\"extra ice cream\", \"value\":1 } ] }" },
-
-
- /* Test that revoked coins cannot be withdrawn */
- { .oc = OC_ADMIN_ADD_INCOMING,
- .label = "payback-create-reserve-3",
- .expected_response_code = MHD_HTTP_OK,
- .details.admin_add_incoming.debit_account_no = 42,
- .details.admin_add_incoming.credit_account_no = EXCHANGE_ACCOUNT_NO,
- .details.admin_add_incoming.auth_username = "user42",
- .details.admin_add_incoming.auth_password = "pass42",
- .details.admin_add_incoming.amount = "EUR:1.01" },
- /* Run wirewatch to observe /admin/add/incoming */
- { .oc = OC_RUN_WIREWATCH,
- .label = "wirewatch-6" },
- { .oc = OC_WITHDRAW_SIGN,
- .label = "payback-withdraw-coin-3-revoked",
- .expected_response_code = MHD_HTTP_NOT_FOUND,
- .details.reserve_withdraw.reserve_reference = "payback-create-reserve-3",
- .details.reserve_withdraw.amount = "EUR:1" },
-
- /* check that we are empty before the rejection test */
- { .oc = OC_CHECK_BANK_TRANSFER,
- .label = "check_bank_transfer-pr1",
- .details.check_bank_transfer.exchange_base_url = "http://localhost:8081/",
- .details.check_bank_transfer.amount = "EUR:5.01",
- .details.check_bank_transfer.account_debit = 42,
- .details.check_bank_transfer.account_credit = 2
- },
- { .oc = OC_CHECK_BANK_TRANSFER,
- .label = "check_bank_transfer-pr2",
- .details.check_bank_transfer.exchange_base_url = "http://localhost:8081/",
- .details.check_bank_transfer.amount = "EUR:2.02",
- .details.check_bank_transfer.account_debit = 42,
- .details.check_bank_transfer.account_credit = 2
- },
- { .oc = OC_CHECK_BANK_TRANSFER,
- .label = "check_bank_transfer-pr3",
- .details.check_bank_transfer.exchange_base_url = "http://localhost:8081/",
- .details.check_bank_transfer.amount = "EUR:1.01",
- .details.check_bank_transfer.account_debit = 42,
- .details.check_bank_transfer.account_credit = 2
- },
-
- { .oc = OC_CHECK_BANK_TRANSFERS_EMPTY,
- .label = "check-empty-again" },
-
- /* Test rejection of bogus wire transfers */
- { .oc = OC_ADMIN_ADD_INCOMING,
- .label = "bogus-subject",
- .expected_response_code = MHD_HTTP_OK,
- .details.admin_add_incoming.subject = "not a reserve public key",
- .details.admin_add_incoming.debit_account_no = 42,
- .details.admin_add_incoming.credit_account_no = EXCHANGE_ACCOUNT_NO,
- .details.admin_add_incoming.auth_username = "user42",
- .details.admin_add_incoming.auth_password = "pass42",
- .details.admin_add_incoming.amount = "EUR:1.01" },
- /* Run wirewatch to observe rejection */
- { .oc = OC_RUN_WIREWATCH,
- .label = "wirewatch-7" },
- { .oc = OC_CHECK_BANK_TRANSFERS_EMPTY,
- .label = "check-empty-from-reject" },
-
-
- /* ************** End of payback API testing************* */
-#endif
-
- { .oc = OC_END }
- };
-
- is = GNUNET_new (struct InterpreterState);
- is->commands = commands;
-
- ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
- &rc);
- GNUNET_assert (NULL != ctx);
- rc = GNUNET_CURL_gnunet_rc_create (ctx);
- fakebank = TALER_FAKEBANK_start (8082);
- exchange = TALER_EXCHANGE_connect (ctx,
- "http://localhost:8081",
- &cert_cb,
- is,
- TALER_EXCHANGE_OPTION_END);
- GNUNET_assert (NULL != exchange);
- timeout_task
- = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
- (GNUNET_TIME_UNIT_SECONDS, 300),
- &do_timeout, NULL);
- GNUNET_SCHEDULER_add_shutdown (&do_shutdown, is);
-}
-
-
-/**
- * Remove files from previous runs
- */
-static void
-cleanup_files ()
-{
- struct GNUNET_CONFIGURATION_Handle *cfg;
- char *dir;
-
- cfg = GNUNET_CONFIGURATION_create ();
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_load (cfg,
- "test_exchange_api.conf"))
- {
- GNUNET_break (0);
- GNUNET_CONFIGURATION_destroy (cfg);
- exit (77);
- }
- GNUNET_assert (GNUNET_OK ==
- GNUNET_CONFIGURATION_get_value_filename (cfg,
- "exchange",
- "keydir",
- &dir));
- if (GNUNET_YES ==
- GNUNET_DISK_directory_test (dir,
- GNUNET_NO))
- GNUNET_break (GNUNET_OK ==
- GNUNET_DISK_directory_remove (dir));
- GNUNET_free (dir);
- GNUNET_CONFIGURATION_destroy (cfg);
-}
-
-
-/**
- * Main function for the testcase for the exchange 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_SIGNAL_Context *shc_chld;
- enum GNUNET_OS_ProcessStatusType type;
- unsigned long code;
- unsigned int iter;
-
- /* These might get in the way... */
- unsetenv ("XDG_DATA_HOME");
- unsetenv ("XDG_CONFIG_HOME");
- GNUNET_log_setup ("test-exchange-api",
- "INFO",
- NULL);
- if (GNUNET_OK !=
- GNUNET_NETWORK_test_port_free (IPPROTO_TCP,
- 8081))
- {
- fprintf (stderr,
- "Required port %u not available, skipping.\n",
- 8081);
- return 77;
- }
- if (GNUNET_OK !=
- GNUNET_NETWORK_test_port_free (IPPROTO_TCP,
- 8082))
- {
- fprintf (stderr,
- "Required port %u not available, skipping.\n",
- 8082);
- return 77;
- }
- cleanup_files ();
-
- proc = GNUNET_OS_start_process (GNUNET_NO,
- GNUNET_OS_INHERIT_STD_ALL,
- NULL, NULL, NULL,
- "taler-exchange-keyup",
- "taler-exchange-keyup",
- "-c", "test_exchange_api.conf",
- "-o", "auditor.in",
- NULL);
- if (NULL == proc)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to run `taler-exchange-keyup`, is your PATH correct?\n");
- return 77;
- }
- GNUNET_OS_process_wait (proc);
- GNUNET_OS_process_destroy (proc);
-
- proc = GNUNET_OS_start_process (GNUNET_NO,
- GNUNET_OS_INHERIT_STD_ALL,
- NULL, NULL, NULL,
- "taler-auditor-sign",
- "taler-auditor-sign",
- "-c", "test_exchange_api.conf",
- "-u", "http://auditor/",
- "-m", "98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG",
- "-r", "auditor.in",
- "-o", "test_exchange_api_home/.local/share/taler/auditors/auditor.out",
- NULL);
- if (NULL == proc)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to run `taler-exchange-keyup`, is your PATH correct?\n");
- return 77;
- }
- GNUNET_OS_process_wait (proc);
- GNUNET_OS_process_destroy (proc);
-
- proc = GNUNET_OS_start_process (GNUNET_NO,
- GNUNET_OS_INHERIT_STD_ALL,
- NULL, NULL, NULL,
- "taler-exchange-dbinit",
- "taler-exchange-dbinit",
- "-c", "test_exchange_api.conf",
- "-r",
- NULL);
- if (NULL == proc)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to run `taler-exchange-dbinit`, is your PATH correct?\n");
- return 77;
- }
- if (GNUNET_SYSERR ==
- GNUNET_OS_process_wait_status (proc,
- &type,
- &code))
- {
- GNUNET_break (0);
- GNUNET_OS_process_destroy (proc);
- return 1;
- }
- GNUNET_OS_process_destroy (proc);
- if ( (type == GNUNET_OS_PROCESS_EXITED) &&
- (0 != code) )
- {
- fprintf (stderr,
- "Failed to setup database\n");
- return 77;
- }
- if ( (type != GNUNET_OS_PROCESS_EXITED) ||
- (0 != code) )
- {
- fprintf (stderr,
- "Unexpected error running `taler-exchange-dbinit'!\n");
- return 1;
- }
- exchanged = GNUNET_OS_start_process (GNUNET_NO,
- GNUNET_OS_INHERIT_STD_ALL,
- NULL, NULL, NULL,
- "taler-exchange-httpd",
- "taler-exchange-httpd",
- "-c", "test_exchange_api.conf",
- "-i",
- NULL);
- /* give child time to start and bind against the socket */
- fprintf (stderr,
- "Waiting for `taler-exchange-httpd' to be ready");
- iter = 0;
- do
- {
- if (10 == iter)
- {
- fprintf (stderr,
- "Failed to launch `taler-exchange-httpd' (or `wget')\n");
- GNUNET_OS_process_kill (exchanged,
- SIGTERM);
- GNUNET_OS_process_wait (exchanged);
- GNUNET_OS_process_destroy (exchanged);
- return 77;
- }
- fprintf (stderr, ".");
- sleep (1);
- iter++;
- }
- 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_NO;
- sigpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_NO);
- GNUNET_assert (NULL != sigpipe);
- shc_chld = GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD,
- &sighandler_child_death);
- GNUNET_SCHEDULER_run (&run, NULL);
- GNUNET_SIGNAL_handler_uninstall (shc_chld);
- shc_chld = NULL;
- GNUNET_DISK_pipe_close (sigpipe);
- GNUNET_break (0 ==
- GNUNET_OS_process_kill (exchanged,
- SIGTERM));
- GNUNET_break (GNUNET_OK ==
- GNUNET_OS_process_wait (exchanged));
- GNUNET_OS_process_destroy (exchanged);
- return (GNUNET_OK == result) ? 0 : 1;
-}
-
-/* end of test_exchange_api.c */
diff --git a/src/exchange-lib/test_exchange_api_keys_cherry_picking.c b/src/exchange-lib/test_exchange_api_keys_cherry_picking.c
deleted file mode 100644
index 0dc0c540a..000000000
--- a/src/exchange-lib/test_exchange_api_keys_cherry_picking.c
+++ /dev/null
@@ -1,803 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014-2017 GNUnet e.V. and Inria
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file exchange/test_exchange_api_keys_cherry_picking.c
- * @brief testcase to test exchange's /keys cherry picking ability
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "taler_util.h"
-#include "taler_signatures.h"
-#include "taler_exchange_service.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_util_lib.h>
-#include <microhttpd.h>
-
-
-/**
- * Main execution context for the main loop.
- */
-static struct GNUNET_CURL_Context *ctx;
-
-/**
- * Handle to access the exchange.
- */
-static struct TALER_EXCHANGE_Handle *exchange;
-
-/**
- * Context for running the CURL event loop.
- */
-static struct GNUNET_CURL_RescheduleContext *rc;
-
-/**
- * Handle to the exchange process.
- */
-static struct GNUNET_OS_Process *exchanged;
-
-/**
- * Task run on timeout.
- */
-static struct GNUNET_SCHEDULER_Task *timeout_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,
-
- /**
- * Run a process.
- */
- OC_RUN_PROCESS,
-
- /**
- * Signal the exchange to reload the keys.
- */
- OC_SIGNAL_EXCHANGE,
-
- /**
- * Check the /keys.
- */
- OC_CHECK_KEYS
-
-};
-
-
-/**
- * Details for a exchange operation to execute.
- */
-struct Command
-{
- /**
- * Opcode of the command.
- */
- enum OpCode oc;
-
- /**
- * Label for the command, can be NULL.
- */
- const char *label;
-
- /**
- * Details about the command.
- */
- union
- {
-
- struct {
-
- /**
- * Binary to execute.
- */
- const char *binary;
-
- /**
- * Command-line arguments for the process to be run.
- */
- char *const *argv;
-
- /**
- * Process handle.
- */
- struct GNUNET_OS_Process *proc;
-
- /**
- * ID of task called whenever we get a SIGCHILD.
- */
- struct GNUNET_SCHEDULER_Task *child_death_task;
-
- } run_process;
-
- struct {
-
- /**
- * Expected number of denomination keys.
- */
- unsigned int num_denom_keys;
-
- /**
- * Which generation of /keys are we verifying here?
- * Used to make sure we got the right number of
- * interactions.
- */
- unsigned int generation;
-
- } check_keys;
-
- } details;
-
-};
-
-
-/**
- * State of the interpreter loop.
- */
-struct InterpreterState
-{
- /**
- * Keys from the exchange.
- */
- const struct TALER_EXCHANGE_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;
-
- /**
- * Is the interpreter running (#GNUNET_YES) or waiting
- * for /keys (#GNUNET_NO)?
- */
- int working;
-
- /**
- * How often have we gotten a /keys response so far?
- */
- unsigned int key_generation;
-
-};
-
-
-/**
- * Pipe used to communicate child death via signal.
- */
-static struct GNUNET_DISK_PipeHandle *sigpipe;
-
-
-/**
- * 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 ();
-}
-
-
-/**
- * Run the main interpreter loop that performs exchange operations.
- *
- * @param cls contains the `struct InterpreterState`
- */
-static void
-interpreter_run (void *cls);
-
-
-/**
- * Run the next command with the interpreter.
- *
- * @param is current interpeter state.
- */
-static void
-next_command (struct InterpreterState *is)
-{
- if (GNUNET_SYSERR == result)
- return; /* ignore, we already failed! */
- is->ip++;
- is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
- is);
-}
-
-
-/**
- * Task triggered whenever we receive a SIGCHLD (child
- * process died).
- *
- * @param cls closure, NULL if we need to self-restart
- */
-static void
-maint_child_death (void *cls)
-{
- struct InterpreterState *is = cls;
- struct Command *cmd = &is->commands[is->ip];
- const struct GNUNET_DISK_FileHandle *pr;
- char c[16];
-
- switch (cmd->oc) {
- case OC_RUN_PROCESS:
- cmd->details.run_process.child_death_task = NULL;
- pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ);
- GNUNET_break (0 < GNUNET_DISK_file_read (pr, &c, sizeof (c)));
- GNUNET_OS_process_wait (cmd->details.run_process.proc);
- GNUNET_OS_process_destroy (cmd->details.run_process.proc);
- cmd->details.run_process.proc = NULL;
- break;
- default:
- GNUNET_break (0);
- fail (is);
- return;
- }
- next_command (is);
-}
-
-
-/**
- * Run the main interpreter loop that performs exchange operations.
- *
- * @param cls contains the `struct InterpreterState`
- */
-static void
-interpreter_run (void *cls)
-{
- struct InterpreterState *is = cls;
- struct Command *cmd = &is->commands[is->ip];
- const struct GNUNET_SCHEDULER_TaskContext *tc;
-
- is->task = NULL;
- tc = GNUNET_SCHEDULER_get_task_context ();
- if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
- {
- fprintf (stderr,
- "Test aborted by shutdown request\n");
- fail (is);
- return;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Running command `%s'\n",
- cmd->label);
- switch (cmd->oc)
- {
- case OC_END:
- result = GNUNET_OK;
- GNUNET_SCHEDULER_shutdown ();
- return;
- case OC_RUN_PROCESS:
- {
- const struct GNUNET_DISK_FileHandle *pr;
-
- cmd->details.run_process.proc
- = GNUNET_OS_start_process_vap (GNUNET_NO,
- GNUNET_OS_INHERIT_STD_ALL,
- NULL, NULL, NULL,
- cmd->details.run_process.binary,
- cmd->details.run_process.argv);
- if (NULL == cmd->details.run_process.proc)
- {
- GNUNET_break (0);
- fail (is);
- return;
- }
- pr = GNUNET_DISK_pipe_handle (sigpipe,
- GNUNET_DISK_PIPE_END_READ);
- cmd->details.run_process.child_death_task
- = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
- pr,
- &maint_child_death,
- is);
- return;
- }
- case OC_SIGNAL_EXCHANGE:
- {
- GNUNET_break (0 ==
- GNUNET_OS_process_kill (exchanged,
- SIGUSR1));
- /* give exchange time to process the signal */
- sleep (1);
- next_command (is);
- return;
- }
- case OC_CHECK_KEYS:
- {
- if (is->key_generation < cmd->details.check_keys.generation)
- {
- /* Go back to waiting for /keys signal! */
- is->working = GNUNET_NO;
- GNUNET_break (0 ==
- TALER_EXCHANGE_check_keys_current (exchange,
- GNUNET_YES).abs_value_us);
- return;
- }
- if (is->key_generation > cmd->details.check_keys.generation)
- {
- /* We got /keys too often, strange. Fatal. May theoretically happen if
- somehow we were really unlucky and /keys expired "naturally", but
- obviously with a sane configuration this should also not be. */
- GNUNET_break (0);
- fail (is);
- return;
- }
- /* /keys was updated, let's check they were OK! */
- if (cmd->details.check_keys.num_denom_keys !=
- is->keys->num_denom_keys)
- {
- /* Did not get the expected number of denomination keys! */
- GNUNET_break (0);
- fprintf (stderr,
- "Got %u keys in step %s\n",
- is->keys->num_denom_keys,
- cmd->label);
- fail (is);
- return;
- }
- next_command (is);
- return;
- }
- default:
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unknown instruction %d at %u (%s)\n",
- cmd->oc,
- is->ip,
- cmd->label);
- fail (is);
- return;
- }
-}
-
-
-/**
- * Signal handler called for SIGCHLD. Triggers the
- * respective handler by writing to the trigger pipe.
- */
-static void
-sighandler_child_death ()
-{
- static char c;
- int old_errno = errno; /* back-up errno */
-
- GNUNET_break (1 ==
- GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle
- (sigpipe, GNUNET_DISK_PIPE_END_WRITE),
- &c, sizeof (c)));
- errno = old_errno; /* restore errno */
-}
-
-
-/**
- * Function run when the test terminates (good or bad) with timeout.
- *
- * @param cls NULL
- */
-static void
-do_timeout (void *cls)
-{
- timeout_task = NULL;
- GNUNET_SCHEDULER_shutdown ();
-}
-
-
-/**
- * Function run when the test terminates (good or bad).
- * Cleans up our state.
- *
- * @param cls the interpreter state.
- */
-static void
-do_shutdown (void *cls)
-{
- struct InterpreterState *is = cls;
- struct Command *cmd;
-
- for (unsigned int i=0;OC_END != (cmd = &is->commands[i])->oc;i++)
- {
- switch (cmd->oc)
- {
- case OC_END:
- GNUNET_assert (0);
- break;
- case OC_RUN_PROCESS:
- if (NULL != cmd->details.run_process.proc)
- {
- GNUNET_break (0 ==
- GNUNET_OS_process_kill (cmd->details.run_process.proc,
- SIGKILL));
- GNUNET_OS_process_wait (cmd->details.run_process.proc);
- GNUNET_OS_process_destroy (cmd->details.run_process.proc);
- cmd->details.run_process.proc = NULL;
- }
- if (NULL != cmd->details.run_process.child_death_task)
- {
- GNUNET_SCHEDULER_cancel (cmd->details.run_process.child_death_task);
- cmd->details.run_process.child_death_task = NULL;
- }
- break;
- case OC_SIGNAL_EXCHANGE:
- /* nothing to do */
- break;
- case OC_CHECK_KEYS:
- /* nothing to do */
- 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 != exchange)
- {
- TALER_EXCHANGE_disconnect (exchange);
- exchange = NULL;
- }
- if (NULL != ctx)
- {
- GNUNET_CURL_fini (ctx);
- ctx = NULL;
- }
- if (NULL != rc)
- {
- GNUNET_CURL_gnunet_rc_destroy (rc);
- rc = NULL;
- }
- if (NULL != timeout_task)
- {
- GNUNET_SCHEDULER_cancel (timeout_task);
- timeout_task = NULL;
- }
-}
-
-
-/**
- * Functions of this type are called to provide the retrieved signing and
- * denomination keys of the exchange. No TALER_EXCHANGE_*() functions should be called
- * in this callback.
- *
- * @param cls closure
- * @param keys information about keys of the exchange
- * @param vc version compatibility
- */
-static void
-cert_cb (void *cls,
- const struct TALER_EXCHANGE_Keys *keys,
- enum TALER_EXCHANGE_VersionCompatibility vc)
-{
- 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;
- if (GNUNET_YES == is->working)
- return;
- is->working = GNUNET_YES;
- is->key_generation++;
- is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
- is);
-}
-
-
-/**
- * Main function that will be run by the scheduler.
- *
- * @param cls closure
- */
-static void
-run (void *cls)
-{
- struct InterpreterState *is;
- static char *keyup[] = {
- "taler-exchange-keyup",
- "-c", "test_exchange_api_keys_cherry_picking_extended.conf",
- "-o", "auditor.in",
- NULL
- };
- static char *auditorsign[] = {
- "taler-auditor-sign",
- "-c", "test_exchange_api_keys_cherry_picking.conf",
- "-u", "http://auditor/",
- "-m", "98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG",
- "-r", "auditor.in",
- "-o", "test_exchange_api_home/.local/share/taler/auditors/auditor.out",
- NULL
- };
- static struct Command commands[] =
- {
- /* Test signal handling by itself */
- { .oc = OC_SIGNAL_EXCHANGE },
- /* Check we got /keys properly */
- { .oc = OC_CHECK_KEYS,
- .details.check_keys.generation = 1,
- .details.check_keys.num_denom_keys = 4
- },
- /* Generate more keys */
- { .oc = OC_RUN_PROCESS,
- .details.run_process.binary = "taler-exchange-keyup",
- .details.run_process.argv = keyup
- },
- /* Auditor-sign them */
- { .oc = OC_RUN_PROCESS,
- .details.run_process.binary = "taler-auditor-sign",
- .details.run_process.argv = auditorsign
- },
- /* Load new keys into exchange via signal */
- { .oc = OC_SIGNAL_EXCHANGE },
- /* Re-download and check /keys */
- { .oc = OC_CHECK_KEYS,
- .details.check_keys.generation = 2,
-#if TALER_EXCHANGE_API_DISABLE_CHERRYPICKING
- .details.check_keys.num_denom_keys = 12
-#else
- .details.check_keys.num_denom_keys = 8
-#endif
- },
- { .oc = OC_END }
- };
-
- is = GNUNET_new (struct InterpreterState);
- is->commands = commands;
-
- ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
- &rc);
- GNUNET_assert (NULL != ctx);
- rc = GNUNET_CURL_gnunet_rc_create (ctx);
- exchange = TALER_EXCHANGE_connect (ctx,
- "http://localhost:8081",
- &cert_cb,
- is,
- TALER_EXCHANGE_OPTION_END);
- GNUNET_assert (NULL != exchange);
- timeout_task
- = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
- (GNUNET_TIME_UNIT_SECONDS, 300),
- &do_timeout,
- NULL);
- GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
- is);
-}
-
-
-/**
- * Remove files from previous runs
- */
-static void
-cleanup_files ()
-{
- struct GNUNET_CONFIGURATION_Handle *cfg;
- char *dir;
-
- cfg = GNUNET_CONFIGURATION_create ();
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_load (cfg,
- "test_exchange_api.conf"))
- {
- GNUNET_break (0);
- GNUNET_CONFIGURATION_destroy (cfg);
- exit (77);
- }
- GNUNET_assert (GNUNET_OK ==
- GNUNET_CONFIGURATION_get_value_filename (cfg,
- "exchange",
- "keydir",
- &dir));
- if (GNUNET_YES ==
- GNUNET_DISK_directory_test (dir,
- GNUNET_NO))
- GNUNET_break (GNUNET_OK ==
- GNUNET_DISK_directory_remove (dir));
- GNUNET_free (dir);
- GNUNET_CONFIGURATION_destroy (cfg);
-}
-
-
-/**
- * Main function for the testcase for the exchange 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_SIGNAL_Context *shc_chld;
- enum GNUNET_OS_ProcessStatusType type;
- unsigned long code;
- unsigned int iter;
-
- /* These might get in the way... */
- unsetenv ("XDG_DATA_HOME");
- unsetenv ("XDG_CONFIG_HOME");
- GNUNET_log_setup ("test-exchange-api-keys-cherry-picking",
- "INFO",
- NULL);
- if (GNUNET_OK !=
- GNUNET_NETWORK_test_port_free (IPPROTO_TCP,
- 8081))
- {
- fprintf (stderr,
- "Required port %u not available, skipping.\n",
- 8081);
- return 77;
- }
- cleanup_files ();
-
- proc = GNUNET_OS_start_process (GNUNET_NO,
- GNUNET_OS_INHERIT_STD_ALL,
- NULL, NULL, NULL,
- "taler-exchange-keyup",
- "taler-exchange-keyup",
- "-c", "test_exchange_api_keys_cherry_picking.conf",
- "-o", "auditor.in",
- NULL);
- if (NULL == proc)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to run `taler-exchange-keyup`, is your PATH correct?\n");
- return 77;
- }
- GNUNET_OS_process_wait (proc);
- GNUNET_OS_process_destroy (proc);
-
- proc = GNUNET_OS_start_process (GNUNET_NO,
- GNUNET_OS_INHERIT_STD_ALL,
- NULL, NULL, NULL,
- "taler-auditor-sign",
- "taler-auditor-sign",
- "-c", "test_exchange_api_keys_cherry_picking.conf",
- "-u", "http://auditor/",
- "-m", "98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG",
- "-r", "auditor.in",
- "-o", "test_exchange_api_home/.local/share/taler/auditors/auditor.out",
- NULL);
- if (NULL == proc)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to run `taler-exchange-keyup`, is your PATH correct?\n");
- return 77;
- }
- GNUNET_OS_process_wait (proc);
- GNUNET_OS_process_destroy (proc);
-
- proc = GNUNET_OS_start_process (GNUNET_NO,
- GNUNET_OS_INHERIT_STD_ALL,
- NULL, NULL, NULL,
- "taler-exchange-dbinit",
- "taler-exchange-dbinit",
- "-c", "test_exchange_api_keys_cherry_picking.conf",
- "-r",
- NULL);
- if (NULL == proc)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to run `taler-exchange-dbinit`, is your PATH correct?\n");
- return 77;
- }
- if (GNUNET_SYSERR ==
- GNUNET_OS_process_wait_status (proc,
- &type,
- &code))
- {
- GNUNET_break (0);
- GNUNET_OS_process_destroy (proc);
- return 1;
- }
- GNUNET_OS_process_destroy (proc);
- if ( (type == GNUNET_OS_PROCESS_EXITED) &&
- (0 != code) )
- {
- fprintf (stderr,
- "Failed to setup database\n");
- return 77;
- }
- if ( (type != GNUNET_OS_PROCESS_EXITED) ||
- (0 != code) )
- {
- fprintf (stderr,
- "Unexpected error running `taler-exchange-dbinit'!\n");
- return 1;
- }
- exchanged = GNUNET_OS_start_process (GNUNET_NO,
- GNUNET_OS_INHERIT_STD_ALL,
- NULL, NULL, NULL,
- "taler-exchange-httpd",
- "taler-exchange-httpd",
- "-c", "test_exchange_api_keys_cherry_picking.conf",
- "-i",
- NULL);
- /* give child time to start and bind against the socket */
- fprintf (stderr,
- "Waiting for `taler-exchange-httpd' to be ready");
- iter = 0;
- do
- {
- if (10 == iter)
- {
- fprintf (stderr,
- "Failed to launch `taler-exchange-httpd' (or `wget')\n");
- GNUNET_OS_process_kill (exchanged,
- SIGTERM);
- GNUNET_OS_process_wait (exchanged);
- GNUNET_OS_process_destroy (exchanged);
- return 77;
- }
- fprintf (stderr, ".");
- sleep (1);
- iter++;
- }
- 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_NO;
- sigpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_NO);
- GNUNET_assert (NULL != sigpipe);
- shc_chld = GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD,
- &sighandler_child_death);
- GNUNET_SCHEDULER_run (&run, NULL);
- GNUNET_SIGNAL_handler_uninstall (shc_chld);
- shc_chld = NULL;
- GNUNET_DISK_pipe_close (sigpipe);
- GNUNET_break (0 ==
- GNUNET_OS_process_kill (exchanged,
- SIGTERM));
- GNUNET_break (GNUNET_OK ==
- GNUNET_OS_process_wait (exchanged));
- GNUNET_OS_process_destroy (exchanged);
- return (GNUNET_OK == result) ? 0 : 1;
-}
-
-/* end of test_exchange_api_keys_cherry_picking.c */
diff --git a/src/exchange-lib/test_exchange_api_keys_cherry_picking.conf b/src/exchange-lib/test_exchange_api_keys_cherry_picking.conf
index ba82c1c34..212e03d6b 100644
--- a/src/exchange-lib/test_exchange_api_keys_cherry_picking.conf
+++ b/src/exchange-lib/test_exchange_api_keys_cherry_picking.conf
@@ -11,14 +11,14 @@ CURRENCY = EUR
[exchange]
# how long is one signkey valid?
-signkey_duration = 4 weeks
+signkey_duration = 5 seconds
# how long are the signatures with the signkey valid?
legal_duration = 2 years
# how long do we provide to clients denomination and signing keys
# ahead of time?
-lookahead_provide = 4 weeks 1 day
+lookahead_provide = 30 seconds
# Keep it short so we can prolong later!
LOOKAHEAD_SIGN = 60 s
@@ -132,8 +132,8 @@ CLOSING-FEE-2026 = EUR:0.01
[coin_eur_ct_1]
value = EUR:0.01
-duration_overlap = 5 s
-duration_withdraw = 35 s
+duration_overlap = 1 s
+duration_withdraw = 25 s
duration_spend = 40 s
duration_legal = 60 s
fee_withdraw = EUR:0.00
@@ -144,8 +144,8 @@ rsa_keysize = 1024
[coin_eur_ct_2]
value = EUR:0.02
-duration_overlap = 5 s
-duration_withdraw = 35 s
+duration_overlap = 1 s
+duration_withdraw = 25 s
duration_spend = 40 s
duration_legal = 60 s
fee_withdraw = EUR:0.01
diff --git a/src/exchange-lib/test_exchange_api_keys_cherry_picking_new.c b/src/exchange-lib/test_exchange_api_keys_cherry_picking_new.c
index d1fd25cf2..8c82f6381 100644
--- a/src/exchange-lib/test_exchange_api_keys_cherry_picking_new.c
+++ b/src/exchange-lib/test_exchange_api_keys_cherry_picking_new.c
@@ -71,6 +71,9 @@ run (void *cls,
1,
4,
is->exchange),
+ /* sleep a bit */
+ TALER_TESTING_cmd_sleep ("sleep",
+ 25),
/* 1st keyup happens at start-up */
TALER_TESTING_cmd_exec_keyup ("keyup-2",
CONFIG_FILE_EXTENDED),
@@ -81,11 +84,23 @@ run (void *cls,
SIGUSR1),
TALER_TESTING_cmd_check_keys ("check-keys-2",
2,
-#if TALER_EXCHANGE_API_DISABLE_CHERRYPICKING
- 12,
-#else
- 8,
-#endif
+ 6,
+ is->exchange),
+
+ /* sleep a bit */
+ TALER_TESTING_cmd_sleep ("sleep",
+ 24),
+ /* Do 2nd keyup */
+ TALER_TESTING_cmd_exec_keyup ("keyup-3",
+ CONFIG_FILE_EXTENDED),
+ TALER_TESTING_cmd_exec_auditor_sign ("sign-keys-2",
+ CONFIG_FILE),
+ TALER_TESTING_cmd_signal ("trigger-keys-reload-2",
+ is->exchanged,
+ SIGUSR1),
+ TALER_TESTING_cmd_check_keys ("check-keys-3",
+ 3,
+ 10,
is->exchange),
TALER_TESTING_cmd_end ()
};
diff --git a/src/exchange-lib/testing_api_cmd_check_keys.c b/src/exchange-lib/testing_api_cmd_check_keys.c
index 56b062a10..8d91d3ece 100644
--- a/src/exchange-lib/testing_api_cmd_check_keys.c
+++ b/src/exchange-lib/testing_api_cmd_check_keys.c
@@ -71,8 +71,8 @@ check_keys_run (void *cls,
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"cmd `%s', key generation: %d\n",
- cmd->label, is->key_generation);
-
+ cmd->label,
+ is->key_generation);
if (is->key_generation < cks->generation)
{
/* Go back to waiting for /keys signal! */
@@ -99,10 +99,11 @@ check_keys_run (void *cls,
{
/* Did not get the expected number of denomination keys! */
GNUNET_break (0);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Got %u keys in step %s\n",
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Got %u keys in step %s, expected %u\n",
is->keys->num_denom_keys,
- cmd->label);
+ cmd->label,
+ cks->num_denom_keys);
TALER_TESTING_interpreter_fail (is);
return;
}
diff --git a/src/exchange-tools/taler-exchange-keyup.c b/src/exchange-tools/taler-exchange-keyup.c
index 9946eac49..22c72d5cc 100644
--- a/src/exchange-tools/taler-exchange-keyup.c
+++ b/src/exchange-tools/taler-exchange-keyup.c
@@ -639,6 +639,15 @@ get_cointype_params (const char *ct,
return GNUNET_SYSERR;
}
GNUNET_TIME_round_rel (&params->duration_overlap);
+ if (params->duration_overlap.rel_value_us >=
+ params->duration_withdraw.rel_value_us)
+ {
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+ ct,
+ "duration_overlap",
+ "duration_overlap must be smaller than duration_withdraw!");
+ return GNUNET_SYSERR;
+ }
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_number (kcfg,
ct,
@@ -814,8 +823,9 @@ exchange_keys_update_cointype (void *cls,
{
dkf = get_cointype_file (&p,
p.anchor);
- GNUNET_break (GNUNET_YES != GNUNET_DISK_file_test (dkf));
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ GNUNET_break (GNUNET_YES !=
+ GNUNET_DISK_file_test (dkf));
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Generating denomination key for type `%s', start %s at %s\n",
coin_alias,
GNUNET_STRINGS_absolute_time_to_string (p.anchor),
diff --git a/src/exchange/taler-exchange-httpd_keystate.c b/src/exchange/taler-exchange-httpd_keystate.c
index 4d1f8888f..ce2eafa71 100644
--- a/src/exchange/taler-exchange-httpd_keystate.c
+++ b/src/exchange/taler-exchange-httpd_keystate.c
@@ -1192,6 +1192,10 @@ build_keys_response (const struct ResponseFactoryContext *rfc,
krd->cherry_pick_date = cherry_pick_date;
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Creating /keys for cherry pick date %s\n",
+ GNUNET_STRINGS_absolute_time_to_string (cherry_pick_date));
+
/* Initialize `rbc` */
memset (&rbc,
0,
@@ -2062,6 +2066,11 @@ TEH_KS_handler_keys (struct TEH_RequestHandler *rh,
sizeof (struct KeysResponseData),
&krd_search_comparator);
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Filtering /keys by cherry pick date %s found entry %u/%u\n",
+ GNUNET_STRINGS_absolute_time_to_string (last_issue_date),
+ (unsigned int) (krd - key_state->krd_array),
+ key_state->krd_array_length);
if ( (NULL == krd) &&
(key_state->krd_array_length > 0) )
{
diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h
index 98223fa6c..d48dd8629 100644
--- a/src/include/taler_exchange_service.h
+++ b/src/include/taler_exchange_service.h
@@ -30,14 +30,6 @@
/* ********************* /keys *********************** */
-
-/**
- * Temporarily disable cherrypicking until it's fixed.
- * See #5315.
- */
-#define TALER_EXCHANGE_API_DISABLE_CHERRYPICKING 1
-
-
/**
* List of possible options to be passed to
* #TALER_EXCHANGE_connect().
@@ -170,11 +162,10 @@ struct TALER_EXCHANGE_AuditorInformation
/**
* Array of length @a num_denom_keys with the denomination
- * keys audited by this auditor. Note that the array
- * elements point to the same locations as the entries
- * in the key's main `denom_keys` array.
+ * keys audited by this auditor. Offsets into the
+ * key's main `denom_keys` array.
*/
- const struct TALER_EXCHANGE_DenomPublicKey **denom_keys;
+ unsigned int *denom_key_offsets;
};