aboutsummaryrefslogtreecommitdiff
path: root/src/testing
diff options
context:
space:
mode:
authorChristian Grothoff <grothoff@gnunet.org>2023-12-25 00:09:25 +0800
committerChristian Grothoff <grothoff@gnunet.org>2023-12-25 00:09:25 +0800
commit3eebc4b18ae109ea54e5f8788ac29453f74282ac (patch)
tree79a0cf4eb1448fff91ba74e027b56c9d2660ef3e /src/testing
parente690e53ebfc3d810e5ffdf90c86d0d4159a7c8da (diff)
parent5d50123ef29a8cbca8be40133a0df5b6c4b86dd4 (diff)
downloadexchange-3eebc4b18ae109ea54e5f8788ac29453f74282ac.tar.xz
Merge branch 'master' of git+ssh://git.taler.net/exchange
Diffstat (limited to 'src/testing')
-rw-r--r--src/testing/.gitignore2
-rw-r--r--src/testing/Makefile.am34
-rw-r--r--src/testing/test_exchange_api_conflicts-cs.conf4
-rw-r--r--src/testing/test_exchange_api_conflicts-rsa.conf4
-rw-r--r--src/testing/test_exchange_api_conflicts.c312
-rw-r--r--src/testing/test_exchange_api_conflicts.conf81
-rw-r--r--src/testing/testing_api_cmd_batch_withdraw.c73
7 files changed, 483 insertions, 27 deletions
diff --git a/src/testing/.gitignore b/src/testing/.gitignore
index 6cac81c82..e1075ab16 100644
--- a/src/testing/.gitignore
+++ b/src/testing/.gitignore
@@ -10,6 +10,8 @@ test_exchange_api_revocation_cs
test_exchange_api_revocation_rsa
test_exchange_api_age_restriction_cs
test_exchange_api_age_restriction_rsa
+test_exchange_api_conflicts_cs
+test_exchange_api_conflicts_rsa
report*
test_exchange_management_api_cs
test_exchange_management_api_rsa
diff --git a/src/testing/Makefile.am b/src/testing/Makefile.am
index 6a07c933d..ae713ab67 100644
--- a/src/testing/Makefile.am
+++ b/src/testing/Makefile.am
@@ -155,6 +155,8 @@ check_PROGRAMS = \
test_exchange_api_rsa \
test_exchange_api_age_restriction_cs \
test_exchange_api_age_restriction_rsa \
+ test_exchange_api_conflicts_cs \
+ test_exchange_api_conflicts_rsa \
test_exchange_api_keys_cherry_picking_cs \
test_exchange_api_keys_cherry_picking_rsa \
test_exchange_api_revocation_cs \
@@ -307,6 +309,38 @@ test_exchange_api_age_restriction_rsa_LDADD = \
-ljansson \
$(XLIB)
+test_exchange_api_conflicts_cs_SOURCES = \
+ test_exchange_api_conflicts.c
+test_exchange_api_conflicts_cs_LDADD = \
+ libtalertesting.la \
+ $(top_builddir)/src/lib/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 \
+ $(top_builddir)/src/extensions/libtalerextensions.la \
+ -lgnunetcurl \
+ -lgnunetutil \
+ -ljansson \
+ $(XLIB)
+
+test_exchange_api_conflicts_rsa_SOURCES = \
+ test_exchange_api_conflicts.c
+test_exchange_api_conflicts_rsa_LDADD = \
+ libtalertesting.la \
+ $(top_builddir)/src/lib/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 \
+ $(top_builddir)/src/extensions/libtalerextensions.la \
+ -lgnunetcurl \
+ -lgnunetutil \
+ -ljansson \
+ $(XLIB)
+
test_exchange_p2p_cs_SOURCES = \
test_exchange_p2p.c
test_exchange_p2p_cs_LDADD = \
diff --git a/src/testing/test_exchange_api_conflicts-cs.conf b/src/testing/test_exchange_api_conflicts-cs.conf
new file mode 100644
index 000000000..c15d55490
--- /dev/null
+++ b/src/testing/test_exchange_api_conflicts-cs.conf
@@ -0,0 +1,4 @@
+# This file is in the public domain.
+#
+@INLINE@ test_exchange_api_conflicts.conf
+@INLINE@ coins-cs.conf
diff --git a/src/testing/test_exchange_api_conflicts-rsa.conf b/src/testing/test_exchange_api_conflicts-rsa.conf
new file mode 100644
index 000000000..f56111eee
--- /dev/null
+++ b/src/testing/test_exchange_api_conflicts-rsa.conf
@@ -0,0 +1,4 @@
+# This file is in the public domain.
+#
+@INLINE@ test_exchange_api_conflicts.conf
+@INLINE@ coins-rsa.conf
diff --git a/src/testing/test_exchange_api_conflicts.c b/src/testing/test_exchange_api_conflicts.c
new file mode 100644
index 000000000..070809d9d
--- /dev/null
+++ b/src/testing/test_exchange_api_conflicts.c
@@ -0,0 +1,312 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2023 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 3, or
+ (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file testing/test_exchange_api_conflicts.c
+ * @brief testcase to test exchange's handling of coin conflicts: same private
+ * keys but different denominations or age restrictions
+ * @author Özgür Kesim
+ */
+#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 <gnunet/gnunet_testing_lib.h>
+#include <microhttpd.h>
+#include "taler_bank_service.h"
+#include "taler_fakebank_lib.h"
+#include "taler_testing_lib.h"
+#include "taler_extensions.h"
+
+/**
+ * Configuration file we use. One (big) configuration is used
+ * for the various components for this test.
+ */
+static char *config_file;
+
+/**
+ * Our credentials.
+ */
+static struct TALER_TESTING_Credentials cred;
+
+/**
+ * Some tests behave differently when using CS as we cannot
+ * reuse the coin private key for different denominations
+ * due to the derivation of it with the /csr values. Hence
+ * some tests behave differently in CS mode, hence this
+ * flag.
+ */
+static bool uses_cs;
+
+/**
+ * Execute the taler-exchange-wirewatch command with
+ * our configuration file.
+ *
+ * @param label label to use for the command.
+ */
+#define CMD_EXEC_WIREWATCH(label) \
+ TALER_TESTING_cmd_exec_wirewatch2 (label, config_file, \
+ "exchange-account-2")
+
+/**
+ * Execute the taler-exchange-aggregator, closer and transfer commands with
+ * our configuration file.
+ *
+ * @param label label to use for the command.
+ */
+#define CMD_EXEC_AGGREGATOR(label) \
+ TALER_TESTING_cmd_sleep ("sleep-before-aggregator", 2), \
+ TALER_TESTING_cmd_exec_aggregator (label "-aggregator", config_file), \
+ TALER_TESTING_cmd_exec_transfer (label "-transfer", config_file)
+
+
+/**
+ * Run wire transfer of funds from some user's account to the
+ * exchange.
+ *
+ * @param label label to use for the command.
+ * @param amount amount to transfer, i.e. "EUR:1"
+ */
+#define CMD_TRANSFER_TO_EXCHANGE(label,amount) \
+ TALER_TESTING_cmd_admin_add_incoming (label, amount, \
+ &cred.ba, \
+ cred.user42_payto)
+
+/**
+ * Main function that will tell the interpreter what commands to
+ * run.
+ *
+ * @param cls closure
+ * @param is interpreter we use to run commands
+ */
+static void
+run (void *cls,
+ struct TALER_TESTING_Interpreter *is)
+{
+ (void) cls;
+ /**
+ * Test withdrawal with conflicting coins.
+ */
+ struct TALER_TESTING_Command withdraw_conflict_denom[] = {
+ /**
+ * Move money to the exchange's bank account.
+ */
+ CMD_TRANSFER_TO_EXCHANGE ("create-reserve-denom",
+ "EUR:21.14"),
+ TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-reserve-denom",
+ "EUR:21.14",
+ cred.user42_payto,
+ cred.exchange_payto,
+ "create-reserve-denom"),
+ /**
+ * Make a reserve exist, according to the previous
+ * transfer.
+ */
+ CMD_EXEC_WIREWATCH ("wirewatch-conflict-denom"),
+ /**
+ * Withdraw EUR:0.10, EUR:1, EUR:5, EUR:15, but using the same private key each time.
+ */
+ TALER_TESTING_cmd_batch_withdraw_with_conflict ("withdraw-coin-denom-1",
+ "create-reserve-denom",
+ true,
+ 0, /* age */
+ MHD_HTTP_OK,
+ "EUR:1",
+ "EUR:5",
+ "EUR:10",
+ "EUR:0.10",
+ NULL),
+
+ TALER_TESTING_cmd_end ()
+ };
+
+ struct TALER_TESTING_Command spend_conflict_denom[] = {
+ /**
+ * Spend the coin.
+ */
+ TALER_TESTING_cmd_deposit ("deposit-denom",
+ "withdraw-coin-denom-1",
+ 0,
+ cred.user42_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:0.99",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_deposit ("deposit-denom-conflict",
+ "withdraw-coin-denom-1",
+ 1,
+ cred.user42_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:4.99",
+ /* Note: For CS, even though the master secret is the
+ * same for each coin, their private keys differ due
+ * to the random choice of the nonce by the exchange. */
+ uses_cs ? MHD_HTTP_OK : MHD_HTTP_CONFLICT),
+ TALER_TESTING_cmd_deposit ("deposit-denom-conflict-2",
+ "withdraw-coin-denom-1",
+ 2,
+ cred.user42_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:9.99",
+ /* Note: For CS, even though the master secret is the
+ * same for each coin, their private keys differ due
+ * to the random choice of the nonce by the exchange. */
+ uses_cs ? MHD_HTTP_OK : MHD_HTTP_CONFLICT),
+ TALER_TESTING_cmd_deposit ("deposit-denom-conflict-3",
+ "withdraw-coin-denom-1",
+ 3,
+ cred.user42_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:0.09",
+ /* Note: For CS, even though the master secret is the
+ * same for each coin, their private keys differ due
+ * to the random choice of the nonce by the exchange. */
+ uses_cs ? MHD_HTTP_OK : MHD_HTTP_CONFLICT),
+ TALER_TESTING_cmd_end ()
+ };
+
+ struct TALER_TESTING_Command withdraw_conflict_age[] = {
+ /**
+ * Move money to the exchange's bank account.
+ */
+ CMD_TRANSFER_TO_EXCHANGE ("create-reserve-age",
+ "EUR:3.03"),
+ TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-reserve-age",
+ "EUR:3.03",
+ cred.user42_payto,
+ cred.exchange_payto,
+ "create-reserve-age"),
+ /**
+ * Make a reserve exist, according to the previous
+ * transfer.
+ */
+ CMD_EXEC_WIREWATCH ("wirewatch-conflict-age"),
+ /**
+ * Withdraw EUR:1, EUR:5, EUR:15, but using the same private key each time.
+ */
+ TALER_TESTING_cmd_batch_withdraw_with_conflict ("withdraw-coin-age-1",
+ "create-reserve-age",
+ true,
+ 10, /* age */
+ MHD_HTTP_OK,
+ "EUR:1",
+ "EUR:1",
+ "EUR:1",
+ NULL),
+
+ TALER_TESTING_cmd_end ()
+ };
+
+ struct TALER_TESTING_Command spend_conflict_age[] = {
+ /**
+ * Spend the coin.
+ */
+ TALER_TESTING_cmd_deposit ("deposit-age",
+ "withdraw-coin-age-1",
+ 0,
+ cred.user42_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:0.99",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_deposit ("deposit-age-conflict",
+ "withdraw-coin-age-1",
+ 1,
+ cred.user42_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:0.99",
+ MHD_HTTP_CONFLICT),
+ TALER_TESTING_cmd_deposit ("deposit-age-conflict-2",
+ "withdraw-coin-age-1",
+ 2,
+ cred.user42_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:0.99",
+ MHD_HTTP_CONFLICT),
+ TALER_TESTING_cmd_end ()
+ };
+
+
+ {
+ struct TALER_TESTING_Command commands[] = {
+ TALER_TESTING_cmd_run_fakebank ("run-fakebank",
+ cred.cfg,
+ "exchange-account-2"),
+ TALER_TESTING_cmd_system_start ("start-taler",
+ config_file,
+ "-e",
+ NULL),
+ TALER_TESTING_cmd_get_exchange ("get-exchange",
+ cred.cfg,
+ NULL,
+ true,
+ true),
+ TALER_TESTING_cmd_batch ("withdraw-conflict-denom",
+ withdraw_conflict_denom),
+ TALER_TESTING_cmd_batch ("spend-conflict-denom",
+ spend_conflict_denom),
+ TALER_TESTING_cmd_batch ("withdraw-conflict-age",
+ withdraw_conflict_age),
+ TALER_TESTING_cmd_batch ("spend-conflict-age",
+ spend_conflict_age),
+ /* End the suite. */
+ TALER_TESTING_cmd_end ()
+ };
+
+ TALER_TESTING_run (is,
+ commands);
+ }
+}
+
+
+int
+main (int argc,
+ char *const *argv)
+{
+ (void) argc;
+ {
+ char *cipher;
+
+ cipher = GNUNET_STRINGS_get_suffix_from_binary_name (argv[0]);
+ GNUNET_assert (NULL != cipher);
+ uses_cs = (0 == strcmp (cipher,
+ "cs"));
+ GNUNET_asprintf (&config_file,
+ "test_exchange_api_conflicts-%s.conf",
+ cipher);
+ GNUNET_free (cipher);
+ }
+ return TALER_TESTING_main (argv,
+ "INFO",
+ config_file,
+ "exchange-account-2",
+ TALER_TESTING_BS_FAKEBANK,
+ &cred,
+ &run,
+ NULL);
+}
+
+
+/* end of test_exchange_api_conflicts.c */
diff --git a/src/testing/test_exchange_api_conflicts.conf b/src/testing/test_exchange_api_conflicts.conf
new file mode 100644
index 000000000..d04379f05
--- /dev/null
+++ b/src/testing/test_exchange_api_conflicts.conf
@@ -0,0 +1,81 @@
+# This file is in the public domain.
+#
+
+[PATHS]
+TALER_TEST_HOME = test_exchange_api_home/
+
+[taler]
+CURRENCY = EUR
+CURRENCY_ROUND_UNIT = EUR:0.01
+
+[auditor]
+BASE_URL = "http://localhost:8083/"
+PORT = 8083
+PUBLIC_KEY = T0XJ9QZ59YDN7QG3RE40SB2HY7W0ASR1EKF4WZDGZ1G159RSQC80
+TINY_AMOUNT = EUR:0.01
+
+[auditordb-postgres]
+CONFIG = "postgres:///talercheck"
+
+[bank]
+HTTP_PORT = 8082
+
+[exchange]
+TERMS_ETAG = tos
+PRIVACY_ETAG = 0
+PORT = 8081
+AML_THRESHOLD = "EUR:99999999"
+MASTER_PUBLIC_KEY = 98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG
+DB = postgres
+BASE_URL = "http://localhost:8081/"
+EXPIRE_SHARD_SIZE ="300 ms"
+EXPIRE_IDLE_SLEEP_INTERVAL ="1 s"
+
+[exchangedb-postgres]
+CONFIG = "postgres:///talercheck"
+
+[taler-exchange-secmod-cs]
+LOOKAHEAD_SIGN = "24 days"
+
+[taler-exchange-secmod-rsa]
+LOOKAHEAD_SIGN = "24 days"
+
+[taler-exchange-secmod-eddsa]
+LOOKAHEAD_SIGN = "24 days"
+DURATION = "14 days"
+
+
+[exchange-account-1]
+PAYTO_URI = "payto://x-taler-bank/localhost/42?receiver-name=42"
+ENABLE_DEBIT = YES
+ENABLE_CREDIT = YES
+
+[exchange-accountcredentials-1]
+WIRE_GATEWAY_AUTH_METHOD = none
+WIRE_GATEWAY_URL = "http://localhost:8082/accounts/42/taler-wire-gateway/"
+
+[admin-accountcredentials-1]
+WIRE_GATEWAY_AUTH_METHOD = none
+WIRE_GATEWAY_URL = "http://localhost:8082/accounts/42/taler-wire-gateway/"
+
+[exchange-account-2]
+PAYTO_URI = "payto://x-taler-bank/localhost/2?receiver-name=2"
+ENABLE_DEBIT = YES
+ENABLE_CREDIT = YES
+
+[exchange-accountcredentials-2]
+WIRE_GATEWAY_AUTH_METHOD = basic
+USERNAME = Exchange
+PASSWORD = x
+WIRE_GATEWAY_URL = "http://localhost:8082/accounts/2/taler-wire-gateway/"
+
+[admin-accountcredentials-2]
+WIRE_GATEWAY_AUTH_METHOD = basic
+USERNAME = Exchange
+PASSWORD = x
+WIRE_GATEWAY_URL = "http://localhost:8082/accounts/2/taler-wire-gateway/"
+
+
+[exchange-extension-age_restriction]
+ENABLED = YES
+#AGE_GROUPS = "8:10:12:14:16:18:21"
diff --git a/src/testing/testing_api_cmd_batch_withdraw.c b/src/testing/testing_api_cmd_batch_withdraw.c
index a106b8150..98bbb7e26 100644
--- a/src/testing/testing_api_cmd_batch_withdraw.c
+++ b/src/testing/testing_api_cmd_batch_withdraw.c
@@ -173,6 +173,11 @@ struct BatchWithdrawState
* Same for all coins in the batch.
*/
uint8_t age;
+
+ /**
+ * Force a conflict:
+ */
+ bool force_conflict;
};
@@ -195,9 +200,10 @@ reserve_batch_withdraw_cb (void *cls,
ws->wsh = NULL;
if (ws->expected_response_code != wr->hr.http_status)
{
- TALER_TESTING_unexpected_status (is,
- wr->hr.http_status,
- ws->expected_response_code);
+ TALER_TESTING_unexpected_status_with_body (is,
+ wr->hr.http_status,
+ ws->expected_response_code,
+ wr->hr.reply);
return;
}
switch (wr->hr.http_status)
@@ -265,6 +271,8 @@ batch_withdraw_run (void *cls,
const struct TALER_TESTING_Command *create_reserve;
const struct TALER_EXCHANGE_DenomPublicKey *dpk;
struct TALER_EXCHANGE_WithdrawCoinInput wcis[ws->num_coins];
+ struct TALER_PlanchetMasterSecretP conflict_ps = {0};
+ struct TALER_AgeMask mask = {0};
(void) cmd;
ws->is = is;
@@ -297,12 +305,37 @@ batch_withdraw_run (void *cls,
= TALER_reserve_make_payto (ws->exchange_url,
&ws->reserve_pub);
+ if (0 < ws->age)
+ mask = TALER_extensions_get_age_restriction_mask ();
+
+ if (ws->force_conflict)
+ TALER_planchet_master_setup_random (&conflict_ps);
+
for (unsigned int i = 0; i<ws->num_coins; i++)
{
struct CoinState *cs = &ws->coins[i];
struct TALER_EXCHANGE_WithdrawCoinInput *wci = &wcis[i];
- TALER_planchet_master_setup_random (&cs->ps);
+ if (ws->force_conflict)
+ cs->ps = conflict_ps;
+ else
+ TALER_planchet_master_setup_random (&cs->ps);
+
+ if (0 < ws->age)
+ {
+ struct GNUNET_HashCode seed = {0};
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
+ &seed,
+ sizeof(seed));
+ TALER_age_restriction_commit (&mask,
+ ws->age,
+ &seed,
+ &cs->age_commitment_proof);
+ TALER_age_commitment_hash (&cs->age_commitment_proof.commitment,
+ &cs->h_age_commitment);
+ }
+
+
dpk = TALER_TESTING_find_pk (keys,
&cs->amount,
ws->age > 0);
@@ -455,12 +488,14 @@ batch_withdraw_traits (void *cls,
struct TALER_TESTING_Command
-TALER_TESTING_cmd_batch_withdraw (const char *label,
- const char *reserve_reference,
- uint8_t age,
- unsigned int expected_response_code,
- const char *amount,
- ...)
+TALER_TESTING_cmd_batch_withdraw_with_conflict (
+ const char *label,
+ const char *reserve_reference,
+ bool conflict,
+ uint8_t age,
+ unsigned int expected_response_code,
+ const char *amount,
+ ...)
{
struct BatchWithdrawState *ws;
unsigned int cnt;
@@ -470,6 +505,7 @@ TALER_TESTING_cmd_batch_withdraw (const char *label,
ws->age = age;
ws->reserve_reference = reserve_reference;
ws->expected_response_code = expected_response_code;
+ ws->force_conflict = conflict;
cnt = 1;
va_start (ap,
@@ -487,23 +523,6 @@ TALER_TESTING_cmd_batch_withdraw (const char *label,
{
struct CoinState *cs = &ws->coins[i];
- if (0 < age)
- {
- struct GNUNET_HashCode seed;
- struct TALER_AgeMask mask;
-
- mask = TALER_extensions_get_age_restriction_mask ();
- GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
- &seed,
- sizeof(seed));
- TALER_age_restriction_commit (&mask,
- age,
- &seed,
- &cs->age_commitment_proof);
- TALER_age_commitment_hash (&cs->age_commitment_proof.commitment,
- &cs->h_age_commitment);
- }
-
if (GNUNET_OK !=
TALER_string_to_amount (amount,
&cs->amount))