diff options
Diffstat (limited to 'src/testing')
138 files changed, 20612 insertions, 9292 deletions
diff --git a/src/testing/.gitignore b/src/testing/.gitignore index 6a19ba005..e1075ab16 100644 --- a/src/testing/.gitignore +++ b/src/testing/.gitignore @@ -8,6 +8,10 @@ test_taler_exchange_aggregator-postgres test_taler_exchange_wirewatch-postgres 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 @@ -46,3 +50,13 @@ test_exchange_api_twisted_cs test_exchange_api_twisted_rsa test_exchange_p2p_cs test_exchange_p2p_rsa +*.edited +tmp-last-response.* +test_exchange_api_home/taler/auditor/ +test_exchange_api_home/taler/exchange-offline/secm_tofus.pub +test_exchange_api_home/taler/exchange-secmod-cs/ +test_exchange_api_home/taler/exchange-secmod-eddsa/ +test_exchange_api_home/taler/exchange-secmod-rsa/ +test_exchange_api_keys_cherry_picking_home/taler/ +test_taler_exchange_httpd_home/taler/ +libeufin-bank.pid diff --git a/src/testing/Makefile.am b/src/testing/Makefile.am index 74facda0a..195ab4c55 100644 --- a/src/testing/Makefile.am +++ b/src/testing/Makefile.am @@ -13,6 +13,9 @@ endif clean-local: rm -rf report* +bin_SCRIPTS = \ + taler-unified-setup.sh + # Libraries lib_LTLIBRARIES = \ @@ -37,11 +40,11 @@ libtalertesting_la_LDFLAGS = \ -version-info 0:0:0 \ -no-undefined libtalertesting_la_SOURCES = \ + testing_api_cmd_age_withdraw.c \ testing_api_cmd_auditor_add_denom_sig.c \ testing_api_cmd_auditor_add.c \ testing_api_cmd_auditor_del.c \ testing_api_cmd_auditor_deposit_confirmation.c \ - testing_api_cmd_auditor_exchanges.c \ testing_api_cmd_auditor_exec_auditor.c \ testing_api_cmd_auditor_exec_auditor_dbinit.c \ testing_api_cmd_bank_admin_add_incoming.c \ @@ -54,8 +57,9 @@ libtalertesting_la_SOURCES = \ testing_api_cmd_batch.c \ testing_api_cmd_batch_deposit.c \ testing_api_cmd_batch_withdraw.c \ - testing_api_cmd_change_auth.c \ - testing_api_cmd_check_keys.c \ + testing_api_cmd_check_aml_decision.c \ + testing_api_cmd_check_aml_decisions.c \ + testing_api_cmd_coin_history.c \ testing_api_cmd_common.c \ testing_api_cmd_contract_get.c \ testing_api_cmd_deposit.c \ @@ -66,7 +70,10 @@ libtalertesting_la_SOURCES = \ testing_api_cmd_exec_expire.c \ testing_api_cmd_exec_router.c \ testing_api_cmd_exec_transfer.c \ + testing_api_cmd_exec_wget.c \ testing_api_cmd_exec_wirewatch.c \ + testing_api_cmd_get_auditor.c \ + testing_api_cmd_get_exchange.c \ testing_api_cmd_insert_deposit.c \ testing_api_cmd_kyc_check_get.c \ testing_api_cmd_kyc_proof.c \ @@ -77,40 +84,46 @@ libtalertesting_la_SOURCES = \ testing_api_cmd_offline_sign_keys.c \ testing_api_cmd_offline_sign_extensions.c \ testing_api_cmd_purse_create_deposit.c \ + testing_api_cmd_purse_delete.c \ testing_api_cmd_purse_deposit.c \ testing_api_cmd_purse_get.c \ testing_api_cmd_purse_merge.c \ - testing_api_cmd_set_wire_fee.c \ testing_api_cmd_recoup.c \ testing_api_cmd_recoup_refresh.c \ testing_api_cmd_refund.c \ testing_api_cmd_refresh.c \ + testing_api_cmd_reserve_attest.c \ + testing_api_cmd_reserve_close.c \ testing_api_cmd_reserve_get.c \ + testing_api_cmd_reserve_get_attestable.c \ testing_api_cmd_reserve_history.c \ + testing_api_cmd_reserve_open.c \ testing_api_cmd_reserve_purse.c \ - testing_api_cmd_reserve_status.c \ testing_api_cmd_revoke.c \ testing_api_cmd_revoke_denom_key.c \ testing_api_cmd_revoke_sign_key.c \ - testing_api_cmd_rewind.c \ - testing_api_cmd_serialize_keys.c \ + testing_api_cmd_run_fakebank.c \ + testing_api_cmd_set_officer.c \ + testing_api_cmd_set_wire_fee.c \ testing_api_cmd_signal.c \ testing_api_cmd_sleep.c \ testing_api_cmd_stat.c \ + testing_api_cmd_system_start.c \ + testing_api_cmd_take_aml_decision.c \ testing_api_cmd_transfer_get.c \ testing_api_cmd_wait.c \ - testing_api_cmd_wire.c \ testing_api_cmd_wire_add.c \ testing_api_cmd_wire_del.c \ testing_api_cmd_withdraw.c \ - testing_api_helpers_auditor.c \ - testing_api_helpers_bank.c \ - testing_api_helpers_exchange.c \ testing_api_loop.c \ + testing_api_misc.c \ testing_api_traits.c + + libtalertesting_la_LIBADD = \ $(top_builddir)/src/lib/libtalerauditor.la \ $(top_builddir)/src/lib/libtalerexchange.la \ + $(top_builddir)/src/exchangedb/libtalerexchangedb.la \ $(top_builddir)/src/json/libtalerjson.la \ $(top_builddir)/src/mhd/libtalermhd.la \ $(top_builddir)/src/util/libtalerutil.la \ @@ -130,16 +143,16 @@ libtalertesting_la_LIBADD = \ AM_TESTS_ENVIRONMENT=export TALER_PREFIX=$${TALER_PREFIX:-@libdir@};export PATH=$${TALER_PREFIX:-@prefix@}/bin:$$PATH; -.NOTPARALLEL: check_PROGRAMS = \ - test_auditor_api_cs \ - test_auditor_api_rsa \ - test_auditor_api_version_rsa \ - test_auditor_api_version_cs \ + test_auditor_api_version \ test_bank_api_with_fakebank \ test_bank_api_with_nexus \ test_exchange_api_cs \ 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 \ @@ -160,6 +173,9 @@ if HAVE_TWISTER test_bank_api_with_fakebank_twisted endif +# Removed for now... +# test_auditor_api_cs +# test_auditor_api_rsa TESTS = \ @@ -176,7 +192,6 @@ test_auditor_api_cs_LDADD = \ $(top_builddir)/src/bank-lib/libtalerbank.la \ $(top_builddir)/src/json/libtalerjson.la \ $(top_builddir)/src/util/libtalerutil.la \ - -lgnunettesting \ -lgnunetcurl \ -lgnunetutil \ -ljansson \ @@ -193,34 +208,19 @@ test_auditor_api_rsa_LDADD = \ $(top_builddir)/src/bank-lib/libtalerbank.la \ $(top_builddir)/src/json/libtalerjson.la \ $(top_builddir)/src/util/libtalerutil.la \ - -lgnunettesting \ -lgnunetcurl \ -lgnunetutil \ -ljansson \ $(XLIB) -test_auditor_api_version_cs_SOURCES = \ - test_auditor_api_version.c -test_auditor_api_version_cs_LDADD = \ - libtalertesting.la \ - $(top_builddir)/src/lib/libtalerauditor.la \ - $(LIBGCRYPT_LIBS) \ - $(top_builddir)/src/util/libtalerutil.la \ - -lgnunettesting \ - -lgnunetcurl \ - -lgnunetutil \ - -ljansson \ - $(XLIB) - -test_auditor_api_version_rsa_SOURCES = \ +test_auditor_api_version_SOURCES = \ test_auditor_api_version.c -test_auditor_api_version_rsa_LDADD = \ +test_auditor_api_version_LDADD = \ libtalertesting.la \ $(top_builddir)/src/lib/libtalerauditor.la \ $(LIBGCRYPT_LIBS) \ $(top_builddir)/src/util/libtalerutil.la \ - -lgnunettesting \ -lgnunetcurl \ -lgnunetutil \ -ljansson \ @@ -230,7 +230,7 @@ test_bank_api_with_nexus_SOURCES = \ test_bank_api.c test_bank_api_with_nexus_LDADD = \ libtalertesting.la \ - -ltalerexchange \ + $(top_builddir)/src/lib/libtalerexchange.la \ -lgnunetutil \ $(top_builddir)/src/bank-lib/libtalerbank.la \ $(XLIB) @@ -239,7 +239,7 @@ test_bank_api_with_fakebank_SOURCES = \ test_bank_api.c test_bank_api_with_fakebank_LDADD = \ libtalertesting.la \ - -ltalerexchange \ + $(top_builddir)/src/lib/libtalerexchange.la \ -lgnunetutil \ $(top_builddir)/src/bank-lib/libtalerbank.la \ $(XLIB) @@ -255,7 +255,6 @@ test_exchange_api_cs_LDADD = \ $(top_builddir)/src/json/libtalerjson.la \ $(top_builddir)/src/util/libtalerutil.la \ $(top_builddir)/src/extensions/libtalerextensions.la \ - -lgnunettesting \ -lgnunetcurl \ -lgnunetutil \ -ljansson \ @@ -272,7 +271,70 @@ test_exchange_api_rsa_LDADD = \ $(top_builddir)/src/json/libtalerjson.la \ $(top_builddir)/src/util/libtalerutil.la \ $(top_builddir)/src/extensions/libtalerextensions.la \ - -lgnunettesting \ + -lgnunetcurl \ + -lgnunetutil \ + -ljansson \ + $(XLIB) + +test_exchange_api_age_restriction_cs_SOURCES = \ + test_exchange_api_age_restriction.c +test_exchange_api_age_restriction_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_age_restriction_rsa_SOURCES = \ + test_exchange_api_age_restriction.c +test_exchange_api_age_restriction_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_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 \ @@ -289,7 +351,6 @@ test_exchange_p2p_cs_LDADD = \ $(top_builddir)/src/json/libtalerjson.la \ $(top_builddir)/src/util/libtalerutil.la \ $(top_builddir)/src/extensions/libtalerextensions.la \ - -lgnunettesting \ -lgnunetcurl \ -lgnunetutil \ -ljansson \ @@ -306,7 +367,6 @@ test_exchange_p2p_rsa_LDADD = \ $(top_builddir)/src/json/libtalerjson.la \ $(top_builddir)/src/util/libtalerutil.la \ $(top_builddir)/src/extensions/libtalerextensions.la \ - -lgnunettesting \ -lgnunetcurl \ -lgnunetutil \ -ljansson \ @@ -322,7 +382,6 @@ test_exchange_api_keys_cherry_picking_cs_LDADD = \ $(top_builddir)/src/json/libtalerjson.la \ $(top_builddir)/src/util/libtalerutil.la \ $(top_builddir)/src/bank-lib/libtalerbank.la \ - -lgnunettesting \ -lgnunetcurl \ -lgnunetutil \ -ljansson \ @@ -337,7 +396,6 @@ test_exchange_api_keys_cherry_picking_rsa_LDADD = \ $(top_builddir)/src/json/libtalerjson.la \ $(top_builddir)/src/util/libtalerutil.la \ $(top_builddir)/src/bank-lib/libtalerbank.la \ - -lgnunettesting \ -lgnunetcurl \ -lgnunetutil \ -ljansson \ @@ -353,7 +411,6 @@ test_exchange_api_revocation_cs_LDADD = \ $(top_builddir)/src/bank-lib/libtalerbank.la \ $(top_builddir)/src/json/libtalerjson.la \ $(top_builddir)/src/util/libtalerutil.la \ - -lgnunettesting \ -lgnunetcurl \ -lgnunetutil \ -ljansson \ @@ -369,7 +426,6 @@ test_exchange_api_revocation_rsa_LDADD = \ $(top_builddir)/src/bank-lib/libtalerbank.la \ $(top_builddir)/src/json/libtalerjson.la \ $(top_builddir)/src/util/libtalerutil.la \ - -lgnunettesting \ -lgnunetcurl \ -lgnunetutil \ -ljansson \ @@ -385,7 +441,6 @@ test_exchange_api_overlapping_keys_bug_cs_LDADD = \ $(top_builddir)/src/json/libtalerjson.la \ $(top_builddir)/src/util/libtalerutil.la \ $(top_builddir)/src/bank-lib/libtalerbank.la \ - -lgnunettesting \ -lgnunetcurl \ -lgnunetutil \ -ljansson \ @@ -400,7 +455,6 @@ test_exchange_api_overlapping_keys_bug_rsa_LDADD = \ $(top_builddir)/src/json/libtalerjson.la \ $(top_builddir)/src/util/libtalerutil.la \ $(top_builddir)/src/bank-lib/libtalerbank.la \ - -lgnunettesting \ -lgnunetcurl \ -lgnunetutil \ -ljansson \ @@ -412,7 +466,6 @@ test_exchange_management_api_cs_LDADD = \ libtalertesting.la \ $(top_builddir)/src/lib/libtalerexchange.la \ $(top_builddir)/src/util/libtalerutil.la \ - -lgnunettesting \ -lgnunetutil \ $(XLIB) @@ -422,7 +475,6 @@ test_exchange_management_api_rsa_LDADD = \ libtalertesting.la \ $(top_builddir)/src/lib/libtalerexchange.la \ $(top_builddir)/src/util/libtalerutil.la \ - -lgnunettesting \ -lgnunetutil \ $(XLIB) @@ -471,7 +523,6 @@ test_exchange_api_twisted_cs_LDADD = \ $(top_builddir)/src/bank-lib/libtalerbank.la \ $(top_builddir)/src/json/libtalerjson.la \ $(top_builddir)/src/util/libtalerutil.la \ - -lgnunettesting \ -lgnunetjson \ -lgnunetcurl \ -lgnunetutil \ @@ -489,7 +540,6 @@ test_exchange_api_twisted_rsa_LDADD = \ $(top_builddir)/src/bank-lib/libtalerbank.la \ $(top_builddir)/src/json/libtalerjson.la \ $(top_builddir)/src/util/libtalerutil.la \ - -lgnunettesting \ -lgnunetjson \ -lgnunetcurl \ -lgnunetutil \ @@ -505,7 +555,6 @@ test_bank_api_with_fakebank_twisted_LDADD = \ $(top_builddir)/src/lib/libtalerexchange.la \ $(top_builddir)/src/json/libtalerjson.la \ libtalertwistertesting.la \ - -lgnunettesting \ -lgnunetjson \ -lgnunetcurl \ -lgnunetutil \ @@ -531,29 +580,38 @@ test_kyc_api_LDADD = \ # Distribution EXTRA_DIST = \ + $(bin_SCRIPTS) \ + valgrind.h \ + coins-cs.conf \ + coins-rsa.conf \ test_auditor_api-cs.conf \ test_auditor_api-rsa.conf \ test_auditor_api_expire_reserve_now-cs.conf \ test_auditor_api_expire_reserve_now-rsa.conf \ + test_bank_api.conf \ test_bank_api_fakebank.conf \ test_bank_api_fakebank_twisted.conf \ - test_exchange_api_home/.config/taler/account-2.json \ + test_bank_api_nexus.conf \ + test_exchange_api_home/taler/auditor/offline-keys/auditor.priv \ test_exchange_api_home/.local/share/taler/exchange-offline/master.priv \ - test_exchange_api_home/.local/share/taler/exchange/offline-keys/master.priv \ - test_exchange_api_keys_cherry_picking_home/.config/taler/x-taler-bank.json \ - test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange-offline/master.priv \ - test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange/offline-keys/master.priv \ + test_exchange_api_home/.local/share/taler/auditor/offline-keys/auditor.priv \ + test_exchange_api.conf \ test_exchange_api-cs.conf \ test_exchange_api-rsa.conf \ + test_exchange_api_age_restriction.conf \ + test_exchange_api_age_restriction-cs.conf \ + test_exchange_api_age_restriction-rsa.conf \ + test_exchange_api_conflicts.conf \ + test_exchange_api_conflicts-cs.conf \ + test_exchange_api_conflicts-rsa.conf \ + test_exchange_api-twisted.conf \ test_exchange_api_twisted-cs.conf \ test_exchange_api_twisted-rsa.conf \ + test_exchange_api_keys_cherry_picking.conf \ test_exchange_api_keys_cherry_picking-cs.conf \ test_exchange_api_keys_cherry_picking-rsa.conf \ test_exchange_api_expire_reserve_now-cs.conf \ test_exchange_api_expire_reserve_now-rsa.conf \ - test_taler_exchange_httpd_home/.config/taler/account-1.json \ - test_taler_exchange_httpd_home/.local/share/taler/exchange-offline/master.priv \ - test_taler_exchange_httpd_home/.local/share/taler/exchange/offline-keys/master.priv \ test-taler-exchange-aggregator-postgres.conf \ test-taler-exchange-wirewatch-postgres.conf \ test_kyc_api.conf diff --git a/src/testing/coins-cs.conf b/src/testing/coins-cs.conf new file mode 100644 index 000000000..92163baac --- /dev/null +++ b/src/testing/coins-cs.conf @@ -0,0 +1,118 @@ + +# Sections starting with "coin_" specify which denominations +# the exchange should support (and their respective fee structure) +[coin_eur_ct_1] +value = EUR:0.01 +duration_withdraw = 7 days +duration_spend = 2 years +duration_legal = 3 years +fee_withdraw = EUR:0.00 +fee_deposit = EUR:0.00 +fee_refresh = EUR:0.01 +fee_refund = EUR:0.01 +CIPHER = CS + +[coin_eur_ct_10] +value = EUR:0.10 +duration_withdraw = 7 days +duration_spend = 2 years +duration_legal = 3 years +fee_withdraw = EUR:0.01 +fee_deposit = EUR:0.01 +fee_refresh = EUR:0.03 +fee_refund = EUR:0.01 +CIPHER = CS + +[coin_eur_1] +value = EUR:1 +duration_withdraw = 7 days +duration_spend = 2 years +duration_legal = 3 years +fee_withdraw = EUR:0.01 +fee_deposit = EUR:0.01 +fee_refresh = EUR:0.03 +fee_refund = EUR:0.01 +CIPHER = CS + +[coin_eur_5] +value = EUR:5 +duration_withdraw = 7 days +duration_spend = 2 years +duration_legal = 3 years +fee_withdraw = EUR:0.01 +fee_deposit = EUR:0.01 +fee_refresh = EUR:0.03 +fee_refund = EUR:0.01 +CIPHER = CS + +[coin_eur_10] +value = EUR:10 +duration_withdraw = 7 days +duration_spend = 2 years +duration_legal = 3 years +fee_withdraw = EUR:0.01 +fee_deposit = EUR:0.01 +fee_refresh = EUR:0.03 +fee_refund = EUR:0.01 +CIPHER = CS + + +[coin_eur_ct_1_age_restricted] +value = EUR:0.01 +duration_withdraw = 7 days +duration_spend = 2 years +duration_legal = 3 years +fee_withdraw = EUR:0.00 +fee_deposit = EUR:0.00 +fee_refresh = EUR:0.01 +fee_refund = EUR:0.01 +age_restricted = YES +CIPHER = CS + +[coin_eur_ct_10_age_restricted] +value = EUR:0.10 +duration_withdraw = 7 days +duration_spend = 2 years +duration_legal = 3 years +fee_withdraw = EUR:0.01 +fee_deposit = EUR:0.01 +fee_refresh = EUR:0.03 +fee_refund = EUR:0.01 +age_restricted = YES +CIPHER = CS + +[coin_eur_1_age_restricted] +value = EUR:1 +duration_withdraw = 7 days +duration_spend = 2 years +duration_legal = 3 years +fee_withdraw = EUR:0.01 +fee_deposit = EUR:0.01 +fee_refresh = EUR:0.03 +fee_refund = EUR:0.01 +age_restricted = YES +CIPHER = CS + +[coin_eur_5_age_restricted] +value = EUR:5 +duration_withdraw = 7 days +duration_spend = 2 years +duration_legal = 3 years +fee_withdraw = EUR:0.01 +fee_deposit = EUR:0.01 +fee_refresh = EUR:0.03 +fee_refund = EUR:0.01 +age_restricted = YES +CIPHER = CS + +[coin_eur_10_age_restricted] +value = EUR:10 +duration_withdraw = 7 days +duration_spend = 2 years +duration_legal = 3 years +fee_withdraw = EUR:0.01 +fee_deposit = EUR:0.01 +fee_refresh = EUR:0.03 +fee_refund = EUR:0.01 +age_restricted = YES +CIPHER = CS diff --git a/src/testing/coins-rsa.conf b/src/testing/coins-rsa.conf new file mode 100644 index 000000000..7a21a343b --- /dev/null +++ b/src/testing/coins-rsa.conf @@ -0,0 +1,128 @@ +# This file is in the public domain. + +# Sections starting with "coin_" specify which denominations +# the exchange should support (and their respective fee structure) +[coin_eur_ct_1] +value = EUR:0.01 +duration_withdraw = 7 days +duration_spend = 2 years +duration_legal = 3 years +fee_withdraw = EUR:0.00 +fee_deposit = EUR:0.00 +fee_refresh = EUR:0.01 +fee_refund = EUR:0.01 +CIPHER = RSA +rsa_keysize = 1024 + +[coin_eur_ct_10] +value = EUR:0.10 +duration_withdraw = 7 days +duration_spend = 2 years +duration_legal = 3 years +fee_withdraw = EUR:0.01 +fee_deposit = EUR:0.01 +fee_refresh = EUR:0.03 +fee_refund = EUR:0.01 +CIPHER = RSA +rsa_keysize = 1024 + +[coin_eur_1] +value = EUR:1 +duration_withdraw = 7 days +duration_spend = 2 years +duration_legal = 3 years +fee_withdraw = EUR:0.01 +fee_deposit = EUR:0.01 +fee_refresh = EUR:0.03 +fee_refund = EUR:0.01 +CIPHER = RSA +rsa_keysize = 1024 + +[coin_eur_5] +value = EUR:5 +duration_withdraw = 7 days +duration_spend = 2 years +duration_legal = 3 years +fee_withdraw = EUR:0.01 +fee_deposit = EUR:0.01 +fee_refresh = EUR:0.03 +fee_refund = EUR:0.01 +CIPHER = RSA +rsa_keysize = 1024 + +[coin_eur_10] +value = EUR:10 +duration_withdraw = 7 days +duration_spend = 2 years +duration_legal = 3 years +fee_withdraw = EUR:0.01 +fee_deposit = EUR:0.01 +fee_refresh = EUR:0.03 +fee_refund = EUR:0.01 +CIPHER = RSA +rsa_keysize = 1024 + +[coin_eur_ct_1_age_restricted] +value = EUR:0.01 +duration_withdraw = 7 days +duration_spend = 2 years +duration_legal = 3 years +fee_withdraw = EUR:0.00 +fee_deposit = EUR:0.00 +fee_refresh = EUR:0.01 +fee_refund = EUR:0.01 +rsa_keysize = 1024 +age_restricted = YES +CIPHER = RSA + +[coin_eur_ct_10_age_restricted] +value = EUR:0.10 +duration_withdraw = 7 days +duration_spend = 2 years +duration_legal = 3 years +fee_withdraw = EUR:0.01 +fee_deposit = EUR:0.01 +fee_refresh = EUR:0.03 +fee_refund = EUR:0.01 +rsa_keysize = 1024 +age_restricted = YES +CIPHER = RSA + +[coin_eur_1_age_restricted] +value = EUR:1 +duration_withdraw = 7 days +duration_spend = 2 years +duration_legal = 3 years +fee_withdraw = EUR:0.01 +fee_deposit = EUR:0.01 +fee_refresh = EUR:0.03 +fee_refund = EUR:0.01 +rsa_keysize = 1024 +age_restricted = YES +CIPHER = RSA + +[coin_eur_5_age_restricted] +value = EUR:5 +duration_withdraw = 7 days +duration_spend = 2 years +duration_legal = 3 years +fee_withdraw = EUR:0.01 +fee_deposit = EUR:0.01 +fee_refresh = EUR:0.03 +fee_refund = EUR:0.01 +rsa_keysize = 1024 +age_restricted = YES +CIPHER = RSA + +[coin_eur_10_age_restricted] +value = EUR:10 +duration_withdraw = 7 days +duration_spend = 2 years +duration_legal = 3 years +fee_withdraw = EUR:0.01 +fee_deposit = EUR:0.01 +fee_refresh = EUR:0.03 +fee_refund = EUR:0.01 +rsa_keysize = 1024 +age_restricted = YES +CIPHER = RSA
\ No newline at end of file diff --git a/src/testing/taler-unified-setup.sh b/src/testing/taler-unified-setup.sh new file mode 100755 index 000000000..d933cc819 --- /dev/null +++ b/src/testing/taler-unified-setup.sh @@ -0,0 +1,934 @@ +#!/bin/bash +# +# This file is part of TALER +# Copyright (C) 2023, 2024 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/> +# +# Author: Christian Grothoff +# +# This script configures and launches various GNU Taler services. +# Which ones depend on command-line options. Use "-h" to find out. +# Prints "<<READY>>" on a separate line once all requested services +# are running. Close STDIN (or input 'NEWLINE') to stop all started +# services again. +# +# shellcheck disable=SC2317 + +set -eu + +# These break TALER_HOME control via TALER_TEST_HOME... +unset XDG_DATA_HOME +unset XDG_CONFIG_HOME +unset XDG_CACHE_HOME + +EXIT_STATUS=2 + +# Exit, with status code "skip" (no 'real' failure) +function exit_skip() { + echo " SKIP: " "$@" >&2 + EXIT_STATUS=77 + exit "$EXIT_STATUS" +} + +# Exit, with error message (hard failure) +function exit_fail() { + echo " FAIL: " "$@" >&2 + EXIT_STATUS=1 + exit "$EXIT_STATUS" +} + +# Cleanup to run whenever we exit +function cleanup() +{ + echo "Taler unified setup terminating at $STAGE!" >&2 + + for n in $(jobs -p) + do + kill "$n" 2> /dev/null || true + done + wait + rm -f libeufin-nexus.pid libeufin-sandbox.pid + exit "$EXIT_STATUS" +} + +STAGE="boot" + +# Install cleanup handler (except for kill -9) +trap cleanup EXIT + +WAIT_FOR_SIGNAL=0 +START_AUDITOR=0 +START_BACKUP=0 +START_EXCHANGE=0 +START_FAKEBANK=0 +START_DONAU=0 +START_CHALLENGER=0 +START_AGGREGATOR=0 +START_MERCHANT=0 +START_NEXUS=0 +START_BANK=0 +START_TRANSFER=0 +START_WIREWATCH=0 +START_DEPOSITCHECK=0 +START_MERCHANT_EXCHANGE=0 +START_MERCHANT_WIREWATCH=0 +USE_ACCOUNT="exchange-account-1" +USE_VALGRIND="" +WIRE_DOMAIN="x-taler-bank" +CONF_ORIG="$HOME/.config/taler.conf" +LOGLEVEL="DEBUG" +DEFAULT_SLEEP="0.2" + +# Parse command-line options +while getopts ':abc:d:DeEfghkL:mMnr:stu:vwWz' OPTION; do + case "$OPTION" in + a) + START_AUDITOR="1" + ;; + b) + START_BANK="1" + ;; + c) + CONF_ORIG="$OPTARG" + ;; + d) + WIRE_DOMAIN="$OPTARG" + ;; + D) + START_DONAU="1" + ;; + e) + START_EXCHANGE="1" + ;; + E) + START_MERCHANT_EXCHANGE="1" + ;; + f) + START_FAKEBANK="1" + ;; + h) + echo 'Supported options:' + echo ' -a -- start auditor' + echo ' -b -- start bank' + # shellcheck disable=SC2016 + echo ' -c $CONF -- set configuration' + # shellcheck disable=SC2016 + echo ' -d $METHOD -- use wire method (default: x-taler-bank)' + echo ' -D -- start donau' + echo ' -e -- start exchange' + echo ' -E -- start taler-merchant-exchange' + echo ' -f -- start fakebank' + echo ' -g -- start taler-exchange-aggregator' + echo ' -h -- print this help' + echo ' -k -- start challenger (KYC service)' + # shellcheck disable=SC2016 + echo ' -L $LOGLEVEL -- set log level' + echo ' -m -- start taler-merchant' + echo ' -M -- start taler-merchant-depositcheck' + echo ' -n -- start nexus' + # shellcheck disable=SC2016 + echo ' -r $MEX -- which exchange to use at the merchant (optional)' + echo ' -s -- start backup/sync' + echo ' -t -- start taler-exchange-transfer' + # shellcheck disable=SC2016 + echo ' -u $SECTION -- exchange account to use' + echo ' -v -- use valgrind' + echo ' -w -- start taler-exchange-wirewatch' + echo ' -W -- wait for signal' + echo ' -z -- start taler-merchant-wirewatch' + exit 0 + ;; + g) + START_AGGREGATOR="1" + ;; + k) + START_CHALLENGER="1" + ;; + L) + LOGLEVEL="$OPTARG" + ;; + m) + START_MERCHANT="1" + ;; + M) + START_DEPOSITCHECK="1" + ;; + n) + START_NEXUS="1" + ;; + r) + USE_MERCHANT_EXCHANGE="$OPTARG" + ;; + s) + START_BACKUP="1" + ;; + t) + START_TRANSFER="1" + ;; + u) + USE_ACCOUNT="$OPTARG" + ;; + v) + USE_VALGRIND="valgrind --leak-check=yes" + DEFAULT_SLEEP="2" + ;; + w) + START_WIREWATCH="1" + ;; + W) + WAIT_FOR_SIGNAL="1" + ;; + z) + START_MERCHANT_WIREWATCH="1" + ;; + ?) + exit_fail "Unrecognized command line option" + ;; + esac +done + +STAGE="init" + +echo "Starting with configuration file at: $CONF_ORIG" +CONF="$CONF_ORIG.edited" +cp "${CONF_ORIG}" "${CONF}" + +STAGE="checks" + +echo -n "Testing for jq" +jq -h > /dev/null || exit_skip " jq required" +echo " FOUND" + +echo -n "Testing for wget" +wget --help > /dev/null || exit_skip " wget required" +echo " FOUND" + +if [ "1" = "$START_EXCHANGE" ] +then + echo -n "Testing for Taler exchange" + taler-exchange-httpd -h > /dev/null || exit_skip " taler-exchange-httpd required" + echo " FOUND" +fi + +if [ "1" = "$START_DONAU" ] +then + echo -n "Testing for Donau" + donau-httpd -h > /dev/null || exit_skip " donau-httpd required" + echo " FOUND" +fi + +if [ "1" = "$START_MERCHANT" ] +then + echo -n "Testing for Taler merchant" + taler-merchant-httpd -h > /dev/null || exit_skip " taler-merchant-httpd required" + echo " FOUND" +fi + +if [ "1" = "$START_CHALLENGER" ] +then + echo -n "Testing for Taler challenger" + challenger-httpd -h > /dev/null || exit_skip " challenger-httpd required" + echo " FOUND" +fi + +if [ "1" = "$START_BACKUP" ] +then + echo -n "Testing for sync-httpd" + sync-httpd -h > /dev/null || exit_skip " sync-httpd required" + echo " FOUND" +fi + +if [ "1" = "$START_NEXUS" ] +then + echo -n "Testing for libeufin-cli" + libeufin-cli --help >/dev/null </dev/null || exit_skip " MISSING" + echo " FOUND" +fi + +if [ "1" = "$START_BANK" ] +then + echo -n "Testing for libeufin-bank" + libeufin-bank --help >/dev/null </dev/null || exit_skip " MISSING" + echo " FOUND" +fi + +STAGE="config" + + +EXCHANGE_URL=$(taler-config -c "$CONF" -s "EXCHANGE" -o "BASE_URL") +CURRENCY=$(taler-config -c "$CONF" -s "TALER" -o "CURRENCY") + +echo "Setting up for $CURRENCY at $EXCHANGE_URL" + +register_bank_account() { + wget \ + --http-user="$AUSER" \ + --http-password="$APASS" \ + --method=DELETE \ + -o /dev/null \ + -O /dev/null \ + -a wget-delete-account.log \ + "http://localhost:${BANK_PORT}/accounts/$1" \ + || true # deletion may fail, that's OK! + if [ "$1" = "exchange" ] || [ "$1" = "Exchange" ] + then + IS_EXCHANGE="true" + else + IS_EXCHANGE="false" + fi + MAYBE_IBAN="${4:-}" + if [ -n "$MAYBE_IBAN" ] + then + # shellcheck disable=SC2001 + ENAME=$(echo "$3" | sed -e "s/ /+/g") + # Note: this assumes that $3 has no spaces. Should probably escape in the future.. + PAYTO="payto://iban/SANDBOXX/${MAYBE_IBAN}?receiver-name=$ENAME" + BODY='{"username":"'"$1"'","password":"'"$2"'","is_taler_exchange":'"$IS_EXCHANGE"',"name":"'"$3"'","payto_uri":"'"$PAYTO"'"}' + else + BODY='{"username":"'"$1"'","password":"'"$2"'","is_taler_exchange":'"$IS_EXCHANGE"',"name":"'"$3"'"}' + fi + wget \ + --http-user="$AUSER" \ + --http-password="$APASS" \ + --method=POST \ + --header='Content-type: application/json' \ + --body-data="${BODY}" \ + -o /dev/null \ + -O /dev/null \ + -a wget-register-account.log \ + "http://localhost:${BANK_PORT}/accounts" +} + +register_fakebank_account() { + if [ "$1" = "exchange" ] || [ "$1" = "Exchange" ] + then + IS_EXCHANGE="true" + else + IS_EXCHANGE="false" + fi + BODY='{"username":"'"$1"'","password":"'"$2"'","name":"'"$1"'","is_taler_exchange":'"$IS_EXCHANGE"'}' + wget \ + --post-data="$BODY" \ + --header='Content-type: application/json' \ + --tries=3 \ + --waitretry=1 \ + --timeout=30 \ + "http://localhost:$BANK_PORT/accounts" \ + -a wget-register-account.log \ + -o /dev/null \ + -O /dev/null \ + >/dev/null +} + + +if [[ "1" = "$START_BANK" ]] +then + BANK_PORT=$(taler-config -c "$CONF" -s "libeufin-bank" -o "PORT") + BANK_URL="http://localhost:${BANK_PORT}/" +fi + +if [[ "1" = "$START_FAKEBANK" ]] +then + BANK_PORT=$(taler-config -c "$CONF" -s "BANK" -o "HTTP_PORT") + BANK_URL="http://localhost:${BANK_PORT}/" +fi + +STAGE="bank" + +if [ "1" = "$START_BANK" ] +then + echo -n "Setting up bank database ... " + libeufin-bank dbinit \ + -r \ + -c "$CONF" \ + &> libeufin-bank-reset.log + echo "DONE" + echo -n "Launching bank ... " + libeufin-bank serve \ + -c "$CONF" \ + > libeufin-bank-stdout.log \ + 2> libeufin-bank-stderr.log & + echo $! > libeufin-bank.pid + echo "DONE" + echo -n "Waiting for Bank ..." + OK="0" + for n in $(seq 1 100); do + echo -n "." + sleep "$DEFAULT_SLEEP" + wget --timeout=1 \ + --tries=3 \ + --waitretry=0 \ + -a wget-bank-check.log \ + -o /dev/null \ + -O /dev/null \ + "${BANK_URL}config" || continue + OK="1" + break + done + if [ "1" != "$OK" ] + then + exit_skip "Failed to launch services (bank)" + fi + echo "OK" + echo -n "Set admin password..." + AUSER="admin" + APASS="secret" + libeufin-bank \ + passwd \ + -c "$CONF" \ + "$AUSER" "$APASS" \ + &> libeufin-bank-passwd.log + libeufin-bank \ + edit-account \ + -c "$CONF" \ + --debit_threshold="$CURRENCY:1000000" \ + "$AUSER" \ + &> libeufin-bank-debit-threshold.log + echo " OK" +fi + +if [ "1" = "$START_NEXUS" ] +then + echo "Nexus currently not supported ..." +fi + +if [ "1" = "$START_FAKEBANK" ] +then + echo -n "Setting up fakebank ..." + $USE_VALGRIND taler-fakebank-run \ + -c "$CONF" \ + -L "$LOGLEVEL" \ + -n 4 \ + 2> taler-fakebank-run.log & + echo " OK" +fi + +if [[ "1" = "$START_NEXUS" || "1" = "$START_FAKEBANK" ]] +then + echo -n "Waiting for the bank" + # Wait for bank to be available (usually the slowest) + OK="0" + for n in $(seq 1 300) + do + echo -n "." + sleep "$DEFAULT_SLEEP" + # bank + wget --tries=1 \ + --waitretry=0 \ + --timeout=1 \ + --user admin \ + --password secret \ + -a wget-bank-check.log \ + -o /dev/null \ + -O /dev/null \ + "http://localhost:${BANK_PORT}/" || continue + OK="1" + break + done + if [ "1" != "$OK" ] + then + exit_skip "Failed to launch services (bank)" + fi + echo " OK" +fi + +STAGE="accounts" + +if [ "1" = "$START_FAKEBANK" ] +then + echo -n "Register Fakebank users ..." + register_fakebank_account fortytwo x + register_fakebank_account fortythree x + register_fakebank_account exchange x + register_fakebank_account tor x + register_fakebank_account gnunet x + register_fakebank_account tutorial x + register_fakebank_account survey x + echo " DONE" +fi + +if [ "1" = "$START_BANK" ] +then + echo -n "Register bank users ..." + # The specified IBAN and name must match the ones hard-coded into + # the C helper for the add-incoming call. Without this value, + # libeufin-bank won't find the target account to debit along a /add-incoming + # call. + register_bank_account fortytwo x "User42" FR7630006000011234567890189 + register_bank_account fortythree x "Forty Three" + register_bank_account exchange x "Exchange Company" DE989651 + register_bank_account tor x "Tor Project" + register_bank_account gnunet x "GNUnet" + register_bank_account tutorial x "Tutorial" + register_bank_account survey x "Survey" + echo " DONE" +fi + +STAGE="exchange" + +if [ "1" = "$START_EXCHANGE" ] +then + echo -n "Starting exchange ..." + EXCHANGE_PORT=$(taler-config -c "$CONF" -s EXCHANGE -o PORT) + SERVE=$(taler-config -c "$CONF" -s EXCHANGE -o SERVE) + if [ "${SERVE}" = "unix" ] + then + EXCHANGE_URL=$(taler-config -c "$CONF" -s EXCHANGE -o BASE_URL) + else + EXCHANGE_URL="http://localhost:${EXCHANGE_PORT}/" + fi + MASTER_PRIV_FILE=$(taler-config -f -c "${CONF}" -s "EXCHANGE-OFFLINE" -o "MASTER_PRIV_FILE") + MASTER_PRIV_DIR=$(dirname "$MASTER_PRIV_FILE") + mkdir -p "${MASTER_PRIV_DIR}" + if [ ! -e "$MASTER_PRIV_FILE" ] + then + gnunet-ecc -g1 "$MASTER_PRIV_FILE" > /dev/null 2> /dev/null + echo -n "." + fi + MASTER_PUB=$(gnunet-ecc -p "${MASTER_PRIV_FILE}") + MPUB=$(taler-config -c "$CONF" -s exchange -o MASTER_PUBLIC_KEY) + if [ "$MPUB" != "$MASTER_PUB" ] + then + echo -n " patching master_pub ($MASTER_PUB)..." + taler-config -c "$CONF" -s exchange -o MASTER_PUBLIC_KEY -V "$MASTER_PUB" + fi + taler-exchange-dbinit -c "$CONF" --reset + $USE_VALGRIND taler-exchange-secmod-eddsa \ + -c "$CONF" \ + -L "$LOGLEVEL" \ + 2> taler-exchange-secmod-eddsa.log & + $USE_VALGRIND taler-exchange-secmod-rsa \ + -c "$CONF" \ + -L "$LOGLEVEL" \ + 2> taler-exchange-secmod-rsa.log & + $USE_VALGRIND taler-exchange-secmod-cs \ + -c "$CONF" \ + -L "$LOGLEVEL" \ + 2> taler-exchange-secmod-cs.log & + $USE_VALGRIND taler-exchange-httpd \ + -c "$CONF" \ + -L "$LOGLEVEL" 2> taler-exchange-httpd.log & + echo " DONE" +fi + +STAGE="donau" + +if [ "1" = "$START_DONAU" ] +then + echo -n "Starting Donau ..." + DONAU_PORT=$(donau-config -c "$CONF" -s DONAU -o PORT) + SERVE=$(donau-config -c "$CONF" -s DONAU -o SERVE) + if [ "${SERVE}" = "unix" ] + then + DONAU_URL=$(donau-config -c "$CONF" -s DONAU -o BASE_URL) + else + DONAU_URL="http://localhost:${DONAU_PORT}/" + fi + donau-dbinit -c "$CONF" --reset + $USE_VALGRIND taler-exchange-secmod-eddsa -c "$CONF" -L "$LOGLEVEL" -s donau 2> donau-secmod-eddsa.log & + $USE_VALGRIND taler-exchange-secmod-rsa -c "$CONF" -L "$LOGLEVEL" -s donau 2> donau-secmod-rsa.log & + $USE_VALGRIND taler-exchange-secmod-cs -c "$CONF" -L "$LOGLEVEL" -s donau 2> donau-secmod-cs.log & + $USE_VALGRIND donau-httpd -c "$CONF" -L "$LOGLEVEL" 2> donau-httpd.log & + echo " DONE" +fi + +STAGE="wirewatch" + +if [ "1" = "$START_WIREWATCH" ] +then + echo -n "Starting wirewatch ..." + $USE_VALGRIND taler-exchange-wirewatch \ + --account="$USE_ACCOUNT" \ + -c "$CONF" \ + -L "$LOGLEVEL" \ + --longpoll-timeout="60 s" \ + 2> taler-exchange-wirewatch.log & + echo " DONE" +fi + +STAGE="aggregator" + +if [ "1" = "$START_AGGREGATOR" ] +then + echo -n "Starting aggregator ..." + $USE_VALGRIND taler-exchange-aggregator \ + -c "$CONF" \ + -L "$LOGLEVEL" \ + 2> taler-exchange-aggregator.log & + echo " DONE" +fi + +STAGE="transfer" + +if [ "1" = "$START_TRANSFER" ] +then + echo -n "Starting transfer ..." + $USE_VALGRIND taler-exchange-transfer \ + -c "$CONF" \ + -L "$LOGLEVEL" \ + 2> taler-exchange-transfer.log & + echo " DONE" +fi + +STAGE="merchant" + +if [ "1" = "$START_MERCHANT" ] +then + echo -n "Starting merchant ..." + if [ -n "${USE_MERCHANT_EXCHANGE+x}" ] + then + MEPUB=$(taler-config -c "$CONF" -s "${USE_MERCHANT_EXCHANGE}" -o MASTER_KEY) + MXPUB=${MASTER_PUB:-$(taler-config -c "$CONF" -s exchange -o MASTER_PUBLIC_KEY)} + if [ "$MEPUB" != "$MXPUB" ] + then + echo -n " patching master_pub ($MXPUB)..." + taler-config -c "$CONF" -s "${USE_MERCHANT_EXCHANGE}" -o MASTER_KEY -V "$MXPUB" + fi + fi + MERCHANT_TYPE=$(taler-config -c "$CONF" -s MERCHANT -o SERVE) + if [ "unix" = "$MERCHANT_TYPE" ] + then + MERCHANT_URL="$(taler-config -c "$CONF" -s MERCHANT -o BASE_URL)" + else + MERCHANT_PORT="$(taler-config -c "$CONF" -s MERCHANT -o PORT)" + MERCHANT_URL="http://localhost:${MERCHANT_PORT}/" + fi + taler-merchant-dbinit \ + -c "$CONF" \ + --reset &> taler-merchant-dbinit.log + $USE_VALGRIND taler-merchant-httpd \ + -c "$CONF" \ + -L "$LOGLEVEL" 2> taler-merchant-httpd.log & + $USE_VALGRIND taler-merchant-webhook \ + -c "$CONF" \ + -L "$LOGLEVEL" 2> taler-merchant-webhook.log & + echo " DONE" + if [ "1" = "$START_MERCHANT_WIREWATCH" ] + then + echo -n "Starting taler-merchant-wirewatch ..." + $USE_VALGRIND taler-merchant-wirewatch \ + -c "$CONF" \ + -L "$LOGLEVEL" \ + --persist \ + 2> taler-merchant-wirewatch.log & + echo " DONE" + fi + if [ "1" = "$START_MERCHANT_EXCHANGE" ] + then + echo -n "Starting taler-merchant-exchange ..." + $USE_VALGRIND taler-merchant-exchange \ + -c "$CONF" \ + -L "$LOGLEVEL" 2> taler-merchant-exchange.log & + echo " DONE" + fi + if [ "1" = "$START_DEPOSITCHECK" ] + then + echo -n "Starting taler-merchant-depositcheck ..." + $USE_VALGRIND taler-merchant-depositcheck \ + -c "$CONF" \ + -L "$LOGLEVEL" 2> taler-merchant-depositcheck.log & + echo " DONE" + fi +fi + +STAGE="sync" + +if [ "1" = "$START_BACKUP" ] +then + echo -n "Starting sync ..." + SYNC_PORT=$(taler-config -c "$CONF" -s SYNC -o PORT) + SERVE=$(taler-config -c "$CONF" -s SYNC -o SERVE) + if [ "${SERVE}" = "unix" ] + then + SYNC_URL=$(taler-config -c "$CONF" -s SYNC -o BASE_URL) + else + SYNC_URL="http://localhost:${SYNC_PORT}/" + fi + sync-dbinit -c "$CONF" --reset + $USE_VALGRIND sync-httpd \ + -c "$CONF" \ + -L "$LOGLEVEL" \ + 2> sync-httpd.log & + echo " DONE" +fi + +STAGE="challenger" + +if [ "1" = "$START_CHALLENGER" ] +then + echo -n "Starting challenger ..." + CHALLENGER_PORT=$(challenger-config -c "$CONF" -s CHALLENGER -o PORT) + SERVE=$(taler-config -c "$CONF" -s CHALLENGER -o SERVE) + if [ "${SERVE}" = "unix" ] + then + CHALLENGER_URL=$(taler-config -c "$CONF" -s CHALLENGER -o BASE_URL) + else + CHALLENGER_URL="http://localhost:${CHALLENGER_PORT}/" + fi + challenger-dbinit \ + -c "$CONF" \ + --reset + $USE_VALGRIND challenger-httpd \ + -c "$CONF" \ + -L "$LOGLEVEL" \ + 2> challenger-httpd.log & + echo " DONE" + for SECTION in $(taler-config -c "$CONF" -S | grep kyc-provider) + do + LOGIC=$(taler-config -c "$CONF" -s "$SECTION" -o "LOGIC") + if [ "${LOGIC}" = "oauth2" ] + then + INFO=$(taler-config -c "$CONF" -s "$SECTION" -o "KYC_OAUTH2_INFO_URL") + if [ "${CHALLENGER_URL}info" = "$INFO" ] + then + echo -n "Enabling Challenger client for $SECTION" + CLIENT_SECRET=$(taler-config -c "$CONF" -s "$SECTION" -o "KYC_OAUTH2_CLIENT_SECRET") + RFC_8959_PREFIX="secret-token:" + if ! echo "${CLIENT_SECRET}" | grep ^${RFC_8959_PREFIX} > /dev/null + then + exit_fail "Client secret does not begin with '${RFC_8959_PREFIX}'" + fi + REDIRECT_URI="${EXCHANGE_URL}kyc-proof/kyc-provider-example-challeger" + CLIENT_ID=$(challenger-admin --add="${CLIENT_SECRET}" --quiet "${REDIRECT_URI}") + taler-config -c "$CONF" -s "$SECTION" -o KYC_OAUTH2_CLIENT_ID -V "$CLIENT_ID" + echo " DONE" + fi + fi + done +fi + +STAGE="auditor" + +if [ "1" = "$START_AUDITOR" ] +then + echo -n "Starting auditor ..." + AUDITOR_URL=$(taler-config -c "$CONF" -s AUDITOR -o BASE_URL) + AUDITOR_PRIV_FILE=$(taler-config -f -c "$CONF" -s AUDITOR -o AUDITOR_PRIV_FILE) + AUDITOR_PRIV_DIR=$(dirname "$AUDITOR_PRIV_FILE") + mkdir -p "$AUDITOR_PRIV_DIR" + if [ ! -e "$AUDITOR_PRIV_FILE" ] + then + gnunet-ecc -g1 "$AUDITOR_PRIV_FILE" > /dev/null 2> /dev/null + echo -n "." + fi + AUDITOR_PUB=$(gnunet-ecc -p "${AUDITOR_PRIV_FILE}") + MAPUB=${MASTER_PUB:-$(taler-config -c "$CONF" -s exchange -o MASTER_PUBLIC_KEY)} + taler-auditor-dbinit \ + -c "$CONF" \ + --reset + $USE_VALGRIND taler-auditor-httpd \ + -L "$LOGLEVEL" \ + -c "$CONF" 2> taler-auditor-httpd.log & +# $USE_VALGRIND taler-helper-auditor-deposits \ +# -L "$LOGLEVEL" \ +# -c "$CONF" 2> taler-helper-auditor.log & + echo " DONE" +fi + +STAGE="wait" + +echo -n "Waiting for Taler services ..." +# Wait for all other taler services to be available +E_DONE=0 +M_DONE=0 +S_DONE=0 +K_DONE=0 +A_DONE=0 +for n in $(seq 1 20) +do + sleep "$DEFAULT_SLEEP" + OK="0" + if [ "0" = "$E_DONE" ] && [ "1" = "$START_EXCHANGE" ] + then + echo -n "E" + wget \ + --tries=1 \ + --timeout=1 \ + "${EXCHANGE_URL}config" \ + -o /dev/null \ + -O /dev/null >/dev/null || continue + E_DONE=1 + fi + if [ "0" = "$M_DONE" ] && [ "1" = "$START_MERCHANT" ] + then + echo -n "M" + wget \ + --tries=1 \ + --timeout=1 \ + "${MERCHANT_URL}config" \ + -o /dev/null \ + -O /dev/null >/dev/null || continue + M_DONE=1 + fi + if [ "0" = "$S_DONE" ] && [ "1" = "$START_BACKUP" ] + then + echo -n "S" + wget \ + --tries=1 \ + --timeout=1 \ + "${SYNC_URL}config" \ + -o /dev/null \ + -O /dev/null >/dev/null || continue + S_DONE=1 + fi + if [ "0" = "$K_DONE" ] && [ "1" = "$START_CHALLENGER" ] + then + echo -n "K" + wget \ + --tries=1 \ + --timeout=1 \ + "${CHALLENGER_URL}config" \ + -o /dev/null \ + -O /dev/null >/dev/null || continue + K_DONE=1 + fi + if [ "0" = "$A_DONE" ] && [ "1" = "$START_AUDITOR" ] + then + echo -n "A" + wget \ + --tries=1 \ + --timeout=1 \ + "${AUDITOR_URL}config" \ + -o /dev/null \ + -O /dev/null >/dev/null || continue + A_DONE=1 + fi + OK="1" + break +done +if [ 1 != "$OK" ] +then + exit_skip "Failed to launch (some) Taler services" +fi +echo " OK" + +if [ "1" = "$START_EXCHANGE" ] +then + echo -n "Wait for exchange /management/keys to be ready " + OK="0" + LAST_RESPONSE=$(mktemp tmp-last-response.XXXXXXXX) + for n in $(seq 1 10) + do + echo -n "." + sleep "$DEFAULT_SLEEP" + # exchange + wget \ + --tries=3 \ + --waitretry=0 \ + --timeout=30 \ + "${EXCHANGE_URL}management/keys"\ + -o /dev/null \ + -O "$LAST_RESPONSE" \ + >/dev/null || continue + OK="1" + break; + done + if [ "1" != "$OK" ] + then + cat "$LAST_RESPONSE" + exit_fail "Failed to setup exchange keys, check secmod logs" + fi + rm "$LAST_RESPONSE" + echo " OK" + + echo -n "Setting up exchange keys ..." + taler-exchange-offline -c "$CONF" \ + download \ + sign \ + wire-fee now "$WIRE_DOMAIN" "$CURRENCY:0.01" "$CURRENCY:0.01" \ + global-fee now "$CURRENCY:0.01" "$CURRENCY:0.01" "$CURRENCY:0.0" 1h 1year 5 \ + upload &> taler-exchange-offline.log + echo "OK" + ENABLED=$(taler-config -c "$CONF" -s "$USE_ACCOUNT" -o "ENABLE_CREDIT") + if [ "YES" = "$ENABLED" ] + then + echo -n "Configuring bank account $USE_ACCOUNT ..." + EXCHANGE_PAYTO_URI=$(taler-config -c "$CONF" -s "$USE_ACCOUNT" -o "PAYTO_URI") + taler-exchange-offline -c "$CONF" \ + enable-account "$EXCHANGE_PAYTO_URI" \ + upload &> "taler-exchange-offline-account.log" + echo " OK" + else + echo "WARNING: Account ${USE_ACCOUNT} not enabled (set to: '$ENABLED')" + fi + if [ "1" = "$START_AUDITOR" ] + then + echo -n "Enabling auditor ..." + taler-exchange-offline -c "$CONF" \ + enable-auditor "$AUDITOR_PUB" "$AUDITOR_URL" "$CURRENCY Auditor" \ + upload &> taler-exchange-offline-auditor.log + echo "OK" + fi + + echo -n "Checking /keys " + OK="0" + LAST_RESPONSE=$(mktemp tmp-last-response.XXXXXXXX) + for n in $(seq 1 10) + do + echo -n "." + sleep "$DEFAULT_SLEEP" + wget \ + --tries=1 \ + --timeout=5 \ + "${EXCHANGE_URL}keys" \ + -a wget-keys-check.log \ + -o /dev/null \ + -O "$LAST_RESPONSE" \ + >/dev/null || continue + OK="1" + break + done + if [ "1" != "$OK" ] + then + cat "$LAST_RESPONSE" + exit_fail " Failed to fetch ${EXCHANGE_URL}keys" + fi + rm "$LAST_RESPONSE" + echo " OK" +fi + +if [ "1" = "$START_AUDITOR" ] +then + echo -n "Setting up auditor signatures ..." + timeout 15 taler-auditor-offline -c "$CONF" \ + download \ + sign \ + upload &> taler-auditor-offline.log + echo " OK" +fi + +STAGE="ready" + +# Signal caller that we are ready. +echo "<<READY>>" + +if [ "1" = "$WAIT_FOR_SIGNAL" ] +then + while true + do + sleep 0.1 + done +else + # Wait until caller stops us. + # shellcheck disable=SC2162 + read +fi + +STAGE="exiting" + +echo "Taler unified setup terminating!" >&2 +EXIT_STATUS=0 +exit "$EXIT_STATUS" diff --git a/src/testing/test-taler-exchange-aggregator-postgres.conf b/src/testing/test-taler-exchange-aggregator-postgres.conf index d3c6c4f2f..8c3ee4ba5 100644 --- a/src/testing/test-taler-exchange-aggregator-postgres.conf +++ b/src/testing/test-taler-exchange-aggregator-postgres.conf @@ -1,84 +1,59 @@ +# This file is in the public domain. + [PATHS] # Persistent data storage for the testcase TALER_TEST_HOME = test_taler_exchange_httpd_home/ -TALER_RUNTIME_DIR = ${TMPDIR:-${TMP:-/tmp}}/${USER:-}/taler-system-runtime/ [taler-exchange-secmod-rsa] # Reduce from 1 year to speed up test LOOKAHEAD_SIGN = 24 days [taler-exchange-secmod-eddsa] -# Reduce from 1 year to speed up test LOOKAHEAD_SIGN = 24 days -# Reduce from 12 weeks to ensure we have multiple DURATION = 14 days [taler] -# Currency supported by the exchange (can only be one) CURRENCY = EUR CURRENCY_ROUND_UNIT = EUR:0.01 [exchange] -# The DB plugin to use +AML_THRESHOLD = EUR:1000000 DB = postgres - -# HTTP port the exchange listens to PORT = 8081 - -# Master public key used to sign the exchange's various keys MASTER_PUBLIC_KEY = 98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG - -# Expected base URL of the exchange. Used in wire transfers for -# the tracking API. BASE_URL = "http://localhost:8081/" [auditor] BASE_URL = "http://auditor.example.com/" +PORT = 8083 [auditordb-postgres] CONFIG = "postgres:///talercheck" [exchangedb] -# After how long do we close idle reserves? The exchange -# and the auditor must agree on this value. We currently -# expect it to be globally defined for the whole system, -# as there is no way for wallets to query this value. Thus, -# it is only configurable for testing, and should be treated -# as constant in production. IDLE_RESERVE_EXPIRATION_TIME = 4 weeks +LEGAL_RESERVE_EXPIRATION_TIME = 7 years [exchangedb-postgres] - -#The connection string the plugin has to use for connecting to the database CONFIG = postgres:///talercheck -[exchangedb] - -# After how long do we close idle reserves? The exchange -# and the auditor must agree on this value. We currently -# expect it to be globally defined for the whole system, -# as there is no way for wallets to query this value. Thus, -# it is only configurable for testing, and should be treated -# as constant in production. -IDLE_RESERVE_EXPIRATION_TIME = 4 weeks - -# After how long do we forget about reserves? Should be above -# the legal expiration timeframe of withdrawn coins. -LEGAL_RESERVE_EXPIRATION_TIME = 7 years - [exchange-account-1] - # What is the account URL? PAYTO_URI = "payto://x-taler-bank/localhost/2?receiver-name=2" ENABLE_DEBIT = YES ENABLE_CREDIT = YES [exchange-accountcredentials-1] -WIRE_GATEWAY_URL = "http://localhost:8082/2/" +WIRE_GATEWAY_URL = "http://localhost:8082/accounts/2/taler-wire-gateway/" WIRE_GATEWAY_AUTH_METHOD = basic USERNAME = Exchange PASSWORD = x +[admin-accountcredentials-1] +WIRE_GATEWAY_URL = "http://localhost:8082/accounts/2/taler-wire-gateway/" +WIRE_GATEWAY_AUTH_METHOD = basic +USERNAME = Exchange +PASSWORD = x [bank] HTTP_PORT = 8082 diff --git a/src/testing/test-taler-exchange-wirewatch-postgres.conf b/src/testing/test-taler-exchange-wirewatch-postgres.conf index ae8ba2329..4f13077ac 100644 --- a/src/testing/test-taler-exchange-wirewatch-postgres.conf +++ b/src/testing/test-taler-exchange-wirewatch-postgres.conf @@ -1,60 +1,41 @@ +# This file is in the public domain. + [PATHS] # Persistent data storage for the testcase TALER_TEST_HOME = test_taler_exchange_httpd_home/ -TALER_RUNTIME_DIR = ${TMPDIR:-${TMP:-/tmp}}/${USER:-}/taler-system-runtime/ [taler-exchange-secmod-rsa] -# Reduce from 1 year to speed up test LOOKAHEAD_SIGN = 24 days [taler-exchange-secmod-eddsa] -# Reduce from 1 year to speed up test LOOKAHEAD_SIGN = 24 days -# Reduce from 12 weeks to ensure we have multiple DURATION = 14 days [taler] -# Currency supported by the exchange (can only be one) CURRENCY = EUR CURRENCY_ROUND_UNIT = EUR:0.01 [exchange] -# The DB plugin to use +AML_THRESHOLD = EUR:1000000 DB = postgres - -# HTTP port the exchange listens to PORT = 8081 - -# Master public key used to sign the exchange's various keys MASTER_PUBLIC_KEY = 98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG - -# Expected base URL of the exchange. BASE_URL = "http://localhost:8081/" [exchangedb] -# After how long do we close idle reserves? The exchange -# and the auditor must agree on this value. We currently -# expect it to be globally defined for the whole system, -# as there is no way for wallets to query this value. Thus, -# it is only configurable for testing, and should be treated -# as constant in production. -# # This is THE test that requires a short reserve expiration time! IDLE_RESERVE_EXPIRATION_TIME = 4 s [exchangedb-postgres] -#The connection string the plugin has to use for connecting to the database -CONFIG = "postgres:///talercheck" - -[auditordb-postgres] CONFIG = "postgres:///talercheck" [auditor] BASE_URL = "http://localhost:8083/" - -# HTTP port the auditor listens to PORT = 8083 +[auditordb-postgres] +CONFIG = "postgres:///talercheck" + [exchange-account-1] # What is the account URL? PAYTO_URI = "payto://x-taler-bank/localhost/2?receiver-name=2" @@ -62,7 +43,13 @@ ENABLE_DEBIT = YES ENABLE_CREDIT = YES [exchange-accountcredentials-1] -WIRE_GATEWAY_URL = "http://localhost:8082/2/" +WIRE_GATEWAY_URL = "http://localhost:8082/accounts/2/taler-wire-gateway/" +WIRE_GATEWAY_AUTH_METHOD = basic +USERNAME = Exchange +PASSWORD = x + +[admin-accountcredentials-1] +WIRE_GATEWAY_URL = "http://localhost:8082/accounts/2/taler-wire-gateway/" WIRE_GATEWAY_AUTH_METHOD = basic USERNAME = Exchange PASSWORD = x @@ -70,6 +57,16 @@ PASSWORD = x [bank] HTTP_PORT = 8082 +[libeufin-bank] +CURRENCY = EUR +DEFAULT_CUSTOMER_DEBT_LIMIT = EUR:200 +DEFAULT_ADMIN_DEBT_LIMIT = EUR:2000 +REGISTRATION_BONUS_ENABLED = yes +REGISTRATION_BONUS = EUR:100 +SUGGESTED_WITHDRAWAL_EXCHANGE = http://localhost:8081/ +SERVE = tcp +PORT = 8082 + # Need at least one coin, otherwise Exchange # refuses to start. [coin_eur_ct_1] diff --git a/src/testing/test_auditor_api-cs.conf b/src/testing/test_auditor_api-cs.conf index cfd1fa6cc..b80696fb2 100644 --- a/src/testing/test_auditor_api-cs.conf +++ b/src/testing/test_auditor_api-cs.conf @@ -1,140 +1,4 @@ - # This file is in the public domain. # -[PATHS] -# Persistent data storage for the testcase -TALER_TEST_HOME = test_exchange_api_home/ -TALER_RUNTIME_DIR = ${TMPDIR:-${TMP:-/tmp}}/${USER:-}/taler-system-runtime/ - -[taler-exchange-secmod-cs] -# Reduce from 1 year to speed up test -LOOKAHEAD_SIGN = 24 days - -[taler-exchange-secmod-eddsa] -# Reduce from 1 year to speed up test -LOOKAHEAD_SIGN = 24 days -# Reduce from 12 weeks to ensure we have multiple -DURATION = 14 days - - -[taler] -# Currency supported by the exchange (can only be one) -CURRENCY = EUR -CURRENCY_ROUND_UNIT = EUR:0.01 - -[auditor] -BASE_URL = "http://localhost:8083/" - -# HTTP port the auditor listens to -PORT = 8083 -PUBLIC_KEY = XNYZPJJ6YPSQ4C6QPW120ACG9B5E5GBTTSYWXDMDB6G4X74TDBPG -TINY_AMOUNT = EUR:0.01 - -[exchange] - -# HTTP port the exchange listens to -PORT = 8081 - -# Master public key used to sign the exchange's various keys -MASTER_PUBLIC_KEY = 98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG - -# How to access our database -DB = postgres - -# Base URL of the exchange. Must be set to a URL where the -# exchange (or the twister) is actually listening. -BASE_URL = "http://localhost:8081/" - -[exchangedb-postgres] -CONFIG = "postgres:///talercheck" - -[auditordb-postgres] -CONFIG = "postgres:///talercheck" - -# Sections starting with "exchange-account-" configure the bank accounts -# of the exchange. The "URL" specifies the account in -# payto://-format. -[exchange-account-1] -# What is the URL of our account? -PAYTO_URI = "payto://x-taler-bank/localhost/42?receiver-name=42" - -[exchange-accountcredentials-1] -WIRE_GATEWAY_URL = "http://localhost:8082/42/" - -[bank] -HTTP_PORT = 8082 - -# ENABLE_CREDIT = YES - -[exchange-account-2] -# What is the bank account (with the "Taler Bank" demo system)? -PAYTO_URI = "payto://x-taler-bank/localhost/2?receiver-name=2" -ENABLE_DEBIT = YES -ENABLE_CREDIT = YES - -# Authentication information for basic authentication -[exchange-accountcredentials-2] -WIRE_GATEWAY_URL = "http://localhost:8082/2/" -WIRE_GATEWAY_AUTH_METHOD = "basic" -USERNAME = user -PASSWORD = pass - - - - -# Sections starting with "coin_" specify which denominations -# the exchange should support (and their respective fee structure) -[coin_eur_ct_1] -value = EUR:0.01 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.00 -fee_deposit = EUR:0.00 -fee_refresh = EUR:0.01 -fee_refund = EUR:0.01 -CIPHER = CS - -[coin_eur_ct_10] -value = EUR:0.10 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.01 -fee_deposit = EUR:0.01 -fee_refresh = EUR:0.03 -fee_refund = EUR:0.01 -CIPHER = CS - -[coin_eur_1] -value = EUR:1 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.01 -fee_deposit = EUR:0.01 -fee_refresh = EUR:0.03 -fee_refund = EUR:0.01 -CIPHER = CS - -[coin_eur_5] -value = EUR:5 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.01 -fee_deposit = EUR:0.01 -fee_refresh = EUR:0.03 -fee_refund = EUR:0.01 -CIPHER = CS - -[coin_eur_10] -value = EUR:10 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.01 -fee_deposit = EUR:0.01 -fee_refresh = EUR:0.03 -fee_refund = EUR:0.01 -CIPHER = CS +@INLINE@ coins-cs.conf +@INLINE@ test_exchange_api.conf diff --git a/src/testing/test_auditor_api-rsa.conf b/src/testing/test_auditor_api-rsa.conf index 577d9057a..671e81108 100644 --- a/src/testing/test_auditor_api-rsa.conf +++ b/src/testing/test_auditor_api-rsa.conf @@ -1,146 +1,4 @@ - # This file is in the public domain. # -[PATHS] -# Persistent data storage for the testcase -TALER_TEST_HOME = test_exchange_api_home/ -TALER_RUNTIME_DIR = ${TMPDIR:-${TMP:-/tmp}}/${USER:-}/taler-system-runtime/ - -[taler-exchange-secmod-rsa] -# Reduce from 1 year to speed up test -LOOKAHEAD_SIGN = 24 days - -[taler-exchange-secmod-eddsa] -# Reduce from 1 year to speed up test -LOOKAHEAD_SIGN = 24 days -# Reduce from 12 weeks to ensure we have multiple -DURATION = 14 days - - -[taler] -# Currency supported by the exchange (can only be one) -CURRENCY = EUR -CURRENCY_ROUND_UNIT = EUR:0.01 - -[auditor] -BASE_URL = "http://localhost:8083/" - -# HTTP port the auditor listens to -PORT = 8083 -PUBLIC_KEY = XNYZPJJ6YPSQ4C6QPW120ACG9B5E5GBTTSYWXDMDB6G4X74TDBPG - -TINY_AMOUNT = EUR:0.01 - -[exchange] - -# HTTP port the exchange listens to -PORT = 8081 - -# Master public key used to sign the exchange's various keys -MASTER_PUBLIC_KEY = 98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG - -# How to access our database -DB = postgres - -# Base URL of the exchange. Must be set to a URL where the -# exchange (or the twister) is actually listening. -BASE_URL = "http://localhost:8081/" - -[exchangedb-postgres] -CONFIG = "postgres:///talercheck" - -[auditordb-postgres] -CONFIG = "postgres:///talercheck" - -# Sections starting with "exchange-account-" configure the bank accounts -# of the exchange. The "URL" specifies the account in -# payto://-format. -[exchange-account-1] -# What is the URL of our account? -PAYTO_URI = "payto://x-taler-bank/localhost/42?receiver-name=42" - -[exchange-accountcredentials-1] -WIRE_GATEWAY_URL = "http://localhost:8082/42/" - -[bank] -HTTP_PORT = 8082 - -# ENABLE_CREDIT = YES - -[exchange-account-2] -# What is the bank account (with the "Taler Bank" demo system)? -PAYTO_URI = "payto://x-taler-bank/localhost/2?receiver-name=2" -ENABLE_DEBIT = YES -ENABLE_CREDIT = YES - -# Authentication information for basic authentication -[exchange-accountcredentials-2] -WIRE_GATEWAY_URL = "http://localhost:8082/2/" -WIRE_GATEWAY_AUTH_METHOD = "basic" -USERNAME = user -PASSWORD = pass - - - - -# Sections starting with "coin_" specify which denominations -# the exchange should support (and their respective fee structure) -[coin_eur_ct_1] -value = EUR:0.01 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.00 -fee_deposit = EUR:0.00 -fee_refresh = EUR:0.01 -fee_refund = EUR:0.01 -CIPHER = RSA -rsa_keysize = 1024 - -[coin_eur_ct_10] -value = EUR:0.10 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.01 -fee_deposit = EUR:0.01 -fee_refresh = EUR:0.03 -fee_refund = EUR:0.01 -CIPHER = RSA -rsa_keysize = 1024 - -[coin_eur_1] -value = EUR:1 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.01 -fee_deposit = EUR:0.01 -fee_refresh = EUR:0.03 -fee_refund = EUR:0.01 -CIPHER = RSA -rsa_keysize = 1024 - -[coin_eur_5] -value = EUR:5 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.01 -fee_deposit = EUR:0.01 -fee_refresh = EUR:0.03 -fee_refund = EUR:0.01 -CIPHER = RSA -rsa_keysize = 1024 - -[coin_eur_10] -value = EUR:10 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.01 -fee_deposit = EUR:0.01 -fee_refresh = EUR:0.03 -fee_refund = EUR:0.01 -CIPHER = RSA -rsa_keysize = 1024 +@INLINE@ coins-rsa.conf +@INLINE@ test_exchange_api.conf diff --git a/src/testing/test_auditor_api.c b/src/testing/test_auditor_api.c index 305d31a09..3810c601e 100644 --- a/src/testing/test_auditor_api.c +++ b/src/testing/test_auditor_api.c @@ -45,14 +45,9 @@ static char *config_file; static char *config_file_expire_reserve_now; /** - * Exchange configuration data. + * Our credentials. */ -static struct TALER_TESTING_ExchangeConfiguration ec; - -/** - * Bank configuration data. - */ -static struct TALER_TESTING_BankConfiguration bc; +static struct TALER_TESTING_Credentials cred; /** * Execute the taler-exchange-wirewatch command with @@ -61,7 +56,7 @@ static struct TALER_TESTING_BankConfiguration bc; * @param label label to use for the command. */ #define CMD_EXEC_WIREWATCH(label) \ - TALER_TESTING_cmd_exec_wirewatch (label, config_file) + TALER_TESTING_cmd_exec_wirewatch2 (label, config_file, "exchange-account-2") /** * Execute the taler-exchange-aggregator, closer and transfer commands with @@ -83,8 +78,8 @@ static struct TALER_TESTING_BankConfiguration bc; */ #define CMD_TRANSFER_TO_EXCHANGE(label,amount) \ TALER_TESTING_cmd_admin_add_incoming (label, amount, \ - &bc.exchange_auth, \ - bc.user42_payto) + &cred.ba, \ + cred.user42_payto) /** * Run the taler-auditor. @@ -116,7 +111,7 @@ run (void *cls, "EUR:5.01"), TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-reserve-1", - "EUR:5.01", bc.user42_payto, bc.exchange_payto, + "EUR:5.01", cred.user42_payto, cred.exchange_payto, "create-reserve-1"), /** * Make a reserve exist, according to the previous transfer. @@ -140,7 +135,7 @@ run (void *cls, TALER_TESTING_cmd_deposit ("deposit-simple", "withdraw-coin-1", 0, - bc.user42_payto, + cred.user42_payto, "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", GNUNET_TIME_UNIT_ZERO, "EUR:5", @@ -157,7 +152,7 @@ run (void *cls, "EUR:5.01"), TALER_TESTING_cmd_check_bank_admin_transfer ("check-refresh-create-reserve-1", - "EUR:5.01", bc.user42_payto, bc.exchange_payto, + "EUR:5.01", cred.user42_payto, cred.exchange_payto, "refresh-create-reserve-1"), /** * Make previous command effective. @@ -178,7 +173,7 @@ run (void *cls, TALER_TESTING_cmd_deposit ("refresh-deposit-partial", "refresh-withdraw-coin-1", 0, - bc.user42_payto, + cred.user42_payto, "{\"items\":[{\"name\":\"ice\",\"value\":\"EUR:1\"}]}", GNUNET_TIME_UNIT_ZERO, "EUR:1", @@ -203,7 +198,7 @@ run (void *cls, TALER_TESTING_cmd_deposit ("refresh-deposit-refreshed-1b", "refresh-reveal-1", 3, - bc.user43_payto, + cred.user43_payto, "{\"items\":[{\"name\":\"ice cream\",\"value\":3}]}", GNUNET_TIME_UNIT_ZERO, "EUR:0.1", @@ -225,75 +220,75 @@ run (void *cls, */ TALER_TESTING_cmd_check_bank_transfer ( "check_bank_transfer-499c", - ec.exchange_url, + cred.exchange_url, "EUR:4.98", - bc.exchange_payto, - bc.user42_payto), + cred.exchange_payto, + cred.user42_payto), TALER_TESTING_cmd_check_bank_transfer ( "check_bank_transfer-99c1", - ec.exchange_url, + cred.exchange_url, "EUR:0.98", - bc.exchange_payto, - bc.user42_payto), + cred.exchange_payto, + cred.user42_payto), TALER_TESTING_cmd_check_bank_transfer ( "check_bank_transfer-99c", - ec.exchange_url, + cred.exchange_url, "EUR:0.08", - bc.exchange_payto, - bc.user43_payto), + cred.exchange_payto, + cred.user43_payto), /* The following transactions got originated within * the "massive deposit confirms" batch. */ TALER_TESTING_cmd_check_bank_transfer ( "check-massive-transfer-1", - ec.exchange_url, + cred.exchange_url, "EUR:0.98", - bc.exchange_payto, bc.user43_payto), + cred.exchange_payto, cred.user43_payto), TALER_TESTING_cmd_check_bank_transfer ("check-massive-transfer-2", - ec.exchange_url, + cred.exchange_url, "EUR:0.98", - bc.exchange_payto, bc.user43_payto), + cred.exchange_payto, cred.user43_payto), TALER_TESTING_cmd_check_bank_transfer ("check-massive-transfer-3", - ec.exchange_url, + cred.exchange_url, "EUR:0.98", - bc.exchange_payto, bc.user43_payto), + cred.exchange_payto, cred.user43_payto), TALER_TESTING_cmd_check_bank_transfer ("check-massive-transfer-4", - ec.exchange_url, + cred.exchange_url, "EUR:0.98", - bc.exchange_payto, bc.user43_payto), + cred.exchange_payto, cred.user43_payto), TALER_TESTING_cmd_check_bank_transfer ("check-massive-transfer-5", - ec.exchange_url, + cred.exchange_url, "EUR:0.98", - bc.exchange_payto, bc.user43_payto), + cred.exchange_payto, cred.user43_payto), TALER_TESTING_cmd_check_bank_transfer ("check-massive-transfer-6", - ec.exchange_url, + cred.exchange_url, "EUR:0.98", - bc.exchange_payto, bc.user43_payto), + cred.exchange_payto, cred.user43_payto), TALER_TESTING_cmd_check_bank_transfer ("check-massive-transfer-7", - ec.exchange_url, + cred.exchange_url, "EUR:0.98", - bc.exchange_payto, bc.user43_payto), + cred.exchange_payto, cred.user43_payto), TALER_TESTING_cmd_check_bank_transfer ("check-massive-transfer-8", - ec.exchange_url, + cred.exchange_url, "EUR:0.98", - bc.exchange_payto, bc.user43_payto), + cred.exchange_payto, cred.user43_payto), TALER_TESTING_cmd_check_bank_transfer ("check-massive-transfer-9", - ec.exchange_url, + cred.exchange_url, "EUR:0.98", - bc.exchange_payto, bc.user43_payto), + cred.exchange_payto, cred.user43_payto), TALER_TESTING_cmd_check_bank_transfer ("check-massive-transfer-10", - ec.exchange_url, + cred.exchange_url, "EUR:0.98", - bc.exchange_payto, bc.user43_payto), + cred.exchange_payto, cred.user43_payto), TALER_TESTING_cmd_check_bank_empty ("check_bank_empty"), TALER_TESTING_cmd_end () }; @@ -311,8 +306,8 @@ run (void *cls, TALER_TESTING_cmd_check_bank_admin_transfer ( "check_bank_transfer-unaggregated", "EUR:5.01", - bc.user42_payto, - bc.exchange_payto, + cred.user42_payto, + cred.exchange_payto, "create-reserve-unaggregated"), TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-unaggregated", "create-reserve-unaggregated", @@ -322,7 +317,7 @@ run (void *cls, TALER_TESTING_cmd_deposit ("deposit-unaggregated", "withdraw-coin-unaggregated", 0, - bc.user43_payto, + cred.user43_payto, "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_YEARS, @@ -359,7 +354,7 @@ run (void *cls, TALER_TESTING_cmd_deposit ("deposit-refund-1", "withdraw-coin-r1", 0, - bc.user42_payto, + cred.user42_payto, "{\"items\":[{\"name\":\"ice\",\"value\":\"EUR:5\"}]}", GNUNET_TIME_UNIT_MINUTES, "EUR:5", @@ -376,7 +371,7 @@ run (void *cls, TALER_TESTING_cmd_deposit ("deposit-refund-2", "withdraw-coin-r1", 0, - bc.user42_payto, + cred.user42_payto, "{\"items\":[{\"name\":\"more\",\"value\":\"EUR:5\"}]}", GNUNET_TIME_UNIT_ZERO, "EUR:4.99", @@ -431,8 +426,9 @@ run (void *cls, */ CMD_TRANSFER_TO_EXCHANGE ("short-lived-reserve", "EUR:5.01"), - TALER_TESTING_cmd_exec_wirewatch ("short-lived-aggregation", - config_file_expire_reserve_now), + TALER_TESTING_cmd_exec_wirewatch2 ("short-lived-aggregation", + config_file_expire_reserve_now, + "exchange-account-2"), TALER_TESTING_cmd_exec_aggregator ("close-reserves", config_file_expire_reserve_now), /** @@ -466,7 +462,7 @@ run (void *cls, TALER_TESTING_cmd_deposit ("recoup-deposit-partial", "recoup-withdraw-coin-2a", 0, - bc.user42_payto, + cred.user42_payto, "{\"items\":[{\"name\":\"more ice cream\",\"value\":1}]}", GNUNET_TIME_UNIT_ZERO, "EUR:0.5", @@ -493,7 +489,8 @@ run (void *cls, TALER_TESTING_cmd_check_bank_admin_transfer ( "check-massive-transfer", "EUR:10.10", - bc.user42_payto, bc.exchange_payto, + cred.user42_payto, + cred.exchange_payto, "massive-reserve"), CMD_EXEC_WIREWATCH ("massive-wirewatch"), TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-1", @@ -550,7 +547,7 @@ run (void *cls, "massive-deposit-1", "massive-withdraw-1", 0, - bc.user43_payto, + cred.user43_payto, "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", GNUNET_TIME_UNIT_ZERO, "EUR:1", @@ -559,7 +556,7 @@ run (void *cls, ("massive-deposit-2", "massive-withdraw-2", 0, - bc.user43_payto, + cred.user43_payto, "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", GNUNET_TIME_UNIT_ZERO, "EUR:1", @@ -568,7 +565,7 @@ run (void *cls, ("massive-deposit-3", "massive-withdraw-3", 0, - bc.user43_payto, + cred.user43_payto, "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", GNUNET_TIME_UNIT_ZERO, "EUR:1", @@ -577,7 +574,7 @@ run (void *cls, ("massive-deposit-4", "massive-withdraw-4", 0, - bc.user43_payto, + cred.user43_payto, "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", GNUNET_TIME_UNIT_ZERO, "EUR:1", @@ -586,7 +583,7 @@ run (void *cls, ("massive-deposit-5", "massive-withdraw-5", 0, - bc.user43_payto, + cred.user43_payto, "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", GNUNET_TIME_UNIT_ZERO, "EUR:1", @@ -595,7 +592,7 @@ run (void *cls, ("massive-deposit-6", "massive-withdraw-6", 0, - bc.user43_payto, + cred.user43_payto, "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", GNUNET_TIME_UNIT_ZERO, "EUR:1", @@ -604,7 +601,7 @@ run (void *cls, ("massive-deposit-7", "massive-withdraw-7", 0, - bc.user43_payto, + cred.user43_payto, "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", GNUNET_TIME_UNIT_ZERO, "EUR:1", @@ -613,7 +610,7 @@ run (void *cls, ("massive-deposit-8", "massive-withdraw-8", 0, - bc.user43_payto, + cred.user43_payto, "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", GNUNET_TIME_UNIT_ZERO, "EUR:1", @@ -622,7 +619,7 @@ run (void *cls, ("massive-deposit-9", "massive-withdraw-9", 0, - bc.user43_payto, + cred.user43_payto, "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", GNUNET_TIME_UNIT_ZERO, "EUR:1", @@ -631,15 +628,14 @@ run (void *cls, "massive-deposit-10", "massive-withdraw-10", 0, - bc.user43_payto, + cred.user43_payto, "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", GNUNET_TIME_UNIT_ZERO, "EUR:1", MHD_HTTP_OK), TALER_TESTING_cmd_deposit_confirmation ("deposit-confirmation", - is->auditor, "massive-deposit-10", - 0, + 1, "EUR:0.99", MHD_HTTP_OK), CMD_RUN_AUDITOR ("massive-auditor"), @@ -648,28 +644,25 @@ run (void *cls, }; struct TALER_TESTING_Command commands[] = { - TALER_TESTING_cmd_exec_offline_sign_fees ("offline-sign-fees", - config_file, - "EUR:0.01", - "EUR:0.01", - "EUR:0.01"), - TALER_TESTING_cmd_auditor_add ("add-auditor-OK", - MHD_HTTP_NO_CONTENT, - false), - TALER_TESTING_cmd_wire_add ("add-wire-account", - "payto://x-taler-bank/localhost/2?receiver-name=2", - MHD_HTTP_NO_CONTENT, - false), - TALER_TESTING_cmd_exec_offline_sign_keys ("offline-sign-future-keys", - config_file), - TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys", - 2), + TALER_TESTING_cmd_run_fakebank ("run-fakebank", + cred.cfg, + "exchange-account-2"), + TALER_TESTING_cmd_system_start ("start-taler", + config_file, + "-u", "exchange-account-2", + "-ae", + NULL), + TALER_TESTING_cmd_get_exchange ("get-exchange", + cred.cfg, + NULL, + true, + true), + TALER_TESTING_cmd_get_auditor ("get-auditor", + cred.cfg, + true), TALER_TESTING_cmd_exec_auditor_offline ("auditor-offline", config_file), CMD_RUN_AUDITOR ("virgin-auditor"), - TALER_TESTING_cmd_exchanges_with_url ("check-exchange", - MHD_HTTP_OK, - "http://localhost:8081/"), TALER_TESTING_cmd_batch ("massive-deposit-confirms", massive_deposit_confirms), TALER_TESTING_cmd_batch ("withdraw", @@ -691,9 +684,8 @@ run (void *cls, }; (void) cls; - TALER_TESTING_run_with_fakebank (is, - commands, - bc.exchange_auth.wire_gateway_url); + TALER_TESTING_run (is, + commands); } @@ -701,60 +693,28 @@ int main (int argc, char *const *argv) { - char *cipher; - (void) argc; - /* These environment variables get in the way... */ - unsetenv ("XDG_DATA_HOME"); - unsetenv ("XDG_CONFIG_HOME"); - GNUNET_log_setup (argv[0], - "INFO", - NULL); - - cipher = GNUNET_TESTING_get_testname_from_underscore (argv[0]); - GNUNET_assert (NULL != cipher); - GNUNET_asprintf (&config_file, - "test_auditor_api-%s.conf", - cipher); - GNUNET_asprintf (&config_file_expire_reserve_now, - "test_auditor_api_expire_reserve_now-%s.conf", - cipher); - GNUNET_free (cipher); - /* Check fakebank port is available and get configuration data. */ - if (GNUNET_OK != - TALER_TESTING_prepare_fakebank (config_file, - "exchange-account-2", - &bc)) - return 77; - TALER_TESTING_cleanup_files (config_file); - /* @helpers. Run keyup, create tables, ... Note: it - * fetches the port number from config in order to see - * if it's available. */ - switch (TALER_TESTING_prepare_exchange (config_file, - GNUNET_YES, - &ec)) { - case GNUNET_SYSERR: - GNUNET_break (0); - return 1; - case GNUNET_NO: - return 78; - case GNUNET_OK: - if (GNUNET_OK != - /* Set up event loop and reschedule context, plus - * start/stop the exchange. It calls TALER_TESTING_setup - * which creates the 'is' object. - */ - TALER_TESTING_auditor_setup (&run, - NULL, - config_file)) - return 2; - break; - default: - GNUNET_break (0); - return 3; + char *cipher; + + cipher = GNUNET_STRINGS_get_suffix_from_binary_name (argv[0]); + GNUNET_assert (NULL != cipher); + GNUNET_asprintf (&config_file, + "test_auditor_api-%s.conf", + cipher); + GNUNET_asprintf (&config_file_expire_reserve_now, + "test_auditor_api_expire_reserve_now-%s.conf", + cipher); + GNUNET_free (cipher); } - return 0; + return TALER_TESTING_main (argv, + "INFO", + config_file, + "exchange-account-2", + TALER_TESTING_BS_FAKEBANK, + &cred, + &run, + NULL); } diff --git a/src/testing/test_auditor_api_version.c b/src/testing/test_auditor_api_version.c index 1b60b15d1..dcd542ad8 100644 --- a/src/testing/test_auditor_api_version.c +++ b/src/testing/test_auditor_api_version.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014-2018 Taler Systems SA + Copyright (C) 2014-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 @@ -39,9 +39,9 @@ * Configuration file we use. One (big) configuration is used * for the various components for this test. */ -#define CONFIG_FILE "test_auditor_api.conf" +#define CONFIG_FILE "test_auditor_api-rsa.conf" -static struct TALER_AUDITOR_Handle *ah; +static struct TALER_AUDITOR_GetConfigHandle *ah; static struct GNUNET_CURL_Context *ctx; @@ -51,6 +51,7 @@ static int global_ret; static struct GNUNET_SCHEDULER_Task *tt; + static void do_shutdown (void *cls) { @@ -61,7 +62,11 @@ do_shutdown (void *cls) GNUNET_SCHEDULER_cancel (tt); tt = NULL; } - TALER_AUDITOR_disconnect (ah); + if (NULL != ah) + { + TALER_AUDITOR_get_config_cancel (ah); + ah = NULL; + } GNUNET_CURL_fini (ctx); GNUNET_CURL_gnunet_rc_destroy (rc); } @@ -81,20 +86,16 @@ do_timeout (void *cls) * Function called with information about the auditor. * * @param cls closure - * @param hr http response details - * @param vi basic information about the auditor - * @param compat protocol compatibility information + * @param vr response details */ static void version_cb (void *cls, - const struct TALER_AUDITOR_HttpResponse *hr, - const struct TALER_AUDITOR_VersionInformation *vi, - enum TALER_AUDITOR_VersionCompatibility compat) + const struct TALER_AUDITOR_ConfigResponse *vr) { (void) cls; - (void) hr; - if ( (NULL != vi) && - (TALER_AUDITOR_VC_MATCH == compat) ) + ah = NULL; + if ( (MHD_HTTP_OK == vr->hr.http_status) && + (TALER_AUDITOR_VC_MATCH == vr->details.ok.compat) ) global_ret = 0; else global_ret = 2; @@ -117,10 +118,10 @@ run (void *cls) ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule, &rc); rc = GNUNET_CURL_gnunet_rc_create (ctx); - ah = TALER_AUDITOR_connect (ctx, - auditor_url, - &version_cb, - NULL); + ah = TALER_AUDITOR_get_config (ctx, + auditor_url, + &version_cb, + NULL); GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL); tt = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, @@ -148,15 +149,16 @@ main (int argc, "taler-auditor-httpd", "taler-auditor-httpd", "-c", CONFIG_FILE, + "-L", "INFO", NULL); if (NULL == proc) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to run `taler-auditor-httpd`," - " is your PATH correct?\n"); + "Failed to run `taler-auditor-httpd`, is your PATH correct?\n"); return 77; } - if (0 != TALER_TESTING_wait_auditor_ready ("http://localhost:8083/")) + global_ret = TALER_TESTING_wait_httpd_ready ("http://localhost:8083/"); + if (0 != global_ret) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to launch `taler-auditor-httpd`\n"); @@ -166,7 +168,8 @@ main (int argc, GNUNET_SCHEDULER_run (&run, NULL); } - GNUNET_OS_process_kill (proc, SIGTERM); + GNUNET_OS_process_kill (proc, + SIGTERM); GNUNET_OS_process_wait (proc); GNUNET_OS_process_destroy (proc); return global_ret; diff --git a/src/testing/test_bank_api.c b/src/testing/test_bank_api.c index cb4609ddf..8cbc86bbd 100644 --- a/src/testing/test_bank_api.c +++ b/src/testing/test_bank_api.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2016-2020 Taler Systems SA + Copyright (C) 2016-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 @@ -34,7 +34,7 @@ #include "taler_testing_lib.h" #define CONFIG_FILE_FAKEBANK "test_bank_api_fakebank.conf" -#define CONFIG_FILE_PYBANK "test_bank_api_pybank.conf" + #define CONFIG_FILE_NEXUS "test_bank_api_nexus.conf" @@ -42,33 +42,19 @@ * Configuration file. It changes based on * whether Nexus or Fakebank are used. */ -const char *cfgfile; - -/** - * Bank configuration data. - */ -static struct TALER_TESTING_BankConfiguration bc; - -/** - * Handle to the Py-bank daemon. - */ -static struct GNUNET_OS_Process *bankd; +static const char *cfgfile; /** - * Flag indicating whether the test is running against the - * Fakebank. Set up at runtime. + * Our credentials. */ -static int with_fakebank; +static struct TALER_TESTING_Credentials cred; /** - * Handles to the libeufin services. + * Which bank is the test running against? + * Set up at runtime. */ -static struct TALER_TESTING_LibeufinServices libeufin_services; +static enum TALER_TESTING_BankSystem bs; -/** - * Needed to shutdown differently. - */ -static int with_libeufin; /** * Main function that will tell the interpreter what commands to @@ -81,20 +67,39 @@ run (void *cls, struct TALER_TESTING_Interpreter *is) { struct TALER_WireTransferIdentifierRawP wtid; + const char *ssoptions; (void) cls; - memset (&wtid, 42, sizeof (wtid)); + switch (bs) + { + case TALER_TESTING_BS_FAKEBANK: + ssoptions = "-f"; + break; + case TALER_TESTING_BS_IBAN: + ssoptions = "-b"; + break; + default: + ssoptions = NULL; + break; + } + memset (&wtid, + 42, + sizeof (wtid)); { struct TALER_TESTING_Command commands[] = { + TALER_TESTING_cmd_system_start ("start-taler", + cfgfile, + ssoptions, + NULL), TALER_TESTING_cmd_bank_credits ("history-0", - &bc.exchange_auth, + &cred.ba, NULL, 1), TALER_TESTING_cmd_admin_add_incoming ("credit-1", - "KUDOS:5.01", - &bc.exchange_auth, - bc.user42_payto), + "EUR:5.01", + &cred.ba_admin, + cred.user42_payto), /** * This CMD doesn't care about the HTTP response code; that's * because Fakebank and euFin behaves differently when a reserve @@ -102,41 +107,36 @@ run (void *cls, * with 200 but it bounces the payment back to the customer. */ TALER_TESTING_cmd_admin_add_incoming_with_ref ("credit-1-fail", - "KUDOS:2.01", - &bc.exchange_auth, - bc.user42_payto, + "EUR:2.01", + &cred.ba_admin, + cred.user42_payto, "credit-1", -1), - TALER_TESTING_cmd_sleep ("Waiting 4s for 'credit-1' to settle", - 4), /** * Check that the incoming payment with a duplicate * reserve public key didn't make it to the exchange. */ TALER_TESTING_cmd_bank_credits ("history-1c", - &bc.exchange_auth, + &cred.ba, NULL, 5), TALER_TESTING_cmd_bank_debits ("history-1d", - &bc.exchange_auth, + &cred.ba, NULL, 5), TALER_TESTING_cmd_admin_add_incoming ("credit-2", - "KUDOS:3.21", - &bc.exchange_auth, - bc.user42_payto), + "EUR:3.21", + &cred.ba_admin, + cred.user42_payto), TALER_TESTING_cmd_transfer ("debit-1", - "KUDOS:3.22", - &bc.exchange_auth, - bc.exchange_payto, - bc.user42_payto, + "EUR:3.22", + &cred.ba, + cred.exchange_payto, + cred.user42_payto, &wtid, "http://exchange.example.com/"), - - TALER_TESTING_cmd_sleep ("Waiting 5s for 'debit-1' to settle", - 5), TALER_TESTING_cmd_bank_debits ("history-2b", - &bc.exchange_auth, + &cred.ba, NULL, 5), TALER_TESTING_cmd_end () @@ -144,151 +144,53 @@ run (void *cls, GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Bank serves at `%s'\n", - bc.exchange_auth.wire_gateway_url); - if (GNUNET_YES == with_fakebank) - TALER_TESTING_run_with_fakebank (is, - commands, - bc.exchange_auth.wire_gateway_url); - else - TALER_TESTING_run (is, - commands); + cred.ba.wire_gateway_url); + TALER_TESTING_run (is, + commands); } } -/** - * Runs #TALER_TESTING_setup() using the configuration. - * - * @param cls unused - * @param cfg configuration to use - * @return status code - */ -static int -setup_with_cfg (void *cls, - const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - (void) cls; - return TALER_TESTING_setup (&run, - NULL, - cfg, - NULL, - GNUNET_NO); -} - - int main (int argc, char *const *argv) { - int rv; - (void) argc; - (void) argv; - /* These environment variables get in the way... */ - unsetenv ("XDG_DATA_HOME"); - unsetenv ("XDG_CONFIG_HOME"); - GNUNET_log_setup ("test-bank-api", - "DEBUG", - NULL); - - with_fakebank = TALER_TESTING_has_in_name (argv[0], - "_with_fakebank"); - if (GNUNET_YES == with_fakebank) + if (TALER_TESTING_has_in_name (argv[0], + "_with_fakebank")) { - TALER_LOG_DEBUG ("Running against the Fakebank.\n"); + bs = TALER_TESTING_BS_FAKEBANK; cfgfile = CONFIG_FILE_FAKEBANK; - if (GNUNET_OK != - TALER_TESTING_prepare_fakebank (CONFIG_FILE_FAKEBANK, - "exchange-account-2", - &bc)) - { - GNUNET_break (0); - return 77; - } - } - else if (GNUNET_YES == TALER_TESTING_has_in_name (argv[0], - "_with_pybank")) - { - TALER_LOG_DEBUG ("Running against the Pybank.\n"); - cfgfile = CONFIG_FILE_PYBANK; - if (GNUNET_OK != - TALER_TESTING_prepare_bank (CONFIG_FILE_PYBANK, - GNUNET_YES, - "exchange-account-2", - &bc)) - { - GNUNET_break (0); - return 77; - } - - if (NULL == (bankd = TALER_TESTING_run_bank ( - CONFIG_FILE_PYBANK, - bc.exchange_auth.wire_gateway_url))) - { - GNUNET_break (0); - return 77; - } } - else if (GNUNET_YES == TALER_TESTING_has_in_name (argv[0], - "_with_nexus")) + else if (TALER_TESTING_has_in_name (argv[0], + "_with_nexus")) { - TALER_LOG_DEBUG ("Running with Nexus.\n"); - with_libeufin = GNUNET_YES; + bs = TALER_TESTING_BS_IBAN; cfgfile = CONFIG_FILE_NEXUS; - if (GNUNET_OK != - TALER_TESTING_prepare_nexus (CONFIG_FILE_NEXUS, - GNUNET_YES, - "exchange-account-2", - &bc)) + if (GNUNET_SYSERR == + GNUNET_OS_check_helper_binary ("libeufin-bank", + false, + NULL)) { - GNUNET_break (0); + fprintf (stderr, + "libeufin-bank not found. Skipping test.\n"); return 77; } - libeufin_services = TALER_TESTING_run_libeufin (&bc); - if ( (NULL == libeufin_services.nexus) || - (NULL == libeufin_services.sandbox) ) - return 77; } else { - /* no bank service was ever invoked. */ + /* no bank service was specified. */ + GNUNET_break (0); return 77; } - - if (GNUNET_OK != - GNUNET_CONFIGURATION_parse_and_run (cfgfile, - &setup_with_cfg, - NULL)) - rv = 1; - else - rv = 0; - - if (GNUNET_NO == with_fakebank) - { - // -> pybank - if (GNUNET_NO == with_libeufin) - { - - GNUNET_OS_process_kill (bankd, - SIGKILL); - GNUNET_OS_process_wait (bankd); - GNUNET_OS_process_destroy (bankd); - } - else // -> libeufin - { - GNUNET_OS_process_kill (libeufin_services.nexus, - SIGKILL); - GNUNET_OS_process_wait (libeufin_services.nexus); - GNUNET_OS_process_destroy (libeufin_services.nexus); - - GNUNET_OS_process_kill (libeufin_services.sandbox, - SIGKILL); - GNUNET_OS_process_wait (libeufin_services.sandbox); - GNUNET_OS_process_destroy (libeufin_services.sandbox); - } - } - - return rv; + return TALER_TESTING_main (argv, + "INFO", + cfgfile, + "exchange-account-2", + bs, + &cred, + &run, + NULL); } diff --git a/src/testing/test_bank_api.conf b/src/testing/test_bank_api.conf new file mode 100644 index 000000000..c262ae197 --- /dev/null +++ b/src/testing/test_bank_api.conf @@ -0,0 +1,23 @@ +# This file is in the public domain + +[PATHS] +TALER_TEST_HOME = test_exchange_api_home/ + +[taler] +currency = EUR + +[bank] +SERVE = http +HTTP_PORT = 8082 + +[libeufin-bank] +CURRENCY = EUR +WIRE_TYPE = iban +IBAN_PAYTO_BIC = SANDBOXX= +DEFAULT_CUSTOMER_DEBT_LIMIT = EUR:200 +DEFAULT_ADMIN_DEBT_LIMIT = EUR:2000 +REGISTRATION_BONUS_ENABLED = yes +REGISTRATION_BONUS = EUR:100 +SUGGESTED_WITHDRAWAL_EXCHANGE = http://localhost:8081/ +SERVE = tcp +PORT = 8082 diff --git a/src/testing/test_bank_api_fakebank.conf b/src/testing/test_bank_api_fakebank.conf index 1e5a4d18e..62fa4cd4c 100644 --- a/src/testing/test_bank_api_fakebank.conf +++ b/src/testing/test_bank_api_fakebank.conf @@ -1,21 +1,21 @@ # This file is in the public domain. +@INLINE@ test_bank_api.conf -[taler] -currency = KUDOS +[exchange-account-1] +PAYTO_URI = "payto://x-taler-bank/localhost:8082/1?receiver-name=1" [exchange-account-2] -PAYTO_URI = "payto://x-taler-bank/localhost/2?receiver-name=2" +PAYTO_URI = "payto://x-taler-bank/localhost:8082/2?receiver-name=2" [exchange-accountcredentials-2] -WIRE_GATEWAY_URL = "http://localhost:8081/2/" +WIRE_GATEWAY_URL = "http://localhost:8082/accounts/2/taler-wire-gateway/" WIRE_GATEWAY_AUTH_METHOD = basic USERNAME = Exchange PASSWORD = x -[bank] -SERVE = http -HTTP_PORT = 8081 -DATABASE = postgres:///talercheck - -[auditor] -BASE_URL = "http://localhost:8083/" +[admin-accountcredentials-2] +WIRE_GATEWAY_URL = "http://localhost:8082/accounts/2/taler-wire-gateway/" +WIRE_GATEWAY_AUTH_METHOD = basic +# For now, fakebank still checks against the Exchange account... +USERNAME = Exchange +PASSWORD = x diff --git a/src/testing/test_bank_api_fakebank_twisted.conf b/src/testing/test_bank_api_fakebank_twisted.conf index 6d316c141..bc66c0d88 100644 --- a/src/testing/test_bank_api_fakebank_twisted.conf +++ b/src/testing/test_bank_api_fakebank_twisted.conf @@ -1,12 +1,15 @@ +# This file is in the public domain. + +@INLINE@ test_bank_api_fakebank.conf [twister] + # HTTP listen port for twister HTTP_PORT = 8888 SERVE = tcp - # HTTP Destination for twister. The test-Webserver needs # to listen on the port used here. Note: no trailing '/'! -DESTINATION_BASE_URL = "http://localhost:8081" +DESTINATION_BASE_URL = "http://localhost:8082" # Control port for TCP # PORT = 8889 @@ -18,20 +21,3 @@ ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/taler-service-twister.sock UNIX_MATCH_UID = NO UNIX_MATCH_GID = YES - -[taler] -currency = KUDOS - -[bank] -serve = http -http_port = 8081 -database = postgres:///talercheck - -[exchange-account-1] -PAYTO_URI = "payto://x-taler-bank/localhost:8081/1?receiver-name=1" - -[exchange-account-2] -PAYTO_URI = "payto://x-taler-bank/localhost:8081/2?receiver-name=2" - -[auditor] -BASE_URL = "http://localhost:8083/" diff --git a/src/testing/test_bank_api_nexus.conf b/src/testing/test_bank_api_nexus.conf index 016399d5e..605c7b00e 100644 --- a/src/testing/test_bank_api_nexus.conf +++ b/src/testing/test_bank_api_nexus.conf @@ -1,21 +1,35 @@ # This file is in the public domain. - -[taler] -currency = TESTKUDOS +@INLINE@ test_bank_api.conf [exchange-account-2] PAYTO_URI = payto://iban/BIC/ES9121000418450200051332?receiver-name=Exchange [exchange-accountcredentials-2] -WIRE_GATEWAY_URL = http://localhost:5001/facades/my-facade/taler-wire-gateway/ +WIRE_GATEWAY_URL = http://localhost:8082/accounts/exchange/taler-wire-gateway/ WIRE_GATEWAY_AUTH_METHOD = basic USERNAME = exchange PASSWORD = x -[bank] -# not (!) used by the nexus, only by the helper -# check to make sure the port is free for Nexus. -HTTP_PORT = 5001 +[admin-accountcredentials-2] +WIRE_GATEWAY_URL = http://localhost:8082/accounts/exchange/taler-wire-gateway/ +WIRE_GATEWAY_AUTH_METHOD = basic +USERNAME = admin +# 'secret' is from taler-unified-setup.sh +PASSWORD = secret + +[libeufin-bankdb-postgres] +CONFIG="postgresql:///talercheck" -[auditor] -BASE_URL = "http://localhost:8083/" +# libeufin doesn't search our config.d/currencies.conf +# as it has a different resource path. Thus replicated +# here. +[currency-euro] +ENABLED = YES +name = "Euro" +code = "EUR" +decimal_separator = "," +fractional_input_digits = 2 +fractional_normal_digits = 2 +fractional_trailing_zero_digits = 2 +is_currency_name_leading = NO +alt_unit_names = {"0":"€"} diff --git a/src/testing/test_bank_api_twisted.c b/src/testing/test_bank_api_twisted.c index c550aaeb2..038ec8a1f 100644 --- a/src/testing/test_bank_api_twisted.c +++ b/src/testing/test_bank_api_twisted.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014-2018 Taler Systems SA + Copyright (C) 2014-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 @@ -17,7 +17,7 @@ <http://www.gnu.org/licenses/> */ /** - * @file testing/test_bank_api_with_fakebank_twisted.c + * @file testing/test_bank_api_twisted.c * @author Marcello Stanisci * @author Sree Harsha Totakura <sreeharsha@totakura.in> * @author Christian Grothoff @@ -42,19 +42,20 @@ #define CONFIG_FILE_FAKEBANK "test_bank_api_fakebank_twisted.conf" /** - * Separate config file for running with the pybank. + * Configuration file we use. */ -#define CONFIG_FILE_PYBANK "test_bank_api_pybank_twisted.conf" +static const char *cfgfile; /** - * True when the test runs against Fakebank. + * Our credentials. */ -static int with_fakebank; +static struct TALER_TESTING_Credentials cred; /** - * Bank configuration data. + * Which bank is the test running against? + * Set up at runtime. */ -static struct TALER_TESTING_BankConfiguration bc; +static enum TALER_TESTING_BankSystem bs; /** * (real) Twister URL. Used at startup time to check if it runs. @@ -66,11 +67,6 @@ static char *twister_url; */ static struct GNUNET_OS_Process *twisterd; -/** - * Python bank process handle. - */ -static struct GNUNET_OS_Process *bankd; - /** * Main function that will tell @@ -83,176 +79,118 @@ run (void *cls, struct TALER_TESTING_Interpreter *is) { struct TALER_WireTransferIdentifierRawP wtid; - /* Route our commands through twister. */ + /* Authentication data to route our commands through twister. */ struct TALER_BANK_AuthenticationData exchange_auth_twisted; + const char *systype = NULL; (void) cls; memset (&wtid, 0x5a, sizeof (wtid)); - memcpy (&exchange_auth_twisted, - &bc.exchange_auth, - sizeof (struct TALER_BANK_AuthenticationData)); - if (with_fakebank) - exchange_auth_twisted.wire_gateway_url = - "http://localhost:8888/2/"; - else - exchange_auth_twisted.wire_gateway_url = - "http://localhost:8888/taler-wire-gateway/Exchange/"; + GNUNET_memcpy (&exchange_auth_twisted, + &cred.ba, + sizeof (struct TALER_BANK_AuthenticationData)); + switch (bs) + { + case TALER_TESTING_BS_FAKEBANK: + exchange_auth_twisted.wire_gateway_url + = "http://localhost:8888/accounts/2/taler-wire-gateway/"; + systype = "-f"; + break; + case TALER_TESTING_BS_IBAN: + exchange_auth_twisted.wire_gateway_url + = "http://localhost:8888/accounts/Exchange/taler-wire-gateway/"; + systype = "-b"; + break; + } + GNUNET_assert (NULL != systype); - struct TALER_TESTING_Command commands[] = { - /* Test retrying transfer after failure. */ - TALER_TESTING_cmd_malform_response ("malform-transfer", - CONFIG_FILE_FAKEBANK), - TALER_TESTING_cmd_transfer_retry ( - TALER_TESTING_cmd_transfer ("debit-1", - "KUDOS:3.22", - &exchange_auth_twisted, - bc.exchange_payto, - bc.user42_payto, - &wtid, - "http://exchange.example.com/")), - TALER_TESTING_cmd_end () - }; + { + struct TALER_TESTING_Command commands[] = { + TALER_TESTING_cmd_system_start ("start-taler", + cfgfile, + systype, + NULL), + /* Test retrying transfer after failure. */ + TALER_TESTING_cmd_malform_response ("malform-transfer", + cfgfile), + TALER_TESTING_cmd_transfer_retry ( + TALER_TESTING_cmd_transfer ("debit-1", + "EUR:3.22", + &exchange_auth_twisted, + cred.exchange_payto, + cred.user42_payto, + &wtid, + "http://exchange.example.com/")), + TALER_TESTING_cmd_end () + }; - if (GNUNET_YES == with_fakebank) - TALER_TESTING_run_with_fakebank (is, - commands, - bc.exchange_auth.wire_gateway_url); - else TALER_TESTING_run (is, commands); + } } /** * Kill, wait, and destroy convenience function. * - * @param process process to purge. + * @param[in] process process to purge. */ static void purge_process (struct GNUNET_OS_Process *process) { - GNUNET_OS_process_kill (process, SIGINT); + GNUNET_OS_process_kill (process, + SIGINT); GNUNET_OS_process_wait (process); GNUNET_OS_process_destroy (process); } -/** - * Runs #TALER_TESTING_setup() using the configuration. - * - * @param cls unused - * @param cfg configuration to use - * @return status code - */ -static int -setup_with_cfg (void *cls, - const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - (void) cls; - return TALER_TESTING_setup (&run, - NULL, - cfg, - NULL, - GNUNET_NO); -} - - int main (int argc, char *const *argv) { int ret; - const char *cfgfilename; (void) argc; - /* These environment variables get in the way... */ - unsetenv ("XDG_DATA_HOME"); - unsetenv ("XDG_CONFIG_HOME"); - GNUNET_log_setup ("test-bank-api-with-(fake)bank-twisted", - "DEBUG", - NULL); - - with_fakebank = TALER_TESTING_has_in_name (argv[0], - "_with_fakebank"); - - if (with_fakebank) - cfgfilename = CONFIG_FILE_FAKEBANK; - else - cfgfilename = CONFIG_FILE_PYBANK; - - if (NULL == (twister_url = TALER_TWISTER_prepare_twister ( - cfgfilename))) + if (TALER_TESTING_has_in_name (argv[0], + "_with_fakebank")) { - GNUNET_break (0); - return 77; + bs = TALER_TESTING_BS_FAKEBANK; + cfgfile = CONFIG_FILE_FAKEBANK; } - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "twister_url is %s\n", - twister_url); - if (NULL == (twisterd = TALER_TWISTER_run_twister (cfgfilename))) + else if (TALER_TESTING_has_in_name (argv[0], + "_with_nexus")) { - GNUNET_break (0); - GNUNET_free (twister_url); - return 77; - } - if (GNUNET_YES == with_fakebank) - { - TALER_LOG_DEBUG ("Running against the Fakebank.\n"); - if (GNUNET_OK != - TALER_TESTING_prepare_fakebank (cfgfilename, - "exchange-account-2", - &bc)) - { - GNUNET_break (0); - GNUNET_free (twister_url); - return 77; - } + GNUNET_assert (0); /* FIXME: test with nexus not yet implemented */ + bs = TALER_TESTING_BS_IBAN; + /* cfgfile = CONFIG_FILE_NEXUS; */ } else { - TALER_LOG_DEBUG ("Running against the Pybank.\n"); - if (GNUNET_OK != - TALER_TESTING_prepare_bank (cfgfilename, - GNUNET_YES, - "exchange-account-2", - &bc)) - { - GNUNET_break (0); - GNUNET_free (twister_url); - return 77; - } - - if (NULL == (bankd = TALER_TESTING_run_bank ( - cfgfilename, - bc.exchange_auth.wire_gateway_url))) - { - GNUNET_break (0); - GNUNET_free (twister_url); - return 77; - } + /* no bank service was specified. */ + GNUNET_break (0); + return 77; } - sleep (5); - ret = GNUNET_CONFIGURATION_parse_and_run (cfgfilename, - &setup_with_cfg, - NULL); + /* FIXME: introduce commands for twister! */ + twister_url = TALER_TWISTER_prepare_twister (cfgfile); + if (NULL == twister_url) + return 77; + twisterd = TALER_TWISTER_run_twister (cfgfile); + if (NULL == twisterd) + return 77; + ret = TALER_TESTING_main (argv, + "INFO", + cfgfile, + "exchange-account-2", + bs, + &cred, + &run, + NULL); purge_process (twisterd); - - if (GNUNET_NO == with_fakebank) - { - GNUNET_OS_process_kill (bankd, - SIGKILL); - GNUNET_OS_process_wait (bankd); - GNUNET_OS_process_destroy (bankd); - } - GNUNET_free (twister_url); - if (GNUNET_OK == ret) - return 0; - - return 1; + return ret; } diff --git a/src/testing/test_exchange_api-cs.conf b/src/testing/test_exchange_api-cs.conf index 9485a724d..b80696fb2 100644 --- a/src/testing/test_exchange_api-cs.conf +++ b/src/testing/test_exchange_api-cs.conf @@ -1,209 +1,4 @@ # This file is in the public domain. # - -[PATHS] -# Persistent data storage for the testcase -TALER_TEST_HOME = test_exchange_api_home/ -TALER_RUNTIME_DIR = ${TMPDIR:-${TMP:-/tmp}}/${USER:-}/taler-system-runtime/ - -[taler-exchange-secmod-rsa] -# Reduce from 1 year to speed up test -LOOKAHEAD_SIGN = 24 days - -[taler-exchange-secmod-eddsa] -# Reduce from 1 year to speed up test -LOOKAHEAD_SIGN = 24 days -# Reduce from 12 weeks to ensure we have multiple -DURATION = 14 days - -[taler] -# Currency supported by the exchange (can only be one) -CURRENCY = EUR -CURRENCY_ROUND_UNIT = EUR:0.01 - -[auditor] -BASE_URL = "http://localhost:8083/" - -# HTTP port the auditor listens to -PORT = 8083 - -[exchange] - -TERMS_ETAG = 0 -PRIVACY_ETAG = 0 - -# HTTP port the exchange listens to -PORT = 8081 - -# Master public key used to sign the exchange's various keys -MASTER_PUBLIC_KEY = 98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG - -# How to access our database -DB = postgres - -# Base URL of the exchange. Must be set to a URL where the -# exchange (or the twister) is actually listening. -BASE_URL = "http://localhost:8081/" - -# How big is an individual shard to be processed -# by taler-exchange-expire (in time). It may take -# this much time for an expired purse to be really -# cleaned up and the coins refunded. -EXPIRE_SHARD_SIZE = 300 ms - -EXPIRE_IDLE_SLEEP_INTERVAL = 1 s - -[exchangedb-postgres] -CONFIG = "postgres:///talercheck" - -[auditordb-postgres] -CONFIG = "postgres:///talercheck" - -# Sections starting with "exchange-account-" configure the bank accounts -# of the exchange. The "URL" specifies the account in -# payto://-format. -[exchange-account-1] -# What is the URL of our account? -PAYTO_URI = "payto://x-taler-bank/localhost/42?receiver-name=42" -# ENABLE_CREDIT = YES - -[exchange-accountcredentials-1] -WIRE_GATEWAY_URL = "http://localhost:9081/42/" - -[exchange-account-2] -# What is the bank account (with the "Taler Bank" demo system)? -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:9081/2/" - -[bank] -HTTP_PORT = 9081 - -# Enabled extensions -[exchange-extension-age_restriction] -ENABLED = YES -# default age groups: -#AGE_GROUPS = "8:10:12:14:16:18:21" - -# Sections starting with "coin_" specify which denominations -# the exchange should support (and their respective fee structure) -[coin_eur_ct_1] -value = EUR:0.01 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.00 -fee_deposit = EUR:0.00 -fee_refresh = EUR:0.01 -fee_refund = EUR:0.01 -CIPHER = CS - -[coin_eur_ct_10] -value = EUR:0.10 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.01 -fee_deposit = EUR:0.01 -fee_refresh = EUR:0.03 -fee_refund = EUR:0.01 -CIPHER = CS - -[coin_eur_1] -value = EUR:1 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.01 -fee_deposit = EUR:0.01 -fee_refresh = EUR:0.03 -fee_refund = EUR:0.01 -CIPHER = CS - -[coin_eur_5] -value = EUR:5 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.01 -fee_deposit = EUR:0.01 -fee_refresh = EUR:0.03 -fee_refund = EUR:0.01 -CIPHER = CS - -[coin_eur_10] -value = EUR:10 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.01 -fee_deposit = EUR:0.01 -fee_refresh = EUR:0.03 -fee_refund = EUR:0.01 -CIPHER = CS - -[coin_eur_ct_1_age_restricted] -value = EUR:0.01 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.00 -fee_deposit = EUR:0.00 -fee_refresh = EUR:0.01 -fee_refund = EUR:0.01 -age_restricted = YES -CIPHER = CS - -[coin_eur_ct_10_age_restricted] -value = EUR:0.10 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.01 -fee_deposit = EUR:0.01 -fee_refresh = EUR:0.03 -fee_refund = EUR:0.01 -age_restricted = YES -CIPHER = CS - -[coin_eur_1_age_restricted] -value = EUR:1 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.01 -fee_deposit = EUR:0.01 -fee_refresh = EUR:0.03 -fee_refund = EUR:0.01 -age_restricted = YES -CIPHER = CS - -[coin_eur_5_age_restricted] -value = EUR:5 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.01 -fee_deposit = EUR:0.01 -fee_refresh = EUR:0.03 -fee_refund = EUR:0.01 -age_restricted = YES -CIPHER = CS - -[coin_eur_10_age_restricted] -value = EUR:10 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.01 -fee_deposit = EUR:0.01 -fee_refresh = EUR:0.03 -fee_refund = EUR:0.01 -age_restricted = YES -CIPHER = CS +@INLINE@ coins-cs.conf +@INLINE@ test_exchange_api.conf diff --git a/src/testing/test_exchange_api-rsa.conf b/src/testing/test_exchange_api-rsa.conf index bd27d560f..351c876d9 100644 --- a/src/testing/test_exchange_api-rsa.conf +++ b/src/testing/test_exchange_api-rsa.conf @@ -1,220 +1,4 @@ # This file is in the public domain. # - -[PATHS] -# Persistent data storage for the testcase -TALER_TEST_HOME = test_exchange_api_home/ -TALER_RUNTIME_DIR = ${TMPDIR:-${TMP:-/tmp}}/${USER:-}/taler-system-runtime/ - -[taler-exchange-secmod-rsa] -# Reduce from 1 year to speed up test -LOOKAHEAD_SIGN = 24 days - -[taler-exchange-secmod-eddsa] -# Reduce from 1 year to speed up test -LOOKAHEAD_SIGN = 24 days -# Reduce from 12 weeks to ensure we have multiple -DURATION = 14 days - -[taler] -# Currency supported by the exchange (can only be one) -CURRENCY = EUR -CURRENCY_ROUND_UNIT = EUR:0.01 - -[auditor] -BASE_URL = "http://localhost:8083/" - -# HTTP port the auditor listens to -PORT = 8083 - -[exchange] - -TERMS_ETAG = 0 -PRIVACY_ETAG = 0 - -# HTTP port the exchange listens to -PORT = 8081 - -# Master public key used to sign the exchange's various keys -MASTER_PUBLIC_KEY = 98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG - -# How to access our database -DB = postgres - -# Base URL of the exchange. Must be set to a URL where the -# exchange (or the twister) is actually listening. -BASE_URL = "http://localhost:8081/" - -# How big is an individual shard to be processed -# by taler-exchange-expire (in time). It may take -# this much time for an expired purse to be really -# cleaned up and the coins refunded. -EXPIRE_SHARD_SIZE = 300 ms - -EXPIRE_IDLE_SLEEP_INTERVAL = 1 s - - -[exchangedb-postgres] -CONFIG = "postgres:///talercheck" - -[auditordb-postgres] -CONFIG = "postgres:///talercheck" - -# Sections starting with "exchange-account-" configure the bank accounts -# of the exchange. The "URL" specifies the account in -# payto://-format. -[exchange-account-1] -# What is the URL of our account? -PAYTO_URI = "payto://x-taler-bank/localhost/42?receiver-name=42" -# ENABLE_CREDIT = YES - -[exchange-accountcredentials-1] -WIRE_GATEWAY_URL = "http://localhost:9081/42/" - -[exchange-account-2] -# What is the bank account (with the "Taler Bank" demo system)? -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:9081/2/" - -[bank] -HTTP_PORT = 9081 - -# Enabled extensions -[exchange-extension-age_restriction] -ENABLED = YES -# default age groups: -#AGE_GROUPS = "8:10:12:14:16:18:21" - -# Sections starting with "coin_" specify which denominations -# the exchange should support (and their respective fee structure) -[coin_eur_ct_1] -value = EUR:0.01 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.00 -fee_deposit = EUR:0.00 -fee_refresh = EUR:0.01 -fee_refund = EUR:0.01 -CIPHER = RSA -rsa_keysize = 1024 - -[coin_eur_ct_10] -value = EUR:0.10 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.01 -fee_deposit = EUR:0.01 -fee_refresh = EUR:0.03 -fee_refund = EUR:0.01 -CIPHER = RSA -rsa_keysize = 1024 - -[coin_eur_1] -value = EUR:1 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.01 -fee_deposit = EUR:0.01 -fee_refresh = EUR:0.03 -fee_refund = EUR:0.01 -CIPHER = RSA -rsa_keysize = 1024 - -[coin_eur_5] -value = EUR:5 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.01 -fee_deposit = EUR:0.01 -fee_refresh = EUR:0.03 -fee_refund = EUR:0.01 -CIPHER = RSA -rsa_keysize = 1024 - -[coin_eur_10] -value = EUR:10 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.01 -fee_deposit = EUR:0.01 -fee_refresh = EUR:0.03 -fee_refund = EUR:0.01 -CIPHER = RSA -rsa_keysize = 1024 - -[coin_eur_ct_1_age_restricted] -value = EUR:0.01 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.00 -fee_deposit = EUR:0.00 -fee_refresh = EUR:0.01 -fee_refund = EUR:0.01 -rsa_keysize = 1024 -age_restricted = YES -CIPHER = RSA - -[coin_eur_ct_10_age_restricted] -value = EUR:0.10 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.01 -fee_deposit = EUR:0.01 -fee_refresh = EUR:0.03 -fee_refund = EUR:0.01 -rsa_keysize = 1024 -age_restricted = YES -CIPHER = RSA - -[coin_eur_1_age_restricted] -value = EUR:1 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.01 -fee_deposit = EUR:0.01 -fee_refresh = EUR:0.03 -fee_refund = EUR:0.01 -rsa_keysize = 1024 -age_restricted = YES -CIPHER = RSA - -[coin_eur_5_age_restricted] -value = EUR:5 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.01 -fee_deposit = EUR:0.01 -fee_refresh = EUR:0.03 -fee_refund = EUR:0.01 -rsa_keysize = 1024 -age_restricted = YES -CIPHER = RSA - -[coin_eur_10_age_restricted] -value = EUR:10 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.01 -fee_deposit = EUR:0.01 -fee_refresh = EUR:0.03 -fee_refund = EUR:0.01 -rsa_keysize = 1024 -age_restricted = YES -CIPHER = RSA +@INLINE@ coins-rsa.conf +@INLINE@ test_exchange_api.conf
\ No newline at end of file diff --git a/src/testing/test_exchange_api-twisted.conf b/src/testing/test_exchange_api-twisted.conf new file mode 100644 index 000000000..536d36ee4 --- /dev/null +++ b/src/testing/test_exchange_api-twisted.conf @@ -0,0 +1,29 @@ +# This file is in the public domain. + +[exchange] +# Base URL of the exchange ('S PROXY). This URL is where the +# twister listens at, so that it will be able to get all the +# connection addressed to the exchange. In fact, the presence +# of the twister is 100% transparent to the test case, as it +# only seeks the exchange/BASE_URL URL to connect to the exchange. +BASE_URL = "http://localhost:8888/" + +[twister] +# HTTP listen port for twister +HTTP_PORT = 8888 +SERVE = tcp + +# HTTP Destination for twister. The test-Webserver needs +# to listen on the port used here. Note: no trailing '/'! +DESTINATION_BASE_URL = "http://localhost:8081" + +# Control port for TCP +# PORT = 8889 +HOSTNAME = localhost +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; + +# Control port for UNIX +UNIXPATH = /tmp/taler-service-twister.sock +UNIX_MATCH_UID = NO +UNIX_MATCH_GID = YES diff --git a/src/testing/test_exchange_api.c b/src/testing/test_exchange_api.c index f30701c34..caeec1e76 100644 --- a/src/testing/test_exchange_api.c +++ b/src/testing/test_exchange_api.c @@ -49,18 +49,13 @@ static char *config_file; static char *config_file_expire_reserve_now; /** - * Exchange configuration data. + * Our credentials. */ -static struct TALER_TESTING_ExchangeConfiguration ec; - -/** - * Bank configuration data. - */ -static struct TALER_TESTING_BankConfiguration bc; +static struct TALER_TESTING_Credentials cred; /** * Some tests behave differently when using CS as we cannot - * re-use the coin private key for different denominations + * 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. @@ -74,7 +69,7 @@ static bool uses_cs; * @param label label to use for the command. */ #define CMD_EXEC_WIREWATCH(label) \ - TALER_TESTING_cmd_exec_wirewatch (label, config_file) + TALER_TESTING_cmd_exec_wirewatch2 (label, config_file, "exchange-account-2") /** * Execute the taler-exchange-aggregator, closer and transfer commands with @@ -97,8 +92,8 @@ static bool uses_cs; */ #define CMD_TRANSFER_TO_EXCHANGE(label,amount) \ TALER_TESTING_cmd_admin_add_incoming (label, amount, \ - &bc.exchange_auth, \ - bc.user42_payto) + &cred.ba, \ + cred.user42_payto) /** * Main function that will tell the interpreter what commands to @@ -112,21 +107,6 @@ run (void *cls, struct TALER_TESTING_Interpreter *is) { /** - * Checks made against /wire response. - */ - struct TALER_TESTING_Command wire[] = { - /** - * Check if 'x-taler-bank' wire method is offered - * by the exchange. - */ - TALER_TESTING_cmd_wire ("wire-taler-bank-1", - "x-taler-bank", - NULL, - MHD_HTTP_OK), - TALER_TESTING_cmd_end () - }; - - /** * Test withdrawal plus spending. */ struct TALER_TESTING_Command withdraw[] = { @@ -142,8 +122,8 @@ run (void *cls, MHD_HTTP_OK), TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-reserve-1", "EUR:6.02", - bc.user42_payto, - bc.exchange_payto, + cred.user42_payto, + cred.exchange_payto, "create-reserve-1"), /** * Make a reserve exist, according to the previous @@ -201,12 +181,17 @@ run (void *cls, TALER_TESTING_cmd_deposit ("deposit-simple", "withdraw-coin-1", 0, - bc.user42_payto, + cred.user42_payto, "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", GNUNET_TIME_UNIT_ZERO, "EUR:5", MHD_HTTP_OK), - TALER_TESTING_cmd_deposit_replay ("deposit-simple-replay", + TALER_TESTING_cmd_deposit_replay ("deposit-simple-replay-1", + "deposit-simple", + MHD_HTTP_OK), + TALER_TESTING_cmd_sleep ("sleep-before-deposit-replay", + 1), + TALER_TESTING_cmd_deposit_replay ("deposit-simple-replay-2", "deposit-simple", MHD_HTTP_OK), /* This creates a conflict, as we have the same coin public key (reuse!), @@ -219,7 +204,7 @@ run (void *cls, TALER_TESTING_cmd_deposit ("deposit-reused-coin-key-failure", "withdraw-coin-1x", 0, - bc.user42_payto, + cred.user42_payto, "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", GNUNET_TIME_UNIT_ZERO, "EUR:1", @@ -232,7 +217,7 @@ run (void *cls, TALER_TESTING_cmd_deposit ("deposit-double-1", "withdraw-coin-1", 0, - bc.user43_payto, + cred.user43_payto, "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", GNUNET_TIME_UNIT_ZERO, "EUR:5", @@ -246,7 +231,7 @@ run (void *cls, TALER_TESTING_cmd_deposit ("deposit-double-1", "withdraw-coin-1", 0, - bc.user43_payto, + cred.user43_payto, "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", GNUNET_TIME_UNIT_ZERO, "EUR:5", @@ -257,7 +242,7 @@ run (void *cls, TALER_TESTING_cmd_deposit ("deposit-double-2", "withdraw-coin-1", 0, - bc.user43_payto, + cred.user43_payto, "{\"items\":[{\"name\":\"ice cream\",\"value\":2}]}", GNUNET_TIME_UNIT_ZERO, "EUR:5", @@ -282,8 +267,8 @@ run (void *cls, "EUR:5.01"), TALER_TESTING_cmd_check_bank_admin_transfer ("ck-refresh-create-reserve-1", "EUR:5.01", - bc.user42_payto, - bc.exchange_payto, + cred.user42_payto, + cred.exchange_payto, "refresh-create-reserve-1"), /** * Make previous command effective. @@ -304,7 +289,7 @@ run (void *cls, TALER_TESTING_cmd_deposit ("refresh-deposit-partial", "refresh-withdraw-coin-1", 0, - bc.user42_payto, + cred.user42_payto, "{\"items\":[{\"name\":\"ice cream\",\"value\":\"EUR:1\"}]}", GNUNET_TIME_UNIT_ZERO, "EUR:1", @@ -341,7 +326,7 @@ run (void *cls, TALER_TESTING_cmd_deposit ("refresh-deposit-refreshed-1a", "refresh-reveal-1-idempotency", 0, - bc.user42_payto, + cred.user42_payto, "{\"items\":[{\"name\":\"ice cream\",\"value\":3}]}", GNUNET_TIME_UNIT_ZERO, "EUR:1", @@ -352,7 +337,7 @@ run (void *cls, TALER_TESTING_cmd_deposit ("refresh-deposit-refreshed-1b", "refresh-reveal-1", 3, - bc.user43_payto, + cred.user43_payto, "{\"items\":[{\"name\":\"ice cream\",\"value\":3}]}", GNUNET_TIME_UNIT_ZERO, "EUR:0.1", @@ -390,8 +375,8 @@ run (void *cls, "EUR:6.01"), TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-reserve-age", "EUR:6.01", - bc.user42_payto, - bc.exchange_payto, + cred.user42_payto, + cred.exchange_payto, "create-reserve-age"), /** * Make a reserve exist, according to the previous @@ -417,7 +402,7 @@ run (void *cls, TALER_TESTING_cmd_deposit ("deposit-simple-age", "withdraw-coin-age-1", 0, - bc.user42_payto, + cred.user42_payto, "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", GNUNET_TIME_UNIT_ZERO, "EUR:4.99", @@ -425,6 +410,14 @@ run (void *cls, TALER_TESTING_cmd_deposit_replay ("deposit-simple-replay-age", "deposit-simple-age", MHD_HTTP_OK), + TALER_TESTING_cmd_deposit_replay ("deposit-simple-replay-age-1", + "deposit-simple-age", + MHD_HTTP_OK), + TALER_TESTING_cmd_sleep ("sleep-before-age-deposit-replay", + 1), + TALER_TESTING_cmd_deposit_replay ("deposit-simple-replay-age-2", + "deposit-simple-age", + MHD_HTTP_OK), TALER_TESTING_cmd_end () }; @@ -464,53 +457,53 @@ run (void *cls, * Check all the transfers took place. */ TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-499c", - ec.exchange_url, + cred.exchange_url, "EUR:4.98", - bc.exchange_payto, - bc.user42_payto), + cred.exchange_payto, + cred.user42_payto), TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-499c2", - ec.exchange_url, + cred.exchange_url, "EUR:4.97", - bc.exchange_payto, - bc.user42_payto), + cred.exchange_payto, + cred.user42_payto), TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-99c1", - ec.exchange_url, + cred.exchange_url, "EUR:0.98", - bc.exchange_payto, - bc.user42_payto), + cred.exchange_payto, + cred.user42_payto), TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-99c2", - ec.exchange_url, + cred.exchange_url, "EUR:0.98", - bc.exchange_payto, - bc.user42_payto), + cred.exchange_payto, + cred.user42_payto), TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-99c3", - ec.exchange_url, + cred.exchange_url, "EUR:0.98", - bc.exchange_payto, - bc.user42_payto), + cred.exchange_payto, + cred.user42_payto), TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-99c4", - ec.exchange_url, + cred.exchange_url, "EUR:0.98", - bc.exchange_payto, - bc.user42_payto), + cred.exchange_payto, + cred.user42_payto), TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-08c", - ec.exchange_url, + cred.exchange_url, "EUR:0.08", - bc.exchange_payto, - bc.user43_payto), + cred.exchange_payto, + cred.user43_payto), TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-08c2", - ec.exchange_url, + cred.exchange_url, "EUR:0.08", - bc.exchange_payto, - bc.user43_payto), + cred.exchange_payto, + cred.user43_payto), /* In case of CS, one transaction above succeeded that failed for RSA, hence we need to check for an extra transfer here */ uses_cs ? TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-98c", - ec.exchange_url, + cred.exchange_url, "EUR:0.98", - bc.exchange_payto, - bc.user42_payto) + cred.exchange_payto, + cred.user42_payto) : TALER_TESTING_cmd_sleep ("dummy", 0), TALER_TESTING_cmd_check_bank_empty ("check_bank_empty"), @@ -544,8 +537,8 @@ run (void *cls, TALER_TESTING_cmd_check_bank_admin_transfer ( "check-create-reserve-unaggregated", "EUR:5.01", - bc.user42_payto, - bc.exchange_payto, + cred.user42_payto, + cred.exchange_payto, "create-reserve-unaggregated"), CMD_EXEC_WIREWATCH ("wirewatch-unaggregated"), TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-unaggregated", @@ -556,7 +549,7 @@ run (void *cls, TALER_TESTING_cmd_deposit ("deposit-unaggregated", "withdraw-coin-unaggregated", 0, - bc.user43_payto, + cred.user43_payto, "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", GNUNET_TIME_relative_multiply ( GNUNET_TIME_UNIT_YEARS, @@ -578,8 +571,8 @@ run (void *cls, TALER_TESTING_cmd_check_bank_admin_transfer ( "ck-refresh-create-reserve-age-1", "EUR:6.01", - bc.user42_payto, - bc.exchange_payto, + cred.user42_payto, + cred.exchange_payto, "refresh-create-reserve-age-1"), /** * Make previous command effective. @@ -600,7 +593,7 @@ run (void *cls, TALER_TESTING_cmd_deposit ("refresh-deposit-partial-age", "refresh-withdraw-coin-age-1", 0, - bc.user42_payto, + cred.user42_payto, "{\"items\":[{\"name\":\"ice cream\",\"value\":\"EUR:1\"}]}", GNUNET_TIME_UNIT_ZERO, "EUR:1", @@ -637,7 +630,7 @@ run (void *cls, TALER_TESTING_cmd_deposit ("refresh-deposit-refreshed-age-1a", "refresh-reveal-age-1-idempotency", 0, - bc.user42_payto, + cred.user42_payto, "{\"items\":[{\"name\":\"ice cream\",\"value\":3}]}", GNUNET_TIME_UNIT_ZERO, "EUR:1", @@ -648,7 +641,7 @@ run (void *cls, TALER_TESTING_cmd_deposit ("refresh-deposit-refreshed-age-1b", "refresh-reveal-age-1", 3, - bc.user43_payto, + cred.user43_payto, "{\"items\":[{\"name\":\"ice cream\",\"value\":3}]}", GNUNET_TIME_UNIT_ZERO, "EUR:0.1", @@ -665,7 +658,6 @@ run (void *cls, "refresh-reveal-age-1", MHD_HTTP_CONFLICT, NULL), - TALER_TESTING_cmd_end () }; @@ -680,8 +672,8 @@ run (void *cls, TALER_TESTING_cmd_check_bank_admin_transfer ( "check-create-reserve-aggtest", "EUR:5.01", - bc.user42_payto, - bc.exchange_payto, + cred.user42_payto, + cred.exchange_payto, "create-reserve-aggtest"), CMD_EXEC_WIREWATCH ("wirewatch-aggtest"), TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-aggtest", @@ -692,7 +684,7 @@ run (void *cls, TALER_TESTING_cmd_deposit ("deposit-aggtest-1", "withdraw-coin-aggtest", 0, - bc.user43_payto, + cred.user43_payto, "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", GNUNET_TIME_UNIT_ZERO, "EUR:2", @@ -700,7 +692,7 @@ run (void *cls, TALER_TESTING_cmd_deposit_with_ref ("deposit-aggtest-2", "withdraw-coin-aggtest", 0, - bc.user43_payto, + cred.user43_payto, "{\"items\":[{\"name\":\"foo bar\",\"value\":1}]}", GNUNET_TIME_UNIT_ZERO, "EUR:2", @@ -708,10 +700,10 @@ run (void *cls, "deposit-aggtest-1"), CMD_EXEC_AGGREGATOR ("aggregation-aggtest"), TALER_TESTING_cmd_check_bank_transfer ("check-bank-transfer-aggtest", - ec.exchange_url, + cred.exchange_url, "EUR:3.97", - bc.exchange_payto, - bc.user43_payto), + cred.exchange_payto, + cred.user43_payto), TALER_TESTING_cmd_check_bank_empty ("check-bank-empty-aggtest"), TALER_TESTING_cmd_end () }; @@ -725,8 +717,8 @@ run (void *cls, "EUR:5.01"), TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-reserve-r1", "EUR:5.01", - bc.user42_payto, - bc.exchange_payto, + cred.user42_payto, + cred.exchange_payto, "create-reserve-r1"), /** * Run wire-watch to trigger the reserve creation. @@ -745,7 +737,7 @@ run (void *cls, TALER_TESTING_cmd_deposit ("deposit-refund-1", "withdraw-coin-r1", 0, - bc.user42_payto, + cred.user42_payto, "{\"items\":[{\"name\":\"ice cream\",\"value\":\"EUR:5\"}]}", GNUNET_TIME_UNIT_MINUTES, "EUR:5", @@ -779,7 +771,7 @@ run (void *cls, TALER_TESTING_cmd_deposit ("deposit-refund-insufficient-refund", "withdraw-coin-r1", 0, - bc.user42_payto, + cred.user42_payto, "{\"items\":[{\"name\":\"ice cream\",\"value\":\"EUR:4\"}]}", GNUNET_TIME_UNIT_MINUTES, "EUR:4", @@ -796,7 +788,7 @@ run (void *cls, TALER_TESTING_cmd_deposit ("deposit-refund-2", "withdraw-coin-r1", 0, - bc.user42_payto, + cred.user42_payto, "{\"items\":[{\"name\":\"more ice cream\",\"value\":\"EUR:5\"}]}", GNUNET_TIME_UNIT_ZERO, "EUR:4.99", @@ -810,10 +802,10 @@ run (void *cls, * Check that deposit did run. */ TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-pre-refund", - ec.exchange_url, + cred.exchange_url, "EUR:4.97", - bc.exchange_payto, - bc.user42_payto), + cred.exchange_payto, + cred.user42_payto), /** * Run failing refund, as past deadline & aggregation. */ @@ -830,8 +822,8 @@ run (void *cls, "EUR:5.01"), TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-reserve-rb", "EUR:5.01", - bc.user42_payto, - bc.exchange_payto, + cred.user42_payto, + cred.exchange_payto, "create-reserve-rb"), CMD_EXEC_WIREWATCH ("wirewatch-rb"), TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-rb", @@ -842,7 +834,7 @@ run (void *cls, TALER_TESTING_cmd_deposit ("deposit-refund-1b", "withdraw-coin-rb", 0, - bc.user42_payto, + cred.user42_payto, "{\"items\":[{\"name\":\"ice cream\",\"value\":\"EUR:5\"}]}", GNUNET_TIME_UNIT_ZERO, "EUR:5", @@ -876,8 +868,8 @@ run (void *cls, TALER_TESTING_cmd_check_bank_admin_transfer ( "recoup-create-reserve-1-check", "EUR:15.02", - bc.user42_payto, - bc.exchange_payto, + cred.user42_payto, + cred.exchange_payto, "recoup-create-reserve-1"), /** * Run wire-watch to trigger the reserve creation. @@ -1006,11 +998,12 @@ run (void *cls, "EUR:5.01"), TALER_TESTING_cmd_check_bank_admin_transfer ("check-short-lived-reserve", "EUR:5.01", - bc.user42_payto, - bc.exchange_payto, + cred.user42_payto, + cred.exchange_payto, "short-lived-reserve"), - TALER_TESTING_cmd_exec_wirewatch ("short-lived-aggregation", - config_file_expire_reserve_now), + TALER_TESTING_cmd_exec_wirewatch2 ("short-lived-aggregation", + config_file_expire_reserve_now, + "exchange-account-2"), TALER_TESTING_cmd_exec_closer ("close-reserves", config_file_expire_reserve_now, "EUR:5", @@ -1029,10 +1022,10 @@ run (void *cls, 0, /* age restriction off */ MHD_HTTP_CONFLICT), TALER_TESTING_cmd_check_bank_transfer ("check_bank_short-lived_reimburse", - ec.exchange_url, + cred.exchange_url, "EUR:5", - bc.exchange_payto, - bc.user42_payto), + cred.exchange_payto, + cred.user42_payto), /* 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 @@ -1042,8 +1035,8 @@ run (void *cls, "EUR:2.02"), TALER_TESTING_cmd_check_bank_admin_transfer ("ck-recoup-create-reserve-2", "EUR:2.02", - bc.user42_payto, - bc.exchange_payto, + cred.user42_payto, + cred.exchange_payto, "recoup-create-reserve-2"), /* Make previous command effective. */ CMD_EXEC_WIREWATCH ("wirewatch-5"), @@ -1062,7 +1055,7 @@ run (void *cls, TALER_TESTING_cmd_deposit ("recoup-deposit-partial", "recoup-withdraw-coin-2a", 0, - bc.user42_payto, + cred.user42_payto, "{\"items\":[{\"name\":\"more ice cream\",\"value\":1}]}", GNUNET_TIME_UNIT_ZERO, "EUR:0.5", @@ -1090,7 +1083,7 @@ run (void *cls, TALER_TESTING_cmd_deposit ("recoup-deposit-revoked", "recoup-withdraw-coin-2b", 0, - bc.user42_payto, + cred.user42_payto, "{\"items\":[{\"name\":\"more ice cream\",\"value\":1}]}", GNUNET_TIME_UNIT_ZERO, "EUR:1", @@ -1102,7 +1095,7 @@ run (void *cls, TALER_TESTING_cmd_deposit ("recoup-deposit-partial-after-recoup", "recoup-withdraw-coin-2a", 0, - bc.user42_payto, + cred.user42_payto, "{\"items\":[{\"name\":\"extra ice cream\",\"value\":1}]}", GNUNET_TIME_UNIT_ZERO, "EUR:0.5", @@ -1113,8 +1106,8 @@ run (void *cls, TALER_TESTING_cmd_check_bank_admin_transfer ( "check-recoup-create-reserve-3", "EUR:1.01", - bc.user42_payto, - bc.exchange_payto, + cred.user42_payto, + cred.exchange_payto, "recoup-create-reserve-3"), CMD_EXEC_WIREWATCH ("wirewatch-6"), TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-3-revoked", @@ -1144,8 +1137,8 @@ run (void *cls, MHD_HTTP_OK), TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-batch-reserve-1", "EUR:6.03", - bc.user42_payto, - bc.exchange_payto, + cred.user42_payto, + cred.exchange_payto, "create-batch-reserve-1"), /* * Make a reserve exist, according to the previous @@ -1174,17 +1167,13 @@ run (void *cls, MHD_HTTP_OK), TALER_TESTING_cmd_reserve_history ("history-batch-1", "create-batch-reserve-1", - "EUR:0", + "EUR:0.01", MHD_HTTP_OK), - TALER_TESTING_cmd_status ("status-batch-2", - "create-batch-reserve-1", - "EUR:0.0", - MHD_HTTP_OK), /** * Spend the coins. */ TALER_TESTING_cmd_batch_deposit ("batch-deposit-1", - bc.user42_payto, + cred.user42_payto, "{\"items\":[{\"name\":\"ice cream\",\"value\":5}]}", GNUNET_TIME_UNIT_ZERO, MHD_HTTP_OK, @@ -1193,6 +1182,10 @@ run (void *cls, "batch-withdraw-coin-1#1", "EUR:1", NULL), + TALER_TESTING_cmd_coin_history ("coin-history-batch-1", + "batch-withdraw-coin-1#0", + "EUR:0.0", + MHD_HTTP_OK), TALER_TESTING_cmd_end () }; @@ -1213,8 +1206,9 @@ run (void *cls, = CMD_TRANSFER_TO_EXCHANGE ("reserve-open-close-key", "EUR:20"); reserve_open_close[(i * RESERVE_OPEN_CLOSE_CHUNK) + 1] - = TALER_TESTING_cmd_exec_wirewatch ("reserve-open-close-wirewatch", - config_file_expire_reserve_now); + = TALER_TESTING_cmd_exec_wirewatch2 ("reserve-open-close-wirewatch", + config_file_expire_reserve_now, + "exchange-account-2"); reserve_open_close[(i * RESERVE_OPEN_CLOSE_CHUNK) + 2] = TALER_TESTING_cmd_exec_closer ("reserve-open-close-aggregation", config_file_expire_reserve_now, @@ -1232,38 +1226,18 @@ run (void *cls, { struct TALER_TESTING_Command commands[] = { - /* setup exchange */ - TALER_TESTING_cmd_auditor_add ("add-auditor-OK", - MHD_HTTP_NO_CONTENT, - false), - TALER_TESTING_cmd_exec_offline_sign_extensions ("offline-sign-extensions", - config_file), - TALER_TESTING_cmd_wire_add ("add-wire-account", - "payto://x-taler-bank/localhost/2?receiver-name=2", - MHD_HTTP_NO_CONTENT, - false), - TALER_TESTING_cmd_exec_offline_sign_global_fees ( - "offline-sign-global-fees", - config_file, - "EUR:0.01", - "EUR:0.01", - "EUR:0.01", - "EUR:0.01", - GNUNET_TIME_UNIT_MINUTES, - GNUNET_TIME_UNIT_MINUTES, - GNUNET_TIME_UNIT_DAYS, - 1), - TALER_TESTING_cmd_exec_offline_sign_keys ("offline-sign-future-keys", - config_file), - TALER_TESTING_cmd_exec_offline_sign_fees ("offline-sign-fees", - config_file, - "EUR:0.01", - "EUR:0.01", - "EUR:0.01"), - TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys", - 1), - TALER_TESTING_cmd_batch ("wire", - wire), + 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", withdraw), TALER_TESTING_cmd_batch ("spend", @@ -1294,9 +1268,8 @@ run (void *cls, TALER_TESTING_cmd_end () }; - TALER_TESTING_run_with_fakebank (is, - commands, - bc.exchange_auth.wire_gateway_url); + TALER_TESTING_run (is, + commands); } } @@ -1305,65 +1278,30 @@ int main (int argc, char *const *argv) { - char *cipher; - (void) argc; - /* These environment variables get in the way... */ - unsetenv ("XDG_DATA_HOME"); - unsetenv ("XDG_CONFIG_HOME"); - GNUNET_log_setup (argv[0], - "INFO", - NULL); - - GNUNET_assert (GNUNET_OK == - TALER_extension_age_restriction_register ()); - - cipher = GNUNET_TESTING_get_testname_from_underscore (argv[0]); - GNUNET_assert (NULL != cipher); - uses_cs = (0 == strcmp (cipher, "cs")); - GNUNET_asprintf (&config_file, - "test_exchange_api-%s.conf", - cipher); - GNUNET_asprintf (&config_file_expire_reserve_now, - "test_exchange_api_expire_reserve_now-%s.conf", - cipher); - GNUNET_free (cipher); - - /* Check fakebank port is available and get config */ - if (GNUNET_OK != - TALER_TESTING_prepare_fakebank (config_file, - "exchange-account-2", - &bc)) - return 77; - TALER_TESTING_cleanup_files (config_file); - /* @helpers. Run keyup, create tables, ... Note: it - * fetches the port number from config in order to see - * if it's available. */ - switch (TALER_TESTING_prepare_exchange (config_file, - GNUNET_YES, - &ec)) { - case GNUNET_SYSERR: - GNUNET_break (0); - return 1; - case GNUNET_NO: - return 78; - case GNUNET_OK: - if (GNUNET_OK != - /* Set up event loop and reschedule context, plus - * start/stop the exchange. It calls TALER_TESTING_setup - * which creates the 'is' object. - */ - TALER_TESTING_setup_with_exchange (&run, - NULL, - config_file)) - return 2; - break; - default: - GNUNET_break (0); - return 3; + 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-%s.conf", + cipher); + GNUNET_asprintf (&config_file_expire_reserve_now, + "test_exchange_api_expire_reserve_now-%s.conf", + cipher); + GNUNET_free (cipher); } - return 0; + return TALER_TESTING_main (argv, + "INFO", + config_file, + "exchange-account-2", + TALER_TESTING_BS_FAKEBANK, + &cred, + &run, + NULL); } diff --git a/src/testing/test_exchange_api.conf b/src/testing/test_exchange_api.conf new file mode 100644 index 000000000..c25f5091a --- /dev/null +++ b/src/testing/test_exchange_api.conf @@ -0,0 +1,118 @@ +# This file is in the public domain. +# + +[PATHS] +TALER_TEST_HOME = test_exchange_api_home/ + +[libeufin-bank] +CURRENCY = EUR +DEFAULT_CUSTOMER_DEBT_LIMIT = EUR:200 +DEFAULT_ADMIN_DEBT_LIMIT = EUR:2000 +REGISTRATION_BONUS_ENABLED = yes +REGISTRATION_BONUS = EUR:100 +SUGGESTED_WITHDRAWAL_EXCHANGE = http://localhost:8081/ +WIRE_TYPE = iban +IBAN_PAYTO_BIC = SANDBOXX +SERVE = tcp +PORT = 8082 + +[libeufin-bankdb-postgres] +CONFIG = postgresql:///talercheck + + +[taler] +CURRENCY = EUR +CURRENCY_ROUND_UNIT = EUR:0.01 + +[auditor] +BASE_URL = "http://localhost:8083/" +PORT = 8083 +PUBLIC_KEY = 9QZ7CCC5QFMWE9FVF50MGYWV7JR92SFHY5KHT8A1A2VNHM37VCRG +TINY_AMOUNT = EUR:0.01 + +[auditordb-postgres] +CONFIG = "postgres:///talercheck" + +[bank] +HTTP_PORT = 8082 + +[exchange] +TERMS_ETAG = tos +PRIVACY_ETAG = 0 +AML_THRESHOLD = EUR:1000000 +PORT = 8081 +MASTER_PUBLIC_KEY = QD6H521CBJBW0Z7PRN0JTAGH5JCQ97RDZRPPV5TQZSE78NQRT3KG +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/2?receiver-name=2" +ENABLE_DEBIT = YES +ENABLE_CREDIT = YES + +[exchange-accountcredentials-1] +WIRE_GATEWAY_AUTH_METHOD = none +WIRE_GATEWAY_URL = "http://localhost:8082/accounts/2/taler-wire-gateway/" + +[admin-accountcredentials-1] +WIRE_GATEWAY_AUTH_METHOD = none +WIRE_GATEWAY_URL = "http://localhost:8082/accounts/2/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 +# For now, fakebank still checks against the Exchange account... +USERNAME = Exchange +PASSWORD = x +WIRE_GATEWAY_URL = "http://localhost:8082/accounts/2/taler-wire-gateway/" + + +[kyc-provider-test-oauth2] +COST = 0 +LOGIC = oauth2 +USER_TYPE = INDIVIDUAL +PROVIDED_CHECKS = DUMMY +KYC_OAUTH2_VALIDITY = forever +KYC_OAUTH2_TOKEN_URL = http://localhost:6666/oauth/v2/token +KYC_OAUTH2_AUTHORIZE_URL = http://localhost:6666/oauth/v2/login +KYC_OAUTH2_INFO_URL = http://localhost:6666/api/user/me +KYC_OAUTH2_CLIENT_ID = taler-exchange +KYC_OAUTH2_CLIENT_SECRET = exchange-secret +KYC_OAUTH2_POST_URL = http://example.com/ +KYC_OAUTH2_CONVERTER_HELPER = taler-exchange-kyc-oauth2-test-converter.sh + +[kyc-legitimization-close] +OPERATION_TYPE = CLOSE +REQUIRED_CHECKS = DUMMY +THRESHOLD = EUR:0 +TIMEFRAME = 1d + +[exchange-extension-age_restriction] +ENABLED = YES +#AGE_GROUPS = "8:10:12:14:16:18:21" diff --git a/src/testing/test_exchange_api_age_restriction-cs.conf b/src/testing/test_exchange_api_age_restriction-cs.conf new file mode 100644 index 000000000..12195f9ba --- /dev/null +++ b/src/testing/test_exchange_api_age_restriction-cs.conf @@ -0,0 +1,4 @@ +# This file is in the public domain. +# +@INLINE@ test_exchange_api_age_restriction.conf +@INLINE@ coins-cs.conf diff --git a/src/testing/test_exchange_api_age_restriction-rsa.conf b/src/testing/test_exchange_api_age_restriction-rsa.conf new file mode 100644 index 000000000..30d75090f --- /dev/null +++ b/src/testing/test_exchange_api_age_restriction-rsa.conf @@ -0,0 +1,4 @@ +# This file is in the public domain. +# +@INLINE@ test_exchange_api_age_restriction.conf +@INLINE@ coins-rsa.conf diff --git a/src/testing/test_exchange_api_age_restriction.c b/src/testing/test_exchange_api_age_restriction.c new file mode 100644 index 000000000..5ba24a00c --- /dev/null +++ b/src/testing/test_exchange_api_age_restriction.c @@ -0,0 +1,370 @@ +/* + 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_age_restriction.c + * @brief testcase to test exchange's age-restrictrition related HTTP API interfaces + * @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 age restriction. Success is expected (because the + * amount is below the kyc threshold ), so it MUST be + * called _after_ TALER_TESTING_cmd_exec_offline_sign_extensions is called, + * i. e. age restriction is activated in the exchange! + * + * TODO: create a test that tries to withdraw coins with age restriction but + * (expectedly) fails because the exchange doesn't support age restriction + * yet. + */ + struct TALER_TESTING_Command withdraw_age[] = { + /** + * Move money to the exchange's bank account. + */ + CMD_TRANSFER_TO_EXCHANGE ("create-reserve-age", + "EUR:6.01"), + TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-reserve-age", + "EUR:6.01", + cred.user42_payto, + cred.exchange_payto, + "create-reserve-age"), + /** + * Make a reserve exist, according to the previous + * transfer. + */ + CMD_EXEC_WIREWATCH ("wirewatch-age"), + /** + * Withdraw EUR:5. + */ + TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-age-1", + "create-reserve-age", + "EUR:5", + 13, + MHD_HTTP_OK), + + TALER_TESTING_cmd_end () + }; + + struct TALER_TESTING_Command spend_age[] = { + /** + * Spend the coin. + */ + TALER_TESTING_cmd_deposit ("deposit-simple-age", + "withdraw-coin-age-1", + 0, + cred.user42_payto, + "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", + GNUNET_TIME_UNIT_ZERO, + "EUR:4.99", + MHD_HTTP_OK), + TALER_TESTING_cmd_deposit_replay ("deposit-simple-replay-age", + "deposit-simple-age", + MHD_HTTP_OK), + TALER_TESTING_cmd_end () + }; + + + struct TALER_TESTING_Command refresh_age[] = { + /* Fill reserve with EUR:5, 1ct is for fees. */ + CMD_TRANSFER_TO_EXCHANGE ("refresh-create-reserve-age-1", + "EUR:6.01"), + TALER_TESTING_cmd_check_bank_admin_transfer ( + "ck-refresh-create-reserve-age-1", + "EUR:6.01", + cred.user42_payto, + cred.exchange_payto, + "refresh-create-reserve-age-1"), + /** + * Make previous command effective. + */ + CMD_EXEC_WIREWATCH ("wirewatch-age-2"), + /** + * Withdraw EUR:7 with age restriction for age 13. + */ + TALER_TESTING_cmd_withdraw_amount ("refresh-withdraw-coin-age-1", + "refresh-create-reserve-age-1", + "EUR:5", + 13, + MHD_HTTP_OK), + /* 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) + */ + TALER_TESTING_cmd_deposit ("refresh-deposit-partial-age", + "refresh-withdraw-coin-age-1", + 0, + cred.user42_payto, + "{\"items\":[{\"name\":\"ice cream\",\"value\":\"EUR:1\"}]}", + GNUNET_TIME_UNIT_ZERO, + "EUR:1", + MHD_HTTP_OK), + /** + * Melt the rest of the coin's value + * (EUR:4.00 = 3x EUR:1.03 + 7x EUR:0.13) */ + TALER_TESTING_cmd_melt_double ("refresh-melt-age-1", + "refresh-withdraw-coin-age-1", + MHD_HTTP_OK, + NULL), + /** + * Complete (successful) melt operation, and + * withdraw the coins + */ + TALER_TESTING_cmd_refresh_reveal ("refresh-reveal-age-1", + "refresh-melt-age-1", + MHD_HTTP_OK), + /** + * Do it again to check idempotency + */ + TALER_TESTING_cmd_refresh_reveal ("refresh-reveal-age-1-idempotency", + "refresh-melt-age-1", + MHD_HTTP_OK), + /** + * Test that /refresh/link works + */ + TALER_TESTING_cmd_refresh_link ("refresh-link-age-1", + "refresh-reveal-age-1", + MHD_HTTP_OK), + /** + * Try to spend a refreshed EUR:1 coin + */ + TALER_TESTING_cmd_deposit ("refresh-deposit-refreshed-age-1a", + "refresh-reveal-age-1-idempotency", + 0, + cred.user42_payto, + "{\"items\":[{\"name\":\"ice cream\",\"value\":3}]}", + GNUNET_TIME_UNIT_ZERO, + "EUR:1", + MHD_HTTP_OK), + /** + * Try to spend a refreshed EUR:0.1 coin + */ + TALER_TESTING_cmd_deposit ("refresh-deposit-refreshed-age-1b", + "refresh-reveal-age-1", + 3, + cred.user43_payto, + "{\"items\":[{\"name\":\"ice cream\",\"value\":3}]}", + GNUNET_TIME_UNIT_ZERO, + "EUR:0.1", + MHD_HTTP_OK), + /* Test running a failing melt operation (same operation + * again must fail) */ + TALER_TESTING_cmd_melt ("refresh-melt-failing-age", + "refresh-withdraw-coin-age-1", + MHD_HTTP_CONFLICT, + NULL), + /* Test running a failing melt operation (on a coin that + was itself revealed and subsequently deposited) */ + TALER_TESTING_cmd_melt ("refresh-melt-failing-age-2", + "refresh-reveal-age-1", + MHD_HTTP_CONFLICT, + NULL), + TALER_TESTING_cmd_end () + }; + + /** + * Test with age-withdraw, after kyc process has set a birthdate + */ + struct TALER_TESTING_Command age_withdraw[] = { + CMD_TRANSFER_TO_EXCHANGE ("create-reserve-kyc-1", + "EUR:30.02"), + TALER_TESTING_cmd_check_bank_admin_transfer ( + "check-create-reserve-kyc-1", + "EUR:30.02", + cred.user42_payto, + cred.exchange_payto, + "create-reserve-kyc-1"), + CMD_EXEC_WIREWATCH ("wirewatch-age-withdraw-1"), + TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-1-lacking-kyc", + "create-reserve-kyc-1", + "EUR:10", + 0, /* age restriction off */ + MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS), + TALER_TESTING_cmd_check_kyc_get ("check-kyc-withdraw", + "withdraw-coin-1-lacking-kyc", + MHD_HTTP_ACCEPTED), + TALER_TESTING_cmd_proof_kyc_oauth2 ("proof-kyc", + "withdraw-coin-1-lacking-kyc", + "kyc-provider-test-oauth2", + "pass", + MHD_HTTP_SEE_OTHER), + TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-1-with-kyc", + "create-reserve-kyc-1", + "EUR:10", + 0, /* age restriction off */ + MHD_HTTP_CONFLICT), + TALER_TESTING_cmd_age_withdraw ("age-withdraw-coin-1-too-low", + "create-reserve-kyc-1", + 18, /* Too high */ + MHD_HTTP_CONFLICT, + "EUR:10", + NULL), + TALER_TESTING_cmd_age_withdraw ("age-withdraw-coins-1", + "create-reserve-kyc-1", + 8, + MHD_HTTP_OK, + "EUR:10", + "EUR:10", + "EUR:5", + NULL), + TALER_TESTING_cmd_age_withdraw_reveal ("age-withdraw-coins-reveal-1", + "age-withdraw-coins-1", + MHD_HTTP_OK), + 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_oauth_with_birthdate ("oauth-service-with-birthdate", + "2015-00-00", /* enough for a while */ + 6666), + TALER_TESTING_cmd_batch ("withdraw-age", + withdraw_age), + TALER_TESTING_cmd_batch ("spend-age", + spend_age), + TALER_TESTING_cmd_batch ("refresh-age", + refresh_age), + TALER_TESTING_cmd_batch ("age-withdraw", + age_withdraw), + /* 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_age_restriction-%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_age_restriction.c */ diff --git a/src/testing/test_exchange_api_age_restriction.conf b/src/testing/test_exchange_api_age_restriction.conf new file mode 100644 index 000000000..1345fcb1a --- /dev/null +++ b/src/testing/test_exchange_api_age_restriction.conf @@ -0,0 +1,119 @@ +# 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 +AML_THRESHOLD = EUR:10 +PORT = 8081 +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/" + + +[kyc-provider-test-oauth2] +COST = 0 +LOGIC = oauth2 +USER_TYPE = INDIVIDUAL +PROVIDED_CHECKS = DUMMY +KYC_OAUTH2_VALIDITY = forever +KYC_OAUTH2_TOKEN_URL = http://localhost:6666/oauth/v2/token +KYC_OAUTH2_AUTHORIZE_URL = http://localhost:6666/oauth/v2/login +KYC_OAUTH2_INFO_URL = http://localhost:6666/api/user/me +KYC_OAUTH2_CLIENT_ID = taler-exchange +KYC_OAUTH2_CLIENT_SECRET = exchange-secret +KYC_OAUTH2_POST_URL = http://example.com/ +KYC_OAUTH2_CONVERTER_HELPER = taler-exchange-kyc-oauth2-test-converter.sh + +[kyc-legitimization-balance-high] +OPERATION_TYPE = BALANCE +REQUIRED_CHECKS = DUMMY +THRESHOLD = EUR:20 + +[kyc-legitimization-deposit-any] +OPERATION_TYPE = DEPOSIT +REQUIRED_CHECKS = DUMMY +THRESHOLD = EUR:10 +TIMEFRAME = 1d + +[kyc-legitimization-withdraw] +OPERATION_TYPE = WITHDRAW +REQUIRED_CHECKS = DUMMY +THRESHOLD = EUR:15 +TIMEFRAME = 1d + +[kyc-legitimization-merge] +OPERATION_TYPE = MERGE +REQUIRED_CHECKS = DUMMY +THRESHOLD = EUR:15 +TIMEFRAME = 1d + + +[exchange-extension-age_restriction] +ENABLED = YES +#AGE_GROUPS = "8:10:12:14:16:18:21" 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/test_exchange_api_home/.config/taler/account-2.json b/src/testing/test_exchange_api_home/.config/taler/account-2.json deleted file mode 100644 index 21a7500b4..000000000 --- a/src/testing/test_exchange_api_home/.config/taler/account-2.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "payto_uri": "payto://x-taler-bank/localhost/2", - "master_sig": "HEWC1XDS0QZ53YQR451VRKD4N968NXWGZXS30HJ59MJ0PESACK1ZYPYCAT15P08WD58C7D7F6EVN26D59JKA75XEBDQCM8VYFETK82R" -}
\ No newline at end of file diff --git a/src/testing/test_exchange_api_home/.local/share/taler/auditor/offline-keys/auditor.priv b/src/testing/test_exchange_api_home/.local/share/taler/auditor/offline-keys/auditor.priv Binary files differnew file mode 100644 index 000000000..5b1c8fa05 --- /dev/null +++ b/src/testing/test_exchange_api_home/.local/share/taler/auditor/offline-keys/auditor.priv diff --git a/src/testing/test_exchange_api_home/.local/share/taler/exchange-offline/master.priv b/src/testing/test_exchange_api_home/.local/share/taler/exchange-offline/master.priv Binary files differindex 394926938..391b6ea73 100644 --- a/src/testing/test_exchange_api_home/.local/share/taler/exchange-offline/master.priv +++ b/src/testing/test_exchange_api_home/.local/share/taler/exchange-offline/master.priv diff --git a/src/testing/test_exchange_api_home/.local/share/taler/exchange/offline-keys/master.priv b/src/testing/test_exchange_api_home/.local/share/taler/exchange/offline-keys/master.priv deleted file mode 100644 index 394926938..000000000 --- a/src/testing/test_exchange_api_home/.local/share/taler/exchange/offline-keys/master.priv +++ /dev/null @@ -1 +0,0 @@ -pÚ^ó-Ú33ˆ€XXÁ!ˆ\0qúýµmUþ_‰ˆ
\ No newline at end of file diff --git a/src/testing/test_exchange_api_home/taler/auditor/offline-keys/auditor.priv b/src/testing/test_exchange_api_home/taler/auditor/offline-keys/auditor.priv new file mode 100644 index 000000000..7e712e483 --- /dev/null +++ b/src/testing/test_exchange_api_home/taler/auditor/offline-keys/auditor.priv @@ -0,0 +1 @@ +·G,U²†{ ~#ræ-½HꑶÒÆÏâÿñ
\ No newline at end of file diff --git a/src/testing/test_exchange_api_keys_cherry_picking-cs.conf b/src/testing/test_exchange_api_keys_cherry_picking-cs.conf index 751850cb2..d25ef3c00 100644 --- a/src/testing/test_exchange_api_keys_cherry_picking-cs.conf +++ b/src/testing/test_exchange_api_keys_cherry_picking-cs.conf @@ -1,89 +1,9 @@ # This file is in the public domain. # -[PATHS] -# Persistent data storage for the testcase -TALER_TEST_HOME = test_exchange_api_keys_cherry_picking_home/ -TALER_RUNTIME_DIR = ${TMPDIR:-${TMP:-/tmp}}/${USER:-}/taler-system-runtime/ - -# Persistent data storage -TALER_DATA_HOME = $TALER_HOME/.local/share/taler/ - -# Configuration files -TALER_CONFIG_HOME = $TALER_HOME/.config/taler/ - -# Cached data, no big deal if lost -TALER_CACHE_HOME = $TALER_HOME/.cache/taler/ - -[taler] -# Currency supported by the exchange (can only be one) -CURRENCY = EUR +@INLINE@ test_exchange_api_keys_cherry_picking.conf [taler-exchange-secmod-cs] -# Reduce from 1 year to speed up test -LOOKAHEAD_SIGN = 24 days - -[taler-exchange-secmod-eddsa] -# Reduce from 1 year to speed up test -LOOKAHEAD_SIGN = 24 days -# Reduce from 12 weeks to ensure we have multiple -DURATION = 14 days - -[auditor] -BASE_URL = "http://localhost:8083/" - -# HTTP port the auditor listens to -PORT = 8083 - -[exchange] -# HTTP port the exchange listens to -PORT = 8081 - -# Master public key used to sign the exchange's various keys -MASTER_PUBLIC_KEY = 98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG - -# How to access our database -DB = postgres - -# Base URL of the exchange. Must be set to a URL where the -# exchange (or the twister) is actually listening. -BASE_URL = "http://localhost:8081/" - - -[exchangedb-postgres] -CONFIG = "postgres:///talercheck" - -[auditordb-postgres] -CONFIG = "postgres:///talercheck" - -[exchange-account-1] -PAYTO_URI = "payto://x-taler-bank/localhost/42?receiver-name=42" - -[exchange-accountcredentials-1] -WIRE_GATEWAY_URL = "http://localhost:9082/42/" - -[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_URL = "http://localhost:9082/2/" - -# Authentication information for basic authentication -TALER_BANK_AUTH_METHOD = "basic" -USERNAME = user -PASSWORD = pass - -[bank] -HTTP_PORT=8082 - -[taler-exchange-secmod-cs] -OVERLAP_DURATION = 1 s -LOOKAHEAD_SIGN = 20 s - -[taler-exchange-secmod-eddsa] OVERLAP_DURATION = 1 s -DURATION = 30 s LOOKAHEAD_SIGN = 20 s [coin_eur_1] diff --git a/src/testing/test_exchange_api_keys_cherry_picking-rsa.conf b/src/testing/test_exchange_api_keys_cherry_picking-rsa.conf index b9ad30549..672639b3f 100644 --- a/src/testing/test_exchange_api_keys_cherry_picking-rsa.conf +++ b/src/testing/test_exchange_api_keys_cherry_picking-rsa.conf @@ -1,89 +1,9 @@ # This file is in the public domain. # -[PATHS] -# Persistent data storage for the testcase -TALER_TEST_HOME = test_exchange_api_keys_cherry_picking_home/ -TALER_RUNTIME_DIR = ${TMPDIR:-${TMP:-/tmp}}/${USER:-}/taler-system-runtime/ - -# Persistent data storage -TALER_DATA_HOME = $TALER_HOME/.local/share/taler/ - -# Configuration files -TALER_CONFIG_HOME = $TALER_HOME/.config/taler/ - -# Cached data, no big deal if lost -TALER_CACHE_HOME = $TALER_HOME/.cache/taler/ - -[taler] -# Currency supported by the exchange (can only be one) -CURRENCY = EUR +@INLINE@ test_exchange_api_keys_cherry_picking.conf [taler-exchange-secmod-rsa] -# Reduce from 1 year to speed up test -LOOKAHEAD_SIGN = 24 days - -[taler-exchange-secmod-eddsa] -# Reduce from 1 year to speed up test -LOOKAHEAD_SIGN = 24 days -# Reduce from 12 weeks to ensure we have multiple -DURATION = 14 days - -[auditor] -BASE_URL = "http://localhost:8083/" - -# HTTP port the auditor listens to -PORT = 8083 - -[exchange] -# HTTP port the exchange listens to -PORT = 8081 - -# Master public key used to sign the exchange's various keys -MASTER_PUBLIC_KEY = 98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG - -# How to access our database -DB = postgres - -# Base URL of the exchange. Must be set to a URL where the -# exchange (or the twister) is actually listening. -BASE_URL = "http://localhost:8081/" - - -[exchangedb-postgres] -CONFIG = "postgres:///talercheck" - -[auditordb-postgres] -CONFIG = "postgres:///talercheck" - -[exchange-account-1] -PAYTO_URI = "payto://x-taler-bank/localhost/42?receiver-name=42" - -[exchange-accountcredentials-1] -WIRE_GATEWAY_URL = "http://localhost:9082/42/" - -[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_URL = "http://localhost:9082/2/" - -# Authentication information for basic authentication -TALER_BANK_AUTH_METHOD = "basic" -USERNAME = user -PASSWORD = pass - -[bank] -HTTP_PORT=8082 - -[taler-exchange-secmod-rsa] -OVERLAP_DURATION = 1 s -LOOKAHEAD_SIGN = 20 s - -[taler-exchange-secmod-eddsa] OVERLAP_DURATION = 1 s -DURATION = 30 s LOOKAHEAD_SIGN = 20 s [coin_eur_1] diff --git a/src/testing/test_exchange_api_keys_cherry_picking.c b/src/testing/test_exchange_api_keys_cherry_picking.c index 4ad2d7207..2919ea8d5 100644 --- a/src/testing/test_exchange_api_keys_cherry_picking.c +++ b/src/testing/test_exchange_api_keys_cherry_picking.c @@ -43,9 +43,9 @@ lished static char *config_file; /** - * Exchange configuration data. + * Our credentials. */ -static struct TALER_TESTING_ExchangeConfiguration ec; +static struct TALER_TESTING_Credentials cred; /** @@ -59,45 +59,27 @@ run (void *cls, struct TALER_TESTING_Interpreter *is) { struct TALER_TESTING_Command commands[] = { - TALER_TESTING_cmd_auditor_add ("add-auditor-OK", - MHD_HTTP_NO_CONTENT, - false), - TALER_TESTING_cmd_wire_add ("add-wire-account", - "payto://x-taler-bank/localhost/2?receiver-name=2", - MHD_HTTP_NO_CONTENT, - false), - TALER_TESTING_cmd_exec_offline_sign_fees ("offline-sign-fees", - config_file, - "EUR:0.01", - "EUR:0.01", - "EUR:0.01"), - TALER_TESTING_cmd_exec_offline_sign_keys ("offline-sign-future-keys", - config_file), - TALER_TESTING_cmd_check_keys_pull_all_keys ("initial-/keys", - 1), + 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_sleep ("sleep", 6 /* seconds */), - TALER_TESTING_cmd_check_keys ("check-keys-1", - 2 /* generation */), - TALER_TESTING_cmd_check_keys_with_last_denom ("check-keys-2", - 3 /* generation */, - "check-keys-1"), - TALER_TESTING_cmd_serialize_keys ("serialize-keys"), - TALER_TESTING_cmd_connect_with_state ("reconnect-with-state", - "serialize-keys"), - /** - * Make sure we have the same keys situation as - * it was before the serialization. - */ - TALER_TESTING_cmd_check_keys ("check-keys-after-deserialization", - 4), - /** - * Use one of the deserialized keys. - */ - TALER_TESTING_cmd_wire ("wire-with-serialized-keys", - "x-taler-bank", - NULL, - MHD_HTTP_OK), + TALER_TESTING_cmd_get_exchange ("get-exchange-1", + cred.cfg, + "get-exchange", + true, + true), + TALER_TESTING_cmd_get_exchange ("get-exchange-2", + cred.cfg, + "get-exchange-1", + true, + true), TALER_TESTING_cmd_end () }; @@ -111,50 +93,25 @@ int main (int argc, char *const *argv) { - char *cipher; - (void) argc; - /* These environment variables get in the way... */ - unsetenv ("XDG_DATA_HOME"); - unsetenv ("XDG_CONFIG_HOME"); - GNUNET_log_setup (argv[0], - "DEBUG", - NULL); - cipher = GNUNET_TESTING_get_testname_from_underscore (argv[0]); - GNUNET_assert (NULL != cipher); - GNUNET_asprintf (&config_file, - "test_exchange_api_keys_cherry_picking-%s.conf", - cipher); - GNUNET_free (cipher); - TALER_TESTING_cleanup_files (config_file); - /* @helpers. Run keyup, create tables, ... Note: it - * fetches the port number from config in order to see - * if it's available. */ - switch (TALER_TESTING_prepare_exchange (config_file, - GNUNET_YES, - &ec)) { - case GNUNET_SYSERR: - GNUNET_break (0); - return 1; - case GNUNET_NO: - return 77; - case GNUNET_OK: - if (GNUNET_OK != - /* Set up event loop and reschedule context, plus - * start/stop the exchange. It calls TALER_TESTING_setup - * which creates the 'is' object. - */ - TALER_TESTING_setup_with_exchange (&run, - NULL, - config_file)) - return 1; - break; - default: - GNUNET_break (0); - return 1; + char *cipher; + + cipher = GNUNET_STRINGS_get_suffix_from_binary_name (argv[0]); + GNUNET_assert (NULL != cipher); + GNUNET_asprintf (&config_file, + "test_exchange_api_keys_cherry_picking-%s.conf", + cipher); + GNUNET_free (cipher); } - return 0; + return TALER_TESTING_main (argv, + "INFO", + config_file, + "exchange-account-2", + TALER_TESTING_BS_FAKEBANK, + &cred, + &run, + NULL); } diff --git a/src/testing/test_exchange_api_keys_cherry_picking.conf b/src/testing/test_exchange_api_keys_cherry_picking.conf new file mode 100644 index 000000000..142242424 --- /dev/null +++ b/src/testing/test_exchange_api_keys_cherry_picking.conf @@ -0,0 +1,58 @@ +# This file is in the public domain. +# +[PATHS] +# Persistent data storage for the testcase +TALER_TEST_HOME = test_exchange_api_keys_cherry_picking_home/ + +[taler] +CURRENCY = EUR +CURRENCY_ROUND_UNIT = EUR:0.01 + +[taler-exchange-secmod-eddsa] +OVERLAP_DURATION = 1 s +DURATION = 30 s +LOOKAHEAD_SIGN = 20 s + +[exchange] +AML_THRESHOLD = EUR:1000000 +PORT = 8081 +MASTER_PUBLIC_KEY = 98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG +DB = postgres +BASE_URL = "http://localhost:8081/" + +[exchangedb-postgres] +CONFIG = "postgres:///talercheck" + +[auditordb-postgres] +CONFIG = "postgres:///talercheck" + +[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_URL = "http://localhost:9082/accounts/42/taler-wire-gateway/" + +[admin-accountcredentials-1] +WIRE_GATEWAY_URL = "http://localhost:9082/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_URL = "http://localhost:9082/accounts/2/taler-wire-gateway/" +WIRE_GATEWAY_AUTH_METHOD = basic +USERNAME = Exchange +PASSWORD = x + +[admin-accountcredentials-2] +WIRE_GATEWAY_URL = "http://localhost:9082/accounts/2/taler-wire-gateway/" +WIRE_GATEWAY_AUTH_METHOD = basic +USERNAME = Exchange +PASSWORD = x + +[bank] +HTTP_PORT=8082 diff --git a/src/testing/test_exchange_api_keys_cherry_picking_home/.config/taler/x-taler-bank.json b/src/testing/test_exchange_api_keys_cherry_picking_home/.config/taler/x-taler-bank.json deleted file mode 100644 index 21a7500b4..000000000 --- a/src/testing/test_exchange_api_keys_cherry_picking_home/.config/taler/x-taler-bank.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "payto_uri": "payto://x-taler-bank/localhost/2", - "master_sig": "HEWC1XDS0QZ53YQR451VRKD4N968NXWGZXS30HJ59MJ0PESACK1ZYPYCAT15P08WD58C7D7F6EVN26D59JKA75XEBDQCM8VYFETK82R" -}
\ No newline at end of file diff --git a/src/testing/test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange-offline/master.priv b/src/testing/test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange-offline/master.priv deleted file mode 100644 index 394926938..000000000 --- a/src/testing/test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange-offline/master.priv +++ /dev/null @@ -1 +0,0 @@ -pÚ^ó-Ú33ˆ€XXÁ!ˆ\0qúýµmUþ_‰ˆ
\ No newline at end of file diff --git a/src/testing/test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange/offline-keys/master.priv b/src/testing/test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange/offline-keys/master.priv deleted file mode 100644 index 394926938..000000000 --- a/src/testing/test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange/offline-keys/master.priv +++ /dev/null @@ -1 +0,0 @@ -pÚ^ó-Ú33ˆ€XXÁ!ˆ\0qúýµmUþ_‰ˆ
\ No newline at end of file diff --git a/src/testing/test_exchange_api_overlapping_keys_bug.c b/src/testing/test_exchange_api_overlapping_keys_bug.c index 1314bdf54..33b547a37 100644 --- a/src/testing/test_exchange_api_overlapping_keys_bug.c +++ b/src/testing/test_exchange_api_overlapping_keys_bug.c @@ -44,9 +44,9 @@ static char *config_file; /** - * Exchange configuration data. + * Our credentials. */ -static struct TALER_TESTING_ExchangeConfiguration ec; +static struct TALER_TESTING_Credentials cred; /** @@ -60,23 +60,28 @@ run (void *cls, struct TALER_TESTING_Interpreter *is) { struct TALER_TESTING_Command commands[] = { - TALER_TESTING_cmd_auditor_add ("add-auditor-OK", - MHD_HTTP_NO_CONTENT, - false), - TALER_TESTING_cmd_wire_add ("add-wire-account", - "payto://x-taler-bank/localhost/2?receiver-name=2", - MHD_HTTP_NO_CONTENT, - false), - TALER_TESTING_cmd_exec_offline_sign_keys ("offline-sign-future-keys", - config_file), - TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys", - 1), - TALER_TESTING_cmd_check_keys ("first-download", - 1), - /* Causes GET /keys?last_denom_issue=0 */ - TALER_TESTING_cmd_check_keys_with_last_denom ("second-download", - 1, - "zero"), + 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_get_exchange ("get-exchange-1", + cred.cfg, + "get-exchange", + true, + true), + TALER_TESTING_cmd_get_exchange ("get-exchange-2", + cred.cfg, + NULL, + true, + true), TALER_TESTING_cmd_end () }; @@ -90,50 +95,25 @@ int main (int argc, char *const *argv) { - char *cipher; - (void) argc; - /* These environment variables get in the way... */ - unsetenv ("XDG_DATA_HOME"); - unsetenv ("XDG_CONFIG_HOME"); - GNUNET_log_setup (argv[0], - "DEBUG", - NULL); - cipher = GNUNET_TESTING_get_testname_from_underscore (argv[0]); - GNUNET_assert (NULL != cipher); - GNUNET_asprintf (&config_file, - "test_exchange_api_keys_cherry_picking-%s.conf", - cipher); - GNUNET_free (cipher); - TALER_TESTING_cleanup_files (config_file); - /* @helpers. Run keyup, create tables, ... Note: it - * fetches the port number from config in order to see - * if it's available. */ - switch (TALER_TESTING_prepare_exchange (config_file, - GNUNET_YES, - &ec)) { - case GNUNET_SYSERR: - GNUNET_break (0); - return 1; - case GNUNET_NO: - return 77; - case GNUNET_OK: - if (GNUNET_OK != - /* Set up event loop and reschedule context, plus - * start/stop the exchange. It calls TALER_TESTING_setup - * which creates the 'is' object. - */ - TALER_TESTING_setup_with_exchange (&run, - NULL, - config_file)) - return 1; - break; - default: - GNUNET_break (0); - return 1; + char *cipher; + + cipher = GNUNET_STRINGS_get_suffix_from_binary_name (argv[0]); + GNUNET_assert (NULL != cipher); + GNUNET_asprintf (&config_file, + "test_exchange_api_keys_cherry_picking-%s.conf", + cipher); + GNUNET_free (cipher); } - return 0; + return TALER_TESTING_main (argv, + "INFO", + config_file, + "exchange-account-2", + TALER_TESTING_BS_FAKEBANK, + &cred, + &run, + NULL); } diff --git a/src/testing/test_exchange_api_revocation.c b/src/testing/test_exchange_api_revocation.c index 33a92551d..92e36a30a 100644 --- a/src/testing/test_exchange_api_revocation.c +++ b/src/testing/test_exchange_api_revocation.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014--2020 Taler Systems SA + Copyright (C) 2014--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 @@ -42,14 +42,9 @@ static char *config_file; /** - * Exchange configuration data. + * Our credentials. */ -static struct TALER_TESTING_ExchangeConfiguration ec; - -/** - * Bank configuration data. - */ -static struct TALER_TESTING_BankConfiguration bc; +static struct TALER_TESTING_Credentials cred; /** @@ -63,35 +58,37 @@ run (void *cls, struct TALER_TESTING_Interpreter *is) { struct TALER_TESTING_Command revocation[] = { - TALER_TESTING_cmd_auditor_add ("add-auditor-OK", - MHD_HTTP_NO_CONTENT, - false), - TALER_TESTING_cmd_wire_add ("add-wire-account", - "payto://x-taler-bank/localhost/2?receiver-name=2", - MHD_HTTP_NO_CONTENT, - false), - TALER_TESTING_cmd_exec_offline_sign_keys ("offline-sign-future-keys", - config_file), - TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys", - 1), + 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), /** * Fill reserve with EUR:10.02, as withdraw fee is 1 ct per * config. */ TALER_TESTING_cmd_admin_add_incoming ("create-reserve-1", "EUR:10.02", - &bc.exchange_auth, - bc.user42_payto), + &cred.ba, + cred.user42_payto), TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-reserve-1", "EUR:10.02", - bc.user42_payto, - bc.exchange_payto, + cred.user42_payto, + cred.exchange_payto, "create-reserve-1"), /** * Run wire-watch to trigger the reserve creation. */ - TALER_TESTING_cmd_exec_wirewatch ("wirewatch-4", - config_file), + TALER_TESTING_cmd_exec_wirewatch2 ("wirewatch-4", + config_file, + "exchange-account-2"), /* Withdraw a 5 EUR coin, at fee of 1 ct */ TALER_TESTING_cmd_withdraw_amount ("withdraw-revocation-coin-1", "create-reserve-1", @@ -109,7 +106,7 @@ run (void *cls, TALER_TESTING_cmd_deposit ("deposit-partial", "withdraw-revocation-coin-1", 0, - bc.user42_payto, + cred.user42_payto, "{\"items\":[{\"name\":\"ice cream\",\"value\":\"EUR:1\"}]}", GNUNET_TIME_UNIT_ZERO, "EUR:1", @@ -118,7 +115,7 @@ run (void *cls, TALER_TESTING_cmd_deposit ("deposit-full", "withdraw-revocation-coin-2", 0, - bc.user42_payto, + cred.user42_payto, "{\"items\":[{\"name\":\"ice cream\",\"value\":\"EUR:5\"}]}", GNUNET_TIME_UNIT_ZERO, "EUR:5", @@ -241,9 +238,8 @@ run (void *cls, }; (void) cls; - TALER_TESTING_run_with_fakebank (is, - revocation, - bc.exchange_auth.wire_gateway_url); + TALER_TESTING_run (is, + revocation); } @@ -251,56 +247,25 @@ int main (int argc, char *const *argv) { - char *cipher; - (void) argc; - /* These environment variables get in the way... */ - unsetenv ("XDG_DATA_HOME"); - unsetenv ("XDG_CONFIG_HOME"); - GNUNET_log_setup (argv[0], - "INFO", - NULL); - cipher = GNUNET_TESTING_get_testname_from_underscore (argv[0]); - GNUNET_assert (NULL != cipher); - GNUNET_asprintf (&config_file, - "test_exchange_api-%s.conf", - cipher); - GNUNET_free (cipher); - /* Check fakebank port is available and get config */ - if (GNUNET_OK != - TALER_TESTING_prepare_fakebank (config_file, - "exchange-account-2", - &bc)) - return 77; - TALER_TESTING_cleanup_files (config_file); - /* @helpers. Run keyup, create tables, ... Note: it - * fetches the port number from config in order to see - * if it's available. */ - switch (TALER_TESTING_prepare_exchange (config_file, - GNUNET_YES, - &ec)) { - case GNUNET_SYSERR: - GNUNET_break (0); - return 1; - case GNUNET_NO: - return 77; - case GNUNET_OK: - if (GNUNET_OK != - /* Set up event loop and reschedule context, plus - * start/stop the exchange. It calls TALER_TESTING_setup - * which creates the 'is' object. - */ - TALER_TESTING_setup_with_exchange (&run, - NULL, - config_file)) - return 1; - break; - default: - GNUNET_break (0); - return 1; + char *cipher; + + cipher = GNUNET_STRINGS_get_suffix_from_binary_name (argv[0]); + GNUNET_assert (NULL != cipher); + GNUNET_asprintf (&config_file, + "test_exchange_api-%s.conf", + cipher); + GNUNET_free (cipher); } - return 0; + return TALER_TESTING_main (argv, + "INFO", + config_file, + "exchange-account-2", + TALER_TESTING_BS_FAKEBANK, + &cred, + &run, + NULL); } diff --git a/src/testing/test_exchange_api_twisted-cs.conf b/src/testing/test_exchange_api_twisted-cs.conf index abb88a742..ae953e732 100644 --- a/src/testing/test_exchange_api_twisted-cs.conf +++ b/src/testing/test_exchange_api_twisted-cs.conf @@ -1,150 +1,4 @@ # This file is in the public domain. -[PATHS] -# Persistent data storage for the testcase -TALER_TEST_HOME = test_exchange_api_home/ -TALER_RUNTIME_DIR = ${TMPDIR:-${TMP:-/tmp}}/${USER:-}/taler-system-runtime/ +@INLINE@ test_exchange_api-cs.conf +@INLINE@ test_exchange_api-twisted.conf -[taler-exchange-secmod-rsa] -# Reduce from 1 year to speed up test -LOOKAHEAD_SIGN = 24 days - -[taler-exchange-secmod-eddsa] -# Reduce from 1 year to speed up test -LOOKAHEAD_SIGN = 24 days -# Reduce from 12 weeks to ensure we have multiple -DURATION = 14 days - -[taler] -# Currency supported by the exchange (can only be one) -CURRENCY = EUR -CURRENCY_ROUND_UNIT = EUR:0.01 - -[exchange] -# HTTP port the exchange listens to -PORT = 8081 - -# Master public key used to sign the exchange's various keys -MASTER_PUBLIC_KEY = 98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG - -# How to access our database -DB = postgres - -# Base URL of the exchange ('S PROXY). This URL is where the -# twister listens at, so that it will be able to get all the -# connection addressed to the exchange. In fact, the presence -# of the twister is 100% transparent to the test case, as it -# only seeks the exchange/BASE_URL URL to connect to the exchange. -BASE_URL = "http://localhost:8888/" - -[exchangedb-postgres] -CONFIG = "postgres:///talercheck" - -[auditor] -BASE_URL = "http://localhost:8083/" -PORT = 8083 - -[auditordb-postgres] -CONFIG = "postgres:///talercheck" - -[exchange-account-1] -# What is the URL of our account? -PAYTO_URI = "payto://x-taler-bank/localhost/42?receiver-name=42" - -[exchange-accountcredentials-1] -WIRE_GATEWAY_URL = "http://localhost:9081/42/" -WIRE_GATEWAY_AUTH_METHOD = NONE - -[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_URL = "http://localhost:8082/2/" -WIRE_GATEWAY_AUTH_METHOD = BASIC -USERNAME = user -PASSWORD = pass - -[bank] -HTTP_PORT = 8082 - -[twister] -# HTTP listen port for twister -HTTP_PORT = 8888 -SERVE = tcp - -# HTTP Destination for twister. The test-Webserver needs -# to listen on the port used here. Note: no trailing '/'! -DESTINATION_BASE_URL = "http://localhost:8081" - -# Control port for TCP -# PORT = 8889 -HOSTNAME = localhost -ACCEPT_FROM = 127.0.0.1; -ACCEPT_FROM6 = ::1; - -# Control port for UNIX -UNIXPATH = /tmp/taler-service-twister.sock -UNIX_MATCH_UID = NO -UNIX_MATCH_GID = YES - -# Launching of twister by ARM -# BINARY = taler-service-twister -# AUTOSTART = NO -# FORCESTART = NO - - -[coin_eur_ct_1] -value = EUR:0.01 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.00 -fee_deposit = EUR:0.00 -fee_refresh = EUR:0.01 -fee_refund = EUR:0.01 -CIPHER = CS - -[coin_eur_ct_10] -value = EUR:0.10 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.01 -fee_deposit = EUR:0.01 -fee_refresh = EUR:0.03 -fee_refund = EUR:0.01 -CIPHER = CS - -[coin_eur_1] -value = EUR:1 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.01 -fee_deposit = EUR:0.01 -fee_refresh = EUR:0.03 -fee_refund = EUR:0.01 -CIPHER = CS - -[coin_eur_5] -value = EUR:5 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.01 -fee_deposit = EUR:0.01 -fee_refresh = EUR:0.03 -fee_refund = EUR:0.01 -CIPHER = CS - -[coin_eur_10] -value = EUR:10 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.01 -fee_deposit = EUR:0.01 -fee_refresh = EUR:0.03 -fee_refund = EUR:0.01 -CIPHER = CS diff --git a/src/testing/test_exchange_api_twisted-rsa.conf b/src/testing/test_exchange_api_twisted-rsa.conf index 847d9e1ce..3fd8f4ff1 100644 --- a/src/testing/test_exchange_api_twisted-rsa.conf +++ b/src/testing/test_exchange_api_twisted-rsa.conf @@ -1,156 +1,4 @@ # This file is in the public domain. -[PATHS] -# Persistent data storage for the testcase -TALER_TEST_HOME = test_exchange_api_home/ -TALER_RUNTIME_DIR = ${TMPDIR:-${TMP:-/tmp}}/${USER:-}/taler-system-runtime/ +@INLINE@ test_exchange_api-rsa.conf +@INLINE@ test_exchange_api-twisted.conf -[taler-exchange-secmod-rsa] -# Reduce from 1 year to speed up test -LOOKAHEAD_SIGN = 24 days - -[taler-exchange-secmod-eddsa] -# Reduce from 1 year to speed up test -LOOKAHEAD_SIGN = 24 days -# Reduce from 12 weeks to ensure we have multiple -DURATION = 14 days - -[taler] -# Currency supported by the exchange (can only be one) -CURRENCY = EUR -CURRENCY_ROUND_UNIT = EUR:0.01 - -[exchange] -# HTTP port the exchange listens to -PORT = 8081 - -# Master public key used to sign the exchange's various keys -MASTER_PUBLIC_KEY = 98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG - -# How to access our database -DB = postgres - -# Base URL of the exchange ('S PROXY). This URL is where the -# twister listens at, so that it will be able to get all the -# connection addressed to the exchange. In fact, the presence -# of the twister is 100% transparent to the test case, as it -# only seeks the exchange/BASE_URL URL to connect to the exchange. -BASE_URL = "http://localhost:8888/" - -[exchangedb-postgres] -CONFIG = "postgres:///talercheck" - -[auditor] -BASE_URL = "http://localhost:8083/" -PORT = 8083 - -[auditordb-postgres] -CONFIG = "postgres:///talercheck" - -[exchange-account-1] -# What is the URL of our account? -PAYTO_URI = "payto://x-taler-bank/localhost/42?receiver-name=42" - -[exchange-accountcredentials-1] -WIRE_GATEWAY_URL = "http://localhost:9081/42/" -WIRE_GATEWAY_AUTH_METHOD = NONE - -[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_URL = "http://localhost:8082/2/" -WIRE_GATEWAY_AUTH_METHOD = BASIC -USERNAME = user -PASSWORD = pass - -[bank] -HTTP_PORT = 8082 - -[twister] -# HTTP listen port for twister -HTTP_PORT = 8888 -SERVE = tcp - -# HTTP Destination for twister. The test-Webserver needs -# to listen on the port used here. Note: no trailing '/'! -DESTINATION_BASE_URL = "http://localhost:8081" - -# Control port for TCP -# PORT = 8889 -HOSTNAME = localhost -ACCEPT_FROM = 127.0.0.1; -ACCEPT_FROM6 = ::1; - -# Control port for UNIX -UNIXPATH = /tmp/taler-service-twister.sock -UNIX_MATCH_UID = NO -UNIX_MATCH_GID = YES - -# Launching of twister by ARM -# BINARY = taler-service-twister -# AUTOSTART = NO -# FORCESTART = NO - - -[coin_eur_ct_1] -value = EUR:0.01 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.00 -fee_deposit = EUR:0.00 -fee_refresh = EUR:0.01 -fee_refund = EUR:0.01 -rsa_keysize = 1024 -CIPHER = RSA - - -[coin_eur_ct_10] -value = EUR:0.10 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.01 -fee_deposit = EUR:0.01 -fee_refresh = EUR:0.03 -fee_refund = EUR:0.01 -rsa_keysize = 1024 -CIPHER = RSA - -[coin_eur_1] -value = EUR:1 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.01 -fee_deposit = EUR:0.01 -fee_refresh = EUR:0.03 -fee_refund = EUR:0.01 -rsa_keysize = 1024 -CIPHER = RSA - -[coin_eur_5] -value = EUR:5 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.01 -fee_deposit = EUR:0.01 -fee_refresh = EUR:0.03 -fee_refund = EUR:0.01 -rsa_keysize = 1024 -CIPHER = RSA - -[coin_eur_10] -value = EUR:10 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.01 -fee_deposit = EUR:0.01 -fee_refresh = EUR:0.03 -fee_refund = EUR:0.01 -rsa_keysize = 1024 -CIPHER = RSA diff --git a/src/testing/test_exchange_api_twisted.c b/src/testing/test_exchange_api_twisted.c index 0fb35b45d..75ffe1f15 100644 --- a/src/testing/test_exchange_api_twisted.c +++ b/src/testing/test_exchange_api_twisted.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014-2020 Taler Systems SA + Copyright (C) 2014-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 @@ -44,19 +44,14 @@ static char *config_file; /** - * (real) Twister URL. Used at startup time to check if it runs. + * Our credentials. */ -static char *twister_url; +static struct TALER_TESTING_Credentials cred; /** - * Exchange configuration data. - */ -static struct TALER_TESTING_ExchangeConfiguration ec; - -/** - * Bank configuration data. + * (real) Twister URL. Used at startup time to check if it runs. */ -static struct TALER_TESTING_BankConfiguration bc; +static char *twister_url; /** * Twister process. @@ -73,8 +68,9 @@ static struct GNUNET_OS_Process *twisterd; static struct TALER_TESTING_Command CMD_EXEC_WIREWATCH (const char *label) { - return TALER_TESTING_cmd_exec_wirewatch (label, - config_file); + return TALER_TESTING_cmd_exec_wirewatch2 (label, + config_file, + "exchange-account-2"); } @@ -92,8 +88,8 @@ CMD_TRANSFER_TO_EXCHANGE (const char *label, { return TALER_TESTING_cmd_admin_add_incoming (label, amount, - &bc.exchange_auth, - bc.user42_payto); + &cred.ba, + cred.user42_payto); } @@ -112,8 +108,9 @@ run (void *cls, * response from a refresh-reveal operation. */ struct TALER_TESTING_Command refresh_409_conflict[] = { - CMD_TRANSFER_TO_EXCHANGE ("refresh-create-reserve", - "EUR:5.01"), + CMD_TRANSFER_TO_EXCHANGE ( + "refresh-create-reserve", + "EUR:5.01"), /** * Make previous command effective. */ @@ -121,34 +118,38 @@ run (void *cls, /** * Withdraw EUR:5. */ - TALER_TESTING_cmd_withdraw_amount ("refresh-withdraw-coin", - "refresh-create-reserve", - "EUR:5", - 0, /* age restriction off */ - MHD_HTTP_OK), - TALER_TESTING_cmd_deposit ("refresh-deposit-partial", - "refresh-withdraw-coin", - 0, - bc.user42_payto, - "{\"items\":[{\"name\":\"ice cream\",\ - \"value\":\"EUR:1\"}]}", - GNUNET_TIME_UNIT_ZERO, - "EUR:1", - MHD_HTTP_OK), + TALER_TESTING_cmd_withdraw_amount ( + "refresh-withdraw-coin", + "refresh-create-reserve", + "EUR:5", + 0, /* age restriction off */ + MHD_HTTP_OK), + TALER_TESTING_cmd_deposit ( + "refresh-deposit-partial", + "refresh-withdraw-coin", + 0, + cred.user42_payto, + "{\"items\":[{\"name\":\"ice cream\",\"value\":\"EUR:1\"}]}", + GNUNET_TIME_UNIT_ZERO, + "EUR:1", + MHD_HTTP_OK), /** * Melt the rest of the coin's value * (EUR:4.00 = 3x EUR:1.03 + 7x EUR:0.13) */ - TALER_TESTING_cmd_melt ("refresh-melt", - "refresh-withdraw-coin", - MHD_HTTP_OK, - NULL), + TALER_TESTING_cmd_melt ( + "refresh-melt", + "refresh-withdraw-coin", + MHD_HTTP_OK, + NULL), /* Trigger 409 Conflict. */ - TALER_TESTING_cmd_flip_upload ("flip-upload", - config_file, - "transfer_privs.0"), - TALER_TESTING_cmd_refresh_reveal ("refresh-(flipped-)reveal", - "refresh-melt", - MHD_HTTP_CONFLICT), + TALER_TESTING_cmd_flip_upload ( + "flip-upload", + config_file, + "transfer_privs.0"), + TALER_TESTING_cmd_refresh_reveal ( + "refresh-(flipped-)reveal", + "refresh-melt", + MHD_HTTP_CONFLICT), TALER_TESTING_cmd_end () }; @@ -159,23 +160,25 @@ run (void *cls, * lib test suite. */ struct TALER_TESTING_Command refund[] = { - CMD_TRANSFER_TO_EXCHANGE ("create-reserve-r1", - "EUR:5.01"), + CMD_TRANSFER_TO_EXCHANGE ( + "create-reserve-r1", + "EUR:5.01"), CMD_EXEC_WIREWATCH ("wirewatch-r1"), - TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-r1", - "create-reserve-r1", - "EUR:5", - 0, /* age restriction off */ - MHD_HTTP_OK), - TALER_TESTING_cmd_deposit ("deposit-refund-1", - "withdraw-coin-r1", - 0, - bc.user42_payto, - "{\"items\":[{\"name\":\"ice cream\"," - "\"value\":\"EUR:5\"}]}", - GNUNET_TIME_UNIT_MINUTES, - "EUR:5", - MHD_HTTP_OK), + TALER_TESTING_cmd_withdraw_amount ( + "withdraw-coin-r1", + "create-reserve-r1", + "EUR:5", + 0, /* age restriction off */ + MHD_HTTP_OK), + TALER_TESTING_cmd_deposit ( + "deposit-refund-1", + "withdraw-coin-r1", + 0, + cred.user42_payto, + "{\"items\":[{\"name\":\"ice cream\",\"value\":\"EUR:5\"}]}", + GNUNET_TIME_UNIT_MINUTES, + "EUR:5", + MHD_HTTP_OK), TALER_TESTING_cmd_refund ("refund-currency-mismatch", MHD_HTTP_BAD_REQUEST, "USD:5", @@ -190,18 +193,18 @@ run (void *cls, /* This next deposit CMD is only used to provide a * good merchant signature to the next (failing) refund * operations. */ - TALER_TESTING_cmd_deposit ("deposit-refund-to-fail", - "withdraw-coin-r1", - 0, /* coin index. */ - bc.user42_payto, - /* This parameter will make any comparison about - h_contract_terms fail, when /refund will be handled. - So in other words, this is h_contract mismatch. */ - "{\"items\":[{\"name\":\"ice skate\"," - "\"value\":\"EUR:5\"}]}", - GNUNET_TIME_UNIT_MINUTES, - "EUR:5", - MHD_HTTP_CONFLICT), + TALER_TESTING_cmd_deposit ( + "deposit-refund-to-fail", + "withdraw-coin-r1", + 0, /* coin index. */ + cred.user42_payto, + /* This parameter will make any comparison about + h_contract_terms fail, when /refund will be handled. + So in other words, this is h_contract mismatch. */ + "{\"items\":[{\"name\":\"ice skate\",\"value\":\"EUR:5\"}]}", + GNUNET_TIME_UNIT_MINUTES, + "EUR:5", + MHD_HTTP_CONFLICT), TALER_TESTING_cmd_refund ("refund-deposit-not-found", MHD_HTTP_NOT_FOUND, "EUR:5", @@ -219,10 +222,11 @@ run (void *cls, * are out of date. */ struct TALER_TESTING_Command expired_keys[] = { - TALER_TESTING_cmd_modify_header_dl ("modify-expiration", - config_file, - MHD_HTTP_HEADER_EXPIRES, - "Wed, 19 Jan 586524 08:01:49 GMT"), + TALER_TESTING_cmd_modify_header_dl ( + "modify-expiration", + config_file, + MHD_HTTP_HEADER_EXPIRES, + "Wed, 19 Jan 586524 08:01:49 GMT"), TALER_TESTING_cmd_check_keys_pull_all_keys ( "check-keys-expiration-0", 2), @@ -232,28 +236,35 @@ run (void *cls, CMD_TRANSFER_TO_EXCHANGE ("create-reserve-r2", "EUR:55.01"), CMD_EXEC_WIREWATCH ("wirewatch-r2"), - TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-r2", - "create-reserve-r2", - "EUR:5", - 0, /* age restriction off */ - MHD_HTTP_OK), + TALER_TESTING_cmd_withdraw_amount ( + "withdraw-coin-r2", + "create-reserve-r2", + "EUR:5", + 0, /* age restriction off */ + MHD_HTTP_OK), TALER_TESTING_cmd_end () }; #endif struct TALER_TESTING_Command commands[] = { - TALER_TESTING_cmd_wire_add ("add-wire-account", - "payto://x-taler-bank/localhost/2?receiver-name=2", - MHD_HTTP_NO_CONTENT, - false), - TALER_TESTING_cmd_exec_offline_sign_keys ("offline-sign-future-keys", - config_file), - TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys", - 1), - TALER_TESTING_cmd_batch ("refresh-reveal-409-conflict", - refresh_409_conflict), - TALER_TESTING_cmd_batch ("refund", - refund), + 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 ( + "refresh-reveal-409-conflict", + refresh_409_conflict), + TALER_TESTING_cmd_batch ( + "refund", + refund), #if 0 TALER_TESTING_cmd_batch ("expired-keys", expired_keys), @@ -262,16 +273,15 @@ run (void *cls, }; (void) cls; - TALER_TESTING_run_with_fakebank (is, - commands, - bc.exchange_auth.wire_gateway_url); + TALER_TESTING_run (is, + commands); } /** * Kill, wait, and destroy convenience function. * - * @param process process to purge. + * @param[in] process process to purge. */ static void purge_process (struct GNUNET_OS_Process *process) @@ -287,57 +297,37 @@ int main (int argc, char *const *argv) { - char *cipher; int ret; (void) argc; - /* These environment variables get in the way... */ - unsetenv ("XDG_DATA_HOME"); - unsetenv ("XDG_CONFIG_HOME"); - GNUNET_log_setup (argv[0], - "DEBUG", - NULL); - cipher = GNUNET_TESTING_get_testname_from_underscore (argv[0]); - GNUNET_assert (NULL != cipher); - GNUNET_asprintf (&config_file, - "test_exchange_api_twisted-%s.conf", - cipher); - GNUNET_free (cipher); - if (GNUNET_OK != - TALER_TESTING_prepare_fakebank (config_file, - "exchange-account-2", - &bc)) - return 77; - if (NULL == (twister_url = TALER_TWISTER_prepare_twister - (config_file))) - return 77; - TALER_TESTING_cleanup_files (config_file); - switch (TALER_TESTING_prepare_exchange (config_file, - GNUNET_YES, - &ec)) { - case GNUNET_SYSERR: - GNUNET_break (0); - return 1; - case GNUNET_NO: - return 77; - case GNUNET_OK: - if (NULL == (twisterd = TALER_TWISTER_run_twister (config_file))) - return 77; - ret = TALER_TESTING_setup_with_exchange (&run, - NULL, - config_file); - purge_process (twisterd); - GNUNET_free (twister_url); + char *cipher; - if (GNUNET_OK != ret) - return 1; - break; - default: - GNUNET_break (0); - return 1; + cipher = GNUNET_STRINGS_get_suffix_from_binary_name (argv[0]); + GNUNET_assert (NULL != cipher); + GNUNET_asprintf (&config_file, + "test_exchange_api_twisted-%s.conf", + cipher); + GNUNET_free (cipher); } - return 0; + /* FIXME: introduce commands for twister! */ + twister_url = TALER_TWISTER_prepare_twister (config_file); + if (NULL == twister_url) + return 77; + twisterd = TALER_TWISTER_run_twister (config_file); + if (NULL == twisterd) + return 77; + ret = TALER_TESTING_main (argv, + "INFO", + config_file, + "exchange-account-2", + TALER_TESTING_BS_FAKEBANK, + &cred, + &run, + NULL); + purge_process (twisterd); + GNUNET_free (twister_url); + return ret; } diff --git a/src/testing/test_exchange_management_api.c b/src/testing/test_exchange_management_api.c index 2bf0af3bd..7cce61b55 100644 --- a/src/testing/test_exchange_management_api.c +++ b/src/testing/test_exchange_management_api.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2020-2022 Taler Systems SA + Copyright (C) 2020-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 @@ -35,16 +35,10 @@ */ static char *config_file; - -/** - * Exchange configuration data. - */ -static struct TALER_TESTING_ExchangeConfiguration ec; - /** - * Bank configuration data. + * Our credentials. */ -static struct TALER_TESTING_BankConfiguration bc; +static struct TALER_TESTING_Credentials cred; /** @@ -58,10 +52,21 @@ run (void *cls, struct TALER_TESTING_Interpreter *is) { struct TALER_TESTING_Command commands[] = { - /* this currently fails, because the - auditor is already added by the test setup logic */ - TALER_TESTING_cmd_auditor_del ("del-auditor-NOT-FOUND", - MHD_HTTP_NOT_FOUND, + TALER_TESTING_cmd_system_start ("start-taler", + config_file, + "-u", "exchange-account-2", + "-ae", + NULL), + TALER_TESTING_cmd_get_exchange ("get-exchange", + cred.cfg, + NULL, + true, + true), + TALER_TESTING_cmd_get_auditor ("get-auditor", + cred.cfg, + true), + TALER_TESTING_cmd_auditor_del ("del-auditor-FROM-SETUP", + MHD_HTTP_NO_CONTENT, false), TALER_TESTING_cmd_auditor_add ("add-auditor-BAD-SIG", MHD_HTTP_FORBIDDEN, @@ -85,35 +90,30 @@ run (void *cls, "foo-method", "EUR:1", "EUR:5", - "EUR:3", MHD_HTTP_NO_CONTENT, false), TALER_TESTING_cmd_set_wire_fee ("set-fee-conflicting", "foo-method", "EUR:1", "EUR:1", - "EUR:3", MHD_HTTP_CONFLICT, false), TALER_TESTING_cmd_set_wire_fee ("set-fee-bad-signature", "bar-method", "EUR:1", "EUR:1", - "EUR:3", MHD_HTTP_FORBIDDEN, true), TALER_TESTING_cmd_set_wire_fee ("set-fee-other-method", "bar-method", "EUR:1", "EUR:1", - "EUR:3", MHD_HTTP_NO_CONTENT, false), TALER_TESTING_cmd_set_wire_fee ("set-fee-idempotent", "bar-method", "EUR:1", "EUR:1", - "EUR:3", MHD_HTTP_NO_CONTENT, false), TALER_TESTING_cmd_wire_add ("add-wire-account", @@ -146,15 +146,22 @@ run (void *cls, false), TALER_TESTING_cmd_exec_offline_sign_keys ("download-future-keys", config_file), - TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys", - 1), + TALER_TESTING_cmd_get_exchange ("get-exchange-1", + cred.cfg, + "get-exchange", + true, + true), + TALER_TESTING_cmd_get_exchange ("get-exchange-2", + cred.cfg, + NULL, + true, + true), TALER_TESTING_cmd_end () }; (void) cls; - TALER_TESTING_run_with_fakebank (is, - commands, - bc.exchange_auth.wire_gateway_url); + TALER_TESTING_run (is, + commands); } @@ -162,56 +169,25 @@ int main (int argc, char *const *argv) { - char *cipher; - (void) argc; - /* These environment variables get in the way... */ - unsetenv ("XDG_DATA_HOME"); - unsetenv ("XDG_CONFIG_HOME"); - GNUNET_log_setup (argv[0], - "INFO", - NULL); - /* Check fakebank port is available and get config */ - cipher = GNUNET_TESTING_get_testname_from_underscore (argv[0]); - GNUNET_assert (NULL != cipher); - GNUNET_asprintf (&config_file, - "test_exchange_api-%s.conf", - cipher); - GNUNET_free (cipher); - if (GNUNET_OK != - TALER_TESTING_prepare_fakebank (config_file, - "exchange-account-2", - &bc)) - return 77; - TALER_TESTING_cleanup_files (config_file); - /* @helpers. Create tables, ... Note: it - * fetches the port number from config in order to see - * if it's available. */ - switch (TALER_TESTING_prepare_exchange (config_file, - GNUNET_YES, /* reset DB? */ - &ec)) { - case GNUNET_SYSERR: - GNUNET_break (0); - return 1; - case GNUNET_NO: - return 77; - case GNUNET_OK: - if (GNUNET_OK != - /* Set up event loop and reschedule context, plus - * start/stop the exchange. It calls TALER_TESTING_setup - * which creates the 'is' object. - */ - TALER_TESTING_setup_with_exchange (&run, - NULL, - config_file)) - return 1; - break; - default: - GNUNET_break (0); - return 1; + char *cipher; + + cipher = GNUNET_STRINGS_get_suffix_from_binary_name (argv[0]); + GNUNET_assert (NULL != cipher); + GNUNET_asprintf (&config_file, + "test_exchange_api-%s.conf", + cipher); + GNUNET_free (cipher); } - return 0; + return TALER_TESTING_main (argv, + "INFO", + config_file, + "exchange-account-2", + TALER_TESTING_BS_FAKEBANK, + &cred, + &run, + NULL); } diff --git a/src/testing/test_exchange_p2p.c b/src/testing/test_exchange_p2p.c index ba6d5bbf2..093730ff2 100644 --- a/src/testing/test_exchange_p2p.c +++ b/src/testing/test_exchange_p2p.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014--2022 Taler Systems SA + Copyright (C) 2014--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 @@ -20,13 +20,9 @@ * @file testing/test_exchange_p2p.c * @brief testcase to test exchange's P2P payments * @author Christian Grothoff - * - * TODO: - * - Test setup with KYC where purse merge is only - * allowed for reserves with KYC completed. - * - Test purse creation with reserve purse quota */ #include "platform.h" +#include "taler_attributes.h" #include "taler_util.h" #include "taler_signatures.h" #include "taler_exchange_service.h" @@ -46,18 +42,13 @@ static char *config_file; /** - * Exchange configuration data. - */ -static struct TALER_TESTING_ExchangeConfiguration ec; - -/** - * Bank configuration data. + * Our credentials. */ -static struct TALER_TESTING_BankConfiguration bc; +struct TALER_TESTING_Credentials cred; /** * Some tests behave differently when using CS as we cannot - * re-use the coin private key for different denominations + * 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. @@ -71,7 +62,7 @@ static bool uses_cs; * @param label label to use for the command. */ #define CMD_EXEC_WIREWATCH(label) \ - TALER_TESTING_cmd_exec_wirewatch (label, config_file) + TALER_TESTING_cmd_exec_wirewatch2 (label, config_file, "exchange-account-2") /** * Execute the taler-exchange-aggregator, closer and transfer commands with @@ -94,8 +85,8 @@ static bool uses_cs; */ #define CMD_TRANSFER_TO_EXCHANGE(label,amount) \ TALER_TESTING_cmd_admin_add_incoming (label, amount, \ - &bc.exchange_auth, \ - bc.user42_payto) + &cred.ba, \ + cred.user42_payto) /** * Main function that will tell the interpreter what commands to @@ -126,13 +117,13 @@ run (void *cls, MHD_HTTP_OK), TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-reserve-1", "EUR:5.04", - bc.user42_payto, - bc.exchange_payto, + cred.user42_payto, + cred.exchange_payto, "create-reserve-1"), TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-reserve-2", "EUR:5.01", - bc.user42_payto, - bc.exchange_payto, + cred.user42_payto, + cred.exchange_payto, "create-reserve-2"), /** * Make a reserve exist, according to the previous @@ -161,7 +152,7 @@ run (void *cls, }; struct TALER_TESTING_Command push[] = { TALER_TESTING_cmd_purse_create_with_deposit ( - "purse-with-deposit", + "purse-with-deposit-for-delete", MHD_HTTP_OK, "{\"amount\":\"EUR:1\",\"summary\":\"ice cream\"}", true, /* upload contract */ @@ -169,11 +160,24 @@ run (void *cls, "withdraw-coin-1", "EUR:1.01", NULL), + TALER_TESTING_cmd_purse_delete ( + "purse-with-deposit-delete", + MHD_HTTP_NO_CONTENT, + "purse-with-deposit-for-delete"), + TALER_TESTING_cmd_purse_create_with_deposit ( + "purse-with-deposit", + MHD_HTTP_OK, + "{\"amount\":\"EUR:0.99\",\"summary\":\"ice cream\"}", + true, /* upload contract */ + GNUNET_TIME_UNIT_MINUTES, /* expiration */ + "withdraw-coin-1", + "EUR:1.00", + NULL), TALER_TESTING_cmd_purse_poll ( "push-poll-purse-before-merge", MHD_HTTP_OK, "purse-with-deposit", - "EUR:1", + "EUR:0.99", true, GNUNET_TIME_UNIT_MINUTES), TALER_TESTING_cmd_contract_get ( @@ -195,13 +199,13 @@ run (void *cls, TALER_TESTING_cmd_status ( "push-check-post-merge-reserve-balance-get", "create-reserve-1", - "EUR:1.03", + "EUR:1.02", MHD_HTTP_OK), /* POST history doesn't yet support P2P transfers */ - TALER_TESTING_cmd_reserve_status ( + TALER_TESTING_cmd_reserve_history ( "push-check-post-merge-reserve-balance-post", "create-reserve-1", - "EUR:1.03", + "EUR:1.02", MHD_HTTP_OK), /* Test conflicting merge */ TALER_TESTING_cmd_purse_merge ( @@ -218,6 +222,7 @@ run (void *cls, MHD_HTTP_OK, "{\"amount\":\"EUR:1\",\"summary\":\"ice cream\"}", true /* upload contract */, + true /* pay purse fee */, GNUNET_TIME_UNIT_MINUTES, /* expiration */ "create-reserve-1"), TALER_TESTING_cmd_contract_get ( @@ -251,18 +256,26 @@ run (void *cls, "create-reserve-1", "EUR:2.02", MHD_HTTP_OK), - /* POST history doesn't yet support P2P transfers */ - TALER_TESTING_cmd_reserve_status ( + TALER_TESTING_cmd_reserve_history ( "push-check-post-merge-reserve-balance-post", "create-reserve-1", "EUR:2.02", MHD_HTTP_OK), + TALER_TESTING_cmd_purse_deposit_coins ( + "purse-deposit-coins-idempotent", + MHD_HTTP_OK, + 0 /* min age */, + "purse-create-with-reserve", + "withdraw-coin-1", + "EUR:1.01", + NULL), /* create 2nd purse for a deposit conflict */ TALER_TESTING_cmd_purse_create_with_reserve ( "purse-create-with-reserve-2", MHD_HTTP_OK, "{\"amount\":\"EUR:4\",\"summary\":\"beer\"}", true /* upload contract */, + true /* pay purse fee */, GNUNET_TIME_UNIT_MINUTES, /* expiration */ "create-reserve-1"), TALER_TESTING_cmd_purse_deposit_coins ( @@ -282,6 +295,7 @@ run (void *cls, MHD_HTTP_OK, "{\"amount\":\"EUR:2\",\"summary\":\"ice cream\"}", true /* upload contract */, + true /* pay purse fee */, GNUNET_TIME_relative_multiply ( GNUNET_TIME_UNIT_SECONDS, 1), /* expiration */ @@ -356,37 +370,143 @@ run (void *cls, NULL), TALER_TESTING_cmd_end () }; + struct TALER_TESTING_Command reserves[] = { + CMD_TRANSFER_TO_EXCHANGE ("create-reserve-100", + "EUR:1.04"), + TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-reserve-100", + "EUR:1.04", + cred.user42_payto, + cred.exchange_payto, + "create-reserve-100"), + CMD_TRANSFER_TO_EXCHANGE ("create-reserve-101", + "EUR:1.04"), + TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-reserve-101", + "EUR:1.04", + cred.user42_payto, + cred.exchange_payto, + "create-reserve-101"), + CMD_EXEC_WIREWATCH ("wirewatch-100"), + TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-100", + "create-reserve-100", + "EUR:1", + 0, /* age restriction off */ + MHD_HTTP_OK), + TALER_TESTING_cmd_reserve_open ("reserve-open-101-fail", + "create-reserve-101", + "EUR:0", + GNUNET_TIME_UNIT_YEARS, + 5, /* min purses */ + MHD_HTTP_PAYMENT_REQUIRED, + NULL, + NULL), + TALER_TESTING_cmd_reserve_open ("reserve-open-101-ok-a", + "create-reserve-101", + "EUR:0.01", + GNUNET_TIME_UNIT_MONTHS, + 1, /* min purses */ + MHD_HTTP_OK, + NULL, + NULL), + TALER_TESTING_cmd_status ("status-101-open-paid", + "create-reserve-101", + "EUR:1.03", + MHD_HTTP_OK), + TALER_TESTING_cmd_reserve_open ("reserve-open-101-ok-b", + "create-reserve-101", + "EUR:0", + GNUNET_TIME_UNIT_MONTHS, + 2, /* min purses */ + MHD_HTTP_OK, + "withdraw-coin-100", + "EUR:0.03", /* 0.02 for the reserve open, 0.01 for deposit fee */ + NULL, + NULL), + /* Use purse creation with purse quota here */ + TALER_TESTING_cmd_purse_create_with_reserve ( + "purse-create-with-reserve-101-a", + MHD_HTTP_OK, + "{\"amount\":\"EUR:1\",\"summary\":\"ice cream\"}", + true /* upload contract */, + false /* pay purse fee */, + GNUNET_TIME_UNIT_MINUTES, /* expiration */ + "create-reserve-101"), + TALER_TESTING_cmd_purse_create_with_reserve ( + "purse-create-with-reserve-101-b", + MHD_HTTP_OK, + "{\"amount\":\"EUR:1\",\"summary\":\"ice cream\"}", + true /* upload contract */, + false /* pay purse fee */, + GNUNET_TIME_UNIT_MINUTES, /* expiration */ + "create-reserve-101"), + TALER_TESTING_cmd_purse_create_with_reserve ( + "purse-create-with-reserve-101-fail", + MHD_HTTP_CONFLICT, + "{\"amount\":\"EUR:1\",\"summary\":\"ice cream\"}", + true /* upload contract */, + false /* pay purse fee */, + GNUNET_TIME_UNIT_MINUTES, /* expiration */ + "create-reserve-101"), + TALER_TESTING_cmd_reserve_get_attestable ("reserve-101-attestable", + "create-reserve-101", + MHD_HTTP_NOT_FOUND, + NULL), + TALER_TESTING_cmd_reserve_get_attestable ("reserve-101-attest", + "create-reserve-101", + MHD_HTTP_NOT_FOUND, + "nx-attribute-name", + NULL), + TALER_TESTING_cmd_oauth ("start-oauth-service", + 6666), + TALER_TESTING_cmd_reserve_close ("reserve-101-close-kyc", + "create-reserve-101", + /* 42b => not to origin */ + "payto://x-taler-bank/localhost/42?receiver-name=42b", + MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS), + + TALER_TESTING_cmd_check_kyc_get ("check-kyc-close-pending", + "reserve-101-close-kyc", + MHD_HTTP_ACCEPTED), + TALER_TESTING_cmd_proof_kyc_oauth2 ("proof-close-kyc", + "reserve-101-close-kyc", + "kyc-provider-test-oauth2", + "pass", + MHD_HTTP_SEE_OTHER), + TALER_TESTING_cmd_check_kyc_get ("check-kyc-close-ok", + "reserve-101-close-kyc", + MHD_HTTP_NO_CONTENT), + /* Now it should pass */ + TALER_TESTING_cmd_reserve_close ("reserve-101-close", + "create-reserve-101", + /* 42b => not to origin */ + "payto://x-taler-bank/localhost/42?receiver-name=42b", + MHD_HTTP_OK), + TALER_TESTING_cmd_exec_closer ("close-reserves-101", + config_file, + "EUR:1.02", + "EUR:0.01", + "create-reserve-101"), + TALER_TESTING_cmd_exec_transfer ("close-reserves-101-transfer", + config_file), + TALER_TESTING_cmd_status ("reserve-101-closed-status", + "create-reserve-101", + "EUR:0", + MHD_HTTP_OK), + TALER_TESTING_cmd_end () + }; struct TALER_TESTING_Command commands[] = { - /* setup exchange */ - TALER_TESTING_cmd_auditor_add ("add-auditor-OK", - MHD_HTTP_NO_CONTENT, - false), - TALER_TESTING_cmd_exec_offline_sign_extensions ("offline-sign-extensions", - config_file), - TALER_TESTING_cmd_wire_add ("add-wire-account", - "payto://x-taler-bank/localhost/2?receiver-name=2", - MHD_HTTP_NO_CONTENT, - false), - TALER_TESTING_cmd_exec_offline_sign_fees ("offline-sign-wire-fees", - config_file, - "EUR:0.01", - "EUR:0.01", - "EUR:0.01"), - TALER_TESTING_cmd_exec_offline_sign_global_fees ("offline-sign-global-fees", - config_file, - "EUR:0.01", - "EUR:0.01", - "EUR:0.01", - "EUR:0.01", - GNUNET_TIME_UNIT_MINUTES, - GNUNET_TIME_UNIT_MINUTES, - GNUNET_TIME_UNIT_DAYS, - 1), - TALER_TESTING_cmd_exec_offline_sign_keys ("offline-sign-future-keys", - config_file), - TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys", - 1), + 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", withdraw), TALER_TESTING_cmd_batch ("push", @@ -395,14 +515,15 @@ run (void *cls, pull), TALER_TESTING_cmd_batch ("expire", expire), + TALER_TESTING_cmd_batch ("reserves", + reserves), /* End the suite. */ TALER_TESTING_cmd_end () }; (void) cls; - TALER_TESTING_run_with_fakebank (is, - commands, - bc.exchange_auth.wire_gateway_url); + TALER_TESTING_run (is, + commands); } @@ -410,62 +531,26 @@ int main (int argc, char *const *argv) { - char *cipher; - (void) argc; - /* These environment variables get in the way... */ - unsetenv ("XDG_DATA_HOME"); - unsetenv ("XDG_CONFIG_HOME"); - GNUNET_log_setup (argv[0], - "INFO", - NULL); - - GNUNET_assert (GNUNET_OK == - TALER_extension_age_restriction_register ()); - - cipher = GNUNET_TESTING_get_testname_from_underscore (argv[0]); - GNUNET_assert (NULL != cipher); - uses_cs = (0 == strcmp (cipher, "cs")); - GNUNET_asprintf (&config_file, - "test_exchange_api-%s.conf", - cipher); - GNUNET_free (cipher); - - /* Check fakebank port is available and get config */ - if (GNUNET_OK != - TALER_TESTING_prepare_fakebank (config_file, - "exchange-account-2", - &bc)) - return 77; - TALER_TESTING_cleanup_files (config_file); - /* @helpers. Run keyup, create tables, ... Note: it - * fetches the port number from config in order to see - * if it's available. */ - switch (TALER_TESTING_prepare_exchange (config_file, - GNUNET_YES, - &ec)) { - case GNUNET_SYSERR: - GNUNET_break (0); - return 1; - case GNUNET_NO: - return 78; - case GNUNET_OK: - if (GNUNET_OK != - /* Set up event loop and reschedule context, plus - * start/stop the exchange. It calls TALER_TESTING_setup - * which creates the 'is' object. - */ - TALER_TESTING_setup_with_exchange (&run, - NULL, - config_file)) - return 2; - break; - default: - GNUNET_break (0); - return 3; + 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-%s.conf", + cipher); + GNUNET_free (cipher); } - return 0; + return TALER_TESTING_main (argv, + "INFO", + config_file, + "exchange-account-2", + TALER_TESTING_BS_FAKEBANK, + &cred, + &run, + NULL); } diff --git a/src/testing/test_kyc_api.c b/src/testing/test_kyc_api.c index cfd793a69..0844c5818 100644 --- a/src/testing/test_kyc_api.c +++ b/src/testing/test_kyc_api.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014-2022 Taler Systems SA + Copyright (C) 2014-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 @@ -23,6 +23,7 @@ */ #include "platform.h" #include "taler_util.h" +#include "taler_attributes.h" #include "taler_signatures.h" #include "taler_exchange_service.h" #include "taler_json_lib.h" @@ -40,14 +41,10 @@ #define CONFIG_FILE "test_kyc_api.conf" /** - * Exchange configuration data. + * Our credentials. */ -static struct TALER_TESTING_ExchangeConfiguration ec; +struct TALER_TESTING_Credentials cred; -/** - * Bank configuration data. - */ -static struct TALER_TESTING_BankConfiguration bc; /** * Execute the taler-exchange-wirewatch command with @@ -56,7 +53,7 @@ static struct TALER_TESTING_BankConfiguration bc; * @param label label to use for the command. */ #define CMD_EXEC_WIREWATCH(label) \ - TALER_TESTING_cmd_exec_wirewatch (label, CONFIG_FILE) + TALER_TESTING_cmd_exec_wirewatch2 (label, CONFIG_FILE, "exchange-account-2") /** * Execute the taler-exchange-aggregator, closer and transfer commands with @@ -78,8 +75,8 @@ static struct TALER_TESTING_BankConfiguration bc; */ #define CMD_TRANSFER_TO_EXCHANGE(label,amount) \ TALER_TESTING_cmd_admin_add_incoming (label, amount, \ - &bc.exchange_auth, \ - bc.user42_payto) + &cred.ba, \ + cred.user42_payto) /** * Main function that will tell the interpreter what commands to @@ -91,15 +88,14 @@ static void run (void *cls, struct TALER_TESTING_Interpreter *is) { - /** - * Test withdraw. - */ struct TALER_TESTING_Command withdraw[] = { CMD_TRANSFER_TO_EXCHANGE ("create-reserve-1", "EUR:15.02"), TALER_TESTING_cmd_check_bank_admin_transfer ( "check-create-reserve-1", - "EUR:15.02", bc.user42_payto, bc.exchange_payto, + "EUR:15.02", + cred.user42_payto, + cred.exchange_payto, "create-reserve-1"), CMD_EXEC_WIREWATCH ("wirewatch-1"), TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-1-no-kyc", @@ -124,17 +120,25 @@ run (void *cls, "EUR:5", 0, /* age restriction off */ MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS), + TALER_TESTING_cmd_check_kyc_get ("check-kyc-withdraw", + "withdraw-coin-1-lacking-kyc", + MHD_HTTP_ACCEPTED), TALER_TESTING_cmd_proof_kyc_oauth2 ("proof-kyc", - "create-reserve-1", + "withdraw-coin-1-lacking-kyc", "kyc-provider-test-oauth2", "pass", - "state", MHD_HTTP_SEE_OTHER), TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-1-with-kyc", "create-reserve-1", "EUR:5", 0, /* age restriction off */ MHD_HTTP_OK), + /* Attestations above are bound to the originating *bank* account, + not to the reserve (!). Hence, they are NOT found here! */ + TALER_TESTING_cmd_reserve_get_attestable ("reserve-get-attestable", + "create-reserve-1", + MHD_HTTP_NOT_FOUND, + NULL), TALER_TESTING_cmd_end () }; struct TALER_TESTING_Command spend[] = { @@ -142,7 +146,7 @@ run (void *cls, "deposit-simple", "withdraw-coin-1", 0, - bc.user43_payto, + cred.user43_payto, "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", GNUNET_TIME_UNIT_ZERO, "EUR:5", @@ -172,7 +176,6 @@ run (void *cls, "track-deposit-kyc-ready", "kyc-provider-test-oauth2", "bad", - "state", MHD_HTTP_BAD_GATEWAY), TALER_TESTING_cmd_oauth ("start-oauth-service", 6666), @@ -180,63 +183,358 @@ run (void *cls, "track-deposit-kyc-ready", "kyc-provider-test-oauth2", "bad", - "state", MHD_HTTP_FORBIDDEN), - TALER_TESTING_cmd_proof_kyc_oauth2 ("proof-kyc-fail", + TALER_TESTING_cmd_check_kyc_get ("check-kyc-deposit-again", + "track-deposit-kyc-ready", + MHD_HTTP_ACCEPTED), + TALER_TESTING_cmd_proof_kyc_oauth2 ("proof-kyc-pass", "track-deposit-kyc-ready", "kyc-provider-test-oauth2", "pass", - "state", MHD_HTTP_SEE_OTHER), CMD_EXEC_AGGREGATOR ("run-aggregator-after-kyc"), TALER_TESTING_cmd_check_bank_transfer ( "check_bank_transfer-499c", - ec.exchange_url, + cred.exchange_url, "EUR:4.98", - bc.exchange_payto, - bc.user43_payto), + cred.exchange_payto, + cred.user43_payto), TALER_TESTING_cmd_check_bank_empty ("check_bank_empty"), TALER_TESTING_cmd_end () }; struct TALER_TESTING_Command wallet_kyc[] = { - TALER_TESTING_cmd_oauth ("start-oauth-service", - 6666), - TALER_TESTING_cmd_wallet_kyc_get ( - "wallet-kyc-fail", - NULL, - "EUR:1000000", - MHD_HTTP_OK), + TALER_TESTING_cmd_wallet_kyc_get ("wallet-kyc-fail", + NULL, + "EUR:1000000", + MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS), + TALER_TESTING_cmd_check_kyc_get ("check-kyc-wallet", + "wallet-kyc-fail", + MHD_HTTP_ACCEPTED), TALER_TESTING_cmd_proof_kyc_oauth2 ("proof-wallet-kyc", "wallet-kyc-fail", "kyc-provider-test-oauth2", "pass", - "state", MHD_HTTP_SEE_OTHER), - TALER_TESTING_cmd_check_kyc_get ( - "wallet-kyc-check", - "wallet-kyc-fail", + TALER_TESTING_cmd_check_kyc_get ("wallet-kyc-check", + "wallet-kyc-fail", + MHD_HTTP_NO_CONTENT), + TALER_TESTING_cmd_reserve_get_attestable ("wallet-get-attestable", + "wallet-kyc-fail", + MHD_HTTP_OK, + TALER_ATTRIBUTE_FULL_NAME, + NULL), + TALER_TESTING_cmd_reserve_attest ("wallet-get-attest", + "wallet-kyc-fail", + MHD_HTTP_OK, + TALER_ATTRIBUTE_FULL_NAME, + NULL), + TALER_TESTING_cmd_end () + }; + + /** + * Test withdrawal for P2P + */ + struct TALER_TESTING_Command p2p_withdraw[] = { + /** + * Move money to the exchange's bank account. + */ + CMD_TRANSFER_TO_EXCHANGE ("p2p_create-reserve-1", + "EUR:5.04"), + CMD_TRANSFER_TO_EXCHANGE ("p2p_create-reserve-2", + "EUR:5.01"), + CMD_TRANSFER_TO_EXCHANGE ("p2p_create-reserve-3", + "EUR:0.03"), + TALER_TESTING_cmd_reserve_poll ("p2p_poll-reserve-1", + "p2p_create-reserve-1", + "EUR:5.04", + GNUNET_TIME_UNIT_MINUTES, + MHD_HTTP_OK), + TALER_TESTING_cmd_check_bank_admin_transfer ("p2p_check-create-reserve-1", + "EUR:5.04", + cred.user42_payto, + cred.exchange_payto, + "p2p_create-reserve-1"), + TALER_TESTING_cmd_check_bank_admin_transfer ("p2p_check-create-reserve-2", + "EUR:5.01", + cred.user42_payto, + cred.exchange_payto, + "p2p_create-reserve-2"), + /** + * Make a reserve exist, according to the previous + * transfer. + */ + CMD_EXEC_WIREWATCH ("p2p_wirewatch-1"), + TALER_TESTING_cmd_reserve_poll_finish ("p2p_finish-poll-reserve-1", + GNUNET_TIME_UNIT_SECONDS, + "p2p_poll-reserve-1"), + /** + * Withdraw EUR:5. + */ + TALER_TESTING_cmd_withdraw_amount ("p2p_withdraw-coin-1", + "p2p_create-reserve-1", + "EUR:5", + 0, /* age restriction off */ + MHD_HTTP_OK), + /** + * Check the reserve is depleted. + */ + TALER_TESTING_cmd_status ("p2p_status-1", + "p2p_create-reserve-1", + "EUR:0.03", + MHD_HTTP_OK), + TALER_TESTING_cmd_end () + }; + struct TALER_TESTING_Command push[] = { + TALER_TESTING_cmd_purse_create_with_deposit ( + "purse-with-deposit", + MHD_HTTP_OK, + "{\"amount\":\"EUR:1\",\"summary\":\"ice cream\"}", + true, /* upload contract */ + GNUNET_TIME_UNIT_MINUTES, /* expiration */ + "p2p_withdraw-coin-1", + "EUR:1.01", + NULL), + TALER_TESTING_cmd_coin_history ("coin-history-purse-with-deposit", + "p2p_withdraw-coin-1#0", + "EUR:3.99", + MHD_HTTP_OK), + TALER_TESTING_cmd_purse_poll ( + "push-poll-purse-before-merge", + MHD_HTTP_OK, + "purse-with-deposit", + "EUR:1", + true, + GNUNET_TIME_UNIT_MINUTES), + TALER_TESTING_cmd_contract_get ( + "push-get-contract", + MHD_HTTP_OK, + true, /* for merge */ + "purse-with-deposit"), + TALER_TESTING_cmd_purse_merge ( + "purse-merge-into-reserve", + MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS, + "push-get-contract", + "p2p_create-reserve-1"), + TALER_TESTING_cmd_check_kyc_get ("check-kyc-purse-merge", + "purse-merge-into-reserve", + MHD_HTTP_ACCEPTED), + TALER_TESTING_cmd_proof_kyc_oauth2 ("p2p_proof-kyc", + "purse-merge-into-reserve", + "kyc-provider-test-oauth2", + "pass", + MHD_HTTP_SEE_OTHER), + TALER_TESTING_cmd_purse_merge ( + "purse-merge-into-reserve", + MHD_HTTP_OK, + "push-get-contract", + "p2p_create-reserve-1"), + TALER_TESTING_cmd_purse_poll_finish ( + "push-merge-purse-poll-finish", + GNUNET_TIME_relative_multiply ( + GNUNET_TIME_UNIT_SECONDS, + 5), + "push-poll-purse-before-merge"), + TALER_TESTING_cmd_status ( + "push-check-post-merge-reserve-balance-get", + "p2p_create-reserve-1", + "EUR:1.03", + MHD_HTTP_OK), + TALER_TESTING_cmd_reserve_history ( + "push-check-post-merge-reserve-balance-post", + "p2p_create-reserve-1", + "EUR:1.03", MHD_HTTP_OK), + + TALER_TESTING_cmd_end () + }; + struct TALER_TESTING_Command pull[] = { + TALER_TESTING_cmd_purse_create_with_reserve ( + "purse-create-with-reserve", + MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS, + "{\"amount\":\"EUR:1\",\"summary\":\"ice cream\"}", + true /* upload contract */, + true /* pay purse fee */, + GNUNET_TIME_UNIT_MINUTES, /* expiration */ + "p2p_create-reserve-3"), + TALER_TESTING_cmd_check_kyc_get ("check-kyc-purse-create", + "purse-create-with-reserve", + MHD_HTTP_ACCEPTED), + TALER_TESTING_cmd_proof_kyc_oauth2 ("p2p_proof-kyc-pull", + "purse-create-with-reserve", + "kyc-provider-test-oauth2", + "pass", + MHD_HTTP_SEE_OTHER), + TALER_TESTING_cmd_purse_create_with_reserve ( + "purse-create-with-reserve", + MHD_HTTP_OK, + "{\"amount\":\"EUR:1\",\"summary\":\"ice cream\"}", + true /* upload contract */, + true /* pay purse fee */, + GNUNET_TIME_UNIT_MINUTES, /* expiration */ + "p2p_create-reserve-3"), + TALER_TESTING_cmd_contract_get ( + "pull-get-contract", + MHD_HTTP_OK, + false, /* for deposit */ + "purse-create-with-reserve"), + TALER_TESTING_cmd_purse_poll ( + "pull-poll-purse-before-deposit", + MHD_HTTP_OK, + "purse-create-with-reserve", + "EUR:1", + false, + GNUNET_TIME_UNIT_MINUTES), + TALER_TESTING_cmd_purse_deposit_coins ( + "purse-deposit-coins", + MHD_HTTP_OK, + 0 /* min age */, + "purse-create-with-reserve", + "p2p_withdraw-coin-1", + "EUR:1.01", + NULL), + TALER_TESTING_cmd_coin_history ("coin-history-purse-pull-deposit", + "p2p_withdraw-coin-1#0", + "EUR:2.98", + MHD_HTTP_OK), + TALER_TESTING_cmd_purse_poll_finish ( + "pull-deposit-purse-poll-finish", + GNUNET_TIME_relative_multiply ( + GNUNET_TIME_UNIT_SECONDS, + 5), + "pull-poll-purse-before-deposit"), + TALER_TESTING_cmd_status ( + "pull-check-post-merge-reserve-balance-get-2", + "p2p_create-reserve-3", + "EUR:1.03", + MHD_HTTP_OK), + TALER_TESTING_cmd_reserve_history ( + "push-check-post-merge-reserve-balance-post-2", + "p2p_create-reserve-3", + "EUR:1.03", + MHD_HTTP_OK), + TALER_TESTING_cmd_end () + }; + struct TALER_TESTING_Command aml[] = { + /* Trigger something upon which an AML officer could act */ + TALER_TESTING_cmd_wallet_kyc_get ("wallet-trigger-kyc-for-aml", + NULL, + "EUR:1000", + MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS), + TALER_TESTING_cmd_set_officer ("create-aml-officer-1", + NULL, + "Peter Falk", + true, + false), + TALER_TESTING_cmd_check_aml_decisions ("check-decisions-none-normal", + "create-aml-officer-1", + TALER_AML_NORMAL, + MHD_HTTP_NO_CONTENT), + TALER_TESTING_cmd_check_aml_decisions ("check-decisions-none-pending", + "create-aml-officer-1", + TALER_AML_PENDING, + MHD_HTTP_NO_CONTENT), + TALER_TESTING_cmd_check_aml_decisions ("check-decisions-none-frozen", + "create-aml-officer-1", + TALER_AML_FROZEN, + MHD_HTTP_NO_CONTENT), + TALER_TESTING_cmd_sleep ("sleep-1a", + 1), + TALER_TESTING_cmd_set_officer ("create-aml-officer-1-disable", + "create-aml-officer-1", + "Peter Falk", + true, + true), + /* Test that we are not allowed to take AML decisions as our + AML staff account is on read-only */ + TALER_TESTING_cmd_take_aml_decision ("aml-decide-while-disabled", + "create-aml-officer-1", + "wallet-trigger-kyc-for-aml", + "EUR:10000", + "party time", + TALER_AML_NORMAL, + NULL, + MHD_HTTP_FORBIDDEN), + /* Check that no decision was taken, but that we are allowed + to read this information */ + TALER_TESTING_cmd_check_aml_decision ("check-aml-decision-empty", + "create-aml-officer-1", + "aml-decide-while-disabled", + MHD_HTTP_NO_CONTENT), + TALER_TESTING_cmd_sleep ("sleep-1b", + 1), + TALER_TESTING_cmd_set_officer ("create-aml-officer-1-enable", + "create-aml-officer-1", + "Peter Falk", + true, + false), + TALER_TESTING_cmd_take_aml_decision ("aml-decide", + "create-aml-officer-1", + "wallet-trigger-kyc-for-aml", + "EUR:10000", + "party time", + TALER_AML_NORMAL, + NULL, + MHD_HTTP_NO_CONTENT), + TALER_TESTING_cmd_check_aml_decisions ("check-decisions-one-normal", + "create-aml-officer-1", + TALER_AML_NORMAL, + MHD_HTTP_OK), + TALER_TESTING_cmd_check_aml_decisions ("check-decisions-zero-frozen", + "create-aml-officer-1", + TALER_AML_FROZEN, + MHD_HTTP_NO_CONTENT), + TALER_TESTING_cmd_check_aml_decision ("check-aml-decision", + "create-aml-officer-1", + "aml-decide", + MHD_HTTP_OK), + TALER_TESTING_cmd_sleep ("sleep-1c", + 1), + TALER_TESTING_cmd_take_aml_decision ("aml-decide-freeze", + "create-aml-officer-1", + "wallet-trigger-kyc-for-aml", + "EUR:1000", + "party over", + TALER_AML_FROZEN, + NULL, + MHD_HTTP_NO_CONTENT), + TALER_TESTING_cmd_check_aml_decisions ("check-decisions-one-frozen", + "create-aml-officer-1", + TALER_AML_FROZEN, + MHD_HTTP_OK), + TALER_TESTING_cmd_check_aml_decisions ("check-decisions-zero-normal", + "create-aml-officer-1", + TALER_AML_NORMAL, + MHD_HTTP_NO_CONTENT), + TALER_TESTING_cmd_sleep ("sleep-1d", + 1), + TALER_TESTING_cmd_set_officer ("create-aml-officer-1-disable", + "create-aml-officer-1", + "Peter Falk", + false, + true), + /* Test that we are NOT allowed to read AML decisions now that + our AML staff account is disabled */ + TALER_TESTING_cmd_check_aml_decision ("check-aml-decision-disabled", + "create-aml-officer-1", + "aml-decide", + MHD_HTTP_FORBIDDEN), TALER_TESTING_cmd_end () }; struct TALER_TESTING_Command commands[] = { - TALER_TESTING_cmd_exec_offline_sign_fees ("offline-sign-fees", - CONFIG_FILE, - "EUR:0.01", - "EUR:0.01", - "EUR:0.01"), - TALER_TESTING_cmd_auditor_add ("add-auditor-OK", - MHD_HTTP_NO_CONTENT, - false), - TALER_TESTING_cmd_wire_add ("add-wire-account", - "payto://x-taler-bank/localhost/2?receiver-name=2", - MHD_HTTP_NO_CONTENT, - false), - TALER_TESTING_cmd_exec_offline_sign_keys ("offline-sign-future-keys", - CONFIG_FILE), - TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys", - 2), + 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", withdraw), TALER_TESTING_cmd_batch ("spend", @@ -247,13 +545,20 @@ run (void *cls, withdraw_kyc), TALER_TESTING_cmd_batch ("wallet-kyc", wallet_kyc), + TALER_TESTING_cmd_batch ("p2p_withdraw", + p2p_withdraw), + TALER_TESTING_cmd_batch ("push", + push), + TALER_TESTING_cmd_batch ("pull", + pull), + TALER_TESTING_cmd_batch ("aml", + aml), TALER_TESTING_cmd_end () }; (void) cls; - TALER_TESTING_run_with_fakebank (is, - commands, - bc.exchange_auth.wire_gateway_url); + TALER_TESTING_run (is, + commands); } @@ -262,48 +567,14 @@ main (int argc, char *const *argv) { (void) argc; - (void) argv; - /* These environment variables get in the way... */ - unsetenv ("XDG_DATA_HOME"); - unsetenv ("XDG_CONFIG_HOME"); - GNUNET_log_setup ("test-kyc-api", - "INFO", - NULL); - /* Check fakebank port is available and get configuration data. */ - if (GNUNET_OK != - TALER_TESTING_prepare_fakebank (CONFIG_FILE, - "exchange-account-2", - &bc)) - return 77; - TALER_TESTING_cleanup_files (CONFIG_FILE); - /* @helpers. Run keyup, create tables, ... Note: it - * fetches the port number from config in order to see - * if it's available. */ - switch (TALER_TESTING_prepare_exchange (CONFIG_FILE, - GNUNET_YES, - &ec)) - { - case GNUNET_SYSERR: - GNUNET_break (0); - return 1; - case GNUNET_NO: - return 77; - case GNUNET_OK: - if (GNUNET_OK != - /* Set up event loop and reschedule context, plus - * start/stop the exchange. It calls TALER_TESTING_setup - * which creates the 'is' object. - */ - TALER_TESTING_setup_with_exchange (&run, - NULL, - CONFIG_FILE)) - return 1; - break; - default: - GNUNET_break (0); - return 1; - } - return 0; + return TALER_TESTING_main (argv, + "INFO", + CONFIG_FILE, + "exchange-account-2", + TALER_TESTING_BS_FAKEBANK, + &cred, + &run, + NULL); } diff --git a/src/testing/test_kyc_api.conf b/src/testing/test_kyc_api.conf index 56c8eb858..b6bfdb055 100644 --- a/src/testing/test_kyc_api.conf +++ b/src/testing/test_kyc_api.conf @@ -1,65 +1,7 @@ - # This file is in the public domain. # -[PATHS] -# Persistent data storage for the testcase -TALER_TEST_HOME = test_exchange_api_home/ -TALER_RUNTIME_DIR = ${TMPDIR:-${TMP:-/tmp}}/${USER:-}/taler-system-runtime/ - -[taler-exchange-secmod-rsa] -# Reduce from 1 year to speed up test -LOOKAHEAD_SIGN = 24 days - -[taler-exchange-secmod-eddsa] -# Reduce from 1 year to speed up test -LOOKAHEAD_SIGN = 24 days -# Reduce from 12 weeks to ensure we have multiple -DURATION = 14 days - - -[taler] -# Currency supported by the exchange (can only be one) -CURRENCY = EUR -CURRENCY_ROUND_UNIT = EUR:0.01 - -[auditor] -BASE_URL = "http://localhost:8083/" - -# HTTP port the auditor listens to -PORT = 8083 - -TINY_AMOUNT = EUR:0.01 - -[exchange] - -# HTTP port the exchange listens to -PORT = 8081 - -# Master public key used to sign the exchange's various keys -MASTER_PUBLIC_KEY = 98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG - -# How to access our database -DB = postgres - -# Base URL of the exchange. Must be set to a URL where the -# exchange (or the twister) is actually listening. -BASE_URL = "http://localhost:8081/" - - -# Obsolete options, migrate to withdraw once implemented... -KYC_MODE = OAUTH2 -KYC_WITHDRAW_PERIOD = "31 days" -KYC_WITHDRAW_LIMIT = EUR:8 - -[exchange-kyc-oauth2] -KYC_OAUTH2_AUTH_URL = http://localhost:6666/oauth/v2/token -KYC_OAUTH2_LOGIN_URL = http://localhost:6666/oauth/v2/login -KYC_INFO_URL = http://localhost:6666/api/user/me -KYC_OAUTH2_CLIENT_ID = taler-exchange -KYC_OAUTH2_CLIENT_SECRET = exchange-secret -KYC_OAUTH2_POST_URL = http://example.com/ - -# end of obsolete options... +@INLINE@ coins-rsa.conf +@INLINE@ test_exchange_api.conf [kyc-provider-test-oauth2] COST = 0 @@ -67,12 +9,14 @@ LOGIC = oauth2 USER_TYPE = INDIVIDUAL PROVIDED_CHECKS = DUMMY KYC_OAUTH2_VALIDITY = forever -KYC_OAUTH2_AUTH_URL = http://localhost:6666/oauth/v2/token -KYC_OAUTH2_LOGIN_URL = http://localhost:6666/oauth/v2/login +KYC_OAUTH2_TOKEN_URL = http://localhost:6666/oauth/v2/token +KYC_OAUTH2_AUTHORIZE_URL = http://localhost:6666/oauth/v2/login KYC_OAUTH2_INFO_URL = http://localhost:6666/api/user/me KYC_OAUTH2_CLIENT_ID = taler-exchange KYC_OAUTH2_CLIENT_SECRET = exchange-secret KYC_OAUTH2_POST_URL = http://example.com/ +KYC_OAUTH2_CONVERTER_HELPER = taler-exchange-kyc-oauth2-test-converter.sh +# "{"full_name":"{{last_name}}, {{first_name}}"}" [kyc-legitimization-balance-high] OPERATION_TYPE = BALANCE @@ -88,159 +32,11 @@ TIMEFRAME = 1d [kyc-legitimization-withdraw] OPERATION_TYPE = WITHDRAW REQUIRED_CHECKS = DUMMY -THRESHOLD = EUR:8 +THRESHOLD = EUR:10 TIMEFRAME = 1d -[exchangedb-postgres] -CONFIG = "postgres:///talercheck" - -[auditordb-postgres] -CONFIG = "postgres:///talercheck" - -# Sections starting with "exchange-account-" configure the bank accounts -# of the exchange. The "URL" specifies the account in -# payto://-format. -[exchange-account-1] -# What is the URL of our account? -PAYTO_URI = "payto://x-taler-bank/localhost/42?receiver-name=42" - -[exchange-accountcredentials-1] -WIRE_GATEWAY_URL = "http://localhost:8082/42/" - -[bank] -HTTP_PORT = 8082 - -# ENABLE_CREDIT = YES - -[exchange-account-2] -# What is the bank account (with the "Taler Bank" demo system)? -PAYTO_URI = "payto://x-taler-bank/localhost/2?receiver-name=2" -ENABLE_DEBIT = YES -ENABLE_CREDIT = YES - -# Authentication information for basic authentication -[exchange-accountcredentials-2] -WIRE_GATEWAY_URL = "http://localhost:8082/2/" -WIRE_GATEWAY_AUTH_METHOD = "basic" -USERNAME = user -PASSWORD = pass - - - - -# Sections starting with "coin_" specify which denominations -# the exchange should support (and their respective fee structure) -[coin_eur_ct_1] -value = EUR:0.01 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.00 -fee_deposit = EUR:0.00 -fee_refresh = EUR:0.01 -fee_refund = EUR:0.01 -CIPHER = RSA -rsa_keysize = 1024 - -[coin_eur_ct_2] -value = EUR:0.01 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.00 -fee_deposit = EUR:0.00 -fee_refresh = EUR:0.01 -fee_refund = EUR:0.01 -CIPHER = CS - -[coin_eur_ct_10] -value = EUR:0.10 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.01 -fee_deposit = EUR:0.01 -fee_refresh = EUR:0.03 -fee_refund = EUR:0.01 -CIPHER = RSA -rsa_keysize = 1024 - -[coin_eur_ct_11] -value = EUR:0.10 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.01 -fee_deposit = EUR:0.01 -fee_refresh = EUR:0.03 -fee_refund = EUR:0.01 -CIPHER = CS - -[coin_eur_1] -value = EUR:1 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.01 -fee_deposit = EUR:0.01 -fee_refresh = EUR:0.03 -fee_refund = EUR:0.01 -CIPHER = RSA -rsa_keysize = 1024 - -[coin_eur_2] -value = EUR:1 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.01 -fee_deposit = EUR:0.01 -fee_refresh = EUR:0.03 -fee_refund = EUR:0.01 -CIPHER = CS - -[coin_eur_5] -value = EUR:5 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.01 -fee_deposit = EUR:0.01 -fee_refresh = EUR:0.03 -fee_refund = EUR:0.01 -CIPHER = RSA -rsa_keysize = 1024 - -[coin_eur_6] -value = EUR:5 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.01 -fee_deposit = EUR:0.01 -fee_refresh = EUR:0.03 -fee_refund = EUR:0.01 -CIPHER = CS - -[coin_eur_10] -value = EUR:10 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.01 -fee_deposit = EUR:0.01 -fee_refresh = EUR:0.03 -fee_refund = EUR:0.01 -CIPHER = RSA -rsa_keysize = 1024 - -[coin_eur_11] -value = EUR:10 -duration_withdraw = 7 days -duration_spend = 2 years -duration_legal = 3 years -fee_withdraw = EUR:0.01 -fee_deposit = EUR:0.01 -fee_refresh = EUR:0.03 -fee_refund = EUR:0.01 -CIPHER = CS
\ No newline at end of file +[kyc-legitimization-merge] +OPERATION_TYPE = MERGE +REQUIRED_CHECKS = DUMMY +THRESHOLD = EUR:0 +TIMEFRAME = 1d diff --git a/src/testing/test_taler_exchange_aggregator.c b/src/testing/test_taler_exchange_aggregator.c index d42d59762..2d7acc6dc 100644 --- a/src/testing/test_taler_exchange_aggregator.c +++ b/src/testing/test_taler_exchange_aggregator.c @@ -31,24 +31,9 @@ /** - * Helper structure to keep exchange configuration values. + * Our credentials. */ -static struct TALER_TESTING_ExchangeConfiguration ec; - -/** - * Bank configuration data. - */ -static struct TALER_TESTING_BankConfiguration bc; - -/** - * Contains plugin. - */ -static struct TALER_TESTING_DatabaseConnection dbc; - -/** - * Return value from main(). - */ -static int result; +struct TALER_TESTING_Credentials cred; /** * Name of the configuration file to use. @@ -71,24 +56,6 @@ static char *config_filename; /** - * Function run on shutdown to unload the DB plugin. - * - * @param cls NULL - */ -static void -unload_db (void *cls) -{ - (void) cls; - if (NULL != dbc.plugin) - { - dbc.plugin->drop_tables (dbc.plugin->cls); - TALER_EXCHANGEDB_plugin_unload (dbc.plugin); - dbc.plugin = NULL; - } -} - - -/** * Collects all the tests. */ static void @@ -96,12 +63,13 @@ run (void *cls, struct TALER_TESTING_Interpreter *is) { struct TALER_TESTING_Command all[] = { - TALER_TESTING_cmd_exec_offline_sign_fees ("offline-sign-fees", - config_filename, - "EUR:0.01", - "EUR:0.01", - "EUR:0.01"), - // check no aggregation happens on a empty database + TALER_TESTING_cmd_run_fakebank ("run-fakebank", + cred.cfg, + "exchange-account-1"), + TALER_TESTING_cmd_system_start ("start-taler", + config_filename, + "-e", + NULL), CMD_EXEC_AGGREGATOR ("run-aggregator-on-empty-db", config_filename), TALER_TESTING_cmd_check_bank_empty ("expect-empty-transactions-on-start"), @@ -109,7 +77,7 @@ run (void *cls, /* check aggregation happens on the simplest case: one deposit into the database. */ TALER_TESTING_cmd_insert_deposit ("do-deposit-1", - &dbc, + cred.cfg, "bob", USER42_ACCOUNT, GNUNET_TIME_timestamp_get (), @@ -120,15 +88,15 @@ run (void *cls, config_filename), TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-1", - ec.exchange_url, + cred.exchange_url, "EUR:0.89", - bc.exchange_payto, - bc.user42_payto), + cred.exchange_payto, + cred.user42_payto), TALER_TESTING_cmd_check_bank_empty ("expect-empty-transactions-after-1"), /* check aggregation accumulates well. */ TALER_TESTING_cmd_insert_deposit ("do-deposit-2a", - &dbc, + cred.cfg, "bob", USER42_ACCOUNT, GNUNET_TIME_timestamp_get (), @@ -137,7 +105,7 @@ run (void *cls, "EUR:0.1"), TALER_TESTING_cmd_insert_deposit ("do-deposit-2b", - &dbc, + cred.cfg, "bob", USER42_ACCOUNT, GNUNET_TIME_timestamp_get (), @@ -149,15 +117,15 @@ run (void *cls, config_filename), TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-2", - ec.exchange_url, + cred.exchange_url, "EUR:1.79", - bc.exchange_payto, - bc.user42_payto), + cred.exchange_payto, + cred.user42_payto), TALER_TESTING_cmd_check_bank_empty ("expect-empty-transactions-after-2"), /* check that different merchants stem different aggregations. */ TALER_TESTING_cmd_insert_deposit ("do-deposit-3a", - &dbc, + cred.cfg, "bob", "4", GNUNET_TIME_timestamp_get (), @@ -165,7 +133,7 @@ run (void *cls, "EUR:1", "EUR:0.1"), TALER_TESTING_cmd_insert_deposit ("do-deposit-3b", - &dbc, + cred.cfg, "bob", "5", GNUNET_TIME_timestamp_get (), @@ -173,7 +141,7 @@ run (void *cls, "EUR:1", "EUR:0.1"), TALER_TESTING_cmd_insert_deposit ("do-deposit-3c", - &dbc, + cred.cfg, "alice", "4", GNUNET_TIME_timestamp_get (), @@ -184,25 +152,25 @@ run (void *cls, config_filename), TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-3a", - ec.exchange_url, + cred.exchange_url, "EUR:0.89", - bc.exchange_payto, + cred.exchange_payto, "payto://x-taler-bank/localhost/4?receiver-name=4"), TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-3b", - ec.exchange_url, + cred.exchange_url, "EUR:0.89", - bc.exchange_payto, + cred.exchange_payto, "payto://x-taler-bank/localhost/4?receiver-name=4"), TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-3c", - ec.exchange_url, + cred.exchange_url, "EUR:0.89", - bc.exchange_payto, + cred.exchange_payto, "payto://x-taler-bank/localhost/5?receiver-name=5"), TALER_TESTING_cmd_check_bank_empty ("expect-empty-transactions-after-3"), /* checking that aggregator waits for the deadline. */ TALER_TESTING_cmd_insert_deposit ("do-deposit-4a", - &dbc, + cred.cfg, "bob", USER42_ACCOUNT, GNUNET_TIME_timestamp_get (), @@ -212,7 +180,7 @@ run (void *cls, "EUR:0.2", "EUR:0.1"), TALER_TESTING_cmd_insert_deposit ("do-deposit-4b", - &dbc, + cred.cfg, "bob", USER42_ACCOUNT, GNUNET_TIME_timestamp_get (), @@ -231,14 +199,14 @@ run (void *cls, CMD_EXEC_AGGREGATOR ("run-aggregator-deposit-4-delayed", config_filename), TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-4", - ec.exchange_url, + cred.exchange_url, "EUR:0.19", - bc.exchange_payto, - bc.user42_payto), + cred.exchange_payto, + cred.user42_payto), // test picking all deposits at earliest deadline TALER_TESTING_cmd_insert_deposit ("do-deposit-5a", - &dbc, + cred.cfg, "bob", USER42_ACCOUNT, GNUNET_TIME_timestamp_get (), @@ -249,7 +217,7 @@ run (void *cls, "EUR:0.1"), TALER_TESTING_cmd_insert_deposit ("do-deposit-5b", - &dbc, + cred.cfg, "bob", USER42_ACCOUNT, GNUNET_TIME_timestamp_get (), @@ -268,13 +236,13 @@ run (void *cls, CMD_EXEC_AGGREGATOR ("run-aggregator-deposit-5-delayed", config_filename), TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-5", - ec.exchange_url, + cred.exchange_url, "EUR:0.19", - bc.exchange_payto, - bc.user42_payto), + cred.exchange_payto, + cred.user42_payto), /* Test NEVER running 'tiny' unless they make up minimum unit */ TALER_TESTING_cmd_insert_deposit ("do-deposit-6a", - &dbc, + cred.cfg, "bob", USER42_ACCOUNT, GNUNET_TIME_timestamp_get (), @@ -286,7 +254,7 @@ run (void *cls, TALER_TESTING_cmd_check_bank_empty ( "expect-empty-transactions-after-6a-tiny"), TALER_TESTING_cmd_insert_deposit ("do-deposit-6b", - &dbc, + cred.cfg, "bob", USER42_ACCOUNT, GNUNET_TIME_timestamp_get (), @@ -294,7 +262,7 @@ run (void *cls, "EUR:0.102", "EUR:0.1"), TALER_TESTING_cmd_insert_deposit ("do-deposit-6c", - &dbc, + cred.cfg, "bob", USER42_ACCOUNT, GNUNET_TIME_timestamp_get (), @@ -306,7 +274,7 @@ run (void *cls, TALER_TESTING_cmd_check_bank_empty ( "expect-empty-transactions-after-6c-tiny"), TALER_TESTING_cmd_insert_deposit ("do-deposit-6d", - &dbc, + cred.cfg, "bob", USER42_ACCOUNT, GNUNET_TIME_timestamp_get (), @@ -318,7 +286,7 @@ run (void *cls, TALER_TESTING_cmd_check_bank_empty ( "expect-empty-transactions-after-6d-tiny"), TALER_TESTING_cmd_insert_deposit ("do-deposit-6e", - &dbc, + cred.cfg, "bob", USER42_ACCOUNT, GNUNET_TIME_timestamp_get (), @@ -328,14 +296,14 @@ run (void *cls, CMD_EXEC_AGGREGATOR ("run-aggregator-deposit-6e", config_filename), TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-6", - ec.exchange_url, + cred.exchange_url, "EUR:0.01", - bc.exchange_payto, - bc.user42_payto), + cred.exchange_payto, + cred.user42_payto), /* Test profiteering if wire deadline is short */ TALER_TESTING_cmd_insert_deposit ("do-deposit-7a", - &dbc, + cred.cfg, "bob", USER42_ACCOUNT, GNUNET_TIME_timestamp_get (), @@ -347,7 +315,7 @@ run (void *cls, TALER_TESTING_cmd_check_bank_empty ( "expect-empty-transactions-after-7a-tiny"), TALER_TESTING_cmd_insert_deposit ("do-deposit-7b", - &dbc, + cred.cfg, "bob", USER42_ACCOUNT, GNUNET_TIME_timestamp_get (), @@ -357,14 +325,14 @@ run (void *cls, CMD_EXEC_AGGREGATOR ("run-aggregator-deposit-7-profit", config_filename), TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-7", - ec.exchange_url, + cred.exchange_url, "EUR:0.01", - bc.exchange_payto, - bc.user42_payto), + cred.exchange_payto, + cred.user42_payto), /* Now check profit was actually taken */ TALER_TESTING_cmd_insert_deposit ("do-deposit-7c", - &dbc, + cred.cfg, "bob", USER42_ACCOUNT, GNUNET_TIME_timestamp_get (), @@ -374,14 +342,14 @@ run (void *cls, CMD_EXEC_AGGREGATOR ("run-aggregator-deposit-7-loss", config_filename), TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-7", - ec.exchange_url, + cred.exchange_url, "EUR:0.01", - bc.exchange_payto, - bc.user42_payto), + cred.exchange_payto, + cred.user42_payto), /* Test that aggregation would happen fully if wire deadline is long */ TALER_TESTING_cmd_insert_deposit ("do-deposit-8a", - &dbc, + cred.cfg, "bob", USER42_ACCOUNT, GNUNET_TIME_timestamp_get (), @@ -395,7 +363,7 @@ run (void *cls, TALER_TESTING_cmd_check_bank_empty ( "expect-empty-transactions-after-8a-tiny"), TALER_TESTING_cmd_insert_deposit ("do-deposit-8b", - &dbc, + cred.cfg, "bob", USER42_ACCOUNT, GNUNET_TIME_timestamp_get (), @@ -411,7 +379,7 @@ run (void *cls, /* now trigger aggregate with large transaction and short deadline */ TALER_TESTING_cmd_insert_deposit ("do-deposit-8c", - &dbc, + cred.cfg, "bob", USER42_ACCOUNT, GNUNET_TIME_timestamp_get (), @@ -421,14 +389,14 @@ run (void *cls, CMD_EXEC_AGGREGATOR ("run-aggregator-deposit-8", config_filename), TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-8", - ec.exchange_url, + cred.exchange_url, "EUR:0.03", - bc.exchange_payto, - bc.user42_payto), + cred.exchange_payto, + cred.user42_payto), /* Test aggregation with fees and rounding profits. */ TALER_TESTING_cmd_insert_deposit ("do-deposit-9a", - &dbc, + cred.cfg, "bob", USER42_ACCOUNT, GNUNET_TIME_timestamp_get (), @@ -442,7 +410,7 @@ run (void *cls, TALER_TESTING_cmd_check_bank_empty ( "expect-empty-transactions-after-9a-tiny"), TALER_TESTING_cmd_insert_deposit ("do-deposit-9b", - &dbc, + cred.cfg, "bob", USER42_ACCOUNT, GNUNET_TIME_timestamp_get (), @@ -458,7 +426,7 @@ run (void *cls, /* now trigger aggregate with large transaction and short deadline */ TALER_TESTING_cmd_insert_deposit ("do-deposit-9c", - &dbc, + cred.cfg, "bob", USER42_ACCOUNT, GNUNET_TIME_timestamp_get (), @@ -469,49 +437,15 @@ run (void *cls, config_filename), /* 0.009 + 0.009 + 0.022 - 0.001 - 0.002 - 0.008 = 0.029 => 0.02 */ TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-9", - ec.exchange_url, + cred.exchange_url, "EUR:0.01", - bc.exchange_payto, - bc.user42_payto), + cred.exchange_payto, + cred.user42_payto), TALER_TESTING_cmd_end () }; - TALER_TESTING_run_with_fakebank (is, - all, - bc.exchange_auth.wire_gateway_url); -} - - -/** - * Prepare database and launch the test. - * - * @param cls unused - * @param is interpreter to use - */ -static void -prepare_database (void *cls, - struct TALER_TESTING_Interpreter *is) -{ - dbc.plugin = TALER_EXCHANGEDB_plugin_load (is->cfg); - if (NULL == dbc.plugin) - { - GNUNET_break (0); - result = 77; - TALER_TESTING_interpreter_fail (is); - return; - } - if (GNUNET_OK != - dbc.plugin->preflight (dbc.plugin->cls)) - { - GNUNET_break (0); - result = 77; - TALER_TESTING_interpreter_fail (is); - return; - } - GNUNET_SCHEDULER_add_shutdown (&unload_db, - NULL); - run (NULL, - is); + TALER_TESTING_run (is, + all); } @@ -520,7 +454,6 @@ main (int argc, char *const argv[]) { const char *plugin_name; - char *testname; if (NULL == (plugin_name = strrchr (argv[0], (int) '-'))) { @@ -528,52 +461,17 @@ main (int argc, return -1; } plugin_name++; - (void) GNUNET_asprintf (&testname, - "test-taler-exchange-aggregator-%s", - plugin_name); (void) GNUNET_asprintf (&config_filename, - "%s.conf", - testname); - - GNUNET_log_setup ("test_taler_exchange_aggregator", - "DEBUG", - NULL); - - /* these might get in the way */ - unsetenv ("XDG_DATA_HOME"); - unsetenv ("XDG_CONFIG_HOME"); - - TALER_TESTING_cleanup_files (config_filename); - - if (GNUNET_OK != - TALER_TESTING_prepare_exchange (config_filename, - GNUNET_YES, - &ec)) - { - TALER_LOG_WARNING ("Could not prepare the exchange.\n"); - return 77; - } - - if (GNUNET_OK != - TALER_TESTING_prepare_fakebank (config_filename, - "exchange-account-1", - &bc)) - { - TALER_LOG_WARNING ("Could not prepare the fakebank\n"); - return 77; - } - result = GNUNET_OK; - if (GNUNET_OK != - TALER_TESTING_setup_with_exchange (&prepare_database, - NULL, - config_filename)) - { - TALER_LOG_WARNING ("Could not prepare database for tests.\n"); - return result; - } - GNUNET_free (config_filename); - GNUNET_free (testname); - return GNUNET_OK == result ? 0 : 1; + "test-taler-exchange-aggregator-%s.conf", + plugin_name); + return TALER_TESTING_main (argv, + "INFO", + config_filename, + "exchange-account-1", + TALER_TESTING_BS_FAKEBANK, + &cred, + &run, + NULL); } diff --git a/src/testing/test_taler_exchange_httpd_home/.config/taler/account-1.json b/src/testing/test_taler_exchange_httpd_home/.config/taler/account-1.json deleted file mode 100644 index 21a7500b4..000000000 --- a/src/testing/test_taler_exchange_httpd_home/.config/taler/account-1.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "payto_uri": "payto://x-taler-bank/localhost/2", - "master_sig": "HEWC1XDS0QZ53YQR451VRKD4N968NXWGZXS30HJ59MJ0PESACK1ZYPYCAT15P08WD58C7D7F6EVN26D59JKA75XEBDQCM8VYFETK82R" -}
\ No newline at end of file diff --git a/src/testing/test_taler_exchange_httpd_home/.local/share/taler/exchange-offline/master.priv b/src/testing/test_taler_exchange_httpd_home/.local/share/taler/exchange-offline/master.priv deleted file mode 100644 index 394926938..000000000 --- a/src/testing/test_taler_exchange_httpd_home/.local/share/taler/exchange-offline/master.priv +++ /dev/null @@ -1 +0,0 @@ -pÚ^ó-Ú33ˆ€XXÁ!ˆ\0qúýµmUþ_‰ˆ
\ No newline at end of file diff --git a/src/testing/test_taler_exchange_httpd_home/.local/share/taler/exchange/offline-keys/master.priv b/src/testing/test_taler_exchange_httpd_home/.local/share/taler/exchange/offline-keys/master.priv deleted file mode 100644 index 394926938..000000000 --- a/src/testing/test_taler_exchange_httpd_home/.local/share/taler/exchange/offline-keys/master.priv +++ /dev/null @@ -1 +0,0 @@ -pÚ^ó-Ú33ˆ€XXÁ!ˆ\0qúýµmUþ_‰ˆ
\ No newline at end of file diff --git a/src/testing/test_taler_exchange_wirewatch.c b/src/testing/test_taler_exchange_wirewatch.c index d62ca55e4..86b616456 100644 --- a/src/testing/test_taler_exchange_wirewatch.c +++ b/src/testing/test_taler_exchange_wirewatch.c @@ -34,14 +34,9 @@ /** - * Bank configuration data. + * Our credentials. */ -static struct TALER_TESTING_BankConfiguration bc; - -/** - * Helper structure to keep exchange configuration values. - */ -static struct TALER_TESTING_ExchangeConfiguration ec; +static struct TALER_TESTING_Credentials cred; /** * Name of the configuration file to use. @@ -66,8 +61,8 @@ transfer_to_exchange (const char *label, { return TALER_TESTING_cmd_admin_add_incoming (label, amount, - &bc.exchange_auth, - bc.user42_payto); + &cred.ba, + cred.user42_payto); } @@ -82,22 +77,19 @@ run (void *cls, struct TALER_TESTING_Interpreter *is) { struct TALER_TESTING_Command all[] = { - TALER_TESTING_cmd_exec_offline_sign_fees ("offline-sign-fees", - config_filename, - "EUR:0.01", - "EUR:0.01", - "EUR:0.01"), - TALER_TESTING_cmd_auditor_add ("add-auditor-OK", - MHD_HTTP_NO_CONTENT, - false), - TALER_TESTING_cmd_wire_add ("add-wire-account", - "payto://x-taler-bank/localhost/2?receiver-name=2", - MHD_HTTP_NO_CONTENT, - false), - TALER_TESTING_cmd_exec_offline_sign_keys ("offline-sign-future-keys", - config_filename), - TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys", - 1), + TALER_TESTING_cmd_run_fakebank ("run-fakebank", + cred.cfg, + "exchange-account-1"), + TALER_TESTING_cmd_system_start ("start-taler", + config_filename, + "-e", + "-u", "exchange-account-1", + NULL), + TALER_TESTING_cmd_get_exchange ("get-exchange", + cred.cfg, + NULL, + true, + true), TALER_TESTING_cmd_check_bank_empty ("expect-empty-transactions-on-start"), CMD_EXEC_AGGREGATOR ("run-aggregator-on-empty"), TALER_TESTING_cmd_exec_wirewatch ("run-wirewatch-on-empty", @@ -112,8 +104,8 @@ run (void *cls, TALER_TESTING_cmd_check_bank_admin_transfer ( "clear-good-transfer-to-the-exchange", "EUR:5", - bc.user42_payto, // debit - bc.exchange_payto, // credit + cred.user42_payto, // debit + cred.exchange_payto, // credit "run-transfer-good-to-exchange"), TALER_TESTING_cmd_exec_closer ("run-closer-non-expired-reserve", @@ -136,18 +128,17 @@ run (void *cls, CMD_EXEC_AGGREGATOR ("run-closer-on-expired-reserve"), TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-1", - ec.exchange_url, + cred.exchange_url, "EUR:4.99", - bc.exchange_payto, - bc.user42_payto), + cred.exchange_payto, + cred.user42_payto), TALER_TESTING_cmd_check_bank_empty ("expect-empty-transactions-2"), TALER_TESTING_cmd_end () }; (void) cls; - TALER_TESTING_run_with_fakebank (is, - all, - bc.exchange_auth.wire_gateway_url); + TALER_TESTING_run (is, + all); } @@ -155,69 +146,29 @@ int main (int argc, char *const argv[]) { - const char *plugin_name; - (void) argc; - /* these might get in the way */ - unsetenv ("XDG_DATA_HOME"); - unsetenv ("XDG_CONFIG_HOME"); - GNUNET_log_setup ("test_taler_exchange_wirewatch", - "DEBUG", - NULL); - - if (NULL == (plugin_name = strrchr (argv[0], (int) '-'))) { - GNUNET_break (0); - return -1; - } - plugin_name++; - { - char *testname; - - GNUNET_asprintf (&testname, - "test-taler-exchange-wirewatch-%s", - plugin_name); + const char *plugin_name; + + plugin_name = strrchr (argv[0], (int) '-'); + if (NULL == plugin_name) + { + GNUNET_break (0); + return -1; + } + plugin_name++; GNUNET_asprintf (&config_filename, - "%s.conf", - testname); - GNUNET_free (testname); - } - /* check database is working */ - { - struct GNUNET_PQ_Context *conn; - struct GNUNET_PQ_ExecuteStatement es[] = { - GNUNET_PQ_EXECUTE_STATEMENT_END - }; - - conn = GNUNET_PQ_connect ("postgres:///talercheck", - NULL, - es, - NULL); - if (NULL == conn) - return 77; - GNUNET_PQ_disconnect (conn); - } - - TALER_TESTING_cleanup_files (config_filename); - if (GNUNET_OK != - TALER_TESTING_prepare_exchange (config_filename, - GNUNET_YES, - &ec)) - { - TALER_LOG_INFO ("Could not prepare the exchange\n"); - return 77; + "test-taler-exchange-wirewatch-%s.conf", + plugin_name); } - - if (GNUNET_OK != - TALER_TESTING_prepare_fakebank (config_filename, - "exchange-account-1", - &bc)) - return 77; - - return (GNUNET_OK == - TALER_TESTING_setup_with_exchange (&run, - NULL, - config_filename)) ? 0 : 1; + return TALER_TESTING_main (argv, + "INFO", + config_filename, + "exchange-account-1", + TALER_TESTING_BS_FAKEBANK, + &cred, + &run, + NULL); } diff --git a/src/testing/testing_api_cmd_age_withdraw.c b/src/testing/testing_api_cmd_age_withdraw.c new file mode 100644 index 000000000..6ad22809e --- /dev/null +++ b/src/testing/testing_api_cmd_age_withdraw.c @@ -0,0 +1,756 @@ +/* + 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/testing_api_cmd_age_withdraw.c + * @brief implements the age-withdraw command + * @author Özgür Kesim + */ + +#include "platform.h" +#include "taler_exchange_service.h" +#include "taler_json_lib.h" +#include <gnunet/gnunet_common.h> +#include <microhttpd.h> +#include <gnunet/gnunet_curl_lib.h> +#include "taler_signatures.h" +#include "taler_extensions.h" +#include "taler_testing_lib.h" + +/* + * The output state of coin + */ +struct CoinOutputState +{ + + /** + * The calculated details during "age-withdraw", for the selected coin. + */ + struct TALER_EXCHANGE_AgeWithdrawCoinPrivateDetails details; + + /** + * The (wanted) value of the coin, MUST be the same as input.denom_pub.value; + */ + struct TALER_Amount amount; + + /** + * Reserve history entry that corresponds to this coin. + * Will be of type #TALER_EXCHANGE_RTT_AGEWITHDRAWAL. + */ + struct TALER_EXCHANGE_ReserveHistoryEntry reserve_history; +}; + +/** + * State for a "age withdraw" CMD: + */ + +struct AgeWithdrawState +{ + + /** + * Interpreter state (during command) + */ + struct TALER_TESTING_Interpreter *is; + + /** + * The age-withdraw handle + */ + struct TALER_EXCHANGE_AgeWithdrawHandle *handle; + + /** + * Exchange base URL. Only used as offered trait. + */ + char *exchange_url; + + /** + * URI of the reserve we are withdrawing from. + */ + char *reserve_payto_uri; + + /** + * Private key of the reserve we are withdrawing from. + */ + struct TALER_ReservePrivateKeyP reserve_priv; + + /** + * Public key of the reserve we are withdrawing from. + */ + struct TALER_ReservePublicKeyP reserve_pub; + + /** + * Which reserve should we withdraw from? + */ + const char *reserve_reference; + + /** + * Expected HTTP response code to the request. + */ + unsigned int expected_response_code; + + /** + * Age mask + */ + struct TALER_AgeMask mask; + + /** + * The maximum age we commit to + */ + uint8_t max_age; + + /** + * Number of coins to withdraw + */ + size_t num_coins; + + /** + * The @e num_coins input that is provided to the + * `TALER_EXCHANGE_age_withdraw` API. + * Each contains kappa secrets, from which we will have + * to disclose kappa-1 in a subsequent age-withdraw-reveal operation. + */ + struct TALER_EXCHANGE_AgeWithdrawCoinInput *coin_inputs; + + /** + * The output state of @e num_coins coins, calculated during the + * "age-withdraw" operation. + */ + struct CoinOutputState *coin_outputs; + + /** + * The index returned by the exchange for the "age-withdraw" operation, + * of the kappa coin candidates that we do not disclose and keep. + */ + uint8_t noreveal_index; + + /** + * The blinded hashes of the non-revealed (to keep) @e num_coins coins. + */ + const struct TALER_BlindedCoinHashP *blinded_coin_hs; + + /** + * The hash of the commitment, needed for the reveal step. + */ + struct TALER_AgeWithdrawCommitmentHashP h_commitment; + + /** + * Set to the KYC requirement payto hash *if* the exchange replied with a + * request for KYC. + */ + struct TALER_PaytoHashP h_payto; + + /** + * Set to the KYC requirement row *if* the exchange replied with + * a request for KYC. + */ + uint64_t requirement_row; + +}; + +/** + * Callback for the "age-withdraw" ooperation; It checks that the response + * code is expected and store the exchange signature in the state. + * + * @param cls Closure of type `struct AgeWithdrawState *` + * @param response Response details + */ +static void +age_withdraw_cb ( + void *cls, + const struct TALER_EXCHANGE_AgeWithdrawResponse *response) +{ + struct AgeWithdrawState *aws = cls; + struct TALER_TESTING_Interpreter *is = aws->is; + + aws->handle = NULL; + if (aws->expected_response_code != response->hr.http_status) + { + TALER_TESTING_unexpected_status_with_body (is, + response->hr.http_status, + aws->expected_response_code, + response->hr.reply); + return; + } + + switch (response->hr.http_status) + { + case MHD_HTTP_OK: + aws->noreveal_index = response->details.ok.noreveal_index; + aws->h_commitment = response->details.ok.h_commitment; + + GNUNET_assert (aws->num_coins == response->details.ok.num_coins); + for (size_t n = 0; n < aws->num_coins; n++) + { + aws->coin_outputs[n].details = response->details.ok.coin_details[n]; + TALER_age_commitment_proof_deep_copy ( + &response->details.ok.coin_details[n].age_commitment_proof, + &aws->coin_outputs[n].details.age_commitment_proof); + } + aws->blinded_coin_hs = response->details.ok.blinded_coin_hs; + break; + case MHD_HTTP_FORBIDDEN: + case MHD_HTTP_NOT_FOUND: + case MHD_HTTP_GONE: + /* nothing to check */ + break; + case MHD_HTTP_CONFLICT: + /* TODO[oec]: Add this to the response-type and handle it here */ + break; + case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS: + default: + /* Unsupported status code (by test harness) */ + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "test command for age-withdraw not support status code %u, body:\n" + ">>%s<<\n", + response->hr.http_status, + json_dumps (response->hr.reply, JSON_INDENT (2))); + GNUNET_break (0); + break; + } + + /* We are done with this command, pick the next one */ + TALER_TESTING_interpreter_next (is); +} + + +/** + * Run the command for age-withdraw. + */ +static void +age_withdraw_run ( + void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct AgeWithdrawState *aws = cls; + struct TALER_EXCHANGE_Keys *keys = TALER_TESTING_get_keys (is); + const struct TALER_ReservePrivateKeyP *rp; + const struct TALER_TESTING_Command *create_reserve; + const struct TALER_EXCHANGE_DenomPublicKey *dpk; + + aws->is = is; + + /* Prepare the reserve related data */ + create_reserve + = TALER_TESTING_interpreter_lookup_command ( + is, + aws->reserve_reference); + + if (NULL == create_reserve) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + if (GNUNET_OK != + TALER_TESTING_get_trait_reserve_priv (create_reserve, + &rp)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + if (NULL == aws->exchange_url) + aws->exchange_url + = GNUNET_strdup (TALER_TESTING_get_exchange_url (is)); + aws->reserve_priv = *rp; + GNUNET_CRYPTO_eddsa_key_get_public (&aws->reserve_priv.eddsa_priv, + &aws->reserve_pub.eddsa_pub); + aws->reserve_payto_uri + = TALER_reserve_make_payto (aws->exchange_url, + &aws->reserve_pub); + + aws->coin_inputs = GNUNET_new_array ( + aws->num_coins, + struct TALER_EXCHANGE_AgeWithdrawCoinInput); + + for (unsigned int i = 0; i<aws->num_coins; i++) + { + struct TALER_EXCHANGE_AgeWithdrawCoinInput *input = &aws->coin_inputs[i]; + struct CoinOutputState *cos = &aws->coin_outputs[i]; + + /* randomly create the secrets for the kappa coin-candidates */ + GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, + &input->secrets, + sizeof(input->secrets)); + /* Find denomination */ + dpk = TALER_TESTING_find_pk (keys, + &cos->amount, + true); /* _always_ use denominations with age-striction */ + if (NULL == dpk) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to determine denomination key for amount at %s\n", + (NULL != cmd) ? cmd->label : "<retried command>"); + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + /* We copy the denomination key, as re-querying /keys + * would free the old one. */ + input->denom_pub = TALER_EXCHANGE_copy_denomination_key (dpk); + cos->reserve_history.type = TALER_EXCHANGE_RTT_AGEWITHDRAWAL; + GNUNET_assert (0 <= + TALER_amount_add (&cos->reserve_history.amount, + &cos->amount, + &input->denom_pub->fees.withdraw)); + cos->reserve_history.details.withdraw.fee = input->denom_pub->fees.withdraw; + } + + /* Execute the age-withdraw protocol */ + aws->handle = + TALER_EXCHANGE_age_withdraw ( + TALER_TESTING_interpreter_get_context (is), + keys, + TALER_TESTING_get_exchange_url (is), + rp, + aws->num_coins, + aws->coin_inputs, + aws->max_age, + &age_withdraw_cb, + aws); + + if (NULL == aws->handle) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } +} + + +/** + * Free the state of a "age withdraw" CMD, and possibly cancel a + * pending operation thereof + * + * @param cls Closure of type `struct AgeWithdrawState` + * @param cmd The command being freed. + */ +static void +age_withdraw_cleanup ( + void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct AgeWithdrawState *aws = cls; + + if (NULL != aws->handle) + { + TALER_TESTING_command_incomplete (aws->is, + cmd->label); + TALER_EXCHANGE_age_withdraw_cancel (aws->handle); + aws->handle = NULL; + } + + if (NULL != aws->coin_inputs) + { + for (size_t n = 0; n < aws->num_coins; n++) + { + struct TALER_EXCHANGE_AgeWithdrawCoinInput *in = &aws->coin_inputs[n]; + struct CoinOutputState *out = &aws->coin_outputs[n]; + + if (NULL != in && NULL != in->denom_pub) + { + TALER_EXCHANGE_destroy_denomination_key (in->denom_pub); + in->denom_pub = NULL; + } + if (NULL != out) + TALER_age_commitment_proof_free (&out->details.age_commitment_proof); + } + GNUNET_free (aws->coin_inputs); + } + GNUNET_free (aws->coin_outputs); + GNUNET_free (aws->exchange_url); + GNUNET_free (aws->reserve_payto_uri); + GNUNET_free (aws); +} + + +/** + * Offer internal data of a "age withdraw" CMD state to other commands. + * + * @param cls Closure of type `struct AgeWithdrawState` + * @param[out] ret result (could be anything) + * @param trait name of the trait + * @param idx index number of the object to offer. + * @return #GNUNET_OK on success + */ +static enum GNUNET_GenericReturnValue +age_withdraw_traits ( + void *cls, + const void **ret, + const char *trait, + unsigned int idx) +{ + struct AgeWithdrawState *aws = cls; + uint8_t k = aws->noreveal_index; + struct TALER_EXCHANGE_AgeWithdrawCoinInput *in = &aws->coin_inputs[idx]; + struct CoinOutputState *out = &aws->coin_outputs[idx]; + struct TALER_EXCHANGE_AgeWithdrawCoinPrivateDetails *details = + &aws->coin_outputs[idx].details; + struct TALER_TESTING_Trait traits[] = { + /* history entry MUST be first due to response code logic below! */ + TALER_TESTING_make_trait_reserve_history (idx, + &out->reserve_history), + TALER_TESTING_make_trait_denom_pub (idx, + in->denom_pub), + TALER_TESTING_make_trait_reserve_priv (&aws->reserve_priv), + TALER_TESTING_make_trait_reserve_pub (&aws->reserve_pub), + TALER_TESTING_make_trait_amounts (idx, + &out->amount), + /* TODO[oec]: add legal requirement to response and handle it here, as well + TALER_TESTING_make_trait_legi_requirement_row (&aws->requirement_row), + TALER_TESTING_make_trait_h_payto (&aws->h_payto), + */ + TALER_TESTING_make_trait_h_blinded_coin (idx, + &aws->blinded_coin_hs[idx]), + TALER_TESTING_make_trait_payto_uri (aws->reserve_payto_uri), + TALER_TESTING_make_trait_exchange_url (aws->exchange_url), + TALER_TESTING_make_trait_coin_priv (idx, + &details->coin_priv), + TALER_TESTING_make_trait_planchet_secrets (idx, + &in->secrets[k]), + TALER_TESTING_make_trait_blinding_key (idx, + &details->blinding_key), + TALER_TESTING_make_trait_exchange_wd_value (idx, + &details->alg_values), + TALER_TESTING_make_trait_age_commitment_proof ( + idx, + &details->age_commitment_proof), + TALER_TESTING_make_trait_h_age_commitment ( + idx, + &details->h_age_commitment), + }; + + if (idx >= aws->num_coins) + return GNUNET_NO; + + return TALER_TESTING_get_trait ((aws->expected_response_code == MHD_HTTP_OK) + ? &traits[0] /* we have reserve history */ + : &traits[1], /* skip reserve history */ + ret, + trait, + idx); +} + + +struct TALER_TESTING_Command +TALER_TESTING_cmd_age_withdraw (const char *label, + const char *reserve_reference, + uint8_t max_age, + unsigned int expected_response_code, + const char *amount, + ...) +{ + struct AgeWithdrawState *aws; + unsigned int cnt; + va_list ap; + + aws = GNUNET_new (struct AgeWithdrawState); + aws->reserve_reference = reserve_reference; + aws->expected_response_code = expected_response_code; + aws->mask = TALER_extensions_get_age_restriction_mask (); + aws->max_age = TALER_get_lowest_age (&aws->mask, max_age); + + cnt = 1; + va_start (ap, amount); + while (NULL != (va_arg (ap, const char *))) + cnt++; + aws->num_coins = cnt; + aws->coin_outputs = GNUNET_new_array (cnt, + struct CoinOutputState); + va_end (ap); + va_start (ap, amount); + + for (unsigned int i = 0; i<aws->num_coins; i++) + { + struct CoinOutputState *out = &aws->coin_outputs[i]; + if (GNUNET_OK != + TALER_string_to_amount (amount, + &out->amount)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to parse amount `%s' at %s\n", + amount, + label); + GNUNET_assert (0); + } + /* move on to next vararg! */ + amount = va_arg (ap, const char *); + } + + GNUNET_assert (NULL == amount); + va_end (ap); + + { + struct TALER_TESTING_Command cmd = { + .cls = aws, + .label = label, + .run = &age_withdraw_run, + .cleanup = &age_withdraw_cleanup, + .traits = &age_withdraw_traits, + }; + + return cmd; + } +} + + +/** + * The state for the age-withdraw-reveal operation + */ +struct AgeWithdrawRevealState +{ + /** + * The reference to the CMD resembling the previous call to age-withdraw + */ + const char *age_withdraw_reference; + + /** + * The state to the previous age-withdraw command + */ + const struct AgeWithdrawState *aws; + + /** + * The expected response code from the call to the + * age-withdraw-reveal operation + */ + unsigned int expected_response_code; + + /** + * Interpreter state (during command) + */ + struct TALER_TESTING_Interpreter *is; + + /** + * The handle to the reveal-operation + */ + struct TALER_EXCHANGE_AgeWithdrawRevealHandle *handle; + + + /** + * Number of coins, extracted form the age withdraw command + */ + size_t num_coins; + + /** + * The signatures of the @e num_coins coins returned + */ + struct TALER_DenominationSignature *denom_sigs; + +}; + +/* + * Callback for the reveal response + * + * @param cls Closure of type `struct AgeWithdrawRevealState` + * @param awr The response + */ +static void +age_withdraw_reveal_cb ( + void *cls, + const struct TALER_EXCHANGE_AgeWithdrawRevealResponse *response) +{ + struct AgeWithdrawRevealState *awrs = cls; + struct TALER_TESTING_Interpreter *is = awrs->is; + + awrs->handle = NULL; + if (awrs->expected_response_code != response->hr.http_status) + { + TALER_TESTING_unexpected_status_with_body (is, + response->hr.http_status, + awrs->expected_response_code, + response->hr.reply); + return; + } + switch (response->hr.http_status) + { + case MHD_HTTP_OK: + { + const struct AgeWithdrawState *aws = awrs->aws; + GNUNET_assert (awrs->num_coins == response->details.ok.num_sigs); + awrs->denom_sigs = GNUNET_new_array (awrs->num_coins, + struct TALER_DenominationSignature); + for (size_t n = 0; n < awrs->num_coins; n++) + { + GNUNET_assert (GNUNET_OK == + TALER_denom_sig_unblind ( + &awrs->denom_sigs[n], + &response->details.ok.blinded_denom_sigs[n], + &aws->coin_outputs[n].details.blinding_key, + &aws->coin_outputs[n].details.h_coin_pub, + &aws->coin_outputs[n].details.alg_values, + &aws->coin_inputs[n].denom_pub->key)); + TALER_denom_sig_free (&awrs->denom_sigs[n]); + } + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "age-withdraw reveal success!\n"); + GNUNET_free (awrs->denom_sigs); + } + break; + case MHD_HTTP_NOT_FOUND: + case MHD_HTTP_FORBIDDEN: + /* nothing to check */ + break; + /* TODO[oec]: handle more cases !? */ + default: + /* Unsupported status code (by test harness) */ + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Age withdraw reveal test command does not support status code %u\n", + response->hr.http_status); + GNUNET_break (0); + break; + } + + /* We are done with this command, pick the next one */ + TALER_TESTING_interpreter_next (is); +} + + +/** + * Run the command for age-withdraw-reveal + */ +static void +age_withdraw_reveal_run ( + void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct AgeWithdrawRevealState *awrs = cls; + const struct TALER_TESTING_Command *age_withdraw_cmd; + const struct AgeWithdrawState *aws; + + (void) cmd; + awrs->is = is; + + /* + * Get the command and state for the previous call to "age witdraw" + */ + age_withdraw_cmd = + TALER_TESTING_interpreter_lookup_command (is, + awrs->age_withdraw_reference); + if (NULL == age_withdraw_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + GNUNET_assert (age_withdraw_cmd->run == age_withdraw_run); + aws = age_withdraw_cmd->cls; + awrs->aws = aws; + awrs->num_coins = aws->num_coins; + + awrs->handle = + TALER_EXCHANGE_age_withdraw_reveal ( + TALER_TESTING_interpreter_get_context (is), + TALER_TESTING_get_exchange_url (is), + aws->num_coins, + aws->coin_inputs, + aws->noreveal_index, + &aws->h_commitment, + &aws->reserve_pub, + age_withdraw_reveal_cb, + awrs); +} + + +/** + * Free the state of a "age-withdraw-reveal" CMD, and possibly + * cancel a pending operation thereof + * + * @param cls Closure of type `struct AgeWithdrawRevealState` + * @param cmd The command being freed. + */ +static void +age_withdraw_reveal_cleanup ( + void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct AgeWithdrawRevealState *awrs = cls; + + if (NULL != awrs->handle) + { + TALER_TESTING_command_incomplete (awrs->is, + cmd->label); + TALER_EXCHANGE_age_withdraw_reveal_cancel (awrs->handle); + awrs->handle = NULL; + } + GNUNET_free (awrs->denom_sigs); + awrs->denom_sigs = NULL; + GNUNET_free (awrs); +} + + +/** + * Offer internal data of a "age withdraw reveal" CMD state to other commands. + * + * @param cls Closure of they `struct AgeWithdrawRevealState` + * @param[out] ret result (could be anything) + * @param trait name of the trait + * @param idx index number of the object to offer. + * @return #GNUNET_OK on success + */ +static enum GNUNET_GenericReturnValue +age_withdraw_reveal_traits ( + void *cls, + const void **ret, + const char *trait, + unsigned int idx) +{ + struct AgeWithdrawRevealState *awrs = cls; + struct TALER_TESTING_Trait traits[] = { + TALER_TESTING_make_trait_denom_sig (idx, + &awrs->denom_sigs[idx]), + /* FIXME: shall we provide the traits from the previous + * call to "age withdraw" as well? */ + }; + + if (idx >= awrs->num_coins) + return GNUNET_NO; + + return TALER_TESTING_get_trait (traits, + ret, + trait, + idx); +} + + +struct TALER_TESTING_Command +TALER_TESTING_cmd_age_withdraw_reveal ( + const char *label, + const char *age_withdraw_reference, + unsigned int expected_response_code) +{ + struct AgeWithdrawRevealState *awrs = + GNUNET_new (struct AgeWithdrawRevealState); + + awrs->age_withdraw_reference = age_withdraw_reference; + awrs->expected_response_code = expected_response_code; + + struct TALER_TESTING_Command cmd = { + .cls = awrs, + .label = label, + .run = age_withdraw_reveal_run, + .cleanup = age_withdraw_reveal_cleanup, + .traits = age_withdraw_reveal_traits, + }; + + return cmd; +} + + +/* end of testing_api_cmd_age_withdraw.c */ diff --git a/src/testing/testing_api_cmd_auditor_add.c b/src/testing/testing_api_cmd_auditor_add.c index 8362b66c9..ac9c2c8fb 100644 --- a/src/testing/testing_api_cmd_auditor_add.c +++ b/src/testing/testing_api_cmd_auditor_add.c @@ -18,7 +18,7 @@ */ /** * @file testing/testing_api_cmd_auditor_add.c - * @brief command for testing /auditor_add. + * @brief command for testing auditor_add * @author Christian Grothoff */ #include "platform.h" @@ -62,27 +62,22 @@ struct AuditorAddState * if the response code is acceptable. * * @param cls closure. - * @param hr HTTP response details + * @param aer response details */ static void -auditor_add_cb (void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr) +auditor_add_cb ( + void *cls, + const struct TALER_EXCHANGE_ManagementAuditorEnableResponse *aer) { struct AuditorAddState *ds = cls; + const struct TALER_EXCHANGE_HttpResponse *hr = &aer->hr; ds->dh = NULL; if (ds->expected_response_code != hr->http_status) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u to command %s in %s:%u\n", - hr->http_status, - ds->is->commands[ds->is->ip].label, - __FILE__, - __LINE__); - json_dumpf (hr->reply, - stderr, - 0); - TALER_TESTING_interpreter_fail (ds->is); + TALER_TESTING_unexpected_status (ds->is, + hr->http_status, + ds->expected_response_code); return; } TALER_TESTING_interpreter_next (ds->is); @@ -104,10 +99,43 @@ auditor_add_run (void *cls, struct AuditorAddState *ds = cls; struct GNUNET_TIME_Timestamp now; struct TALER_MasterSignatureP master_sig; + const struct TALER_AuditorPublicKeyP *auditor_pub; + const struct TALER_TESTING_Command *auditor_cmd; + const struct TALER_TESTING_Command *exchange_cmd; + const char *exchange_url; + const char *auditor_url; (void) cmd; now = GNUNET_TIME_timestamp_get (); ds->is = is; + + auditor_cmd = TALER_TESTING_interpreter_get_command (is, + "auditor"); + if (NULL == auditor_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_auditor_pub (auditor_cmd, + &auditor_pub)); + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_auditor_url (auditor_cmd, + &auditor_url)); + exchange_cmd = TALER_TESTING_interpreter_get_command (is, + "exchange"); + if (NULL == exchange_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_exchange_url (exchange_cmd, + &exchange_url)); + + if (ds->bad_sig) { memset (&master_sig, @@ -116,17 +144,22 @@ auditor_add_run (void *cls, } else { - TALER_exchange_offline_auditor_add_sign (&is->auditor_pub, - is->auditor_url, + const struct TALER_MasterPrivateKeyP *master_priv; + + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_master_priv (exchange_cmd, + &master_priv)); + TALER_exchange_offline_auditor_add_sign (auditor_pub, + auditor_url, now, - &is->master_priv, + master_priv, &master_sig); } ds->dh = TALER_EXCHANGE_management_enable_auditor ( - is->ctx, - is->exchange_url, - &is->auditor_pub, - is->auditor_url, + TALER_TESTING_interpreter_get_context (is), + exchange_url, + auditor_pub, + auditor_url, "test-case auditor", /* human-readable auditor name */ now, &master_sig, @@ -156,10 +189,8 @@ auditor_add_cleanup (void *cls, if (NULL != ds->dh) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - ds->is->ip, - cmd->label); + TALER_TESTING_command_incomplete (ds->is, + cmd->label); TALER_EXCHANGE_management_enable_auditor_cancel (ds->dh); ds->dh = NULL; } diff --git a/src/testing/testing_api_cmd_auditor_add_denom_sig.c b/src/testing/testing_api_cmd_auditor_add_denom_sig.c index 3d7ea82f1..6b7776896 100644 --- a/src/testing/testing_api_cmd_auditor_add_denom_sig.c +++ b/src/testing/testing_api_cmd_auditor_add_denom_sig.c @@ -67,27 +67,22 @@ struct AuditorAddDenomSigState * if the response code is acceptable. * * @param cls closure. - * @param hr HTTP response details + * @param adr response details */ static void -denom_sig_add_cb (void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr) +denom_sig_add_cb ( + void *cls, + const struct TALER_EXCHANGE_AuditorAddDenominationResponse *adr) { struct AuditorAddDenomSigState *ds = cls; + const struct TALER_EXCHANGE_HttpResponse *hr = &adr->hr; ds->dh = NULL; if (ds->expected_response_code != hr->http_status) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u to command %s in %s:%u\n", - hr->http_status, - ds->is->commands[ds->is->ip].label, - __FILE__, - __LINE__); - json_dumpf (hr->reply, - stderr, - 0); - TALER_TESTING_interpreter_fail (ds->is); + TALER_TESTING_unexpected_status (ds->is, + hr->http_status, + ds->expected_response_code); return; } TALER_TESTING_interpreter_next (ds->is); @@ -110,6 +105,11 @@ auditor_add_run (void *cls, struct TALER_AuditorSignatureP auditor_sig; struct TALER_DenominationHashP h_denom_pub; const struct TALER_EXCHANGE_DenomPublicKey *dk; + const struct TALER_AuditorPublicKeyP *auditor_pub; + const struct TALER_TESTING_Command *auditor_cmd; + const struct TALER_TESTING_Command *exchange_cmd; + const char *exchange_url; + const char *auditor_url; (void) cmd; /* Get denom pub from trait */ @@ -118,7 +118,6 @@ auditor_add_run (void *cls, denom_cmd = TALER_TESTING_interpreter_lookup_command (is, ds->denom_ref); - if (NULL == denom_cmd) { GNUNET_break (0); @@ -131,6 +130,31 @@ auditor_add_run (void *cls, &dk)); } ds->is = is; + auditor_cmd = TALER_TESTING_interpreter_get_command (is, + "auditor"); + if (NULL == auditor_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_auditor_pub (auditor_cmd, + &auditor_pub)); + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_auditor_url (auditor_cmd, + &auditor_url)); + exchange_cmd = TALER_TESTING_interpreter_get_command (is, + "exchange"); + if (NULL == exchange_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_exchange_url (exchange_cmd, + &exchange_url)); if (ds->bad_sig) { memset (&auditor_sig, @@ -139,28 +163,33 @@ auditor_add_run (void *cls, } else { - struct TALER_MasterPublicKeyP master_pub; + const struct TALER_MasterPublicKeyP *master_pub; + const struct TALER_AuditorPrivateKeyP *auditor_priv; - GNUNET_CRYPTO_eddsa_key_get_public (&is->master_priv.eddsa_priv, - &master_pub.eddsa_pub); + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_master_pub (exchange_cmd, + &master_pub)); + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_auditor_priv (auditor_cmd, + &auditor_priv)); TALER_auditor_denom_validity_sign ( - is->auditor_url, + auditor_url, &dk->h_key, - &master_pub, + master_pub, dk->valid_from, dk->withdraw_valid_until, dk->expire_deposit, dk->expire_legal, &dk->value, &dk->fees, - &is->auditor_priv, + auditor_priv, &auditor_sig); } ds->dh = TALER_EXCHANGE_add_auditor_denomination ( - is->ctx, - is->exchange_url, + TALER_TESTING_interpreter_get_context (is), + exchange_url, &h_denom_pub, - &is->auditor_pub, + auditor_pub, &auditor_sig, &denom_sig_add_cb, ds); @@ -188,10 +217,8 @@ auditor_add_cleanup (void *cls, if (NULL != ds->dh) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - ds->is->ip, - cmd->label); + TALER_TESTING_command_incomplete (ds->is, + cmd->label); TALER_EXCHANGE_add_auditor_denomination_cancel (ds->dh); ds->dh = NULL; } diff --git a/src/testing/testing_api_cmd_auditor_del.c b/src/testing/testing_api_cmd_auditor_del.c index de03d1632..8256bc1c7 100644 --- a/src/testing/testing_api_cmd_auditor_del.c +++ b/src/testing/testing_api_cmd_auditor_del.c @@ -62,27 +62,23 @@ struct AuditorDelState * if the response code is acceptable. * * @param cls closure. - * @param hr HTTP response details + * @param adr response details */ static void -auditor_del_cb (void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr) +auditor_del_cb ( + void *cls, + const struct TALER_EXCHANGE_ManagementAuditorDisableResponse *adr) + { struct AuditorDelState *ds = cls; + const struct TALER_EXCHANGE_HttpResponse *hr = &adr->hr; ds->dh = NULL; if (ds->expected_response_code != hr->http_status) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u to command %s in %s:%u\n", - hr->http_status, - ds->is->commands[ds->is->ip].label, - __FILE__, - __LINE__); - json_dumpf (hr->reply, - stderr, - 0); - TALER_TESTING_interpreter_fail (ds->is); + TALER_TESTING_unexpected_status (ds->is, + hr->http_status, + ds->expected_response_code); return; } TALER_TESTING_interpreter_next (ds->is); @@ -104,10 +100,36 @@ auditor_del_run (void *cls, struct AuditorDelState *ds = cls; struct TALER_MasterSignatureP master_sig; struct GNUNET_TIME_Timestamp now; + const struct TALER_AuditorPublicKeyP *auditor_pub; + const struct TALER_TESTING_Command *auditor_cmd; + const struct TALER_TESTING_Command *exchange_cmd; + const char *exchange_url; (void) cmd; now = GNUNET_TIME_timestamp_get (); ds->is = is; + auditor_cmd = TALER_TESTING_interpreter_get_command (is, + "auditor"); + if (NULL == auditor_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_auditor_pub (auditor_cmd, + &auditor_pub)); + exchange_cmd = TALER_TESTING_interpreter_get_command (is, + "exchange"); + if (NULL == exchange_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_exchange_url (exchange_cmd, + &exchange_url)); if (ds->bad_sig) { memset (&master_sig, @@ -116,15 +138,20 @@ auditor_del_run (void *cls, } else { - TALER_exchange_offline_auditor_del_sign (&is->auditor_pub, + const struct TALER_MasterPrivateKeyP *master_priv; + + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_master_priv (exchange_cmd, + &master_priv)); + TALER_exchange_offline_auditor_del_sign (auditor_pub, now, - &is->master_priv, + master_priv, &master_sig); } ds->dh = TALER_EXCHANGE_management_disable_auditor ( - is->ctx, - is->exchange_url, - &is->auditor_pub, + TALER_TESTING_interpreter_get_context (is), + exchange_url, + auditor_pub, now, &master_sig, &auditor_del_cb, @@ -153,10 +180,8 @@ auditor_del_cleanup (void *cls, if (NULL != ds->dh) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - ds->is->ip, - cmd->label); + TALER_TESTING_command_incomplete (ds->is, + cmd->label); TALER_EXCHANGE_management_disable_auditor_cancel (ds->dh); ds->dh = NULL; } diff --git a/src/testing/testing_api_cmd_auditor_deposit_confirmation.c b/src/testing/testing_api_cmd_auditor_deposit_confirmation.c index d99b12937..9477a5d7e 100644 --- a/src/testing/testing_api_cmd_auditor_deposit_confirmation.c +++ b/src/testing/testing_api_cmd_auditor_deposit_confirmation.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2018, 2021 Taler Systems SA + Copyright (C) 2018-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 @@ -59,9 +59,9 @@ struct DepositConfirmationState const char *amount_without_fee; /** - * Which coin of the @e deposit_reference should we confirm. + * How many coins were there in the @e deposit_reference? */ - unsigned int coin_index; + unsigned int num_coins; /** * DepositConfirmation handle while operation is running. @@ -69,11 +69,6 @@ struct DepositConfirmationState struct TALER_AUDITOR_DepositConfirmationHandle *dc; /** - * Auditor connection. - */ - struct TALER_AUDITOR_Handle *auditor; - - /** * Interpreter state. */ struct TALER_TESTING_Interpreter *is; @@ -125,8 +120,7 @@ do_retry (void *cls) struct DepositConfirmationState *dcs = cls; dcs->retry_task = NULL; - dcs->is->commands[dcs->is->ip].last_req_time - = GNUNET_TIME_absolute_get (); + TALER_TESTING_touch_cmd (dcs->is); deposit_confirmation_run (dcs, NULL, dcs->is); @@ -138,13 +132,15 @@ do_retry (void *cls) * to check if the response code is acceptable. * * @param cls closure. - * @param hr HTTP response details + * @param dcr response details */ static void -deposit_confirmation_cb (void *cls, - const struct TALER_AUDITOR_HttpResponse *hr) +deposit_confirmation_cb ( + void *cls, + const struct TALER_AUDITOR_DepositConfirmationResponse *dcr) { struct DepositConfirmationState *dcs = cls; + const struct TALER_AUDITOR_HttpResponse *hr = &dcr->hr; dcs->dc = NULL; if (dcs->expected_response_code != hr->http_status) @@ -166,21 +162,16 @@ deposit_confirmation_cb (void *cls, else dcs->backoff = GNUNET_TIME_randomized_backoff (dcs->backoff, MAX_BACKOFF); - dcs->is->commands[dcs->is->ip].num_tries++; + TALER_TESTING_inc_tries (dcs->is); dcs->retry_task = GNUNET_SCHEDULER_add_delayed (dcs->backoff, &do_retry, dcs); return; } } - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u to command %s in %s:%u\n", - hr->http_status, - dcs->is->commands[dcs->is->ip].label, - __FILE__, - __LINE__); - json_dumpf (hr->reply, stderr, 0); - TALER_TESTING_interpreter_fail (dcs->is); + TALER_TESTING_unexpected_status (dcs->is, + hr->http_status, + dcs->expected_response_code); return; } TALER_TESTING_interpreter_next (dcs->is); @@ -199,7 +190,7 @@ deposit_confirmation_run (void *cls, const struct TALER_TESTING_Command *cmd, struct TALER_TESTING_Interpreter *is) { - static struct TALER_ExtensionContractHashP no_h_extensions; + static struct TALER_ExtensionPolicyHashP no_h_policy; struct DepositConfirmationState *dcs = cls; const struct TALER_TESTING_Command *deposit_cmd; struct TALER_MerchantWireHashP h_wire; @@ -210,20 +201,43 @@ deposit_confirmation_run (void *cls, struct GNUNET_TIME_Timestamp refund_deadline = GNUNET_TIME_UNIT_ZERO_TS; struct TALER_Amount amount_without_fee; - struct TALER_CoinSpendPublicKeyP coin_pub; + struct TALER_CoinSpendPublicKeyP coin_pubs[dcs->num_coins]; + const struct TALER_CoinSpendPublicKeyP *coin_pubps[dcs->num_coins]; + const struct TALER_CoinSpendSignatureP *coin_sigps[dcs->num_coins]; const struct TALER_MerchantPrivateKeyP *merchant_priv; struct TALER_MerchantPublicKeyP merchant_pub; const struct TALER_ExchangePublicKeyP *exchange_pub; const struct TALER_ExchangeSignatureP *exchange_sig; const json_t *wire_details; const json_t *contract_terms; - const struct TALER_CoinSpendPrivateKeyP *coin_priv; const struct TALER_EXCHANGE_Keys *keys; const struct TALER_EXCHANGE_SigningPublicKey *spk; + const char *auditor_url; (void) cmd; dcs->is = is; GNUNET_assert (NULL != dcs->deposit_reference); + { + const struct TALER_TESTING_Command *auditor_cmd; + + auditor_cmd + = TALER_TESTING_interpreter_get_command (is, + "auditor"); + if (NULL == auditor_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + if (GNUNET_OK != + TALER_TESTING_get_trait_auditor_url (auditor_cmd, + &auditor_url)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + } deposit_cmd = TALER_TESTING_interpreter_lookup_command (is, dcs->deposit_reference); @@ -236,22 +250,22 @@ deposit_confirmation_run (void *cls, GNUNET_assert (GNUNET_OK == TALER_TESTING_get_trait_exchange_pub (deposit_cmd, - dcs->coin_index, + 0, &exchange_pub)); GNUNET_assert (GNUNET_OK == TALER_TESTING_get_trait_exchange_sig (deposit_cmd, - dcs->coin_index, + 0, &exchange_sig)); GNUNET_assert (GNUNET_OK == TALER_TESTING_get_trait_timestamp (deposit_cmd, - dcs->coin_index, + 0, &exchange_timestamp)); GNUNET_assert (GNUNET_OK == TALER_TESTING_get_trait_wire_deadline (deposit_cmd, - dcs->coin_index, + 0, &wire_deadline)); GNUNET_assert (NULL != exchange_timestamp); - keys = TALER_EXCHANGE_get_keys (dcs->is->exchange); + keys = TALER_TESTING_get_keys (is); GNUNET_assert (NULL != keys); spk = TALER_EXCHANGE_get_signing_key_info (keys, exchange_pub); @@ -270,12 +284,23 @@ deposit_confirmation_run (void *cls, GNUNET_assert (GNUNET_OK == TALER_JSON_merchant_wire_signature_hash (wire_details, &h_wire)); - GNUNET_assert (GNUNET_OK == - TALER_TESTING_get_trait_coin_priv (deposit_cmd, - dcs->coin_index, - &coin_priv)); - GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv, - &coin_pub.eddsa_pub); + + for (unsigned int i = 0; i<dcs->num_coins; i++) + { + const struct TALER_CoinSpendPrivateKeyP *coin_priv; + + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_coin_priv (deposit_cmd, + i, + &coin_priv)); + GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv, + &coin_pubs[i].eddsa_pub); + coin_pubps[i] = &coin_pubs[i]; + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_coin_sig (deposit_cmd, + i, + &coin_sigps[i])); + } GNUNET_assert (GNUNET_OK == TALER_TESTING_get_trait_merchant_priv (deposit_cmd, &merchant_priv)); @@ -308,25 +333,29 @@ deposit_confirmation_run (void *cls, if (GNUNET_TIME_absolute_is_zero (refund_deadline.abs_time)) refund_deadline = timestamp; } - dcs->dc = TALER_AUDITOR_deposit_confirmation (dcs->auditor, - &h_wire, - &no_h_extensions, - &h_contract_terms, - *exchange_timestamp, - *wire_deadline, - refund_deadline, - &amount_without_fee, - &coin_pub, - &merchant_pub, - exchange_pub, - exchange_sig, - &keys->master_pub, - spk->valid_from, - spk->valid_until, - spk->valid_legal, - &spk->master_sig, - &deposit_confirmation_cb, - dcs); + dcs->dc = TALER_AUDITOR_deposit_confirmation ( + TALER_TESTING_interpreter_get_context (is), + auditor_url, + &h_wire, + &no_h_policy, + &h_contract_terms, + *exchange_timestamp, + *wire_deadline, + refund_deadline, + &amount_without_fee, + dcs->num_coins, + coin_pubps, + coin_sigps, + &merchant_pub, + exchange_pub, + exchange_sig, + &keys->master_pub, + spk->valid_from, + spk->valid_until, + spk->valid_legal, + &spk->master_sig, + &deposit_confirmation_cb, + dcs); if (NULL == dcs->dc) { @@ -353,10 +382,8 @@ deposit_confirmation_cleanup (void *cls, if (NULL != dcs->dc) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - dcs->is->ip, - cmd->label); + TALER_TESTING_command_incomplete (dcs->is, + cmd->label); TALER_AUDITOR_deposit_confirmation_cancel (dcs->dc); dcs->dc = NULL; } @@ -371,18 +398,16 @@ deposit_confirmation_cleanup (void *cls, struct TALER_TESTING_Command TALER_TESTING_cmd_deposit_confirmation (const char *label, - struct TALER_AUDITOR_Handle *auditor, const char *deposit_reference, - unsigned int coin_index, + unsigned int num_coins, const char *amount_without_fee, unsigned int expected_response_code) { struct DepositConfirmationState *dcs; dcs = GNUNET_new (struct DepositConfirmationState); - dcs->auditor = auditor; dcs->deposit_reference = deposit_reference; - dcs->coin_index = coin_index; + dcs->num_coins = num_coins; dcs->amount_without_fee = amount_without_fee; dcs->expected_response_code = expected_response_code; diff --git a/src/testing/testing_api_cmd_auditor_exchanges.c b/src/testing/testing_api_cmd_auditor_exchanges.c deleted file mode 100644 index 1e412b2d1..000000000 --- a/src/testing/testing_api_cmd_auditor_exchanges.c +++ /dev/null @@ -1,380 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2018 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3, or (at your - option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - <http://www.gnu.org/licenses/> -*/ -/** - * @file testing/testing_api_cmd_auditor_exchanges.c - * @brief command for testing /exchanges of the auditor - * @author Christian Grothoff - */ -#include "platform.h" -#include "taler_json_lib.h" -#include <gnunet/gnunet_curl_lib.h> -#include "taler_auditor_service.h" -#include "taler_testing_lib.h" -#include "taler_signatures.h" -#include "backoff.h" - -/** - * How long do we wait AT MOST when retrying? - */ -#define MAX_BACKOFF GNUNET_TIME_relative_multiply ( \ - GNUNET_TIME_UNIT_MILLISECONDS, 100) - - -/** - * How often do we retry before giving up? - */ -#define NUM_RETRIES 5 - - -/** - * State for a "deposit confirmation" CMD. - */ -struct ExchangesState -{ - - /** - * Exchanges handle while operation is running. - */ - struct TALER_AUDITOR_ListExchangesHandle *leh; - - /** - * Auditor connection. - */ - struct TALER_AUDITOR_Handle *auditor; - - /** - * Interpreter state. - */ - struct TALER_TESTING_Interpreter *is; - - /** - * Task scheduled to try later. - */ - struct GNUNET_SCHEDULER_Task *retry_task; - - /** - * How long do we wait until we retry? - */ - struct GNUNET_TIME_Relative backoff; - - /** - * Expected HTTP response code. - */ - unsigned int expected_response_code; - - /** - * URL of the exchange expected to be included in the response. - */ - const char *exchange_url; - - /** - * How often should we retry on (transient) failures? - */ - unsigned int do_retry; - -}; - - -/** - * Run the command. - * - * @param cls closure. - * @param cmd the command to execute. - * @param is the interpreter state. - */ -static void -exchanges_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is); - - -/** - * Task scheduled to re-try #exchanges_run. - * - * @param cls a `struct ExchangesState` - */ -static void -do_retry (void *cls) -{ - struct ExchangesState *es = cls; - - es->retry_task = NULL; - es->is->commands[es->is->ip].last_req_time - = GNUNET_TIME_absolute_get (); - exchanges_run (es, - NULL, - es->is); -} - - -/** - * Callback to analyze the /exchanges response. - * - * @param cls closure. - * @param hr HTTP response details - * @param num_exchanges length of the @a ei array - * @param ei array with information about the exchanges - */ -static void -exchanges_cb (void *cls, - const struct TALER_AUDITOR_HttpResponse *hr, - unsigned int num_exchanges, - const struct TALER_AUDITOR_ExchangeInfo *ei) -{ - struct ExchangesState *es = cls; - - es->leh = NULL; - if (es->expected_response_code != hr->http_status) - { - if (0 != es->do_retry) - { - es->do_retry--; - if ( (0 == hr->http_status) || - (TALER_EC_GENERIC_DB_SOFT_FAILURE == hr->ec) || - (MHD_HTTP_INTERNAL_SERVER_ERROR == hr->http_status) ) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Retrying list exchanges failed with %u/%d\n", - hr->http_status, - (int) hr->ec); - /* on DB conflicts, do not use backoff */ - if (TALER_EC_GENERIC_DB_SOFT_FAILURE == hr->ec) - es->backoff = GNUNET_TIME_UNIT_ZERO; - else - es->backoff = GNUNET_TIME_randomized_backoff (es->backoff, - MAX_BACKOFF); - es->is->commands[es->is->ip].num_tries++; - es->retry_task = GNUNET_SCHEDULER_add_delayed (es->backoff, - &do_retry, - es); - return; - } - } - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u/%d to command %s in %s:%u\n", - hr->http_status, - (int) hr->ec, - es->is->commands[es->is->ip].label, - __FILE__, - __LINE__); - json_dumpf (hr->reply, - stderr, - 0); - TALER_TESTING_interpreter_fail (es->is); - return; - } - if (NULL != es->exchange_url) - { - unsigned int found = GNUNET_NO; - - for (unsigned int i = 0; - i<num_exchanges; - i++) - if (0 == strcmp (es->exchange_url, - ei[i].exchange_url)) - found = GNUNET_YES; - if (GNUNET_NO == found) - { - TALER_LOG_ERROR ("Exchange '%s' doesn't exist at this auditor\n", - es->exchange_url); - TALER_TESTING_interpreter_fail (es->is); - return; - } - - TALER_LOG_DEBUG ("Exchange '%s' exists at this auditor!\n", - es->exchange_url); - } - TALER_TESTING_interpreter_next (es->is); -} - - -/** - * Run the command. - * - * @param cls closure. - * @param cmd the command to execute. - * @param is the interpreter state. - */ -static void -exchanges_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - struct ExchangesState *es = cls; - - (void) cmd; - es->is = is; - es->leh = TALER_AUDITOR_list_exchanges - (is->auditor, - &exchanges_cb, - es); - - if (NULL == es->leh) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - return; -} - - -/** - * Free the state of a "exchanges" CMD, and possibly cancel a - * pending operation thereof. - * - * @param cls closure, a `struct ExchangesState` - * @param cmd the command which is being cleaned up. - */ -static void -exchanges_cleanup (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - struct ExchangesState *es = cls; - - if (NULL != es->leh) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - es->is->ip, - cmd->label); - TALER_AUDITOR_list_exchanges_cancel (es->leh); - es->leh = NULL; - } - if (NULL != es->retry_task) - { - GNUNET_SCHEDULER_cancel (es->retry_task); - es->retry_task = NULL; - } - GNUNET_free (es); -} - - -/** - * Offer internal data to other commands. - * - * @param cls closure. - * @param[out] ret set to the wanted data. - * @param trait name of the trait. - * @param index index number of the traits to be returned. - * @return #GNUNET_OK on success - */ -static int -exchanges_traits (void *cls, - const void **ret, - const char *trait, - unsigned int index) -{ - (void) cls; - (void) ret; - (void) trait; - (void) index; - /* Must define this function because some callbacks - * look for certain traits on _all_ the commands. */ - return GNUNET_SYSERR; -} - - -/** - * Create a "list exchanges" command. - * - * @param label command label. - * @param auditor auditor connection. - * @param expected_response_code expected HTTP response code. - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_exchanges (const char *label, - struct TALER_AUDITOR_Handle *auditor, - unsigned int expected_response_code) -{ - struct ExchangesState *es; - - es = GNUNET_new (struct ExchangesState); - es->auditor = auditor; - es->expected_response_code = expected_response_code; - - { - struct TALER_TESTING_Command cmd = { - .cls = es, - .label = label, - .run = &exchanges_run, - .cleanup = &exchanges_cleanup, - .traits = &exchanges_traits - }; - - return cmd; - } -} - - -/** - * Create a "list exchanges" command and check whether - * a particular exchange belongs to the returned bundle. - * - * @param label command label. - * @param expected_response_code expected HTTP response code. - * @param exchange_url URL of the exchange supposed to - * be included in the response. - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_exchanges_with_url (const char *label, - unsigned int expected_response_code, - const char *exchange_url) -{ - struct ExchangesState *es; - - es = GNUNET_new (struct ExchangesState); - es->expected_response_code = expected_response_code; - es->exchange_url = exchange_url; - { - struct TALER_TESTING_Command cmd = { - .cls = es, - .label = label, - .run = &exchanges_run, - .cleanup = &exchanges_cleanup, - .traits = &exchanges_traits - }; - - return cmd; - } -} - - -/** - * Modify an exchanges command to enable retries when we get - * transient errors from the auditor. - * - * @param cmd a deposit confirmation command - * @return the command with retries enabled - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_exchanges_with_retry (struct TALER_TESTING_Command cmd) -{ - struct ExchangesState *es; - - GNUNET_assert (&exchanges_run == cmd.run); - es = cmd.cls; - es->do_retry = NUM_RETRIES; - return cmd; -} - - -/* end of testing_auditor_api_cmd_exchanges.c */ diff --git a/src/testing/testing_api_cmd_bank_admin_add_incoming.c b/src/testing/testing_api_cmd_bank_admin_add_incoming.c index 9db874faf..5c031d0b3 100644 --- a/src/testing/testing_api_cmd_bank_admin_add_incoming.c +++ b/src/testing/testing_api_cmd_bank_admin_add_incoming.c @@ -180,8 +180,7 @@ do_retry (void *cls) struct AdminAddIncomingState *fts = cls; fts->retry_task = NULL; - fts->is->commands[fts->is->ip].last_req_time - = GNUNET_TIME_absolute_get (); + TALER_TESTING_touch_cmd (fts->is); admin_add_incoming_run (fts, NULL, fts->is); @@ -194,28 +193,15 @@ do_retry (void *cls) * acceptable. * * @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 timestamp time stamp of the transaction made. - * @param json raw response + * @param air response details */ static void confirmation_cb (void *cls, - unsigned int http_status, - enum TALER_ErrorCode ec, - uint64_t serial_id, - struct GNUNET_TIME_Timestamp timestamp, - const json_t *json) + const struct TALER_BANK_AdminAddIncomingResponse *air) { struct AdminAddIncomingState *fts = cls; struct TALER_TESTING_Interpreter *is = fts->is; - (void) json; - fts->reserve_history.details.in_details.timestamp = timestamp; - fts->reserve_history.details.in_details.wire_reference = serial_id; fts->aih = NULL; /** * Test case not caring about the HTTP status code. @@ -232,22 +218,29 @@ confirmation_cb (void *cls, * bounces the payment back in the same way it does for * malformed reserve public keys. */ - if (-1 == fts->expected_http_status) + if (-1 == (int) fts->expected_http_status) { TALER_TESTING_interpreter_next (is); return; } - if (http_status != fts->expected_http_status) + if (air->http_status != fts->expected_http_status) { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); + TALER_TESTING_unexpected_status (is, + air->http_status, + fts->expected_http_status); return; } - switch (http_status) + switch (air->http_status) { case MHD_HTTP_OK: - fts->serial_id = serial_id; - fts->timestamp = timestamp; + fts->reserve_history.details.in_details.timestamp + = air->details.ok.timestamp; + fts->reserve_history.details.in_details.wire_reference + = air->details.ok.serial_id; + fts->serial_id + = air->details.ok.serial_id; + fts->timestamp + = air->details.ok.timestamp; TALER_TESTING_interpreter_next (is); return; case MHD_HTTP_UNAUTHORIZED: @@ -271,22 +264,22 @@ confirmation_cb (void *cls, if (0 != fts->do_retry) { fts->do_retry--; - if ( (0 == http_status) || - (TALER_EC_GENERIC_DB_SOFT_FAILURE == ec) || - (MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) ) + if ( (0 == air->http_status) || + (TALER_EC_GENERIC_DB_SOFT_FAILURE == air->ec) || + (MHD_HTTP_INTERNAL_SERVER_ERROR == air->http_status) ) { GNUNET_log ( GNUNET_ERROR_TYPE_INFO, "Retrying fakebank transfer failed with %u/%d\n", - http_status, - (int) ec); + air->http_status, + (int) air->ec); /* on DB conflicts, do not use backoff */ - if (TALER_EC_GENERIC_DB_SOFT_FAILURE == ec) + if (TALER_EC_GENERIC_DB_SOFT_FAILURE == air->ec) fts->backoff = GNUNET_TIME_UNIT_ZERO; else fts->backoff = GNUNET_TIME_randomized_backoff (fts->backoff, MAX_BACKOFF); - fts->is->commands[fts->is->ip].num_tries++; + TALER_TESTING_inc_tries (fts->is); fts->retry_task = GNUNET_SCHEDULER_add_delayed ( fts->backoff, &do_retry, @@ -299,8 +292,8 @@ confirmation_cb (void *cls, GNUNET_break (0); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fakebank returned HTTP status %u/%d\n", - http_status, - (int) ec); + air->http_status, + (int) air->ec); TALER_TESTING_interpreter_fail (is); } @@ -321,6 +314,7 @@ admin_add_incoming_run (void *cls, bool have_public = false; (void) cmd; + fts->is = is; /* Use reserve public key as subject */ if (NULL != fts->reserve_reference) { @@ -371,7 +365,6 @@ admin_add_incoming_run (void *cls, fts->reserve_history.amount = fts->amount; fts->reserve_history.details.in_details.sender_url = (char *) fts->payto_debit_account; /* remember to NOT free this one... */ - fts->is = is; fts->aih = TALER_BANK_admin_add_incoming ( TALER_TESTING_interpreter_get_context (is), @@ -405,9 +398,8 @@ admin_add_incoming_cleanup (void *cls, if (NULL != fts->aih) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %s did not complete\n", - cmd->label); + TALER_TESTING_command_incomplete (fts->is, + cmd->label); TALER_BANK_admin_add_incoming_cancel (fts->aih); fts->aih = NULL; } @@ -446,12 +438,12 @@ admin_add_incoming_traits (void *cls, { struct TALER_TESTING_Trait traits[] = { TALER_TESTING_make_trait_bank_row (&fts->serial_id), - TALER_TESTING_make_trait_debit_payto_uri (&fts->payto_debit_account), - TALER_TESTING_make_trait_payto_uri (&fts->payto_debit_account), + TALER_TESTING_make_trait_debit_payto_uri (fts->payto_debit_account), + TALER_TESTING_make_trait_payto_uri (fts->payto_debit_account), /* Used as a marker, content does not matter */ - TALER_TESTING_make_trait_credit_payto_uri (&void_uri), + TALER_TESTING_make_trait_credit_payto_uri (void_uri), TALER_TESTING_make_trait_exchange_bank_account_url ( - &fts->exchange_credit_url), + fts->exchange_credit_url), TALER_TESTING_make_trait_amount (&fts->amount), TALER_TESTING_make_trait_timestamp (0, &fts->timestamp), @@ -471,13 +463,14 @@ admin_add_incoming_traits (void *cls, { struct TALER_TESTING_Trait traits[] = { TALER_TESTING_make_trait_bank_row (&fts->serial_id), - TALER_TESTING_make_trait_debit_payto_uri (&fts->payto_debit_account), + TALER_TESTING_make_trait_debit_payto_uri (fts->payto_debit_account), /* Used as a marker, content does not matter */ - TALER_TESTING_make_trait_credit_payto_uri (&void_uri), + TALER_TESTING_make_trait_credit_payto_uri (void_uri), TALER_TESTING_make_trait_exchange_bank_account_url ( - &fts->exchange_credit_url), + fts->exchange_credit_url), TALER_TESTING_make_trait_amount (&fts->amount), - TALER_TESTING_make_trait_timestamp (0, &fts->timestamp), + TALER_TESTING_make_trait_timestamp (0, + &fts->timestamp), TALER_TESTING_make_trait_reserve_pub (&fts->reserve_pub), TALER_TESTING_make_trait_reserve_history (0, &fts->reserve_history), diff --git a/src/testing/testing_api_cmd_bank_admin_check.c b/src/testing/testing_api_cmd_bank_admin_check.c index c49e49d8d..6406fe2c2 100644 --- a/src/testing/testing_api_cmd_bank_admin_check.c +++ b/src/testing/testing_api_cmd_bank_admin_check.c @@ -82,8 +82,30 @@ check_bank_admin_transfer_run (void *cls, const char *credit_payto; const struct TALER_ReservePublicKeyP *reserve_pub; const struct TALER_TESTING_Command *cmd_ref; + struct TALER_FAKEBANK_Handle *fakebank; (void) cmd; + { + const struct TALER_TESTING_Command *fakebank_cmd; + + fakebank_cmd + = TALER_TESTING_interpreter_get_command (is, + "fakebank"); + if (NULL == fakebank_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + if (GNUNET_OK != + TALER_TESTING_get_trait_fakebank (fakebank_cmd, + &fakebank)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + } cmd_ref = TALER_TESTING_interpreter_lookup_command (is, bcs->reserve_pub_ref); @@ -109,9 +131,9 @@ check_bank_admin_transfer_run (void *cls, &amount)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to parse amount `%s' at %u\n", + "Failed to parse amount `%s' at %s\n", bcs->amount, - is->ip); + TALER_TESTING_interpreter_get_current_label (is)); TALER_TESTING_interpreter_fail (is); return; } @@ -122,7 +144,7 @@ check_bank_admin_transfer_run (void *cls, debit_payto, debit_account); if (GNUNET_OK != - TALER_FAKEBANK_check_credit (is->fakebank, + TALER_FAKEBANK_check_credit (fakebank, &amount, debit_account, credit_account, diff --git a/src/testing/testing_api_cmd_bank_check.c b/src/testing/testing_api_cmd_bank_check.c index f2148d05c..77d120e09 100644 --- a/src/testing/testing_api_cmd_bank_check.c +++ b/src/testing/testing_api_cmd_bank_check.c @@ -91,26 +91,48 @@ check_bank_transfer_run (void *cls, struct TALER_Amount amount; char *debit_account; char *credit_account; - const char **exchange_base_url; - const char **debit_payto; - const char **credit_payto; + const char *exchange_base_url; + const char *debit_payto; + const char *credit_payto; + struct TALER_FAKEBANK_Handle *fakebank; (void) cmd; + { + const struct TALER_TESTING_Command *fakebank_cmd; + + fakebank_cmd + = TALER_TESTING_interpreter_get_command (is, + "fakebank"); + if (NULL == fakebank_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + if (GNUNET_OK != + TALER_TESTING_get_trait_fakebank (fakebank_cmd, + &fakebank)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + } if (NULL == bcs->deposit_reference) { TALER_LOG_INFO ("Deposit reference NOT given\n"); - debit_payto = &bcs->debit_payto; - credit_payto = &bcs->credit_payto; - exchange_base_url = &bcs->exchange_base_url; + debit_payto = bcs->debit_payto; + credit_payto = bcs->credit_payto; + exchange_base_url = bcs->exchange_base_url; if (GNUNET_OK != TALER_string_to_amount (bcs->amount, &amount)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to parse amount `%s' at %u\n", + "Failed to parse amount `%s' at %s\n", bcs->amount, - is->ip); + TALER_TESTING_interpreter_get_current_label (is)); TALER_TESTING_interpreter_fail (is); return; } @@ -145,27 +167,22 @@ check_bank_transfer_run (void *cls, TALER_TESTING_FAIL (is); amount = *amount_ptr; } - - - debit_account = TALER_xtalerbank_account_from_payto (*debit_payto); - credit_account = TALER_xtalerbank_account_from_payto (*credit_payto); - + debit_account = TALER_xtalerbank_account_from_payto (debit_payto); + credit_account = TALER_xtalerbank_account_from_payto (credit_payto); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "converted debit_payto (%s) to debit_account (%s)\n", - *debit_payto, + debit_payto, debit_account); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "converted credit_payto (%s) to credit_account (%s)\n", - *credit_payto, + credit_payto, credit_account); - if (GNUNET_OK != - TALER_FAKEBANK_check_debit (is->fakebank, + TALER_FAKEBANK_check_debit (fakebank, &amount, debit_account, credit_account, - *exchange_base_url, + exchange_base_url, &bcs->wtid)) { GNUNET_break (0); @@ -217,7 +234,7 @@ check_bank_transfer_traits (void *cls, struct TALER_TESTING_Trait traits[] = { TALER_TESTING_make_trait_wtid (wtid_ptr), TALER_TESTING_make_trait_exchange_url ( - &bcs->exchange_base_url), + bcs->exchange_base_url), TALER_TESTING_trait_end () }; diff --git a/src/testing/testing_api_cmd_bank_check_empty.c b/src/testing/testing_api_cmd_bank_check_empty.c index 84976b0b5..60f00fbb4 100644 --- a/src/testing/testing_api_cmd_bank_check_empty.c +++ b/src/testing/testing_api_cmd_bank_check_empty.c @@ -58,9 +58,33 @@ check_bank_empty_run (void *cls, const struct TALER_TESTING_Command *cmd, struct TALER_TESTING_Interpreter *is) { + struct TALER_FAKEBANK_Handle *fakebank; + (void) cls; (void) cmd; - if (GNUNET_OK != TALER_FAKEBANK_check_empty (is->fakebank)) + { + const struct TALER_TESTING_Command *fakebank_cmd; + + fakebank_cmd + = TALER_TESTING_interpreter_get_command (is, + "fakebank"); + if (NULL == fakebank_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + if (GNUNET_OK != + TALER_TESTING_get_trait_fakebank (fakebank_cmd, + &fakebank)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + } + if (GNUNET_OK != + TALER_FAKEBANK_check_empty (fakebank)) { GNUNET_break (0); TALER_TESTING_interpreter_fail (is); diff --git a/src/testing/testing_api_cmd_bank_history_credit.c b/src/testing/testing_api_cmd_bank_history_credit.c index c65c84c13..956e6c857 100644 --- a/src/testing/testing_api_cmd_bank_history_credit.c +++ b/src/testing/testing_api_cmd_bank_history_credit.c @@ -83,6 +83,11 @@ struct HistoryState struct TALER_BANK_CreditHistoryHandle *hh; /** + * The interpreter. + */ + struct TALER_TESTING_Interpreter *is; + + /** * Authentication data for the operation. */ struct TALER_BANK_AuthenticationData auth; @@ -144,35 +149,161 @@ print_expected (struct History *h, /** + * Closure for command_cb(). + */ +struct IteratorContext +{ + /** + * Array of history items to return. + */ + struct History *h; + + /** + * Set to the row ID from where on we should actually process history items, + * or NULL if we should process all of them. + */ + const uint64_t *row_id_start; + + /** + * History state we are working on. + */ + struct HistoryState *hs; + + /** + * Current length of the @e h array. + */ + unsigned int total; + + /** + * Current write position in @e h array. + */ + unsigned int pos; + + /** + * Ok equals True whenever a starting row_id was provided AND was found + * among the CMDs, OR no starting row was given in the first place. + */ + bool ok; + +}; + + +/** + * Helper function of build_history() that expands + * the history for each relevant command encountered. + * + * @param[in,out] cls our `struct IteratorContext` + * @param cmd a command to process + */ +static void +command_cb (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct IteratorContext *ic = cls; + struct HistoryState *hs = ic->hs; + const uint64_t *row_id; + const char *credit_account; + const char *debit_account; + const struct TALER_Amount *amount; + const struct TALER_ReservePublicKeyP *reserve_pub; + const char *exchange_credit_url; + + /** + * The following command allows us to skip over those CMDs + * that do not offer a "row_id" trait. Such skipped CMDs are + * not interesting for building a history. + */ + if ( (GNUNET_OK != + TALER_TESTING_get_trait_bank_row (cmd, + &row_id)) || + (GNUNET_OK != + TALER_TESTING_get_trait_credit_payto_uri (cmd, + &credit_account)) || + (GNUNET_OK != + TALER_TESTING_get_trait_debit_payto_uri (cmd, + &debit_account)) || + (GNUNET_OK != + TALER_TESTING_get_trait_amount (cmd, + &amount)) || + (GNUNET_OK != + TALER_TESTING_get_trait_reserve_pub (cmd, + &reserve_pub)) || + (GNUNET_OK != + TALER_TESTING_get_trait_exchange_bank_account_url ( + cmd, + &exchange_credit_url)) ) + return; // Not an interesting event + + /** + * Is the interesting event a match with regard to + * the row_id value? If yes, store this condition + * to the state and analyze the next CMDs. + */ + if ( (NULL != ic->row_id_start) && + (*(ic->row_id_start) == *row_id) && + (! ic->ok) ) + { + ic->ok = true; + return; + } + /** + * The interesting event didn't match the wanted + * row_id value, analyze the next CMDs. Note: this + * branch is relevant only when row_id WAS given. + */ + if (! ic->ok) + return; + if (0 != strcasecmp (hs->account_url, + exchange_credit_url)) + return; // Account mismatch + if (ic->total >= GNUNET_MAX (hs->num_results, + -hs->num_results) ) + { + TALER_LOG_DEBUG ("Hit history limit\n"); + return; + } + TALER_LOG_INFO ("Found history: %s->%s for account %s\n", + debit_account, + credit_account, + hs->account_url); + /* found matching record, make sure we have room */ + if (ic->pos == ic->total) + GNUNET_array_grow (ic->h, + ic->total, + ic->pos * 2); + ic->h[ic->pos].url = GNUNET_strdup (debit_account); + ic->h[ic->pos].details.debit_account_uri = ic->h[ic->pos].url; + ic->h[ic->pos].details.amount = *amount; + ic->h[ic->pos].row_id = *row_id; + ic->h[ic->pos].details.reserve_pub = *reserve_pub; + ic->pos++; +} + + +/** * This function constructs the list of history elements that * interest the account number of the caller. It has two main * loops: the first to figure out how many history elements have * to be allocated, and the second to actually populate every * element. * - * @param is interpreter state (supposedly having the - * current CMD pointing at a "history" CMD). + * @param hs history state * @param[out] rh history array to initialize. * @return number of entries in @a rh. */ static unsigned int -build_history (struct TALER_TESTING_Interpreter *is, +build_history (struct HistoryState *hs, struct History **rh) { - struct HistoryState *hs = is->commands[is->ip].cls; - unsigned int total; - unsigned int pos; - struct History *h; - const struct TALER_TESTING_Command *add_incoming_cmd; - int inc; - unsigned int start; - unsigned int end; - - int ok; - const uint64_t *row_id_start = NULL; + struct TALER_TESTING_Interpreter *is = hs->is; + struct IteratorContext ic = { + .hs = hs + }; if (NULL != hs->start_row_reference) { + const struct TALER_TESTING_Command *add_incoming_cmd; + TALER_LOG_INFO ("`%s': start row given via reference `%s'\n", TALER_TESTING_interpreter_get_current_label (is), hs->start_row_reference); @@ -182,131 +313,91 @@ build_history (struct TALER_TESTING_Interpreter *is, GNUNET_assert (NULL != add_incoming_cmd); GNUNET_assert (GNUNET_OK == TALER_TESTING_get_trait_row (add_incoming_cmd, - &row_id_start)); + &ic.row_id_start)); } + ic.ok = false; + if (NULL == ic.row_id_start) + ic.ok = true; + GNUNET_array_grow (ic.h, + ic.total, + 4); GNUNET_assert (0 != hs->num_results); - if (0 == is->ip) - { - TALER_LOG_DEBUG ("Checking history at FIRST transaction (EMPTY)\n"); - *rh = NULL; - return 0; - } + TALER_TESTING_iterate (is, + hs->num_results > 0, + &command_cb, + &ic); + GNUNET_assert (ic.ok); + GNUNET_array_grow (ic.h, + ic.total, + ic.pos); + if (0 == ic.pos) + TALER_LOG_DEBUG ("Empty credit history computed\n"); + *rh = ic.h; + return ic.pos; +} - if (hs->num_results > 0) + +/** + * Normalize IBAN-based payto URI in @a in. + * + * @param in input payto://-URI to normalize + * @return normalized IBAN for the test + */ +static char * +normalize (const char *in) +{ + char *npt; + const char *q = strchr (in, + '?'); + const char *mptr; + const char *bic; + const char *iban; + + if (NULL == q) + npt = GNUNET_strdup (in); + else + npt = GNUNET_strndup (in, + q - in); + if (0 != strncasecmp (npt, + "payto://", + strlen ("payto://"))) { - inc = 1; /* _inc_rement */ - start = 0; - end = is->ip - 1; + GNUNET_break (0); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Invalid payto: %s\n", + npt); + GNUNET_free (npt); + return NULL; } - else + mptr = npt + strlen ("payto://"); + bic = strchr (mptr, '/'); + if (NULL == bic) { - inc = -1; - start = is->ip - 1; - end = 0; + GNUNET_break (0); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Invalid payto: %s\n", + npt); + GNUNET_free (npt); + return NULL; } - /** - * ok equals GNUNET_YES whenever a starting row_id - * was provided AND was found among the CMDs, OR no - * starting row was given in the first place. - */ - ok = GNUNET_NO; - if (NULL == row_id_start) - ok = GNUNET_YES; - h = NULL; - total = 0; - GNUNET_array_grow (h, - total, - 4); - pos = 0; - for (unsigned int off = start; off != end + inc; off += inc) + bic++; + iban = strchr (bic, '/'); + if (NULL != iban) { - const struct TALER_TESTING_Command *cmd = &is->commands[off]; - const uint64_t *row_id; - const char **credit_account; - const char **debit_account; - const struct TALER_Amount *amount; - const struct TALER_ReservePublicKeyP *reserve_pub; - const char **exchange_credit_url; - - /** - * The following command allows us to skip over those CMDs - * that do not offer a "row_id" trait. Such skipped CMDs are - * not interesting for building a history. - */ - if ( (GNUNET_OK != - TALER_TESTING_get_trait_bank_row (cmd, - &row_id)) || - (GNUNET_OK != - TALER_TESTING_get_trait_credit_payto_uri (cmd, - &credit_account)) || - (GNUNET_OK != - TALER_TESTING_get_trait_debit_payto_uri (cmd, - &debit_account)) || - (GNUNET_OK != - TALER_TESTING_get_trait_amount (cmd, - &amount)) || - (GNUNET_OK != - TALER_TESTING_get_trait_reserve_pub (cmd, - &reserve_pub)) || - (GNUNET_OK != - TALER_TESTING_get_trait_exchange_bank_account_url ( - cmd, - &exchange_credit_url)) ) - continue; // Not an interesting event - /** - * Is the interesting event a match with regard to - * the row_id value? If yes, store this condition - * to the state and analyze the next CMDs. - */ - if ( (NULL != row_id_start) && - (*row_id_start == *row_id) && - (GNUNET_NO == ok) ) - { - ok = GNUNET_YES; - continue; - } - /** - * The interesting event didn't match the wanted - * row_id value, analyze the next CMDs. Note: this - * branch is relevant only when row_id WAS given. - */ - if (GNUNET_NO == ok) - continue; - if (0 != strcasecmp (hs->account_url, - *exchange_credit_url)) - continue; // Account mismatch - if (total >= GNUNET_MAX (hs->num_results, - -hs->num_results) ) - { - TALER_LOG_DEBUG ("Hit history limit\n"); - break; - } - TALER_LOG_INFO ("Found history: %s->%s for account %s\n", - *debit_account, - *credit_account, - hs->account_url); - /* found matching record, make sure we have room */ - if (pos == total) - GNUNET_array_grow (h, - total, - pos * 2); - h[pos].url = GNUNET_strdup (*debit_account); - h[pos].details.debit_account_uri = h[pos].url; - h[pos].details.amount = *amount; - h[pos].row_id = *row_id; - h[pos].details.reserve_pub = *reserve_pub; - h[pos].details.credit_account_uri = *exchange_credit_url; - pos++; + /* need to remove bic */ + char *n; + + iban++; + GNUNET_asprintf (&n, + "payto://%.*s/%s", + (int) ((bic - mptr) - 1), + mptr, + iban); + GNUNET_free (npt); + npt = n; } - GNUNET_assert (GNUNET_YES == ok); - GNUNET_array_grow (h, - total, - pos); - if (0 == pos) - TALER_LOG_DEBUG ("Empty credit history computed\n"); - *rh = h; - return total; + return npt; } @@ -327,6 +418,9 @@ check_result (struct History *h, unsigned int off, const struct TALER_BANK_CreditDetails *details) { + char *u1; + char *u2; + if (off >= total) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, @@ -339,25 +433,42 @@ check_result (struct History *h, off); return GNUNET_SYSERR; } + u1 = normalize (h[off].details.debit_account_uri); + if (NULL == u1) + return GNUNET_SYSERR; + u2 = normalize (details->debit_account_uri); + if (NULL == u2) + { + GNUNET_free (u1); + return GNUNET_SYSERR; + } if ( (0 != GNUNET_memcmp (&h[off].details.reserve_pub, &details->reserve_pub)) || (0 != TALER_amount_cmp (&h[off].details.amount, &details->amount)) || - (0 != strcasecmp (h[off].details.debit_account_uri, - details->debit_account_uri)) ) + (0 != strcasecmp (u1, + u2)) ) { GNUNET_break (0); GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "expected debit_account_uri: %s\n", - details->debit_account_uri); + "expected debit_account_uri: %s with %s for %s\n", + u1, + TALER_amount2s (&h[off].details.amount), + TALER_B2S (&h[off].details.reserve_pub)); GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "actual debit_account_uri: %s\n", - h[off].details.debit_account_uri); + "actual debit_account_uri: %s with %s for %s\n", + u2, + TALER_amount2s (&details->amount), + TALER_B2S (&details->reserve_pub)); print_expected (h, total, off); + GNUNET_free (u1); + GNUNET_free (u2); return GNUNET_SYSERR; } + GNUNET_free (u1); + GNUNET_free (u2); return GNUNET_OK; } @@ -370,99 +481,86 @@ check_result (struct History *h, * finally check it against what the bank returned. * * @param cls closure. - * @param http_status HTTP response code, #MHD_HTTP_OK (200) - * for successful status request 0 if the bank's reply is - * bogus (fails to follow the protocol), - * #MHD_HTTP_NO_CONTENT if there are no more results; on - * success the last callback is always of this status - * (even if `abs(num_results)` were already returned). - * @param ec taler status code. - * @param row_id monotonically increasing counter corresponding to - * the transaction. - * @param details details about the wire transfer. - * @param json detailed response from the HTTPD, or NULL if - * reply was not in JSON. - * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration + * @param chr http response details */ -static enum GNUNET_GenericReturnValue +static void history_cb (void *cls, - unsigned int http_status, - enum TALER_ErrorCode ec, - uint64_t row_id, - const struct TALER_BANK_CreditDetails *details, - const json_t *json) + const struct TALER_BANK_CreditHistoryResponse *chr) { - struct TALER_TESTING_Interpreter *is = cls; - struct HistoryState *hs = is->commands[is->ip].cls; + struct HistoryState *hs = cls; + struct TALER_TESTING_Interpreter *is = hs->is; - (void) row_id; - if (NULL == details) + hs->hh = NULL; + switch (chr->http_status) { - hs->hh = NULL; - if ( (MHD_HTTP_NOT_FOUND == http_status) && - (0 == hs->total) ) + case 0: + GNUNET_break (0); + goto error; + case MHD_HTTP_OK: + for (unsigned int i = 0; i<chr->details.ok.details_length; i++) + { + const struct TALER_BANK_CreditDetails *cd = + &chr->details.ok.details[i]; + + /* check current element */ + if (GNUNET_OK != + check_result (hs->h, + hs->total, + hs->results_obtained, + cd)) + { + GNUNET_break (0); + json_dumpf (chr->response, + stderr, + JSON_COMPACT); + hs->failed = true; + hs->hh = NULL; + TALER_TESTING_interpreter_fail (is); + return; + } + hs->results_obtained++; + } + TALER_TESTING_interpreter_next (is); + return; + case MHD_HTTP_NO_CONTENT: + if (0 == hs->total) { /* not found is OK for empty history */ TALER_TESTING_interpreter_next (is); - return GNUNET_OK; + return; } - if ( (hs->results_obtained != hs->total) || - (hs->failed) || - (MHD_HTTP_NO_CONTENT != http_status) ) + GNUNET_break (0); + goto error; + case MHD_HTTP_NOT_FOUND: + if (0 == hs->total) { - GNUNET_break (0); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Expected history of length %u, got %llu;" - " HTTP status code: %u/%d, failed: %d\n", - hs->total, - (unsigned long long) hs->results_obtained, - http_status, - (int) ec, - hs->failed ? 1 : 0); - print_expected (hs->h, - hs->total, - UINT_MAX); - TALER_TESTING_interpreter_fail (is); - return GNUNET_SYSERR; + /* not found is OK for empty history */ + TALER_TESTING_interpreter_next (is); + return; } - TALER_TESTING_interpreter_next (is); - return GNUNET_OK; - } - if (MHD_HTTP_OK != http_status) - { + GNUNET_break (0); + goto error; + default: hs->hh = NULL; GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unwanted response code from /history/incoming: %u\n", - http_status); - TALER_TESTING_interpreter_fail (is); - return GNUNET_SYSERR; - } - - /* check current element */ - if (GNUNET_OK != - check_result (hs->h, - hs->total, - hs->results_obtained, - details)) - { - char *acc; - - GNUNET_break (0); - acc = json_dumps (json, - JSON_COMPACT); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Result %u was `%s'\n", - (unsigned int) hs->results_obtained++, - acc); - if (NULL != acc) - free (acc); - hs->failed = true; - hs->hh = NULL; + chr->http_status); TALER_TESTING_interpreter_fail (is); - return GNUNET_SYSERR; + return; } - hs->results_obtained++; - return GNUNET_OK; +error: + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Expected history of length %u, got %llu;" + " HTTP status code: %u/%d, failed: %d\n", + hs->total, + (unsigned long long) hs->results_obtained, + chr->http_status, + (int) chr->ec, + hs->failed ? 1 : 0); + print_expected (hs->h, + hs->total, + UINT_MAX); + TALER_TESTING_interpreter_fail (is); } @@ -483,6 +581,7 @@ history_run (void *cls, const uint64_t *row_ptr; (void) cmd; + hs->is = is; /* Get row_id from trait. */ if (NULL != hs->start_row_reference) { @@ -503,15 +602,16 @@ history_run (void *cls, TALER_LOG_DEBUG ("row id (from trait) is %llu\n", (unsigned long long) row_id); } - hs->total = build_history (is, + hs->total = build_history (hs, &hs->h); - hs->hh = TALER_BANK_credit_history (is->ctx, - &hs->auth, - row_id, - hs->num_results, - GNUNET_TIME_UNIT_ZERO, - &history_cb, - is); + hs->hh = TALER_BANK_credit_history ( + TALER_TESTING_interpreter_get_context (is), + &hs->auth, + row_id, + hs->num_results, + GNUNET_TIME_UNIT_ZERO, + &history_cb, + hs); GNUNET_assert (NULL != hs->hh); } @@ -532,7 +632,8 @@ history_cleanup (void *cls, (void) cmd; if (NULL != hs->hh) { - TALER_LOG_WARNING ("/history/incoming did not complete\n"); + TALER_TESTING_command_incomplete (hs->is, + cmd->label); TALER_BANK_credit_history_cancel (hs->hh); } GNUNET_free (hs->account_url); diff --git a/src/testing/testing_api_cmd_bank_history_debit.c b/src/testing/testing_api_cmd_bank_history_debit.c index cb3f68097..1cb7320fa 100644 --- a/src/testing/testing_api_cmd_bank_history_debit.c +++ b/src/testing/testing_api_cmd_bank_history_debit.c @@ -92,6 +92,11 @@ struct HistoryState struct TALER_BANK_DebitHistoryHandle *hh; /** + * Our interpreter. + */ + struct TALER_TESTING_Interpreter *is; + + /** * Expected number of results (= rows). */ uint64_t results_obtained; @@ -147,38 +152,155 @@ print_expected (struct History *h, /** + * Closure for command_cb(). + */ +struct IteratorContext +{ + /** + * Array of history items to return. + */ + struct History *h; + + /** + * Set to the row ID from where on we should actually process history items, + * or NULL if we should process all of them. + */ + const uint64_t *row_id_start; + + /** + * History state we are working on. + */ + struct HistoryState *hs; + + /** + * Current length of the @e h array. + */ + unsigned int total; + + /** + * Current write position in @e h array. + */ + unsigned int pos; + + /** + * Ok equals True whenever a starting row_id was provided AND was found + * among the CMDs, OR no starting row was given in the first place. + */ + bool ok; + +}; + + +/** + * Helper function of build_history() that expands + * the history for each relevant command encountered. + * + * @param[in,out] cls our `struct IteratorContext` + * @param cmd a command to process + */ +static void +command_cb (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct IteratorContext *ic = cls; + struct HistoryState *hs = ic->hs; + + const uint64_t *row_id; + const char *debit_account; + const char *credit_account; + const struct TALER_Amount *amount; + const struct TALER_WireTransferIdentifierRawP *wtid; + const char *exchange_base_url; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Checking if command %s is relevant for debit history\n", + cmd->label); + if ( (GNUNET_OK != + TALER_TESTING_get_trait_bank_row (cmd, + &row_id)) || + (GNUNET_OK != + TALER_TESTING_get_trait_debit_payto_uri (cmd, + &debit_account)) || + (GNUNET_OK != + TALER_TESTING_get_trait_credit_payto_uri (cmd, + &credit_account)) || + (GNUNET_OK != + TALER_TESTING_get_trait_amount (cmd, + &amount)) || + (GNUNET_OK != + TALER_TESTING_get_trait_wtid (cmd, + &wtid)) || + (GNUNET_OK != + TALER_TESTING_get_trait_exchange_url (cmd, + &exchange_base_url)) ) + return; /* not an event we care about */ + /* Seek "/history/outgoing" starting row. */ + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Command %s is relevant for debit history!\n", + cmd->label); + if ( (NULL != ic->row_id_start) && + (*(ic->row_id_start) == *row_id) && + (! ic->ok) ) + { + /* Until here, nothing counted. */ + ic->ok = true; + return; + } + /* when 'start' was _not_ given, then ok == GNUNET_YES */ + if (! ic->ok) + return; /* skip until we find the marker */ + if (ic->total >= GNUNET_MAX (hs->num_results, + -hs->num_results) ) + { + TALER_LOG_DEBUG ("Hit history limit\n"); + return; + } + TALER_LOG_INFO ("Found history: %s->%s for account %s\n", + debit_account, + credit_account, + hs->account_url); + /* found matching record, make sure we have room */ + if (ic->pos == ic->total) + GNUNET_array_grow (ic->h, + ic->total, + ic->pos * 2); + ic->h[ic->pos].c_url = GNUNET_strdup (credit_account); + ic->h[ic->pos].d_url = GNUNET_strdup (debit_account); + ic->h[ic->pos].details.credit_account_uri = ic->h[ic->pos].c_url; + ic->h[ic->pos].details.amount = *amount; + ic->h[ic->pos].row_id = *row_id; + ic->h[ic->pos].details.wtid = *wtid; + ic->h[ic->pos].details.exchange_base_url = exchange_base_url; + ic->pos++; +} + + +/** * This function constructs the list of history elements that * interest the account number of the caller. It has two main * loops: the first to figure out how many history elements have * to be allocated, and the second to actually populate every * element. * - * @param is interpreter state (supposedly having the - * current CMD pointing at a "history" CMD). + * @param hs history state command context * @param[out] rh history array to initialize. * @return number of entries in @a rh. */ static unsigned int -build_history (struct TALER_TESTING_Interpreter *is, +build_history (struct HistoryState *hs, struct History **rh) { - struct HistoryState *hs = is->commands[is->ip].cls; - unsigned int total; - unsigned int pos; - struct History *h; - const struct TALER_TESTING_Command *add_incoming_cmd; - int inc; - int start; - int end; - /* #GNUNET_YES whenever either no 'start' value was given for the history - * query, or the given value is found in the list of all the CMDs. */ - int ok; - const uint64_t *row_id_start = NULL; + struct TALER_TESTING_Interpreter *is = hs->is; + struct IteratorContext ic = { + .hs = hs + }; if (NULL != hs->start_row_reference) { - TALER_LOG_INFO - ("`%s': start row given via reference `%s'\n", + const struct TALER_TESTING_Command *add_incoming_cmd; + + TALER_LOG_INFO ( + "`%s': start row given via reference `%s'\n", TALER_TESTING_interpreter_get_current_label (is), hs->start_row_reference); add_incoming_cmd = TALER_TESTING_interpreter_lookup_command ( @@ -187,124 +309,91 @@ build_history (struct TALER_TESTING_Interpreter *is, GNUNET_assert (NULL != add_incoming_cmd); GNUNET_assert (GNUNET_OK == TALER_TESTING_get_trait_row (add_incoming_cmd, - &row_id_start)); + &ic.row_id_start)); } + ic.ok = false; + if (NULL == ic.row_id_start) + ic.ok = true; + GNUNET_array_grow (ic.h, + ic.total, + 4); GNUNET_assert (0 != hs->num_results); - if (0 == is->ip) - { - TALER_LOG_DEBUG ("Checking history at first CMD..\n"); - *rh = NULL; - return 0; - } + TALER_TESTING_iterate (is, + hs->num_results > 0, + &command_cb, + &ic); + GNUNET_assert (ic.ok); + GNUNET_array_grow (ic.h, + ic.total, + ic.pos); + if (0 == ic.pos) + TALER_LOG_DEBUG ("Empty credit history computed\n"); + *rh = ic.h; + return ic.pos; +} - /* AKA 'delta' */ - if (hs->num_results > 0) - { - inc = 1; /* _inc_rement: go forwards */ - start = 0; - end = is->ip; - } + +/** + * Normalize IBAN-based payto URI in @a in. + * + * @param in input payto://-URI to normalize + * @return normalized IBAN for the test + */ +static char * +normalize (const char *in) +{ + char *npt; + const char *q = strchr (in, + '?'); + const char *mptr; + const char *bic; + const char *iban; + + if (NULL == q) + npt = GNUNET_strdup (in); else + npt = GNUNET_strndup (in, + q - in); + if (0 != strncasecmp (npt, + "payto://", + strlen ("payto://"))) { - inc = -1; /* decrement: we go backwards */ - start = is->ip - 1; - end = -1; /* range is exclusive, do look at 0! */ + GNUNET_break (0); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Invalid payto: %s\n", + npt); + GNUNET_free (npt); + return NULL; } - - ok = GNUNET_NO; - if (NULL == row_id_start) - ok = GNUNET_YES; - h = NULL; - total = 0; - GNUNET_array_grow (h, - total, - 4); - pos = 0; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Checking commands %u to %u for debit history\n", - start, - end); - for (int off = start; off != end; off += inc) + mptr = npt + strlen ("payto://"); + bic = strchr (mptr, '/'); + if (NULL == bic) { - const struct TALER_TESTING_Command *cmd = &is->commands[off]; - const uint64_t *row_id; - const char **debit_account; - const char **credit_account; - const struct TALER_Amount *amount; - const struct TALER_WireTransferIdentifierRawP *wtid; - const char **exchange_base_url; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Checking if command %s is relevant for debit history\n", - cmd->label); - if ( (GNUNET_OK != - TALER_TESTING_get_trait_bank_row (cmd, - &row_id)) || - (GNUNET_OK != - TALER_TESTING_get_trait_debit_payto_uri (cmd, - &debit_account)) || - (GNUNET_OK != - TALER_TESTING_get_trait_credit_payto_uri (cmd, - &credit_account)) || - (GNUNET_OK != - TALER_TESTING_get_trait_amount (cmd, - &amount)) || - (GNUNET_OK != - TALER_TESTING_get_trait_wtid (cmd, - &wtid)) || - (GNUNET_OK != - TALER_TESTING_get_trait_exchange_url (cmd, - &exchange_base_url)) ) - continue; /* not an event we care about */ - /* Seek "/history/outgoing" starting row. */ + GNUNET_break (0); GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Command %s is relevant for debit history!\n", - cmd->label); - if ( (NULL != row_id_start) && - (*row_id_start == *row_id) && - (GNUNET_NO == ok) ) - { - /* Until here, nothing counted. */ - ok = GNUNET_YES; - continue; - } - /* when 'start' was _not_ given, then ok == GNUNET_YES */ - if (GNUNET_NO == ok) - continue; /* skip until we find the marker */ - if (total >= GNUNET_MAX (hs->num_results, - -hs->num_results) ) - { - TALER_LOG_DEBUG ("Hit history limit\n"); - break; - } - TALER_LOG_INFO ("Found history: %s->%s for account %s\n", - *debit_account, - *credit_account, - hs->account_url); - /* found matching record, make sure we have room */ - if (pos == total) - GNUNET_array_grow (h, - total, - pos * 2); - h[pos].c_url = GNUNET_strdup (*credit_account); - h[pos].d_url = GNUNET_strdup (*debit_account); - h[pos].details.credit_account_uri = h[pos].c_url; - h[pos].details.debit_account_uri = h[pos].d_url; - h[pos].details.amount = *amount; - h[pos].row_id = *row_id; - h[pos].details.wtid = *wtid; - h[pos].details.exchange_base_url = *exchange_base_url; - pos++; + "Invalid payto: %s\n", + npt); + GNUNET_free (npt); + return NULL; } - GNUNET_assert (GNUNET_YES == ok); - GNUNET_array_grow (h, - total, - pos); - if (0 == pos) - TALER_LOG_DEBUG ("Empty debit history computed\n"); - *rh = h; - return total; + bic++; + iban = strchr (bic, '/'); + if (NULL != iban) + { + /* need to remove bic */ + char *n; + + iban++; + GNUNET_asprintf (&n, + "payto://%.*s/%s", + (int) ((bic - mptr) - 1), + mptr, + iban); + GNUNET_free (npt); + npt = n; + } + return npt; } @@ -325,6 +414,9 @@ check_result (struct History *h, unsigned int off, const struct TALER_BANK_DebitDetails *details) { + char *u1; + char *u2; + if (off >= total) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, @@ -337,14 +429,33 @@ check_result (struct History *h, off); return GNUNET_SYSERR; } + u1 = normalize (h[off].details.credit_account_uri); + if (NULL == u1) + return GNUNET_SYSERR; + u2 = normalize (details->credit_account_uri); + if (NULL == u2) + { + GNUNET_free (u1); + return GNUNET_SYSERR; + } if ( (0 != GNUNET_memcmp (&h[off].details.wtid, &details->wtid)) || (0 != TALER_amount_cmp (&h[off].details.amount, &details->amount)) || - (0 != strcasecmp (h[off].details.credit_account_uri, - details->credit_account_uri)) ) + (0 != strcasecmp (u1, + u2)) ) { GNUNET_break (0); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "expected debit_account_uri: %s with %s for %s\n", + u1, + TALER_amount2s (&h[off].details.amount), + TALER_B2S (&h[off].details.wtid)); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "actual debit_account_uri: %s with %s for %s\n", + u2, + TALER_amount2s (&details->amount), + TALER_B2S (&details->wtid)); print_expected (h, total, off); @@ -362,99 +473,86 @@ check_result (struct History *h, * finally check it against what the bank returned. * * @param cls closure. - * @param http_status HTTP response code, #MHD_HTTP_OK (200) - * for successful status request 0 if the bank's reply is - * bogus (fails to follow the protocol), - * #MHD_HTTP_NO_CONTENT if there are no more results; on - * success the last callback is always of this status - * (even if `abs(num_results)` were already returned). - * @param ec taler status code. - * @param row_id monotonically increasing counter corresponding to - * the transaction. - * @param details details about the wire transfer. - * @param json detailed response from the HTTPD, or NULL if - * reply was not in JSON. - * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration + * @param dhr http response details */ -static enum GNUNET_GenericReturnValue +static void history_cb (void *cls, - unsigned int http_status, - enum TALER_ErrorCode ec, - uint64_t row_id, - const struct TALER_BANK_DebitDetails *details, - const json_t *json) + const struct TALER_BANK_DebitHistoryResponse *dhr) { - struct TALER_TESTING_Interpreter *is = cls; - struct HistoryState *hs = is->commands[is->ip].cls; + struct HistoryState *hs = cls; + struct TALER_TESTING_Interpreter *is = hs->is; - (void) row_id; - if (NULL == details) + hs->hh = NULL; + switch (dhr->http_status) { - hs->hh = NULL; - if ( (MHD_HTTP_NOT_FOUND == http_status) && - (0 == hs->total) ) + case 0: + GNUNET_break (0); + goto error; + case MHD_HTTP_OK: + for (unsigned int i = 0; i<dhr->details.ok.details_length; i++) + { + const struct TALER_BANK_DebitDetails *dd = + &dhr->details.ok.details[i]; + + /* check current element */ + if (GNUNET_OK != + check_result (hs->h, + hs->total, + hs->results_obtained, + dd)) + { + GNUNET_break (0); + json_dumpf (dhr->response, + stderr, + JSON_COMPACT); + hs->failed = true; + hs->hh = NULL; + TALER_TESTING_interpreter_fail (is); + return; + } + hs->results_obtained++; + } + TALER_TESTING_interpreter_next (is); + return; + case MHD_HTTP_NO_CONTENT: + if (0 == hs->total) { /* not found is OK for empty history */ TALER_TESTING_interpreter_next (is); - return GNUNET_OK; + return; } - if ( (hs->results_obtained != hs->total) || - (GNUNET_YES == hs->failed) || - (MHD_HTTP_NO_CONTENT != http_status) ) + GNUNET_break (0); + goto error; + case MHD_HTTP_NOT_FOUND: + if (0 == hs->total) { - GNUNET_break (0); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Expected history of length %u, got %llu;" - " HTTP status code: %u/%d, failed: %d\n", - hs->total, - (unsigned long long) hs->results_obtained, - http_status, - (int) ec, - hs->failed); - print_expected (hs->h, - hs->total, - UINT_MAX); - TALER_TESTING_interpreter_fail (is); - return GNUNET_SYSERR; + /* not found is OK for empty history */ + TALER_TESTING_interpreter_next (is); + return; } - TALER_TESTING_interpreter_next (is); - return GNUNET_OK; - } - if (MHD_HTTP_OK != http_status) - { - hs->hh = NULL; - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unwanted response code from /history/outgoing: %u\n", - http_status); - TALER_TESTING_interpreter_fail (is); - return GNUNET_SYSERR; - } - - /* check current element */ - if (GNUNET_OK != - check_result (hs->h, - hs->total, - hs->results_obtained, - details)) - { - char *acc; - GNUNET_break (0); - acc = json_dumps (json, - JSON_COMPACT); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Result %u was `%s'\n", - (unsigned int) hs->results_obtained++, - acc); - if (NULL != acc) - free (acc); - hs->failed = GNUNET_YES; + goto error; + default: hs->hh = NULL; + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unwanted response code from /history/incoming: %u\n", + dhr->http_status); TALER_TESTING_interpreter_fail (is); - return GNUNET_SYSERR; + return; } - hs->results_obtained++; - return GNUNET_OK; +error: + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Expected history of length %u, got %llu;" + " HTTP status code: %u/%d, failed: %d\n", + hs->total, + (unsigned long long) hs->results_obtained, + dhr->http_status, + (int) dhr->ec, + hs->failed ? 1 : 0); + print_expected (hs->h, + hs->total, + UINT_MAX); + TALER_TESTING_interpreter_fail (is); } @@ -475,6 +573,7 @@ history_run (void *cls, const uint64_t *row_ptr; (void) cmd; + hs->is = is; /* Get row_id from trait. */ if (NULL != hs->start_row_reference) { @@ -495,14 +594,16 @@ history_run (void *cls, TALER_LOG_DEBUG ("row id (from trait) is %llu\n", (unsigned long long) row_id); } - hs->total = build_history (is, &hs->h); - hs->hh = TALER_BANK_debit_history (is->ctx, - &hs->auth, - row_id, - hs->num_results, - GNUNET_TIME_UNIT_ZERO, - &history_cb, - is); + hs->total = build_history (hs, + &hs->h); + hs->hh = TALER_BANK_debit_history ( + TALER_TESTING_interpreter_get_context (is), + &hs->auth, + row_id, + hs->num_results, + GNUNET_TIME_UNIT_ZERO, + &history_cb, + hs); GNUNET_assert (NULL != hs->hh); } @@ -523,7 +624,8 @@ history_cleanup (void *cls, (void) cmd; if (NULL != hs->hh) { - TALER_LOG_WARNING ("/history/outgoing did not complete\n"); + TALER_TESTING_command_incomplete (hs->is, + cmd->label); TALER_BANK_debit_history_cancel (hs->hh); } for (unsigned int off = 0; off<hs->total; off++) diff --git a/src/testing/testing_api_cmd_bank_transfer.c b/src/testing/testing_api_cmd_bank_transfer.c index 8c14aac19..bfb29e120 100644 --- a/src/testing/testing_api_cmd_bank_transfer.c +++ b/src/testing/testing_api_cmd_bank_transfer.c @@ -149,8 +149,7 @@ do_retry (void *cls) struct TransferState *fts = cls; fts->retry_task = NULL; - fts->is->commands[fts->is->ip].last_req_time - = GNUNET_TIME_absolute_get (); + TALER_TESTING_touch_cmd (fts->is); transfer_run (fts, NULL, fts->is); @@ -163,43 +162,35 @@ do_retry (void *cls) * acceptable. * * @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 timestamp time stamp of the transaction made. + * @param tr response details */ static void confirmation_cb (void *cls, - unsigned int http_status, - enum TALER_ErrorCode ec, - uint64_t serial_id, - struct GNUNET_TIME_Timestamp timestamp) + const struct TALER_BANK_TransferResponse *tr) { struct TransferState *fts = cls; struct TALER_TESTING_Interpreter *is = fts->is; fts->weh = NULL; - if (MHD_HTTP_OK != http_status) + if (MHD_HTTP_OK != tr->http_status) { if (0 != fts->do_retry) { fts->do_retry--; - if ( (0 == http_status) || - (TALER_EC_GENERIC_DB_SOFT_FAILURE == ec) || - (MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) ) + if ( (0 == tr->http_status) || + (TALER_EC_GENERIC_DB_SOFT_FAILURE == tr->ec) || + (MHD_HTTP_INTERNAL_SERVER_ERROR == tr->http_status) ) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Retrying transfer failed with %u/%d\n", - http_status, - (int) ec); + tr->http_status, + (int) tr->ec); /* on DB conflicts, do not use backoff */ - if (TALER_EC_GENERIC_DB_SOFT_FAILURE == ec) + if (TALER_EC_GENERIC_DB_SOFT_FAILURE == tr->ec) fts->backoff = GNUNET_TIME_UNIT_ZERO; else fts->backoff = EXCHANGE_LIB_BACKOFF (fts->backoff); - fts->is->commands[fts->is->ip].num_tries++; + TALER_TESTING_inc_tries (fts->is); fts->retry_task = GNUNET_SCHEDULER_add_delayed (fts->backoff, &do_retry, @@ -207,17 +198,14 @@ confirmation_cb (void *cls, return; } } - GNUNET_break (0); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Bank returned HTTP status %u/%d\n", - http_status, - (int) ec); - TALER_TESTING_interpreter_fail (is); + TALER_TESTING_unexpected_status (is, + tr->http_status, + MHD_HTTP_OK); return; } - fts->serial_id = serial_id; - fts->timestamp = timestamp; + fts->serial_id = tr->details.ok.row_id; + fts->timestamp = tr->details.ok.timestamp; TALER_TESTING_interpreter_next (is); } @@ -284,9 +272,8 @@ transfer_cleanup (void *cls, if (NULL != fts->weh) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %s did not complete\n", - cmd->label); + TALER_TESTING_command_incomplete (fts->is, + cmd->label); TALER_BANK_transfer_cancel (fts->weh); fts->weh = NULL; } @@ -319,12 +306,12 @@ transfer_traits (void *cls, struct TransferState *fts = cls; struct TALER_TESTING_Trait traits[] = { TALER_TESTING_make_trait_exchange_url ( - (const char **) &fts->exchange_base_url), + fts->exchange_base_url), TALER_TESTING_make_trait_bank_row (&fts->serial_id), TALER_TESTING_make_trait_credit_payto_uri ( - (const char **) &fts->payto_credit_account), + fts->payto_credit_account), TALER_TESTING_make_trait_debit_payto_uri ( - (const char **) &fts->payto_debit_account), + fts->payto_debit_account), TALER_TESTING_make_trait_amount (&fts->amount), TALER_TESTING_make_trait_timestamp (0, &fts->timestamp), TALER_TESTING_make_trait_wtid (&fts->wtid), diff --git a/src/testing/testing_api_cmd_batch.c b/src/testing/testing_api_cmd_batch.c index e8f76ca37..5bb7b974e 100644 --- a/src/testing/testing_api_cmd_batch.c +++ b/src/testing/testing_api_cmd_batch.c @@ -38,6 +38,11 @@ struct BatchState struct TALER_TESTING_Command *batch; /** + * My command (the batch command). + */ + const struct TALER_TESTING_Command *cmd; + + /** * Internal command pointer. */ unsigned int batch_ip; @@ -58,6 +63,7 @@ batch_run (void *cls, { struct BatchState *bs = cls; + bs->cmd = cmd; if (NULL != bs->batch[bs->batch_ip].label) TALER_LOG_INFO ("Running batched command: %s\n", bs->batch[bs->batch_ip].label); @@ -97,8 +103,9 @@ batch_cleanup (void *cls, for (unsigned int i = 0; NULL != bs->batch[i].label; i++) - bs->batch[i].cleanup (bs->batch[i].cls, - &bs->batch[i]); + if (NULL != bs->batch[i].cleanup) + bs->batch[i].cleanup (bs->batch[i].cls, + &bs->batch[i]); GNUNET_free (bs->batch); GNUNET_free (bs); } @@ -121,7 +128,7 @@ batch_traits (void *cls, { struct BatchState *bs = cls; struct TALER_TESTING_Trait traits[] = { - TALER_TESTING_make_trait_batch_cmds (&bs->batch), + TALER_TESTING_make_trait_batch_cmds (bs->batch), TALER_TESTING_trait_end () }; @@ -149,9 +156,9 @@ TALER_TESTING_cmd_batch (const char *label, bs->batch = GNUNET_new_array (i + 1, struct TALER_TESTING_Command); - memcpy (bs->batch, - batch, - sizeof (struct TALER_TESTING_Command) * i); + GNUNET_memcpy (bs->batch, + batch, + sizeof (struct TALER_TESTING_Command) * i); { struct TALER_TESTING_Command cmd = { .cls = bs, @@ -166,19 +173,33 @@ TALER_TESTING_cmd_batch (const char *label, } -void -TALER_TESTING_cmd_batch_next (struct TALER_TESTING_Interpreter *is) +bool +TALER_TESTING_cmd_batch_next (struct TALER_TESTING_Interpreter *is, + void *cls) { - struct BatchState *bs = is->commands[is->ip].cls; + struct BatchState *bs = cls; + struct TALER_TESTING_Command *bcmd = &bs->batch[bs->batch_ip]; - if (NULL == bs->batch[bs->batch_ip].label) + if (NULL == bcmd->label) { - is->commands[is->ip].finish_time = GNUNET_TIME_absolute_get (); - is->ip++; - return; + /* This batch is done */ + return true; + } + if (TALER_TESTING_cmd_is_batch (bcmd)) + { + if (TALER_TESTING_cmd_batch_next (is, + bcmd->cls)) + { + /* sub-batch is done */ + bcmd->finish_time = GNUNET_TIME_absolute_get (); + bs->batch_ip++; + return false; + } } - bs->batch[bs->batch_ip].finish_time = GNUNET_TIME_absolute_get (); + /* Simple command is done */ + bcmd->finish_time = GNUNET_TIME_absolute_get (); bs->batch_ip++; + return false; } diff --git a/src/testing/testing_api_cmd_batch_deposit.c b/src/testing/testing_api_cmd_batch_deposit.c index 967a5ac33..5139d3524 100644 --- a/src/testing/testing_api_cmd_batch_deposit.c +++ b/src/testing/testing_api_cmd_batch_deposit.c @@ -59,17 +59,33 @@ struct Coin struct TALER_Amount deposit_fee; /** + * Our coin signature. + */ + struct TALER_CoinSpendSignatureP coin_sig; + + /** * Reference to any command that is able to provide a coin, * possibly using $LABEL#$INDEX notation. */ char *coin_reference; /** + * Denomination public key of the coin. + */ + const struct TALER_EXCHANGE_DenomPublicKey *denom_pub; + + /** * The command being referenced. */ const struct TALER_TESTING_Command *coin_cmd; /** + * Expected entry in the coin history created by this + * coin. + */ + struct TALER_EXCHANGE_CoinHistoryEntry che; + + /** * Index of the coin at @e coin_cmd. */ unsigned int coin_idx; @@ -151,10 +167,9 @@ struct BatchDepositState struct GNUNET_SCHEDULER_Task *retry_task; /** - * Array of @e num_coins signatures from the exchange on the - * deposit confirmation. + * Deposit confirmation signature from the exchange. */ - struct TALER_ExchangeSignatureP *exchange_sigs; + struct TALER_ExchangeSignatureP exchange_sig; /** * Reference to previous deposit operation. @@ -198,33 +213,17 @@ batch_deposit_cb (void *cls, ds->dh = NULL; if (ds->expected_response_code != dr->hr.http_status) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u to command %s in %s:%u\n", - dr->hr.http_status, - ds->is->commands[ds->is->ip].label, - __FILE__, - __LINE__); - json_dumpf (dr->hr.reply, - stderr, - JSON_INDENT (2)); - TALER_TESTING_interpreter_fail (ds->is); + TALER_TESTING_unexpected_status (ds->is, + dr->hr.http_status, + ds->expected_response_code); return; } if (MHD_HTTP_OK == dr->hr.http_status) { - if (ds->num_coins != dr->details.success.num_signatures) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (ds->is); - return; - } ds->deposit_succeeded = GNUNET_YES; - ds->exchange_timestamp = dr->details.success.deposit_timestamp; - ds->exchange_pub = *dr->details.success.exchange_pub; - ds->exchange_sigs = GNUNET_memdup (dr->details.success.exchange_sigs, - dr->details.success.num_signatures - * sizeof (struct - TALER_ExchangeSignatureP)); + ds->exchange_timestamp = dr->details.ok.deposit_timestamp; + ds->exchange_pub = *dr->details.ok.exchange_pub; + ds->exchange_sig = *dr->details.ok.exchange_sig; } TALER_TESTING_interpreter_next (ds->is); } @@ -243,7 +242,6 @@ batch_deposit_run (void *cls, struct TALER_TESTING_Interpreter *is) { struct BatchDepositState *ds = cls; - const struct TALER_EXCHANGE_DenomPublicKey *denom_pub; const struct TALER_DenominationSignature *denom_pub_sig; struct TALER_MerchantPublicKeyP merchant_pub; struct TALER_PrivateContractHashP h_contract_terms; @@ -259,8 +257,15 @@ batch_deposit_run (void *cls, &wire_salt), GNUNET_JSON_spec_end () }; + const char *exchange_url + = TALER_TESTING_get_exchange_url (is); (void) cmd; + if (NULL == exchange_url) + { + GNUNET_break (0); + return; + } memset (cdds, 0, sizeof (cdds)); @@ -340,7 +345,7 @@ batch_deposit_run (void *cls, (GNUNET_OK != TALER_TESTING_get_trait_denom_pub (coin->coin_cmd, coin->coin_idx, - &denom_pub)) || + &coin->denom_pub)) || (GNUNET_OK != TALER_TESTING_get_trait_denom_sig (coin->coin_cmd, coin->coin_idx, @@ -355,23 +360,38 @@ batch_deposit_run (void *cls, TALER_age_commitment_hash (&age_commitment_proof->commitment, &cdd->h_age_commitment); } - coin->deposit_fee = denom_pub->fees.deposit; + coin->deposit_fee = coin->denom_pub->fees.deposit; GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv, &cdd->coin_pub.eddsa_pub); cdd->denom_sig = *denom_pub_sig; - cdd->h_denom_pub = denom_pub->h_key; + cdd->h_denom_pub = coin->denom_pub->h_key; TALER_wallet_deposit_sign (&coin->amount, - &denom_pub->fees.deposit, + &coin->denom_pub->fees.deposit, &h_wire, &h_contract_terms, + NULL, /* wallet_data_hash */ &cdd->h_age_commitment, - NULL, /* FIXME #7270: add hash of extensions */ - &denom_pub->h_key, + NULL, /* hash of extensions */ + &coin->denom_pub->h_key, ds->wallet_timestamp, &merchant_pub, ds->refund_deadline, coin_priv, &cdd->coin_sig); + coin->coin_sig = cdd->coin_sig; + coin->che.type = TALER_EXCHANGE_CTT_DEPOSIT; + coin->che.amount = coin->amount; + coin->che.details.deposit.h_wire = h_wire; + coin->che.details.deposit.h_contract_terms = h_contract_terms; + coin->che.details.deposit.no_h_policy = true; + coin->che.details.deposit.no_wallet_data_hash = true; + coin->che.details.deposit.wallet_timestamp = ds->wallet_timestamp; + coin->che.details.deposit.merchant_pub = merchant_pub; + coin->che.details.deposit.refund_deadline = ds->refund_deadline; + coin->che.details.deposit.sig = cdd->coin_sig; + coin->che.details.deposit.no_hac = GNUNET_is_zero (&cdd->h_age_commitment); + coin->che.details.deposit.hac = cdd->h_age_commitment; + coin->che.details.deposit.deposit_fee = coin->denom_pub->fees.deposit; } GNUNET_assert (NULL == ds->dh); @@ -381,19 +401,22 @@ batch_deposit_run (void *cls, .merchant_payto_uri = payto_uri, .wire_salt = wire_salt, .h_contract_terms = h_contract_terms, - .extension_details = NULL /* FIXME #7270-OEC */, - .timestamp = ds->wallet_timestamp, + .policy_details = NULL /* FIXME #7270-OEC */, + .wallet_timestamp = ds->wallet_timestamp, .merchant_pub = merchant_pub, .refund_deadline = ds->refund_deadline }; - ds->dh = TALER_EXCHANGE_batch_deposit (is->exchange, - &dcd, - ds->num_coins, - cdds, - &batch_deposit_cb, - ds, - &ec); + ds->dh = TALER_EXCHANGE_batch_deposit ( + TALER_TESTING_interpreter_get_context (is), + exchange_url, + TALER_TESTING_get_keys (is), + &dcd, + ds->num_coins, + cdds, + &batch_deposit_cb, + ds, + &ec); } if (NULL == ds->dh) { @@ -422,10 +445,8 @@ batch_deposit_cleanup (void *cls, if (NULL != ds->dh) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - ds->is->ip, - cmd->label); + TALER_TESTING_command_incomplete (ds->is, + cmd->label); TALER_EXCHANGE_batch_deposit_cancel (ds->dh); ds->dh = NULL; } @@ -437,7 +458,6 @@ batch_deposit_cleanup (void *cls, for (unsigned int i = 0; i<ds->num_coins; i++) GNUNET_free (ds->coins[i].coin_reference); GNUNET_free (ds->coins); - GNUNET_free (ds->exchange_sigs); json_decref (ds->wire_details); json_decref (ds->contract_terms); GNUNET_free (ds); @@ -460,9 +480,10 @@ batch_deposit_traits (void *cls, unsigned int index) { struct BatchDepositState *ds = cls; - struct Coin *coin = &ds->coins[index]; + const struct Coin *coin = &ds->coins[index]; /* Will point to coin cmd internals. */ const struct TALER_CoinSpendPrivateKeyP *coin_spent_priv; + struct TALER_CoinSpendPublicKeyP coin_spent_pub; const struct TALER_AgeCommitmentProof *age_commitment_proof; if (index >= ds->num_coins) @@ -489,27 +510,38 @@ batch_deposit_traits (void *cls, TALER_TESTING_interpreter_fail (ds->is); return GNUNET_NO; } + + GNUNET_CRYPTO_eddsa_key_get_public (&coin_spent_priv->eddsa_priv, + &coin_spent_pub.eddsa_pub); + { struct TALER_TESTING_Trait traits[] = { /* First two traits are only available if ds->traits is #GNUNET_YES */ - TALER_TESTING_make_trait_exchange_pub (index, + TALER_TESTING_make_trait_exchange_pub (0, &ds->exchange_pub), - TALER_TESTING_make_trait_exchange_sig (index, - &ds->exchange_sigs[index]), + TALER_TESTING_make_trait_exchange_sig (0, + &ds->exchange_sig), /* These traits are always available */ TALER_TESTING_make_trait_wire_details (ds->wire_details), TALER_TESTING_make_trait_contract_terms (ds->contract_terms), TALER_TESTING_make_trait_merchant_priv (&ds->merchant_priv), TALER_TESTING_make_trait_age_commitment_proof (index, age_commitment_proof), + TALER_TESTING_make_trait_coin_history (index, + &coin->che), + TALER_TESTING_make_trait_coin_pub (index, + &coin_spent_pub), + TALER_TESTING_make_trait_denom_pub (index, + coin->denom_pub), TALER_TESTING_make_trait_coin_priv (index, coin_spent_priv), + TALER_TESTING_make_trait_coin_sig (index, + &coin->coin_sig), TALER_TESTING_make_trait_deposit_amount (index, &coin->amount), TALER_TESTING_make_trait_deposit_fee_amount (index, &coin->deposit_fee), - TALER_TESTING_make_trait_timestamp (index, &ds->exchange_timestamp), TALER_TESTING_make_trait_wire_deadline (index, diff --git a/src/testing/testing_api_cmd_batch_withdraw.c b/src/testing/testing_api_cmd_batch_withdraw.c index 0cc881155..1b056bdbb 100644 --- a/src/testing/testing_api_cmd_batch_withdraw.c +++ b/src/testing/testing_api_cmd_batch_withdraw.c @@ -23,6 +23,7 @@ * @author Marcello Stanisci */ #include "platform.h" +#include "taler_exchange_service.h" #include "taler_json_lib.h" #include <microhttpd.h> #include <gnunet/gnunet_curl_lib.h> @@ -56,9 +57,14 @@ struct CoinState struct TALER_CoinSpendPrivateKeyP coin_priv; /** + * Public key of the coin. + */ + struct TALER_CoinSpendPublicKeyP coin_pub; + + /** * Blinding key used during the operation. */ - union TALER_DenominationBlindingKeyP bks; + union GNUNET_CRYPTO_BlindingSecretP bks; /** * Values contributed from the exchange during the @@ -79,10 +85,10 @@ struct CoinState /** * If age > 0, put here the corresponding age commitment with its proof and - * its hash, respectivelly, NULL otherwise. + * its hash, respectively. */ - struct TALER_AgeCommitmentProof *age_commitment_proof; - struct TALER_AgeCommitmentHash *h_age_commitment; + struct TALER_AgeCommitmentProof age_commitment_proof; + struct TALER_AgeCommitmentHash h_age_commitment; /** * Reserve history entry that corresponds to this coin. @@ -141,10 +147,16 @@ struct BatchWithdrawState struct CoinState *coins; /** - * Set to the KYC UUID *if* the exchange replied with + * Set to the KYC requirement payto hash *if* the exchange replied with a + * request for KYC. + */ + struct TALER_PaytoHashP h_payto; + + /** + * Set to the KYC requirement row *if* the exchange replied with * a request for KYC. */ - uint64_t kyc_uuid; + uint64_t requirement_row; /** * Length of the @e coins array. @@ -161,6 +173,11 @@ struct BatchWithdrawState * Same for all coins in the batch. */ uint8_t age; + + /** + * Force a conflict: + */ + bool force_conflict; }; @@ -183,18 +200,10 @@ reserve_batch_withdraw_cb (void *cls, ws->wsh = NULL; if (ws->expected_response_code != wr->hr.http_status) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u/%d to command %s in %s:%u\n", - wr->hr.http_status, - (int) wr->hr.ec, - TALER_TESTING_interpreter_get_current_label (is), - __FILE__, - __LINE__); - json_dumpf (wr->hr.reply, - stderr, - 0); - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); + TALER_TESTING_unexpected_status_with_body (is, + wr->hr.http_status, + ws->expected_response_code, + wr->hr.reply); return; } switch (wr->hr.http_status) @@ -204,19 +213,19 @@ reserve_batch_withdraw_cb (void *cls, { struct CoinState *cs = &ws->coins[i]; const struct TALER_EXCHANGE_PrivateCoinDetails *pcd - = &wr->details.success.coins[i]; + = &wr->details.ok.coins[i]; - TALER_denom_sig_deep_copy (&cs->sig, - &pcd->sig); + TALER_denom_sig_copy (&cs->sig, + &pcd->sig); cs->coin_priv = pcd->coin_priv; + GNUNET_CRYPTO_eddsa_key_get_public (&cs->coin_priv.eddsa_priv, + &cs->coin_pub.eddsa_pub); + cs->bks = pcd->bks; - cs->exchange_vals = pcd->exchange_vals; + TALER_denom_ewv_copy (&cs->exchange_vals, + &pcd->exchange_vals); } break; - case MHD_HTTP_ACCEPTED: - /* nothing to check */ - ws->kyc_uuid = wr->details.accepted.payment_target_uuid; - break; case MHD_HTTP_FORBIDDEN: /* nothing to check */ break; @@ -224,11 +233,18 @@ reserve_batch_withdraw_cb (void *cls, /* nothing to check */ break; case MHD_HTTP_CONFLICT: - /* nothing to check */ + /* TODO[oec]: Check if age-requirement is the reason */ break; case MHD_HTTP_GONE: /* theoretically could check that the key was actually */ break; + case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS: + /* nothing to check */ + ws->requirement_row + = wr->details.unavailable_for_legal_reasons.requirement_row; + ws->h_payto + = wr->details.unavailable_for_legal_reasons.h_payto; + break; default: /* Unsupported status code (by test harness) */ GNUNET_log (GNUNET_ERROR_TYPE_WARNING, @@ -250,10 +266,13 @@ batch_withdraw_run (void *cls, struct TALER_TESTING_Interpreter *is) { struct BatchWithdrawState *ws = cls; + const struct TALER_EXCHANGE_Keys *keys = TALER_TESTING_get_keys (is); const struct TALER_ReservePrivateKeyP *rp; 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; @@ -278,7 +297,7 @@ batch_withdraw_run (void *cls, } if (NULL == ws->exchange_url) ws->exchange_url - = GNUNET_strdup (TALER_EXCHANGE_get_base_url (is->exchange)); + = GNUNET_strdup (TALER_TESTING_get_exchange_url (is)); ws->reserve_priv = *rp; GNUNET_CRYPTO_eddsa_key_get_public (&ws->reserve_priv.eddsa_priv, &ws->reserve_pub.eddsa_pub); @@ -286,13 +305,38 @@ 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); - dpk = TALER_TESTING_find_pk (TALER_EXCHANGE_get_keys (is->exchange), + 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); if (NULL == dpk) @@ -316,14 +360,17 @@ batch_withdraw_run (void *cls, wci->pk = cs->pk; wci->ps = &cs->ps; - wci->ach = cs->h_age_commitment; + wci->ach = &cs->h_age_commitment; } - ws->wsh = TALER_EXCHANGE_batch_withdraw (is->exchange, - rp, - wcis, - ws->num_coins, - &reserve_batch_withdraw_cb, - ws); + ws->wsh = TALER_EXCHANGE_batch_withdraw ( + TALER_TESTING_interpreter_get_context (is), + TALER_TESTING_get_exchange_url (is), + keys, + rp, + ws->num_coins, + wcis, + &reserve_batch_withdraw_cb, + ws); if (NULL == ws->wsh) { GNUNET_break (0); @@ -348,9 +395,8 @@ batch_withdraw_cleanup (void *cls, if (NULL != ws->wsh) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %s did not complete\n", - cmd->label); + TALER_TESTING_command_incomplete (ws->is, + cmd->label); TALER_EXCHANGE_batch_withdraw_cancel (ws->wsh); ws->wsh = NULL; } @@ -358,19 +404,15 @@ batch_withdraw_cleanup (void *cls, { struct CoinState *cs = &ws->coins[i]; + TALER_denom_ewv_free (&cs->exchange_vals); TALER_denom_sig_free (&cs->sig); if (NULL != cs->pk) { TALER_EXCHANGE_destroy_denomination_key (cs->pk); cs->pk = NULL; } - if (NULL != cs->age_commitment_proof) - { - TALER_age_commitment_proof_free (cs->age_commitment_proof); - cs->age_commitment_proof = NULL; - } - if (NULL != cs->h_age_commitment) - GNUNET_free (cs->h_age_commitment); + if (0 < ws->age) + TALER_age_commitment_proof_free (&cs->age_commitment_proof); } GNUNET_free (ws->coins); GNUNET_free (ws->exchange_url); @@ -403,6 +445,8 @@ batch_withdraw_traits (void *cls, &cs->reserve_history), TALER_TESTING_make_trait_coin_priv (index, &cs->coin_priv), + TALER_TESTING_make_trait_coin_pub (index, + &cs->coin_pub), TALER_TESTING_make_trait_planchet_secrets (index, &cs->ps), TALER_TESTING_make_trait_blinding_key (index, @@ -417,15 +461,18 @@ batch_withdraw_traits (void *cls, TALER_TESTING_make_trait_reserve_pub (&ws->reserve_pub), TALER_TESTING_make_trait_amounts (index, &cs->amount), - TALER_TESTING_make_trait_payment_target_uuid (&ws->kyc_uuid), - TALER_TESTING_make_trait_payto_uri ( - (const char **) &ws->reserve_payto_uri), - TALER_TESTING_make_trait_exchange_url ( - (const char **) &ws->exchange_url), + TALER_TESTING_make_trait_legi_requirement_row (&ws->requirement_row), + TALER_TESTING_make_trait_h_payto (&ws->h_payto), + TALER_TESTING_make_trait_payto_uri (ws->reserve_payto_uri), + TALER_TESTING_make_trait_exchange_url (ws->exchange_url), TALER_TESTING_make_trait_age_commitment_proof (index, - cs->age_commitment_proof), + ws->age > 0 ? + &cs->age_commitment_proof: + NULL), TALER_TESTING_make_trait_h_age_commitment (index, - cs->h_age_commitment), + ws->age > 0 ? + &cs->h_age_commitment : + NULL), TALER_TESTING_trait_end () }; @@ -441,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; @@ -456,54 +505,24 @@ 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, amount); - while (NULL != (va_arg (ap, const char *))) + va_start (ap, + amount); + while (NULL != (va_arg (ap, + const char *))) cnt++; ws->num_coins = cnt; ws->coins = GNUNET_new_array (cnt, struct CoinState); va_end (ap); - va_start (ap, amount); + va_start (ap, + amount); for (unsigned int i = 0; i<ws->num_coins; i++) { struct CoinState *cs = &ws->coins[i]; - if (0 < age) - { - struct TALER_AgeCommitmentProof *acp; - struct TALER_AgeCommitmentHash *hac; - struct GNUNET_HashCode seed; - struct TALER_AgeMask mask; - - acp = GNUNET_new (struct TALER_AgeCommitmentProof); - hac = GNUNET_new (struct TALER_AgeCommitmentHash); - mask = TALER_extensions_age_restriction_ageMask (); - GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, - &seed, - sizeof(seed)); - - if (GNUNET_OK != - TALER_age_restriction_commit ( - &mask, - age, - &seed, - acp)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to generate age commitment for age %d at %s\n", - age, - label); - GNUNET_assert (0); - } - - TALER_age_commitment_hash (&acp->commitment, - hac); - cs->age_commitment_proof = acp; - cs->h_age_commitment = hac; - } - if (GNUNET_OK != TALER_string_to_amount (amount, &cs->amount)) @@ -515,7 +534,8 @@ TALER_TESTING_cmd_batch_withdraw (const char *label, GNUNET_assert (0); } /* move on to next vararg! */ - amount = va_arg (ap, const char *); + amount = va_arg (ap, + const char *); } GNUNET_assert (NULL == amount); va_end (ap); diff --git a/src/testing/testing_api_cmd_change_auth.c b/src/testing/testing_api_cmd_change_auth.c deleted file mode 100644 index c3a60a1da..000000000 --- a/src/testing/testing_api_cmd_change_auth.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - This file is part of TALER - (C) 2021 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/testing_api_cmd_change_auth.c - * @brief command(s) to change CURL context authorization header - * @author Christian Grothoff - */ -#include "platform.h" -#include "taler_json_lib.h" -#include <gnunet/gnunet_curl_lib.h> -#include "taler_testing_lib.h" - - -/** - * State for a "authchange" CMD. - */ -struct AuthchangeState -{ - - /** - * What is the new authorization token to send? - */ - const char *auth_token; - - /** - * Old context, clean up on termination. - */ - struct GNUNET_CURL_Context *old_ctx; -}; - - -/** - * Run the command. - * - * @param cls closure. - * @param cmd the command to execute. - * @param is the interpreter state. - */ -static void -authchange_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - struct AuthchangeState *ss = cls; - - (void) cmd; - ss->old_ctx = is->ctx; - if (NULL != is->rc) - { - GNUNET_CURL_gnunet_rc_destroy (is->rc); - is->rc = NULL; - } - is->ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule, - &is->rc); - GNUNET_CURL_enable_async_scope_header (is->ctx, - "Taler-Correlation-Id"); - GNUNET_assert (NULL != is->ctx); - is->rc = GNUNET_CURL_gnunet_rc_create (is->ctx); - if (NULL != ss->auth_token) - { - char *authorization; - - GNUNET_asprintf (&authorization, - "%s: %s", - MHD_HTTP_HEADER_AUTHORIZATION, - ss->auth_token); - GNUNET_assert (GNUNET_OK == - GNUNET_CURL_append_header (is->ctx, - authorization)); - GNUNET_free (authorization); - } - TALER_TESTING_interpreter_next (is); -} - - -/** - * Call GNUNET_CURL_fini(). Done as a separate task to - * ensure that all of the command's cleanups have been - * executed first. See #7151. - * - * @param cls a `struct GNUNET_CURL_Context *` to clean up. - */ -static void -deferred_cleanup_cb (void *cls) -{ - struct GNUNET_CURL_Context *ctx = cls; - - GNUNET_CURL_fini (ctx); -} - - -/** - * Cleanup the state from a "authchange" CMD. - * - * @param cls closure. - * @param cmd the command which is being cleaned up. - */ -static void -authchange_cleanup (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - struct AuthchangeState *ss = cls; - - (void) cmd; - if (NULL != ss->old_ctx) - { - (void) GNUNET_SCHEDULER_add_now (&deferred_cleanup_cb, - ss->old_ctx); - ss->old_ctx = NULL; - } - GNUNET_free (ss); -} - - -struct TALER_TESTING_Command -TALER_TESTING_cmd_set_authorization (const char *label, - const char *auth_token) -{ - struct AuthchangeState *ss; - - ss = GNUNET_new (struct AuthchangeState); - ss->auth_token = auth_token; - - { - struct TALER_TESTING_Command cmd = { - .cls = ss, - .label = label, - .run = &authchange_run, - .cleanup = &authchange_cleanup - }; - - return cmd; - } -} - - -/* end of testing_api_cmd_change_auth.c */ diff --git a/src/testing/testing_api_cmd_check_aml_decision.c b/src/testing/testing_api_cmd_check_aml_decision.c new file mode 100644 index 000000000..fa0981e0d --- /dev/null +++ b/src/testing/testing_api_cmd_check_aml_decision.c @@ -0,0 +1,270 @@ +/* + 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/testing_api_cmd_check_aml_decision.c + * @brief command for testing /management/XXX + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_json_lib.h" +#include <gnunet/gnunet_curl_lib.h> +#include "taler_testing_lib.h" +#include "taler_signatures.h" +#include "backoff.h" + + +/** + * State for a "check_aml_decision" CMD. + */ +struct AmlCheckState +{ + + /** + * Handle while operation is running. + */ + struct TALER_EXCHANGE_LookupAmlDecision *dh; + + /** + * Our interpreter. + */ + struct TALER_TESTING_Interpreter *is; + + /** + * Reference to command to previous set officer. + */ + const char *ref_officer; + + /** + * Reference to command to the previous set AML status operation. + */ + const char *ref_operation; + + /** + * Expected HTTP status. + */ + unsigned int expected_http_status; + +}; + + +/** + * Callback to analyze the /aml/$OFFICER_PUB/$decision/$H_PAYTO response, just used to check + * if the response code is acceptable. + * + * @param cls closure. + * @param adr response details + */ +static void +check_aml_decision_cb (void *cls, + const struct TALER_EXCHANGE_AmlDecisionResponse *adr) +{ + struct AmlCheckState *ds = cls; + + ds->dh = NULL; + if (ds->expected_http_status != adr->hr.http_status) + { + TALER_TESTING_unexpected_status (ds->is, + adr->hr.http_status, + ds->expected_http_status); + return; + } + if (MHD_HTTP_OK == adr->hr.http_status) + { + const struct TALER_TESTING_Command *ref; + const char *justification; + enum TALER_AmlDecisionState *new_state; + const struct TALER_Amount *amount; + const struct TALER_EXCHANGE_AmlDecisionDetail *oldest = NULL; + + ref = TALER_TESTING_interpreter_lookup_command (ds->is, + ds->ref_operation); + if (NULL == ref) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (ds->is); + return; + } + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_aml_justification (ref, + &justification)); + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_aml_decision (ref, + &new_state)); + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_amount (ref, + &amount)); + for (unsigned int i = 0; i<adr->details.ok.aml_history_length; i++) + { + const struct TALER_EXCHANGE_AmlDecisionDetail *aml_history + = &adr->details.ok.aml_history[i]; + + if ( (NULL == oldest) || + (0 != + TALER_amount_cmp (amount, + &oldest->new_threshold)) || + (GNUNET_TIME_timestamp_cmp (oldest->decision_time, + >, + aml_history->decision_time)) ) + oldest = aml_history; + } + if (NULL == oldest) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (ds->is); + return; + } + if ( (oldest->new_state != *new_state) || + (0 != strcmp (oldest->justification, + justification) ) ) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (ds->is); + return; + } + } + TALER_TESTING_interpreter_next (ds->is); +} + + +/** + * Run the command. + * + * @param cls closure. + * @param cmd the command to execute. + * @param is the interpreter state. + */ +static void +check_aml_decision_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct AmlCheckState *ds = cls; + const struct TALER_PaytoHashP *h_payto; + const struct TALER_AmlOfficerPrivateKeyP *officer_priv; + const struct TALER_TESTING_Command *ref; + const char *exchange_url; + + (void) cmd; + ds->is = is; + { + const struct TALER_TESTING_Command *exchange_cmd; + + exchange_cmd = TALER_TESTING_interpreter_get_command (is, + "exchange"); + if (NULL == exchange_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_exchange_url (exchange_cmd, + &exchange_url)); + } + + ref = TALER_TESTING_interpreter_lookup_command (is, + ds->ref_operation); + if (NULL == ref) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_h_payto (ref, + &h_payto)); + ref = TALER_TESTING_interpreter_lookup_command (is, + ds->ref_officer); + if (NULL == ref) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_officer_priv (ref, + &officer_priv)); + ds->dh = TALER_EXCHANGE_lookup_aml_decision ( + TALER_TESTING_interpreter_get_context (is), + exchange_url, + h_payto, + officer_priv, + true, /* history */ + &check_aml_decision_cb, + ds); + if (NULL == ds->dh) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } +} + + +/** + * Free the state of a "check_aml_decision" CMD, and possibly cancel a + * pending operation thereof. + * + * @param cls closure, must be a `struct AmlCheckState`. + * @param cmd the command which is being cleaned up. + */ +static void +check_aml_decision_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct AmlCheckState *ds = cls; + + if (NULL != ds->dh) + { + TALER_TESTING_command_incomplete (ds->is, + cmd->label); + TALER_EXCHANGE_lookup_aml_decision_cancel (ds->dh); + ds->dh = NULL; + } + GNUNET_free (ds); +} + + +struct TALER_TESTING_Command +TALER_TESTING_cmd_check_aml_decision ( + const char *label, + const char *ref_officer, + const char *ref_operation, + unsigned int expected_http_status) +{ + struct AmlCheckState *ds; + + ds = GNUNET_new (struct AmlCheckState); + ds->ref_officer = ref_officer; + ds->ref_operation = ref_operation; + ds->expected_http_status = expected_http_status; + { + struct TALER_TESTING_Command cmd = { + .cls = ds, + .label = label, + .run = &check_aml_decision_run, + .cleanup = &check_aml_decision_cleanup + }; + + return cmd; + } +} + + +/* end of testing_api_cmd_check_aml_decision.c */ diff --git a/src/testing/testing_api_cmd_check_aml_decisions.c b/src/testing/testing_api_cmd_check_aml_decisions.c new file mode 100644 index 000000000..c8c2ec3f5 --- /dev/null +++ b/src/testing/testing_api_cmd_check_aml_decisions.c @@ -0,0 +1,204 @@ +/* + 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/testing_api_cmd_check_aml_decisions.c + * @brief command for testing /aml/$OFFICER/decisions/$FILTER + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_json_lib.h" +#include <gnunet/gnunet_curl_lib.h> +#include "taler_testing_lib.h" +#include "taler_signatures.h" +#include "backoff.h" + + +/** + * State for a "check_aml_decision" CMD. + */ +struct AmlCheckState +{ + + /** + * Handle while operation is running. + */ + struct TALER_EXCHANGE_LookupAmlDecisions *dh; + + /** + * Our interpreter. + */ + struct TALER_TESTING_Interpreter *is; + + /** + * Reference to command to previous set officer. + */ + const char *ref_officer; + + /** + * Which states to filter by. + */ + enum TALER_AmlDecisionState filter; + + /** + * Expected HTTP status. + */ + unsigned int expected_http_status; + +}; + + +/** + * Callback to analyze the /aml/$OFFICER_PUB/$decisions/$FILTER response, just used to check + * if the response code is acceptable. + * + * @param cls closure. + * @param adr response details + */ +static void +check_aml_decisions_cb (void *cls, + const struct TALER_EXCHANGE_AmlDecisionsResponse *adr) +{ + struct AmlCheckState *ds = cls; + + ds->dh = NULL; + if (ds->expected_http_status != adr->hr.http_status) + { + TALER_TESTING_unexpected_status (ds->is, + adr->hr.http_status, + ds->expected_http_status); + return; + } + TALER_TESTING_interpreter_next (ds->is); +} + + +/** + * Run the command. + * + * @param cls closure. + * @param cmd the command to execute. + * @param is the interpreter state. + */ +static void +check_aml_decisions_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct AmlCheckState *ds = cls; + const struct TALER_AmlOfficerPrivateKeyP *officer_priv; + const struct TALER_TESTING_Command *ref; + const char *exchange_url; + + (void) cmd; + ds->is = is; + { + const struct TALER_TESTING_Command *exchange_cmd; + + exchange_cmd = TALER_TESTING_interpreter_get_command (is, + "exchange"); + if (NULL == exchange_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_exchange_url (exchange_cmd, + &exchange_url)); + } + ref = TALER_TESTING_interpreter_lookup_command (is, + ds->ref_officer); + if (NULL == ref) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_officer_priv (ref, + &officer_priv)); + ds->dh = TALER_EXCHANGE_lookup_aml_decisions ( + TALER_TESTING_interpreter_get_context (is), + exchange_url, + INT64_MAX, + -1, /* return last one for testing */ + ds->filter, + officer_priv, + &check_aml_decisions_cb, + ds); + if (NULL == ds->dh) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } +} + + +/** + * Free the state of a "check_aml_decisions" CMD, and possibly cancel a + * pending operation thereof. + * + * @param cls closure, must be a `struct AmlCheckState`. + * @param cmd the command which is being cleaned up. + */ +static void +check_aml_decisions_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct AmlCheckState *ds = cls; + + if (NULL != ds->dh) + { + TALER_TESTING_command_incomplete (ds->is, + cmd->label); + TALER_EXCHANGE_lookup_aml_decisions_cancel (ds->dh); + ds->dh = NULL; + } + GNUNET_free (ds); +} + + +struct TALER_TESTING_Command +TALER_TESTING_cmd_check_aml_decisions ( + const char *label, + const char *ref_officer, + enum TALER_AmlDecisionState filter, + unsigned int expected_http_status) +{ + struct AmlCheckState *ds; + + ds = GNUNET_new (struct AmlCheckState); + ds->ref_officer = ref_officer; + ds->filter = filter; + ds->expected_http_status = expected_http_status; + { + struct TALER_TESTING_Command cmd = { + .cls = ds, + .label = label, + .run = &check_aml_decisions_run, + .cleanup = &check_aml_decisions_cleanup + }; + + return cmd; + } +} + + +/* end of testing_api_cmd_check_aml_decisions.c */ diff --git a/src/testing/testing_api_cmd_check_keys.c b/src/testing/testing_api_cmd_check_keys.c deleted file mode 100644 index 0dee8be3a..000000000 --- a/src/testing/testing_api_cmd_check_keys.c +++ /dev/null @@ -1,251 +0,0 @@ -/* - This file is part of TALER - (C) 2018, 2020, 2021 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/testing_api_cmd_check_keys.c - * @brief Implementation of "check keys" test command. - * @author Marcello Stanisci - * @author Christian Grothoff - */ -#include "platform.h" -#include "taler_json_lib.h" -#include <gnunet/gnunet_curl_lib.h> -#include "taler_testing_lib.h" - - -/** - * State for a "check keys" CMD. - */ -struct CheckKeysState -{ - /** - * This number will instruct the CMD interpreter to - * make sure that /keys was downloaded `generation` times - * _before_ running the very CMD logic. - */ - unsigned int generation; - - /** - * If this value is true, then the "cherry - * picking" facility is turned off; whole /keys is - * downloaded. - */ - bool pull_all_keys; - - /** - * Label of a command to use to derive the "last_denom_issue" date to use. - */ - const char *last_denom_date_ref; - - /** - * Last denomination date we received when doing this request. - */ - struct GNUNET_TIME_Timestamp my_denom_date; -}; - - -/** - * Run the "check keys" command. - * - * @param cls closure. - * @param cmd the command currently being executed. - * @param is the interpreter state. - */ -static void -check_keys_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - struct CheckKeysState *cks = cls; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "cmd `%s' (ip: %u), key generation: %d\n", - cmd->label, - is->ip, - is->key_generation); - if (is->key_generation < cks->generation) - { - struct GNUNET_TIME_Timestamp rdate; - - is->working = GNUNET_NO; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Triggering GET /keys, cmd `%s'\n", - cmd->label); - if (NULL != cks->last_denom_date_ref) - { - if (0 == strcmp ("zero", - cks->last_denom_date_ref)) - { - TALER_LOG_DEBUG ("Forcing last_denom_date URL argument set to zero\n"); - TALER_EXCHANGE_set_last_denom (is->exchange, - GNUNET_TIME_UNIT_ZERO_TS); - } - else - { - const struct GNUNET_TIME_Timestamp *last_denom_date; - const struct TALER_TESTING_Command *ref; - - ref = TALER_TESTING_interpreter_lookup_command (is, - cks->last_denom_date_ref); - if (NULL == ref) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - if (GNUNET_OK != - TALER_TESTING_get_trait_timestamp (ref, - 0, - &last_denom_date)) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - - TALER_LOG_DEBUG ("Forcing last_denom_date URL argument\n"); - TALER_EXCHANGE_set_last_denom (is->exchange, - *last_denom_date); - } - } - - rdate = TALER_EXCHANGE_check_keys_current ( - is->exchange, - cks->pull_all_keys - ? TALER_EXCHANGE_CKF_FORCE_ALL_NOW - : TALER_EXCHANGE_CKF_FORCE_DOWNLOAD); - /* Redownload /keys. */ - GNUNET_break (GNUNET_TIME_absolute_is_zero (rdate.abs_time)); - return; - } - { - const struct TALER_EXCHANGE_Keys *keys; - - keys = TALER_EXCHANGE_get_keys (is->exchange); - if (NULL == keys) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - cks->my_denom_date = keys->last_denom_issue_date; - } - TALER_TESTING_interpreter_next (is); -} - - -/** - * Cleanup the state. - * - * @param cls closure. - * @param cmd the command which is being cleaned up. - */ -static void -check_keys_cleanup (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - struct CheckKeysState *cks = cls; - - (void) cmd; - GNUNET_free (cks); -} - - -/** - * Offer internal data to a "check_keys" CMD state to other - * commands. - * - * @param cls closure - * @param[out] ret result (could be anything) - * @param trait name of the trait - * @param index index number of the object to offer. - * @return #GNUNET_OK on success - */ -static int -check_keys_traits (void *cls, - const void **ret, - const char *trait, - unsigned int index) -{ - struct CheckKeysState *cks = cls; - struct TALER_TESTING_Trait traits[] = { - /* history entry MUST be first due to response code logic below! */ - TALER_TESTING_make_trait_timestamp (0, - &cks->my_denom_date), - TALER_TESTING_trait_end () - }; - - return TALER_TESTING_get_trait (traits, - ret, - trait, - index); -} - - -struct TALER_TESTING_Command -TALER_TESTING_cmd_check_keys (const char *label, - unsigned int generation) -{ - struct CheckKeysState *cks; - - cks = GNUNET_new (struct CheckKeysState); - cks->generation = generation; - { - struct TALER_TESTING_Command cmd = { - .cls = cks, - .label = label, - .run = &check_keys_run, - .cleanup = &check_keys_cleanup, - .traits = &check_keys_traits - }; - - return cmd; - } -} - - -struct TALER_TESTING_Command -TALER_TESTING_cmd_check_keys_pull_all_keys (const char *label, - unsigned int generation) -{ - struct TALER_TESTING_Command cmd - = TALER_TESTING_cmd_check_keys (label, - generation); - struct CheckKeysState *cks = cmd.cls; - - cks->pull_all_keys = true; - return cmd; -} - - -struct TALER_TESTING_Command -TALER_TESTING_cmd_check_keys_with_last_denom ( - const char *label, - unsigned int generation, - const char *last_denom_date_ref) -{ - struct TALER_TESTING_Command cmd - = TALER_TESTING_cmd_check_keys (label, - generation); - struct CheckKeysState *cks = cmd.cls; - cks->last_denom_date_ref = last_denom_date_ref; - return cmd; -} - - -/* end of testing_api_cmd_check_keys.c */ diff --git a/src/testing/testing_api_cmd_coin_history.c b/src/testing/testing_api_cmd_coin_history.c new file mode 100644 index 000000000..a1345f67f --- /dev/null +++ b/src/testing/testing_api_cmd_coin_history.c @@ -0,0 +1,609 @@ +/* + 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/testing_api_cmd_coin_history.c + * @brief Implement the /coins/$COIN_PUB/history test command. + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_json_lib.h" +#include <gnunet/gnunet_curl_lib.h> +#include "taler_testing_lib.h" + + +/** + * State for a "history" CMD. + */ +struct HistoryState +{ + + /** + * Public key of the coin being analyzed. + */ + struct TALER_CoinSpendPublicKeyP coin_pub; + + /** + * Label to the command which created the coin to check, + * needed to resort the coin key. + */ + const char *coin_reference; + + /** + * Handle to the "coin history" operation. + */ + struct TALER_EXCHANGE_CoinsHistoryHandle *rsh; + + /** + * Expected coin balance. + */ + const char *expected_balance; + + /** + * Private key of the coin being analyzed. + */ + const struct TALER_CoinSpendPrivateKeyP *coin_priv; + + /** + * Interpreter state. + */ + struct TALER_TESTING_Interpreter *is; + + /** + * Expected HTTP response code. + */ + unsigned int expected_response_code; + +}; + + +/** + * Closure for analysis_cb(). + */ +struct AnalysisContext +{ + /** + * Coin public key we are looking at. + */ + const struct TALER_CoinSpendPublicKeyP *coin_pub; + + /** + * Length of the @e history array. + */ + unsigned int history_length; + + /** + * Array of history items to match. + */ + const struct TALER_EXCHANGE_CoinHistoryEntry *history; + + /** + * Array of @e history_length of matched entries. + */ + bool *found; + + /** + * Set to true if an entry could not be found. + */ + bool failure; +}; + + +/** + * Compare @a h1 and @a h2. + * + * @param h1 a history entry + * @param h2 a history entry + * @return 0 if @a h1 and @a h2 are equal + */ +static int +history_entry_cmp ( + const struct TALER_EXCHANGE_CoinHistoryEntry *h1, + const struct TALER_EXCHANGE_CoinHistoryEntry *h2) +{ + if (h1->type != h2->type) + return 1; + if (0 != TALER_amount_cmp (&h1->amount, + &h2->amount)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Amount mismatch (%s)\n", + TALER_amount2s (&h1->amount)); + return 1; + } + switch (h1->type) + { + case TALER_EXCHANGE_CTT_NONE: + GNUNET_break (0); + break; + case TALER_EXCHANGE_CTT_DEPOSIT: + if (0 != GNUNET_memcmp (&h1->details.deposit.h_contract_terms, + &h2->details.deposit.h_contract_terms)) + return 1; + if (0 != GNUNET_memcmp (&h1->details.deposit.merchant_pub, + &h2->details.deposit.merchant_pub)) + return 1; + if (0 != GNUNET_memcmp (&h1->details.deposit.h_wire, + &h2->details.deposit.h_wire)) + return 1; + if (0 != GNUNET_memcmp (&h1->details.deposit.sig, + &h2->details.deposit.sig)) + return 1; + return 0; + case TALER_EXCHANGE_CTT_MELT: + if (0 != GNUNET_memcmp (&h1->details.melt.h_age_commitment, + &h2->details.melt.h_age_commitment)) + return 1; + /* Note: most other fields are not initialized + in the trait as they are hard to extract from + the API */ + return 0; + case TALER_EXCHANGE_CTT_REFUND: + if (0 != GNUNET_memcmp (&h1->details.refund.sig, + &h2->details.refund.sig)) + return 1; + return 0; + case TALER_EXCHANGE_CTT_RECOUP: + if (0 != GNUNET_memcmp (&h1->details.recoup.coin_sig, + &h2->details.recoup.coin_sig)) + return 1; + /* Note: exchange_sig, exchange_pub and timestamp are + fundamentally not available in the initiating command */ + return 0; + case TALER_EXCHANGE_CTT_RECOUP_REFRESH: + if (0 != GNUNET_memcmp (&h1->details.recoup_refresh.coin_sig, + &h2->details.recoup_refresh.coin_sig)) + return 1; + /* Note: exchange_sig, exchange_pub and timestamp are + fundamentally not available in the initiating command */ + return 0; + case TALER_EXCHANGE_CTT_OLD_COIN_RECOUP: + if (0 != GNUNET_memcmp (&h1->details.old_coin_recoup.new_coin_pub, + &h2->details.old_coin_recoup.new_coin_pub)) + return 1; + /* Note: exchange_sig, exchange_pub and timestamp are + fundamentally not available in the initiating command */ + return 0; + case TALER_EXCHANGE_CTT_PURSE_DEPOSIT: + /* coin_sig is not initialized */ + if (0 != GNUNET_memcmp (&h1->details.purse_deposit.purse_pub, + &h2->details.purse_deposit.purse_pub)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Purse public key mismatch\n"); + return 1; + } + if (0 != strcmp (h1->details.purse_deposit.exchange_base_url, + h2->details.purse_deposit.exchange_base_url)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Exchange base URL mismatch (%s/%s)\n", + h1->details.purse_deposit.exchange_base_url, + h2->details.purse_deposit.exchange_base_url); + GNUNET_break (0); + return 1; + } + return 0; + case TALER_EXCHANGE_CTT_PURSE_REFUND: + /* NOTE: not supported yet (trait not returned) */ + return 0; + case TALER_EXCHANGE_CTT_RESERVE_OPEN_DEPOSIT: + /* NOTE: not supported yet (trait not returned) */ + if (0 != GNUNET_memcmp (&h1->details.reserve_open_deposit.coin_sig, + &h2->details.reserve_open_deposit.coin_sig)) + return 1; + return 0; + } + GNUNET_assert (0); + return -1; +} + + +/** + * Check if @a cmd changed the coin, if so, find the + * entry in our history and set the respective index in found + * to true. If the entry is not found, set failure. + * + * @param cls our `struct AnalysisContext *` + * @param cmd command to analyze for impact on history + */ +static void +analyze_command (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct AnalysisContext *ac = cls; + const struct TALER_CoinSpendPublicKeyP *coin_pub = ac->coin_pub; + const struct TALER_EXCHANGE_CoinHistoryEntry *history = ac->history; + unsigned int history_length = ac->history_length; + bool *found = ac->found; + + if (TALER_TESTING_cmd_is_batch (cmd)) + { + struct TALER_TESTING_Command *cur; + struct TALER_TESTING_Command *bcmd; + + cur = TALER_TESTING_cmd_batch_get_current (cmd); + if (GNUNET_OK != + TALER_TESTING_get_trait_batch_cmds (cmd, + &bcmd)) + { + GNUNET_break (0); + ac->failure = true; + return; + } + for (unsigned int i = 0; NULL != bcmd[i].label; i++) + { + struct TALER_TESTING_Command *step = &bcmd[i]; + + analyze_command (ac, + step); + if (ac->failure) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Entry for batch step `%s' missing in history\n", + step->label); + return; + } + if (step == cur) + break; /* if *we* are in a batch, make sure not to analyze commands past 'now' */ + } + return; + } + + for (unsigned int j = 0; true; j++) + { + const struct TALER_CoinSpendPublicKeyP *rp; + const struct TALER_EXCHANGE_CoinHistoryEntry *he; + bool matched = false; + + if (GNUNET_OK != + TALER_TESTING_get_trait_coin_pub (cmd, + j, + &rp)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Command `%s#%u' has no public key for a coin\n", + cmd->label, + j); + break; /* command does nothing for coins */ + } + if (0 != + GNUNET_memcmp (rp, + coin_pub)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Command `%s#%u' is about another coin\n", + cmd->label, + j); + continue; /* command affects some _other_ coin */ + } + if (GNUNET_OK != + TALER_TESTING_get_trait_coin_history (cmd, + j, + &he)) + { + /* NOTE: only for debugging... */ + if (0 == j) + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Command `%s' has the coin_pub, but lacks coin history trait\n", + cmd->label); + return; /* command does nothing for coins */ + } + for (unsigned int i = 0; i<history_length; i++) + { + if (found[i]) + continue; /* already found, skip */ + if (0 == + history_entry_cmp (he, + &history[i])) + { + found[i] = true; + matched = true; + break; + } + } + if (! matched) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Command `%s' coin history entry #%u not found\n", + cmd->label, + j); + ac->failure = true; + return; + } + } +} + + +/** + * Check that the coin balance and HTTP response code are + * both acceptable. + * + * @param cls closure. + * @param rs HTTP response details + */ +static void +coin_history_cb (void *cls, + const struct TALER_EXCHANGE_CoinHistory *rs) +{ + struct HistoryState *ss = cls; + struct TALER_TESTING_Interpreter *is = ss->is; + struct TALER_Amount eb; + unsigned int hlen; + + ss->rsh = NULL; + if (ss->expected_response_code != rs->hr.http_status) + { + TALER_TESTING_unexpected_status (ss->is, + rs->hr.http_status, + ss->expected_response_code); + return; + } + if (MHD_HTTP_OK != rs->hr.http_status) + { + TALER_TESTING_interpreter_next (is); + return; + } + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (ss->expected_balance, + &eb)); + + if (0 != TALER_amount_cmp (&eb, + &rs->details.ok.balance)) + { + GNUNET_break (0); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected balance for coin: %s\n", + TALER_amount_to_string (&rs->details.ok.balance)); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Expected balance of: %s\n", + TALER_amount_to_string (&eb)); + TALER_TESTING_interpreter_fail (ss->is); + return; + } + hlen = json_array_size (rs->details.ok.history); + { + bool found[GNUNET_NZL (hlen)]; + struct TALER_EXCHANGE_CoinHistoryEntry rhist[GNUNET_NZL (hlen)]; + struct AnalysisContext ac = { + .coin_pub = &ss->coin_pub, + .history = rhist, + .history_length = hlen, + .found = found + }; + const struct TALER_EXCHANGE_DenomPublicKey *dk; + struct TALER_Amount total_in; + struct TALER_Amount total_out; + struct TALER_Amount hbal; + + dk = TALER_EXCHANGE_get_denomination_key_by_hash ( + TALER_TESTING_get_keys (is), + &rs->details.ok.h_denom_pub); + memset (found, + 0, + sizeof (found)); + memset (rhist, + 0, + sizeof (rhist)); + if (GNUNET_OK != + TALER_EXCHANGE_parse_coin_history ( + TALER_TESTING_get_keys (is), + dk, + rs->details.ok.history, + &ss->coin_pub, + &total_in, + &total_out, + hlen, + rhist)) + { + GNUNET_break (0); + json_dumpf (rs->hr.reply, + stderr, + JSON_INDENT (2)); + TALER_TESTING_interpreter_fail (ss->is); + return; + } + if (0 > + TALER_amount_subtract (&hbal, + &total_in, + &total_out)) + { + GNUNET_break (0); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Coin credits: %s\n", + TALER_amount2s (&total_in)); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Coin debits: %s\n", + TALER_amount2s (&total_out)); + TALER_TESTING_interpreter_fail (ss->is); + return; + } + if (0 != TALER_amount_cmp (&hbal, + &rs->details.ok.balance)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (ss->is); + return; + } + (void) ac; + TALER_TESTING_iterate (is, + true, + &analyze_command, + &ac); + if (ac.failure) + { + json_dumpf (rs->hr.reply, + stderr, + JSON_INDENT (2)); + TALER_TESTING_interpreter_fail (ss->is); + return; + } +#if 1 + for (unsigned int i = 0; i<hlen; i++) + { + if (found[i]) + continue; + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "History entry at index %u of type %d not justified by command history\n", + i, + rs->details.ok.history[i].type); + json_dumpf (rs->hr.reply, + stderr, + JSON_INDENT (2)); + TALER_TESTING_interpreter_fail (ss->is); + return; + } +#endif + } + TALER_TESTING_interpreter_next (is); +} + + +/** + * Run the command. + * + * @param cls closure. + * @param cmd the command being executed. + * @param is the interpreter state. + */ +static void +history_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct HistoryState *ss = cls; + const struct TALER_TESTING_Command *create_coin; + char *cref; + unsigned int idx; + + ss->is = is; + GNUNET_assert ( + GNUNET_OK == + TALER_TESTING_parse_coin_reference ( + ss->coin_reference, + &cref, + &idx)); + create_coin + = TALER_TESTING_interpreter_lookup_command (is, + cref); + if (NULL == create_coin) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + if (GNUNET_OK != + TALER_TESTING_get_trait_coin_priv (create_coin, + idx, + &ss->coin_priv)) + { + GNUNET_break (0); + TALER_LOG_ERROR ("Failed to find coin_priv for history query\n"); + TALER_TESTING_interpreter_fail (is); + return; + } + GNUNET_CRYPTO_eddsa_key_get_public (&ss->coin_priv->eddsa_priv, + &ss->coin_pub.eddsa_pub); + ss->rsh = TALER_EXCHANGE_coins_history ( + TALER_TESTING_interpreter_get_context (is), + TALER_TESTING_get_exchange_url (is), + ss->coin_priv, + 0, + &coin_history_cb, + ss); +} + + +/** + * Offer internal data from a "history" CMD, to other commands. + * + * @param cls closure. + * @param[out] ret result. + * @param trait name of the trait. + * @param index index number of the object to offer. + * @return #GNUNET_OK on success. + */ +static enum GNUNET_GenericReturnValue +history_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + struct HistoryState *hs = cls; + struct TALER_TESTING_Trait traits[] = { + TALER_TESTING_make_trait_coin_pub (0, + &hs->coin_pub), + TALER_TESTING_trait_end () + }; + + return TALER_TESTING_get_trait (traits, + ret, + trait, + index); +} + + +/** + * Cleanup the state from a "coin history" CMD, and possibly + * cancel a pending operation thereof. + * + * @param cls closure. + * @param cmd the command which is being cleaned up. + */ +static void +history_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct HistoryState *ss = cls; + + if (NULL != ss->rsh) + { + TALER_TESTING_command_incomplete (ss->is, + cmd->label); + TALER_EXCHANGE_coins_history_cancel (ss->rsh); + ss->rsh = NULL; + } + GNUNET_free (ss); +} + + +struct TALER_TESTING_Command +TALER_TESTING_cmd_coin_history (const char *label, + const char *coin_reference, + const char *expected_balance, + unsigned int expected_response_code) +{ + struct HistoryState *ss; + + GNUNET_assert (NULL != coin_reference); + ss = GNUNET_new (struct HistoryState); + ss->coin_reference = coin_reference; + ss->expected_balance = expected_balance; + ss->expected_response_code = expected_response_code; + { + struct TALER_TESTING_Command cmd = { + .cls = ss, + .label = label, + .run = &history_run, + .cleanup = &history_cleanup, + .traits = &history_traits + }; + + return cmd; + } +} diff --git a/src/testing/testing_api_cmd_common.c b/src/testing/testing_api_cmd_common.c index 138e5502a..2d828a2b0 100644 --- a/src/testing/testing_api_cmd_common.c +++ b/src/testing/testing_api_cmd_common.c @@ -25,117 +25,6 @@ #include "taler_testing_lib.h" -int -TALER_TESTING_history_entry_cmp ( - const struct TALER_EXCHANGE_ReserveHistoryEntry *h1, - const struct TALER_EXCHANGE_ReserveHistoryEntry *h2) -{ - if (h1->type != h2->type) - return 1; - switch (h1->type) - { - case TALER_EXCHANGE_RTT_CREDIT: - if ( (0 == - TALER_amount_cmp (&h1->amount, - &h2->amount)) && - (0 == strcasecmp (h1->details.in_details.sender_url, - h2->details.in_details.sender_url)) && - (h1->details.in_details.wire_reference == - h2->details.in_details.wire_reference) && - (GNUNET_TIME_timestamp_cmp (h1->details.in_details.timestamp, - ==, - h2->details.in_details.timestamp)) ) - return 0; - return 1; - case TALER_EXCHANGE_RTT_WITHDRAWAL: - if ( (0 == - TALER_amount_cmp (&h1->amount, - &h2->amount)) && - (0 == - TALER_amount_cmp (&h1->details.withdraw.fee, - &h2->details.withdraw.fee)) ) - /* testing_api_cmd_withdraw doesn't set the out_authorization_sig, - so we cannot test for it here. but if the amount matches, - that should be good enough. */ - return 0; - return 1; - case TALER_EXCHANGE_RTT_RECOUP: - /* exchange_sig, exchange_pub and timestamp are NOT available - from the original recoup response, hence here NOT check(able/ed) */ - if ( (0 == - TALER_amount_cmp (&h1->amount, - &h2->amount)) && - (0 == - GNUNET_memcmp (&h1->details.recoup_details.coin_pub, - &h2->details.recoup_details.coin_pub)) ) - return 0; - return 1; - case TALER_EXCHANGE_RTT_CLOSE: - /* testing_api_cmd_exec_closer doesn't set the - receiver_account_details, exchange_sig, exchange_pub or wtid or timestamp - so we cannot test for it here. but if the amount matches, - that should be good enough. */ - if ( (0 == - TALER_amount_cmp (&h1->amount, - &h2->amount)) && - (0 == - TALER_amount_cmp (&h1->details.close_details.fee, - &h2->details.close_details.fee)) ) - return 0; - return 1; - case TALER_EXCHANGE_RTT_HISTORY: - if ( (0 == - TALER_amount_cmp (&h1->amount, - &h2->amount)) && - (GNUNET_TIME_timestamp_cmp ( - h1->details.history_details.request_timestamp, - ==, - h2->details.history_details. - request_timestamp)) && - (0 == - GNUNET_memcmp (&h1->details.history_details.reserve_sig, - &h2->details.history_details.reserve_sig)) ) - return 0; - return 1; - case TALER_EXCHANGE_RTT_MERGE: - if ( (0 == - TALER_amount_cmp (&h1->amount, - &h2->amount)) && - (0 == - TALER_amount_cmp (&h1->details.merge_details.purse_fee, - &h2->details.merge_details.purse_fee)) && - (GNUNET_TIME_timestamp_cmp (h1->details.merge_details.merge_timestamp, - ==, - h2->details.merge_details.merge_timestamp)) - && - (GNUNET_TIME_timestamp_cmp (h1->details.merge_details.purse_expiration, - ==, - h2->details.merge_details.purse_expiration)) - && - (0 == - GNUNET_memcmp (&h1->details.merge_details.merge_pub, - &h2->details.merge_details.merge_pub)) && - (0 == - GNUNET_memcmp (&h1->details.merge_details.h_contract_terms, - &h2->details.merge_details.h_contract_terms)) && - (0 == - GNUNET_memcmp (&h1->details.merge_details.purse_pub, - &h2->details.merge_details.purse_pub)) && - (0 == - GNUNET_memcmp (&h1->details.merge_details.reserve_sig, - &h2->details.merge_details.reserve_sig)) && - (h1->details.merge_details.min_age == - h2->details.merge_details.min_age) && - (h1->details.merge_details.flags == - h2->details.merge_details.flags) ) - return 0; - return 1; - } - GNUNET_assert (0); - return 1; -} - - enum GNUNET_GenericReturnValue TALER_TESTING_parse_coin_reference ( const char *coin_reference, diff --git a/src/testing/testing_api_cmd_contract_get.c b/src/testing/testing_api_cmd_contract_get.c index 10a43aa3b..fa83d83f7 100644 --- a/src/testing/testing_api_cmd_contract_get.c +++ b/src/testing/testing_api_cmd_contract_get.c @@ -101,26 +101,20 @@ get_cb (void *cls, ds->dh = NULL; if (ds->expected_response_code != dr->hr.http_status) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u to command %s in %s:%u\n", - dr->hr.http_status, - ds->is->commands[ds->is->ip].label, - __FILE__, - __LINE__); - json_dumpf (dr->hr.reply, - stderr, - 0); - TALER_TESTING_interpreter_fail (ds->is); + TALER_TESTING_unexpected_status (ds->is, + dr->hr.http_status, + ds->expected_response_code); return; } ref = TALER_TESTING_interpreter_lookup_command (ds->is, ds->contract_ref); + GNUNET_assert (NULL != ref); if (MHD_HTTP_OK == dr->hr.http_status) { const struct TALER_PurseMergePrivateKeyP *mp; const json_t *ct; - ds->purse_pub = dr->details.success.purse_pub; + ds->purse_pub = dr->details.ok.purse_pub; if (ds->merge) { if (GNUNET_OK != @@ -135,8 +129,8 @@ get_cb (void *cls, TALER_CRYPTO_contract_decrypt_for_merge ( &ds->contract_priv, &ds->purse_pub, - dr->details.success.econtract, - dr->details.success.econtract_size, + dr->details.ok.econtract, + dr->details.ok.econtract_size, &ds->merge_priv); if (0 != GNUNET_memcmp (mp, @@ -152,8 +146,8 @@ get_cb (void *cls, ds->contract_terms = TALER_CRYPTO_contract_decrypt_for_deposit ( &ds->contract_priv, - dr->details.success.econtract, - dr->details.success.econtract_size); + dr->details.ok.econtract, + dr->details.ok.econtract_size); } if (NULL == ds->contract_terms) { @@ -197,9 +191,16 @@ get_run (void *cls, struct ContractGetState *ds = cls; const struct TALER_ContractDiffiePrivateP *contract_priv; const struct TALER_TESTING_Command *ref; + const char *exchange_url; (void) cmd; ds->is = is; + exchange_url = TALER_TESTING_get_exchange_url (is); + if (NULL == exchange_url) + { + GNUNET_break (0); + return; + } ref = TALER_TESTING_interpreter_lookup_command (ds->is, ds->contract_ref); GNUNET_assert (NULL != ref); @@ -213,7 +214,8 @@ get_run (void *cls, } ds->contract_priv = *contract_priv; ds->dh = TALER_EXCHANGE_contract_get ( - is->exchange, + TALER_TESTING_interpreter_get_context (is), + exchange_url, contract_priv, &get_cb, ds); @@ -243,10 +245,8 @@ get_cleanup (void *cls, if (NULL != ds->dh) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - ds->is->ip, - cmd->label); + TALER_TESTING_command_incomplete (ds->is, + cmd->label); TALER_EXCHANGE_contract_get_cancel (ds->dh); ds->dh = NULL; } diff --git a/src/testing/testing_api_cmd_deposit.c b/src/testing/testing_api_cmd_deposit.c index e48fec36d..849c78c70 100644 --- a/src/testing/testing_api_cmd_deposit.c +++ b/src/testing/testing_api_cmd_deposit.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2018-2021 Taler Systems SA + Copyright (C) 2018-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 @@ -69,6 +69,11 @@ struct DepositState unsigned int coin_index; /** + * Our coin signature. + */ + struct TALER_CoinSpendSignatureP coin_sig; + + /** * Wire details of who is depositing -- this would be merchant * wire details in a normal scenario. */ @@ -98,7 +103,12 @@ struct DepositState /** * Deposit handle while operation is running. */ - struct TALER_EXCHANGE_DepositHandle *dh; + struct TALER_EXCHANGE_BatchDepositHandle *dh; + + /** + * Denomination public key of the deposited coin. + */ + const struct TALER_EXCHANGE_DenomPublicKey *denom_pub; /** * Timestamp of the /deposit operation in the wallet (contract signing time). @@ -131,10 +141,16 @@ struct DepositState unsigned int do_retry; /** - * Set to #GNUNET_YES if the /deposit succeeded + * Set to true if the /deposit succeeded * and we now can provide the resulting traits. */ - int deposit_succeeded; + bool deposit_succeeded; + + /** + * Expected entry in the coin history created by this + * operation. + */ + struct TALER_EXCHANGE_CoinHistoryEntry che; /** * When did the exchange receive the deposit? @@ -165,7 +181,7 @@ struct DepositState * When we're referencing another deposit operation, * this will only be set after the command has been started. */ - int command_initialized; + bool command_initialized; /** * Reference to fetch the merchant private key from. @@ -199,8 +215,7 @@ do_retry (void *cls) struct DepositState *ds = cls; ds->retry_task = NULL; - ds->is->commands[ds->is->ip].last_req_time - = GNUNET_TIME_absolute_get (); + TALER_TESTING_touch_cmd (ds->is); deposit_run (ds, NULL, ds->is); @@ -216,7 +231,7 @@ do_retry (void *cls) */ static void deposit_cb (void *cls, - const struct TALER_EXCHANGE_DepositResult *dr) + const struct TALER_EXCHANGE_BatchDepositResult *dr) { struct DepositState *ds = cls; @@ -240,7 +255,7 @@ deposit_cb (void *cls, else ds->backoff = GNUNET_TIME_randomized_backoff (ds->backoff, MAX_BACKOFF); - ds->is->commands[ds->is->ip].num_tries++; + TALER_TESTING_inc_tries (ds->is); GNUNET_assert (NULL == ds->retry_task); ds->retry_task = GNUNET_SCHEDULER_add_delayed (ds->backoff, @@ -249,24 +264,20 @@ deposit_cb (void *cls, return; } } - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u to command %s in %s:%u\n", - dr->hr.http_status, - ds->is->commands[ds->is->ip].label, - __FILE__, - __LINE__); - json_dumpf (dr->hr.reply, - stderr, - JSON_INDENT (2)); - TALER_TESTING_interpreter_fail (ds->is); + TALER_TESTING_unexpected_status_with_body ( + ds->is, + dr->hr.http_status, + ds->expected_response_code, + dr->hr.reply); + return; } if (MHD_HTTP_OK == dr->hr.http_status) { - ds->deposit_succeeded = GNUNET_YES; - ds->exchange_timestamp = dr->details.success.deposit_timestamp; - ds->exchange_pub = *dr->details.success.exchange_pub; - ds->exchange_sig = *dr->details.success.exchange_sig; + ds->deposit_succeeded = true; + ds->exchange_timestamp = dr->details.ok.deposit_timestamp; + ds->exchange_pub = *dr->details.ok.exchange_pub; + ds->exchange_sig = *dr->details.ok.exchange_sig; } TALER_TESTING_interpreter_next (ds->is); } @@ -288,11 +299,8 @@ deposit_run (void *cls, const struct TALER_TESTING_Command *coin_cmd; const struct TALER_CoinSpendPrivateKeyP *coin_priv; struct TALER_CoinSpendPublicKeyP coin_pub; - const struct TALER_AgeCommitmentProof *age_commitment_proof = NULL; - struct TALER_AgeCommitmentHash h_age_commitment = {0}; - const struct TALER_EXCHANGE_DenomPublicKey *denom_pub; + const struct TALER_AgeCommitmentHash *phac; const struct TALER_DenominationSignature *denom_pub_sig; - struct TALER_CoinSpendSignatureP coin_sig; struct TALER_MerchantPublicKeyP merchant_pub; struct TALER_PrivateContractHashP h_contract_terms; enum TALER_ErrorCode ec; @@ -305,9 +313,32 @@ deposit_run (void *cls, &wire_salt), GNUNET_JSON_spec_end () }; + const char *exchange_url + = TALER_TESTING_get_exchange_url (is); (void) cmd; + if (NULL == exchange_url) + { + GNUNET_break (0); + return; + } ds->is = is; + if (! GNUNET_TIME_absolute_is_zero (ds->refund_deadline.abs_time)) + { + struct GNUNET_TIME_Relative refund_deadline; + + refund_deadline + = GNUNET_TIME_absolute_get_remaining (ds->refund_deadline.abs_time); + ds->wire_deadline + = GNUNET_TIME_relative_to_timestamp ( + GNUNET_TIME_relative_multiply (refund_deadline, + 2)); + } + else + { + ds->refund_deadline = ds->wallet_timestamp; + ds->wire_deadline = GNUNET_TIME_timestamp_get (); + } if (NULL != ds->deposit_reference) { /* We're copying another deposit operation, initialize here. */ @@ -330,9 +361,10 @@ deposit_run (void *cls, ds->contract_terms = json_incref (ods->contract_terms); ds->wallet_timestamp = ods->wallet_timestamp; ds->refund_deadline = ods->refund_deadline; + ds->wire_deadline = ods->wire_deadline; ds->amount = ods->amount; ds->merchant_priv = ods->merchant_priv; - ds->command_initialized = GNUNET_YES; + ds->command_initialized = true; } else if (NULL != ds->merchant_priv_reference) { @@ -386,13 +418,13 @@ deposit_run (void *cls, ds->coin_index, &coin_priv)) || (GNUNET_OK != - TALER_TESTING_get_trait_age_commitment_proof (coin_cmd, - ds->coin_index, - &age_commitment_proof)) || + TALER_TESTING_get_trait_h_age_commitment (coin_cmd, + ds->coin_index, + &phac)) || (GNUNET_OK != TALER_TESTING_get_trait_denom_pub (coin_cmd, ds->coin_index, - &denom_pub)) || + &ds->denom_pub)) || (GNUNET_OK != TALER_TESTING_get_trait_denom_sig (coin_cmd, ds->coin_index, @@ -406,32 +438,10 @@ deposit_run (void *cls, return; } - if (NULL != age_commitment_proof) - { - TALER_age_commitment_hash (&age_commitment_proof->commitment, - &h_age_commitment); - } - ds->deposit_fee = denom_pub->fees.deposit; + ds->deposit_fee = ds->denom_pub->fees.deposit; GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv, &coin_pub.eddsa_pub); - if (! GNUNET_TIME_absolute_is_zero (ds->refund_deadline.abs_time)) - { - struct GNUNET_TIME_Relative refund_deadline; - - refund_deadline - = GNUNET_TIME_absolute_get_remaining (ds->refund_deadline.abs_time); - ds->wire_deadline - = - GNUNET_TIME_relative_to_timestamp ( - GNUNET_TIME_relative_multiply (refund_deadline, - 2)); - } - else - { - ds->refund_deadline = ds->wallet_timestamp; - ds->wire_deadline = GNUNET_TIME_timestamp_get (); - } GNUNET_CRYPTO_eddsa_key_get_public (&ds->merchant_priv.eddsa_priv, &merchant_pub.eddsa_pub); { @@ -441,45 +451,64 @@ deposit_run (void *cls, TALER_JSON_merchant_wire_signature_hash (ds->wire_details, &h_wire)); TALER_wallet_deposit_sign (&ds->amount, - &denom_pub->fees.deposit, + &ds->denom_pub->fees.deposit, &h_wire, &h_contract_terms, - &h_age_commitment, - NULL, /* FIXME #7270: add hash of extensions */ - &denom_pub->h_key, + NULL, /* wallet data hash */ + phac, + NULL, /* hash of extensions */ + &ds->denom_pub->h_key, ds->wallet_timestamp, &merchant_pub, ds->refund_deadline, coin_priv, - &coin_sig); + &ds->coin_sig); + ds->che.type = TALER_EXCHANGE_CTT_DEPOSIT; + ds->che.amount = ds->amount; + ds->che.details.deposit.h_wire = h_wire; + ds->che.details.deposit.h_contract_terms = h_contract_terms; + ds->che.details.deposit.no_h_policy = true; + ds->che.details.deposit.no_wallet_data_hash = true; + ds->che.details.deposit.wallet_timestamp = ds->wallet_timestamp; + ds->che.details.deposit.merchant_pub = merchant_pub; + ds->che.details.deposit.refund_deadline = ds->refund_deadline; + ds->che.details.deposit.sig = ds->coin_sig; + ds->che.details.deposit.no_hac = true; + ds->che.details.deposit.deposit_fee = ds->denom_pub->fees.deposit; } GNUNET_assert (NULL == ds->dh); { struct TALER_EXCHANGE_CoinDepositDetail cdd = { .amount = ds->amount, - .h_age_commitment = h_age_commitment, .coin_pub = coin_pub, - .coin_sig = coin_sig, + .coin_sig = ds->coin_sig, .denom_sig = *denom_pub_sig, - .h_denom_pub = denom_pub->h_key + .h_denom_pub = ds->denom_pub->h_key, + .h_age_commitment = {{{0}}}, }; struct TALER_EXCHANGE_DepositContractDetail dcd = { .wire_deadline = ds->wire_deadline, .merchant_payto_uri = payto_uri, .wire_salt = wire_salt, .h_contract_terms = h_contract_terms, - .extension_details = NULL /* FIXME #7270-OEC */, - .timestamp = ds->wallet_timestamp, + .wallet_timestamp = ds->wallet_timestamp, .merchant_pub = merchant_pub, .refund_deadline = ds->refund_deadline }; - ds->dh = TALER_EXCHANGE_deposit (is->exchange, - &dcd, - &cdd, - &deposit_cb, - ds, - &ec); + if (NULL != phac) + cdd.h_age_commitment = *phac; + + ds->dh = TALER_EXCHANGE_batch_deposit ( + TALER_TESTING_interpreter_get_context (is), + exchange_url, + TALER_TESTING_get_keys (is), + &dcd, + 1, + &cdd, + &deposit_cb, + ds, + &ec); } if (NULL == ds->dh) { @@ -508,11 +537,9 @@ deposit_cleanup (void *cls, if (NULL != ds->dh) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - ds->is->ip, - cmd->label); - TALER_EXCHANGE_deposit_cancel (ds->dh); + TALER_TESTING_command_incomplete (ds->is, + cmd->label); + TALER_EXCHANGE_batch_deposit_cancel (ds->dh); ds->dh = NULL; } if (NULL != ds->retry_task) @@ -545,9 +572,11 @@ deposit_traits (void *cls, const struct TALER_TESTING_Command *coin_cmd; /* Will point to coin cmd internals. */ const struct TALER_CoinSpendPrivateKeyP *coin_spent_priv; + struct TALER_CoinSpendPublicKeyP coin_spent_pub; const struct TALER_AgeCommitmentProof *age_commitment_proof; + const struct TALER_AgeCommitmentHash *h_age_commitment; - if (GNUNET_YES != ds->command_initialized) + if (! ds->command_initialized) { /* No access to traits yet. */ GNUNET_break (0); @@ -570,25 +599,43 @@ deposit_traits (void *cls, (GNUNET_OK != TALER_TESTING_get_trait_age_commitment_proof (coin_cmd, ds->coin_index, - &age_commitment_proof)) ) + &age_commitment_proof)) || + (GNUNET_OK != + TALER_TESTING_get_trait_h_age_commitment (coin_cmd, + ds->coin_index, + &h_age_commitment)) ) { GNUNET_break (0); TALER_TESTING_interpreter_fail (ds->is); return GNUNET_NO; } + + GNUNET_CRYPTO_eddsa_key_get_public (&coin_spent_priv->eddsa_priv, + &coin_spent_pub.eddsa_pub); + { struct TALER_TESTING_Trait traits[] = { /* First two traits are only available if - ds->traits is #GNUNET_YES */ + ds->traits is true */ TALER_TESTING_make_trait_exchange_pub (0, &ds->exchange_pub), TALER_TESTING_make_trait_exchange_sig (0, &ds->exchange_sig), /* These traits are always available */ + TALER_TESTING_make_trait_coin_history (0, + &ds->che), TALER_TESTING_make_trait_coin_priv (0, coin_spent_priv), + TALER_TESTING_make_trait_coin_pub (0, + &coin_spent_pub), + TALER_TESTING_make_trait_denom_pub (0, + ds->denom_pub), + TALER_TESTING_make_trait_coin_sig (0, + &ds->coin_sig), TALER_TESTING_make_trait_age_commitment_proof (0, age_commitment_proof), + TALER_TESTING_make_trait_h_age_commitment (0, + h_age_commitment), TALER_TESTING_make_trait_wire_details (ds->wire_details), TALER_TESTING_make_trait_contract_terms (ds->contract_terms), TALER_TESTING_make_trait_merchant_priv (&ds->merchant_priv), @@ -616,14 +663,15 @@ deposit_traits (void *cls, struct TALER_TESTING_Command -TALER_TESTING_cmd_deposit (const char *label, - const char *coin_reference, - unsigned int coin_index, - const char *target_account_payto, - const char *contract_terms, - struct GNUNET_TIME_Relative refund_deadline, - const char *amount, - unsigned int expected_response_code) +TALER_TESTING_cmd_deposit ( + const char *label, + const char *coin_reference, + unsigned int coin_index, + const char *target_account_payto, + const char *contract_terms, + struct GNUNET_TIME_Relative refund_deadline, + const char *amount, + unsigned int expected_response_code) { struct DepositState *ds; @@ -663,7 +711,7 @@ TALER_TESTING_cmd_deposit (const char *label, TALER_string_to_amount (amount, &ds->amount)); ds->expected_response_code = expected_response_code; - ds->command_initialized = GNUNET_YES; + ds->command_initialized = true; { struct TALER_TESTING_Command cmd = { .cls = ds, @@ -679,15 +727,16 @@ TALER_TESTING_cmd_deposit (const char *label, struct TALER_TESTING_Command -TALER_TESTING_cmd_deposit_with_ref (const char *label, - const char *coin_reference, - unsigned int coin_index, - const char *target_account_payto, - const char *contract_terms, - struct GNUNET_TIME_Relative refund_deadline, - const char *amount, - unsigned int expected_response_code, - const char *merchant_priv_reference) +TALER_TESTING_cmd_deposit_with_ref ( + const char *label, + const char *coin_reference, + unsigned int coin_index, + const char *target_account_payto, + const char *contract_terms, + struct GNUNET_TIME_Relative refund_deadline, + const char *amount, + unsigned int expected_response_code, + const char *merchant_priv_reference) { struct DepositState *ds; @@ -709,21 +758,25 @@ TALER_TESTING_cmd_deposit_with_ref (const char *label, GNUNET_assert (0); } ds->wallet_timestamp = GNUNET_TIME_timestamp_get (); - json_object_set_new (ds->contract_terms, - "timestamp", - GNUNET_JSON_from_timestamp (ds->wallet_timestamp)); + GNUNET_assert (0 == + json_object_set_new (ds->contract_terms, + "timestamp", + GNUNET_JSON_from_timestamp ( + ds->wallet_timestamp))); if (0 != refund_deadline.rel_value_us) { ds->refund_deadline = GNUNET_TIME_relative_to_timestamp (refund_deadline); - json_object_set_new (ds->contract_terms, - "refund_deadline", - GNUNET_JSON_from_timestamp (ds->refund_deadline)); + GNUNET_assert (0 == + json_object_set_new (ds->contract_terms, + "refund_deadline", + GNUNET_JSON_from_timestamp ( + ds->refund_deadline))); } GNUNET_assert (GNUNET_OK == TALER_string_to_amount (amount, &ds->amount)); ds->expected_response_code = expected_response_code; - ds->command_initialized = GNUNET_YES; + ds->command_initialized = true; { struct TALER_TESTING_Command cmd = { .cls = ds, @@ -739,9 +792,10 @@ TALER_TESTING_cmd_deposit_with_ref (const char *label, struct TALER_TESTING_Command -TALER_TESTING_cmd_deposit_replay (const char *label, - const char *deposit_reference, - unsigned int expected_response_code) +TALER_TESTING_cmd_deposit_replay ( + const char *label, + const char *deposit_reference, + unsigned int expected_response_code) { struct DepositState *ds; diff --git a/src/testing/testing_api_cmd_deposits_get.c b/src/testing/testing_api_cmd_deposits_get.c index 42dc1cb81..5d4436e2a 100644 --- a/src/testing/testing_api_cmd_deposits_get.c +++ b/src/testing/testing_api_cmd_deposits_get.c @@ -40,6 +40,11 @@ struct TrackTransactionState const char *bank_transfer_reference; /** + * Our command. + */ + const struct TALER_TESTING_Command *cmd; + + /** * The WTID associated by the transaction being tracked. */ struct TALER_WireTransferIdentifierRawP wtid; @@ -50,10 +55,18 @@ struct TrackTransactionState unsigned int expected_response_code; /** - * Set to the KYC UUID *if* the exchange replied with + * Set to the KYC requirement payto hash *if* the exchange replied with a + * request for KYC (#MHD_HTTP_ACCEPTED). + * Note: set based on our @e merchant_payto_uri, as + * the exchange does not respond with the payto hash. + */ + struct TALER_PaytoHashP h_payto; + + /** + * Set to the KYC requirement row *if* the exchange replied with * a request for KYC (#MHD_HTTP_ACCEPTED). */ - uint64_t kyc_uuid; + uint64_t requirement_row; /** * Reference to any operation that can provide a transaction. @@ -99,28 +112,19 @@ deposit_wtid_cb (void *cls, { struct TrackTransactionState *tts = cls; struct TALER_TESTING_Interpreter *is = tts->is; - struct TALER_TESTING_Command *cmd = &is->commands[is->ip]; tts->tth = NULL; if (tts->expected_response_code != dr->hr.http_status) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u/%d to command %s in %s:%u\n", - dr->hr.http_status, - (int) dr->hr.ec, - cmd->label, - __FILE__, - __LINE__); - json_dumpf (dr->hr.reply, - stderr, - 0); - TALER_TESTING_interpreter_fail (is); + TALER_TESTING_unexpected_status (is, + dr->hr.http_status, + tts->expected_response_code); return; } switch (dr->hr.http_status) { case MHD_HTTP_OK: - tts->wtid = dr->details.success.wtid; + tts->wtid = dr->details.ok.wtid; if (NULL != tts->bank_transfer_reference) { const struct TALER_TESTING_Command *bank_transfer_cmd; @@ -147,7 +151,7 @@ deposit_wtid_cb (void *cls, } /* Compare that expected and gotten subjects match. */ - if (0 != GNUNET_memcmp (&dr->details.success.wtid, + if (0 != GNUNET_memcmp (&dr->details.ok.wtid, wtid_want)) { GNUNET_break (0); @@ -158,7 +162,10 @@ deposit_wtid_cb (void *cls, break; case MHD_HTTP_ACCEPTED: /* allowed, nothing to check here */ - tts->kyc_uuid = dr->details.accepted.payment_target_uuid; + TALER_payto_hash (tts->merchant_payto_uri, + &tts->h_payto); + tts->requirement_row + = dr->details.accepted.requirement_row; break; case MHD_HTTP_NOT_FOUND: /* allowed, nothing to check here */ @@ -193,7 +200,7 @@ track_transaction_run (void *cls, struct TALER_PrivateContractHashP h_contract_terms; const struct TALER_MerchantPrivateKeyP *merchant_priv; - (void) cmd; + tts->cmd = cmd; tts->is = is; transaction_cmd = TALER_TESTING_interpreter_lookup_command (tts->is, @@ -265,13 +272,17 @@ track_transaction_run (void *cls, return; } - tts->tth = TALER_EXCHANGE_deposits_get (is->exchange, - merchant_priv, - &h_wire_details, - &h_contract_terms, - &coin_pub, - &deposit_wtid_cb, - tts); + tts->tth = TALER_EXCHANGE_deposits_get ( + TALER_TESTING_interpreter_get_context (is), + TALER_TESTING_get_exchange_url (is), + TALER_TESTING_get_keys (is), + merchant_priv, + &h_wire_details, + &h_contract_terms, + &coin_pub, + GNUNET_TIME_UNIT_ZERO, + &deposit_wtid_cb, + tts); GNUNET_assert (NULL != tts->tth); } @@ -291,10 +302,8 @@ track_transaction_cleanup (void *cls, if (NULL != tts->tth) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - tts->is->ip, - cmd->label); + TALER_TESTING_command_incomplete (tts->is, + cmd->label); TALER_EXCHANGE_deposits_get_cancel (tts->tth); tts->tth = NULL; } @@ -321,9 +330,10 @@ track_transaction_traits (void *cls, struct TrackTransactionState *tts = cls; struct TALER_TESTING_Trait traits[] = { TALER_TESTING_make_trait_wtid (&tts->wtid), - TALER_TESTING_make_trait_payment_target_uuid (&tts->kyc_uuid), - TALER_TESTING_make_trait_payto_uri ( - (const char **) &tts->merchant_payto_uri), + TALER_TESTING_make_trait_legi_requirement_row ( + &tts->requirement_row), + TALER_TESTING_make_trait_h_payto (&tts->h_payto), + TALER_TESTING_make_trait_payto_uri (tts->merchant_payto_uri), TALER_TESTING_trait_end () }; diff --git a/src/testing/testing_api_cmd_exec_aggregator.c b/src/testing/testing_api_cmd_exec_aggregator.c index 0f3cc1e14..1f05576ff 100644 --- a/src/testing/testing_api_cmd_exec_aggregator.c +++ b/src/testing/testing_api_cmd_exec_aggregator.c @@ -72,7 +72,6 @@ aggregator_run (void *cls, "taler-exchange-aggregator", "taler-exchange-aggregator", "-c", as->config_filename, - "-L", "INFO", "-t", /* exit when done */ (as->kyc_on) ? NULL diff --git a/src/testing/testing_api_cmd_exec_closer.c b/src/testing/testing_api_cmd_exec_closer.c index 75eab2d9f..2501b39a6 100644 --- a/src/testing/testing_api_cmd_exec_closer.c +++ b/src/testing/testing_api_cmd_exec_closer.c @@ -91,6 +91,7 @@ closer_run (void *cls, rcmd = TALER_TESTING_interpreter_lookup_command (is, as->reserve_ref); + GNUNET_assert (NULL != rcmd); if (GNUNET_OK != TALER_TESTING_get_trait_reserve_pub (rcmd, &reserve_pubp)) @@ -221,11 +222,11 @@ TALER_TESTING_cmd_exec_closer (const char *label, /* expected amount includes fee, while our argument gives the amount _without_ the fee. So add the fee. */ GNUNET_assert (0 <= - TALER_amount_add (&as->reserve_history.amount, - &as->reserve_history.amount, - &as->reserve_history.details.close_details. - fee)); - as->reserve_history.type = TALER_EXCHANGE_RTT_CLOSE; + TALER_amount_add ( + &as->reserve_history.amount, + &as->reserve_history.amount, + &as->reserve_history.details.close_details.fee)); + as->reserve_history.type = TALER_EXCHANGE_RTT_CLOSING; } { struct TALER_TESTING_Command cmd = { diff --git a/src/testing/testing_api_cmd_exec_transfer.c b/src/testing/testing_api_cmd_exec_transfer.c index f8af443bd..300413b4b 100644 --- a/src/testing/testing_api_cmd_exec_transfer.c +++ b/src/testing/testing_api_cmd_exec_transfer.c @@ -67,7 +67,6 @@ transfer_run (void *cls, "taler-exchange-transfer", "taler-exchange-transfer", "-c", as->config_filename, - "-L", "INFO", "-S", "1", "-w", "0", "-t", /* exit when done */ diff --git a/src/testing/testing_api_cmd_exec_wget.c b/src/testing/testing_api_cmd_exec_wget.c new file mode 100644 index 000000000..67aceca0a --- /dev/null +++ b/src/testing/testing_api_cmd_exec_wget.c @@ -0,0 +1,158 @@ +/* + 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/testing_api_cmd_exec_wget.c + * @brief run a wget command + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_json_lib.h" +#include <gnunet/gnunet_curl_lib.h> +#include "taler_signatures.h" +#include "taler_testing_lib.h" + + +/** + * State for a "wget" CMD. + */ +struct WgetState +{ + /** + * Process for the wgeter. + */ + struct GNUNET_OS_Process *wget_proc; + + /** + * URL to used by the wget. + */ + const char *url; +}; + + +/** + * Run the command; use the `wget' program. + * + * @param cls closure. + * @param cmd command currently being executed. + * @param is interpreter state. + */ +static void +wget_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct WgetState *ws = cls; + + (void) cmd; + ws->wget_proc + = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL, + NULL, NULL, NULL, + "wget", + "wget", + ws->url, + NULL); + if (NULL == ws->wget_proc) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + TALER_TESTING_wait_for_sigchld (is); +} + + +/** + * Free the state of a "wget" CMD, and possibly + * kills its process if it did not terminate regularly. + * + * @param cls closure. + * @param cmd the command being freed. + */ +static void +wget_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct WgetState *ws = cls; + + (void) cmd; + if (NULL != ws->wget_proc) + { + GNUNET_break (0 == + GNUNET_OS_process_kill (ws->wget_proc, + SIGKILL)); + GNUNET_OS_process_wait (ws->wget_proc); + GNUNET_OS_process_destroy (ws->wget_proc); + ws->wget_proc = NULL; + } + GNUNET_free (ws); +} + + +/** + * Offer "wget" CMD internal data to other commands. + * + * @param cls closure. + * @param[out] ret result. + * @param trait name of the trait. + * @param index index number of the object to offer. + * @return #GNUNET_OK on success. + */ +static enum GNUNET_GenericReturnValue +wget_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + struct WgetState *ws = cls; + struct TALER_TESTING_Trait traits[] = { + TALER_TESTING_make_trait_process (&ws->wget_proc), + TALER_TESTING_trait_end () + }; + + return TALER_TESTING_get_trait (traits, + ret, + trait, + index); +} + + +struct TALER_TESTING_Command +TALER_TESTING_cmd_exec_wget (const char *label, + const char *url) +{ + struct WgetState *ws; + + ws = GNUNET_new (struct WgetState); + ws->url = url; + + { + struct TALER_TESTING_Command cmd = { + .cls = ws, + .label = label, + .run = &wget_run, + .cleanup = &wget_cleanup, + .traits = &wget_traits + }; + + return cmd; + } +} + + +/* end of testing_api_cmd_exec_wget.c */ diff --git a/src/testing/testing_api_cmd_exec_wirewatch.c b/src/testing/testing_api_cmd_exec_wirewatch.c index cd31688d5..b6ed4f0f1 100644 --- a/src/testing/testing_api_cmd_exec_wirewatch.c +++ b/src/testing/testing_api_cmd_exec_wirewatch.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2018 Taler Systems SA + Copyright (C) 2018, 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 @@ -34,7 +34,6 @@ */ struct WirewatchState { - /** * Process for the wirewatcher. */ @@ -44,6 +43,11 @@ struct WirewatchState * Configuration file used by the wirewatcher. */ const char *config_filename; + + /** + * Account section to be used by the wirewatcher. + */ + const char *account_section; }; @@ -71,6 +75,10 @@ wirewatch_run (void *cls, "-S", "1", "-w", "0", "-t", /* exit when done */ + (NULL == ws->account_section) + ? NULL + : "-a", + ws->account_section, NULL); if (NULL == ws->wirewatch_proc) { @@ -138,14 +146,15 @@ wirewatch_traits (void *cls, struct TALER_TESTING_Command -TALER_TESTING_cmd_exec_wirewatch (const char *label, - const char *config_filename) +TALER_TESTING_cmd_exec_wirewatch2 (const char *label, + const char *config_filename, + const char *account_section) { struct WirewatchState *ws; ws = GNUNET_new (struct WirewatchState); ws->config_filename = config_filename; - + ws->account_section = account_section; { struct TALER_TESTING_Command cmd = { .cls = ws, @@ -160,4 +169,14 @@ TALER_TESTING_cmd_exec_wirewatch (const char *label, } +struct TALER_TESTING_Command +TALER_TESTING_cmd_exec_wirewatch (const char *label, + const char *config_filename) +{ + return TALER_TESTING_cmd_exec_wirewatch2 (label, + config_filename, + NULL); +} + + /* end of testing_api_cmd_exec_wirewatch.c */ diff --git a/src/testing/testing_api_cmd_get_auditor.c b/src/testing/testing_api_cmd_get_auditor.c new file mode 100644 index 000000000..ab4e32665 --- /dev/null +++ b/src/testing/testing_api_cmd_get_auditor.c @@ -0,0 +1,286 @@ +/* + This file is part of TALER + (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/testing_api_cmd_get_auditor.c + * @brief Command to get an auditor handle + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_json_lib.h" +#include <gnunet/gnunet_curl_lib.h> +#include "taler_testing_lib.h" + + +/** + * State for a "get auditor" CMD. + */ +struct GetAuditorState +{ + + /** + * Private key of the auditor. + */ + struct TALER_AuditorPrivateKeyP auditor_priv; + + /** + * Public key of the auditor. + */ + struct TALER_AuditorPublicKeyP auditor_pub; + + /** + * Our interpreter state. + */ + struct TALER_TESTING_Interpreter *is; + + /** + * Auditor handle used to get the configuration. + */ + struct TALER_AUDITOR_GetConfigHandle *auditor; + + /** + * URL of the auditor. + */ + char *auditor_url; + + /** + * Filename of the master private key of the auditor. + */ + char *priv_file; + +}; + + +/** + * Function called with information about the auditor. + * + * @param cls closure + * @param vr response data + */ +static void +version_cb ( + void *cls, + const struct TALER_AUDITOR_ConfigResponse *vr) +{ + struct GetAuditorState *gas = cls; + + gas->auditor = NULL; + if (MHD_HTTP_OK != vr->hr.http_status) + { + TALER_TESTING_unexpected_status (gas->is, + vr->hr.http_status, + MHD_HTTP_OK); + return; + } + if ( (NULL != gas->priv_file) && + (0 != GNUNET_memcmp (&gas->auditor_pub, + &vr->details.ok.vi.auditor_pub)) ) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (gas->is); + return; + } + TALER_TESTING_interpreter_next (gas->is); +} + + +/** + * Run the "get_auditor" command. + * + * @param cls closure. + * @param cmd the command currently being executed. + * @param is the interpreter state. + */ +static void +get_auditor_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct GetAuditorState *gas = cls; + + (void) cmd; + if (NULL == gas->auditor_url) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + if (NULL != gas->priv_file) + { + if (GNUNET_SYSERR == + GNUNET_CRYPTO_eddsa_key_from_file (gas->priv_file, + GNUNET_YES, + &gas->auditor_priv.eddsa_priv)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + GNUNET_CRYPTO_eddsa_key_get_public (&gas->auditor_priv.eddsa_priv, + &gas->auditor_pub.eddsa_pub); + } + gas->is = is; + gas->auditor + = TALER_AUDITOR_get_config (TALER_TESTING_interpreter_get_context (is), + gas->auditor_url, + &version_cb, + gas); + if (NULL == gas->auditor) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } +} + + +/** + * Cleanup the state. + * + * @param cls closure. + * @param cmd the command which is being cleaned up. + */ +static void +get_auditor_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct GetAuditorState *gas = cls; + + if (NULL != gas->auditor) + { + GNUNET_break (0); + TALER_AUDITOR_get_config_cancel (gas->auditor); + gas->auditor = NULL; + } + GNUNET_free (gas->priv_file); + GNUNET_free (gas->auditor_url); + GNUNET_free (gas); +} + + +/** + * Offer internal data to a "get_auditor" CMD state to other commands. + * + * @param cls closure + * @param[out] ret result (could be anything) + * @param trait name of the trait + * @param index index number of the object to offer. + * @return #GNUNET_OK on success + */ +static enum GNUNET_GenericReturnValue +get_auditor_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + struct GetAuditorState *gas = cls; + unsigned int off = (NULL == gas->priv_file) ? 2 : 0; + struct TALER_TESTING_Trait traits[] = { + TALER_TESTING_make_trait_auditor_priv (&gas->auditor_priv), + TALER_TESTING_make_trait_auditor_pub (&gas->auditor_pub), + TALER_TESTING_make_trait_auditor_url (gas->auditor_url), + TALER_TESTING_trait_end () + }; + + return TALER_TESTING_get_trait (&traits[off], + ret, + trait, + index); +} + + +/** + * Get the base URL of the auditor from @a cfg. + * + * @param cfg configuration to evaluate + * @return base URL of the auditor according to @a cfg + */ +static char * +get_auditor_base_url ( + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + char *auditor_url; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, + "auditor", + "BASE_URL", + &auditor_url)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "auditor", + "BASE_URL"); + return NULL; + } + return auditor_url; +} + + +/** + * Get the file name of the master private key file of the auditor from @a + * cfg. + * + * @param cfg configuration to evaluate + * @return base URL of the auditor according to @a cfg + */ +static char * +get_auditor_priv_file ( + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + char *fn; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (cfg, + "auditor", + "AUDITOR_PRIV_FILE", + &fn)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "auditor", + "AUDITOR_PRIV_FILE"); + return NULL; + } + return fn; +} + + +struct TALER_TESTING_Command +TALER_TESTING_cmd_get_auditor ( + const char *label, + const struct GNUNET_CONFIGURATION_Handle *cfg, + bool load_auditor_keys) +{ + struct GetAuditorState *gas; + + gas = GNUNET_new (struct GetAuditorState); + gas->auditor_url = get_auditor_base_url (cfg); + if (load_auditor_keys) + gas->priv_file = get_auditor_priv_file (cfg); + { + struct TALER_TESTING_Command cmd = { + .cls = gas, + .label = label, + .run = &get_auditor_run, + .cleanup = &get_auditor_cleanup, + .traits = &get_auditor_traits, + .name = "auditor" + }; + + return cmd; + } +} diff --git a/src/testing/testing_api_cmd_get_exchange.c b/src/testing/testing_api_cmd_get_exchange.c new file mode 100644 index 000000000..69a6e82b0 --- /dev/null +++ b/src/testing/testing_api_cmd_get_exchange.c @@ -0,0 +1,411 @@ +/* + This file is part of TALER + (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/testing_api_cmd_get_exchange.c + * @brief Command to get an exchange handle + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_json_lib.h" +#include <gnunet/gnunet_curl_lib.h> +#include "taler_testing_lib.h" + + +/** + * State for a "get exchange" CMD. + */ +struct GetExchangeState +{ + + /** + * Master private key of the exchange. + */ + struct TALER_MasterPrivateKeyP master_priv; + + /** + * Our interpreter state. + */ + struct TALER_TESTING_Interpreter *is; + + /** + * Exchange handle we produced. + */ + struct TALER_EXCHANGE_GetKeysHandle *exchange; + + /** + * Keys of the exchange. + */ + struct TALER_EXCHANGE_Keys *keys; + + /** + * URL of the exchange. + */ + char *exchange_url; + + /** + * Filename of the master private key of the exchange. + */ + char *master_priv_file; + + /** + * Label of a command to use to obtain existing + * keys. + */ + const char *last_keys_ref; + + /** + * Last denomination date we received when doing this request. + */ + struct GNUNET_TIME_Timestamp my_denom_date; + + /** + * Are we waiting for /keys before continuing? + */ + bool wait_for_keys; +}; + + +/** + * Function called with information about who is auditing + * a particular exchange and what keys the exchange is using. + * + * @param cls closure + * @param kr response from /keys + * @param[in] keys the keys of the exchange + */ +static void +cert_cb (void *cls, + const struct TALER_EXCHANGE_KeysResponse *kr, + struct TALER_EXCHANGE_Keys *keys) +{ + struct GetExchangeState *ges = cls; + const struct TALER_EXCHANGE_HttpResponse *hr = &kr->hr; + struct TALER_TESTING_Interpreter *is = ges->is; + + ges->exchange = NULL; + ges->keys = keys; + switch (hr->http_status) + { + case MHD_HTTP_OK: + if (ges->wait_for_keys) + { + ges->wait_for_keys = false; + TALER_TESTING_interpreter_next (is); + return; + } + ges->my_denom_date = kr->details.ok.keys->last_denom_issue_date; + return; + default: + GNUNET_break (0); + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "/keys responded with HTTP status %u\n", + hr->http_status); + if (ges->wait_for_keys) + { + ges->wait_for_keys = false; + TALER_TESTING_interpreter_fail (is); + return; + } + return; + } +} + + +/** + * Run the "get_exchange" command. + * + * @param cls closure. + * @param cmd the command currently being executed. + * @param is the interpreter state. + */ +static void +get_exchange_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct GetExchangeState *ges = cls; + struct TALER_EXCHANGE_Keys *xkeys = NULL; + + (void) cmd; + if (NULL == ges->exchange_url) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + if (NULL != ges->last_keys_ref) + { + const struct TALER_TESTING_Command *state_cmd; + struct TALER_EXCHANGE_Keys *old_keys; + const char *exchange_url; + json_t *s_keys; + + state_cmd + = TALER_TESTING_interpreter_lookup_command (is, + ges->last_keys_ref); + if (NULL == state_cmd) + { + /* Command providing serialized keys not found. */ + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + if (GNUNET_OK != + TALER_TESTING_get_trait_keys (state_cmd, + &old_keys)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + if (NULL == old_keys) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + if (GNUNET_OK != + TALER_TESTING_get_trait_exchange_url (state_cmd, + &exchange_url)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + if (0 != strcmp (exchange_url, + ges->exchange_url)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + s_keys = TALER_EXCHANGE_keys_to_json (old_keys); + if (NULL == s_keys) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + xkeys = TALER_EXCHANGE_keys_from_json (s_keys); + if (NULL == xkeys) + { + GNUNET_break (0); + json_dumpf (s_keys, + stderr, + JSON_INDENT (2)); + json_decref (s_keys); + TALER_TESTING_interpreter_fail (is); + return; + } + json_decref (s_keys); + } + if (NULL != ges->master_priv_file) + { + if (GNUNET_SYSERR == + GNUNET_CRYPTO_eddsa_key_from_file (ges->master_priv_file, + GNUNET_YES, + &ges->master_priv.eddsa_priv)) + { + GNUNET_break (0); + TALER_EXCHANGE_keys_decref (xkeys); + TALER_TESTING_interpreter_fail (is); + return; + } + } + ges->is = is; + ges->exchange + = TALER_EXCHANGE_get_keys (TALER_TESTING_interpreter_get_context (is), + ges->exchange_url, + xkeys, + &cert_cb, + ges); + TALER_EXCHANGE_keys_decref (xkeys); + if (NULL == ges->exchange) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + if (! ges->wait_for_keys) + TALER_TESTING_interpreter_next (is); +} + + +/** + * Cleanup the state. + * + * @param cls closure. + * @param cmd the command which is being cleaned up. + */ +static void +get_exchange_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct GetExchangeState *ges = cls; + + if (NULL != ges->exchange) + { + TALER_EXCHANGE_get_keys_cancel (ges->exchange); + ges->exchange = NULL; + } + TALER_EXCHANGE_keys_decref (ges->keys); + ges->keys = NULL; + GNUNET_free (ges->master_priv_file); + GNUNET_free (ges->exchange_url); + GNUNET_free (ges); +} + + +/** + * Offer internal data to a "get_exchange" CMD state to other commands. + * + * @param cls closure + * @param[out] ret result (could be anything) + * @param trait name of the trait + * @param index index number of the object to offer. + * @return #GNUNET_OK on success + */ +static enum GNUNET_GenericReturnValue +get_exchange_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + struct GetExchangeState *ges = cls; + unsigned int off = (NULL == ges->master_priv_file) ? 1 : 0; + + if (NULL != ges->keys) + { + struct TALER_TESTING_Trait traits[] = { + TALER_TESTING_make_trait_master_priv (&ges->master_priv), + TALER_TESTING_make_trait_master_pub (&ges->keys->master_pub), + TALER_TESTING_make_trait_keys (ges->keys), + TALER_TESTING_make_trait_exchange_url (ges->exchange_url), + TALER_TESTING_make_trait_timestamp (0, + &ges->my_denom_date), + TALER_TESTING_trait_end () + }; + + return TALER_TESTING_get_trait (&traits[off], + ret, + trait, + index); + } + else + { + struct TALER_TESTING_Trait traits[] = { + TALER_TESTING_make_trait_master_priv (&ges->master_priv), + TALER_TESTING_make_trait_exchange_url (ges->exchange_url), + TALER_TESTING_make_trait_timestamp (0, + &ges->my_denom_date), + TALER_TESTING_trait_end () + }; + + return TALER_TESTING_get_trait (&traits[off], + ret, + trait, + index); + } +} + + +/** + * Get the base URL of the exchange from @a cfg. + * + * @param cfg configuration to evaluate + * @return base URL of the exchange according to @a cfg + */ +static char * +get_exchange_base_url ( + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + char *exchange_url; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, + "exchange", + "BASE_URL", + &exchange_url)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "exchange", + "BASE_URL"); + return NULL; + } + return exchange_url; +} + + +/** + * Get the file name of the master private key file of the exchange from @a + * cfg. + * + * @param cfg configuration to evaluate + * @return base URL of the exchange according to @a cfg + */ +static char * +get_exchange_master_priv_file ( + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + char *fn; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (cfg, + "exchange-offline", + "MASTER_PRIV_FILE", + &fn)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "exchange-offline", + "MASTER_PRIV_FILE"); + return NULL; + } + return fn; +} + + +struct TALER_TESTING_Command +TALER_TESTING_cmd_get_exchange ( + const char *label, + const struct GNUNET_CONFIGURATION_Handle *cfg, + const char *last_keys_ref, + bool wait_for_keys, + bool load_private_key) +{ + struct GetExchangeState *ges; + + ges = GNUNET_new (struct GetExchangeState); + ges->exchange_url = get_exchange_base_url (cfg); + ges->last_keys_ref = last_keys_ref; + if (load_private_key) + ges->master_priv_file = get_exchange_master_priv_file (cfg); + ges->wait_for_keys = wait_for_keys; + { + struct TALER_TESTING_Command cmd = { + .cls = ges, + .label = label, + .run = &get_exchange_run, + .cleanup = &get_exchange_cleanup, + .traits = &get_exchange_traits, + .name = "exchange" + }; + + return cmd; + } +} diff --git a/src/testing/testing_api_cmd_insert_deposit.c b/src/testing/testing_api_cmd_insert_deposit.c index 032ff72dc..03e704c72 100644 --- a/src/testing/testing_api_cmd_insert_deposit.c +++ b/src/testing/testing_api_cmd_insert_deposit.c @@ -29,6 +29,7 @@ #include "taler_signatures.h" #include "taler_testing_lib.h" #include "taler_exchangedb_plugin.h" +#include "taler_exchangedb_lib.h" /** @@ -37,9 +38,9 @@ struct InsertDepositState { /** - * Configuration file used by the command. + * Database connection we use. */ - const struct TALER_TESTING_DatabaseConnection *dbc; + struct TALER_EXCHANGEDB_Plugin *plugin; /** * Human-readable name of the shop. @@ -71,6 +72,11 @@ struct InsertDepositState * Deposit fee. */ const char *deposit_fee; + + /** + * Do we used a cached @e plugin? + */ + bool cached; }; /** @@ -126,32 +132,46 @@ insert_deposit_run (void *cls, struct TALER_TESTING_Interpreter *is) { struct InsertDepositState *ids = cls; - struct TALER_EXCHANGEDB_Deposit deposit; + struct TALER_EXCHANGEDB_CoinDepositInformation deposit; + struct TALER_EXCHANGEDB_BatchDeposit bd; struct TALER_MerchantPrivateKeyP merchant_priv; struct TALER_EXCHANGEDB_DenominationKeyInformation issue; struct TALER_DenominationPublicKey dpk; struct TALER_DenominationPrivateKey denom_priv; + char *receiver_wire_account; (void) cmd; - // prepare and store issue first. + if (NULL == ids->plugin) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + if (GNUNET_OK != + ids->plugin->preflight (ids->plugin->cls)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } fake_issue (&issue); GNUNET_assert (GNUNET_OK == TALER_denom_priv_create (&denom_priv, &dpk, - TALER_DENOMINATION_RSA, + GNUNET_CRYPTO_BSA_RSA, 1024)); TALER_denom_pub_hash (&dpk, &issue.denom_hash); if ( (GNUNET_OK != - ids->dbc->plugin->start (ids->dbc->plugin->cls, - "talertestinglib: denomination insertion")) || + ids->plugin->start (ids->plugin->cls, + "talertestinglib: denomination insertion")) || (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != - ids->dbc->plugin->insert_denomination_info (ids->dbc->plugin->cls, - &dpk, - &issue)) || + ids->plugin->insert_denomination_info (ids->plugin->cls, + &dpk, + &issue)) || (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != - ids->dbc->plugin->commit (ids->dbc->plugin->cls)) ) + ids->plugin->commit (ids->plugin->cls)) ) { TALER_TESTING_interpreter_fail (is); TALER_denom_pub_free (&dpk); @@ -163,6 +183,11 @@ insert_deposit_run (void *cls, memset (&deposit, 0, sizeof (deposit)); + memset (&bd, + 0, + sizeof (bd)); + bd.cdis = &deposit; + bd.num_cdis = 1; GNUNET_assert ( GNUNET_YES == @@ -175,15 +200,12 @@ insert_deposit_run (void *cls, NULL, 0)); GNUNET_CRYPTO_eddsa_key_get_public (&merchant_priv.eddsa_priv, - &deposit.merchant_pub.eddsa_pub); + &bd.merchant_pub.eddsa_pub); GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, - &deposit.h_contract_terms.hash); - if ( (GNUNET_OK != - TALER_string_to_amount (ids->amount_with_fee, - &deposit.amount_with_fee)) || - (GNUNET_OK != - TALER_string_to_amount (ids->deposit_fee, - &deposit.deposit_fee)) ) + &bd.h_contract_terms.hash); + if (GNUNET_OK != + TALER_string_to_amount (ids->amount_with_fee, + &deposit.amount_with_fee)) { TALER_TESTING_interpreter_fail (is); TALER_denom_pub_free (&dpk); @@ -201,19 +223,20 @@ insert_deposit_run (void *cls, struct TALER_PlanchetDetail pd; struct TALER_BlindedDenominationSignature bds; struct TALER_PlanchetMasterSecretP ps; - struct TALER_ExchangeWithdrawValues alg_values; - union TALER_DenominationBlindingKeyP bks; + union GNUNET_CRYPTO_BlindingSecretP bks; + const struct TALER_ExchangeWithdrawValues *alg_values; - alg_values.cipher = TALER_DENOMINATION_RSA; + alg_values = TALER_denom_ewv_rsa_singleton (); TALER_planchet_blinding_secret_create (&ps, - &alg_values, + alg_values, &bks); GNUNET_assert (GNUNET_OK == TALER_denom_blind (&dpk, &bks, NULL, /* no age restriction active */ + NULL, /* no nonce needed */ &deposit.coin.coin_pub, - &alg_values, + alg_values, &c_hash, &pd.blinded_planchet)); GNUNET_assert (GNUNET_OK == @@ -227,45 +250,54 @@ insert_deposit_run (void *cls, &bds, &bks, &c_hash, - &alg_values, + alg_values, &dpk)); TALER_blinded_denom_sig_free (&bds); } - GNUNET_asprintf (&deposit.receiver_wire_account, + GNUNET_asprintf (&receiver_wire_account, "payto://x-taler-bank/localhost/%s?receiver-name=%s", ids->merchant_account, ids->merchant_account); - memset (&deposit.wire_salt, + bd.receiver_wire_account = receiver_wire_account; + TALER_payto_hash (bd.receiver_wire_account, + &bd.wire_target_h_payto); + memset (&bd.wire_salt, 46, - sizeof (deposit.wire_salt)); - deposit.timestamp = GNUNET_TIME_timestamp_get (); - deposit.wire_deadline = GNUNET_TIME_relative_to_timestamp ( + sizeof (bd.wire_salt)); + bd.wallet_timestamp = GNUNET_TIME_timestamp_get (); + bd.wire_deadline = GNUNET_TIME_relative_to_timestamp ( ids->wire_deadline); /* finally, actually perform the DB operation */ { uint64_t known_coin_id; struct TALER_DenominationHashP dph; struct TALER_AgeCommitmentHash agh; + bool balance_ok; + uint32_t bad_index; + bool ctr_conflict; if ( (GNUNET_OK != - ids->dbc->plugin->start (ids->dbc->plugin->cls, - "libtalertesting: insert deposit")) || + ids->plugin->start (ids->plugin->cls, + "libtalertesting: insert deposit")) || (0 > - ids->dbc->plugin->ensure_coin_known (ids->dbc->plugin->cls, - &deposit.coin, - &known_coin_id, - &dph, - &agh)) || + ids->plugin->ensure_coin_known (ids->plugin->cls, + &deposit.coin, + &known_coin_id, + &dph, + &agh)) || (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != - ids->dbc->plugin->insert_deposit (ids->dbc->plugin->cls, - ids->exchange_timestamp, - &deposit)) || + ids->plugin->do_deposit (ids->plugin->cls, + &bd, + &ids->exchange_timestamp, + &balance_ok, + &bad_index, + &ctr_conflict)) || (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != - ids->dbc->plugin->commit (ids->dbc->plugin->cls)) ) + ids->plugin->commit (ids->plugin->cls)) ) { GNUNET_break (0); - ids->dbc->plugin->rollback (ids->dbc->plugin->cls); - GNUNET_free (deposit.receiver_wire_account); + ids->plugin->rollback (ids->plugin->cls); + GNUNET_free (receiver_wire_account); TALER_denom_pub_free (&dpk); TALER_denom_priv_free (&denom_priv); TALER_TESTING_interpreter_fail (is); @@ -276,7 +308,7 @@ insert_deposit_run (void *cls, TALER_denom_sig_free (&deposit.coin.denom_sig); TALER_denom_pub_free (&dpk); TALER_denom_priv_free (&denom_priv); - GNUNET_free (deposit.receiver_wire_account); + GNUNET_free (receiver_wire_account); TALER_TESTING_interpreter_next (is); } @@ -295,6 +327,14 @@ insert_deposit_cleanup (void *cls, struct InsertDepositState *ids = cls; (void) cmd; + if ( (NULL != ids->plugin) && + (! ids->cached) ) + { + // FIXME: historically, we also did: + // ids->plugin->drop_tables (ids->plugin->cls); + TALER_EXCHANGEDB_plugin_unload (ids->plugin); + ids->plugin = NULL; + } GNUNET_free (ids); } @@ -302,7 +342,7 @@ insert_deposit_cleanup (void *cls, struct TALER_TESTING_Command TALER_TESTING_cmd_insert_deposit ( const char *label, - const struct TALER_TESTING_DatabaseConnection *dbc, + const struct GNUNET_CONFIGURATION_Handle *db_cfg, const char *merchant_name, const char *merchant_account, struct GNUNET_TIME_Timestamp exchange_timestamp, @@ -310,10 +350,22 @@ TALER_TESTING_cmd_insert_deposit ( const char *amount_with_fee, const char *deposit_fee) { + static struct TALER_EXCHANGEDB_Plugin *pluginc; + static const struct GNUNET_CONFIGURATION_Handle *db_cfgc; struct InsertDepositState *ids; ids = GNUNET_new (struct InsertDepositState); - ids->dbc = dbc; + if (db_cfgc == db_cfg) + { + ids->plugin = pluginc; + ids->cached = true; + } + else + { + ids->plugin = TALER_EXCHANGEDB_plugin_load (db_cfg); + pluginc = ids->plugin; + db_cfgc = db_cfg; + } ids->merchant_name = merchant_name; ids->merchant_account = merchant_account; ids->exchange_timestamp = exchange_timestamp; diff --git a/src/testing/testing_api_cmd_kyc_check_get.c b/src/testing/testing_api_cmd_kyc_check_get.c index 03b2321d1..25c7e98b8 100644 --- a/src/testing/testing_api_cmd_kyc_check_get.c +++ b/src/testing/testing_api_cmd_kyc_check_get.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2021 Taler Systems SA + Copyright (C) 2021-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 @@ -73,19 +73,13 @@ check_kyc_cb (void *cls, { struct KycCheckGetState *kcg = cls; struct TALER_TESTING_Interpreter *is = kcg->is; - struct TALER_TESTING_Command *cmd = &is->commands[is->ip]; kcg->kwh = NULL; if (kcg->expected_response_code != ks->http_status) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u/%d to command %s in %s:%u\n", - ks->http_status, - (int) ks->ec, - cmd->label, - __FILE__, - __LINE__); - TALER_TESTING_interpreter_fail (is); + TALER_TESTING_unexpected_status (is, + ks->http_status, + kcg->expected_response_code); return; } switch (ks->http_status) @@ -93,7 +87,7 @@ check_kyc_cb (void *cls, case MHD_HTTP_OK: break; case MHD_HTTP_ACCEPTED: - kcg->kyc_url = GNUNET_strdup (ks->details.kyc_url); + kcg->kyc_url = GNUNET_strdup (ks->details.accepted.kyc_url); break; case MHD_HTTP_NO_CONTENT: break; @@ -119,15 +113,14 @@ check_kyc_run (void *cls, { struct KycCheckGetState *kcg = cls; const struct TALER_TESTING_Command *res_cmd; - const char **payto_uri; - const uint64_t *payment_target; - struct TALER_PaytoHashP h_payto; + const uint64_t *requirement_row; + const struct TALER_PaytoHashP *h_payto; (void) cmd; kcg->is = is; - res_cmd = TALER_TESTING_interpreter_lookup_command (kcg->is, - kcg-> - payment_target_reference); + res_cmd = TALER_TESTING_interpreter_lookup_command ( + kcg->is, + kcg->payment_target_reference); if (NULL == res_cmd) { GNUNET_break (0); @@ -135,39 +128,37 @@ check_kyc_run (void *cls, return; } if (GNUNET_OK != - TALER_TESTING_get_trait_payto_uri (res_cmd, - &payto_uri)) + TALER_TESTING_get_trait_legi_requirement_row (res_cmd, + &requirement_row)) { GNUNET_break (0); TALER_TESTING_interpreter_fail (kcg->is); return; } if (GNUNET_OK != - TALER_TESTING_get_trait_payment_target_uuid (res_cmd, - &payment_target)) + TALER_TESTING_get_trait_h_payto (res_cmd, + &h_payto)) { GNUNET_break (0); TALER_TESTING_interpreter_fail (kcg->is); return; } - if ( (NULL == *payto_uri) || - (0 == *payment_target) ) + if (0 == *requirement_row) { GNUNET_break (0); TALER_TESTING_interpreter_fail (kcg->is); return; } - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Running KYC check for payto URI: %s\n", - *payto_uri); - TALER_payto_hash (*payto_uri, - &h_payto); - kcg->kwh = TALER_EXCHANGE_kyc_check (is->exchange, - *payment_target, - &h_payto, - GNUNET_TIME_UNIT_SECONDS, - &check_kyc_cb, - kcg); + kcg->kwh = TALER_EXCHANGE_kyc_check ( + TALER_TESTING_interpreter_get_context (is), + TALER_TESTING_get_exchange_url (is), + TALER_TESTING_get_keys (is), + *requirement_row, + h_payto, + TALER_KYCLOGIC_KYC_UT_INDIVIDUAL, + GNUNET_TIME_UNIT_SECONDS, + &check_kyc_cb, + kcg); GNUNET_assert (NULL != kcg->kwh); } @@ -187,10 +178,8 @@ check_kyc_cleanup (void *cls, if (NULL != kcg->kwh) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - kcg->is->ip, - cmd->label); + TALER_TESTING_command_incomplete (kcg->is, + cmd->label); TALER_EXCHANGE_kyc_check_cancel (kcg->kwh); kcg->kwh = NULL; } @@ -216,8 +205,7 @@ check_kyc_traits (void *cls, { struct KycCheckGetState *kcg = cls; struct TALER_TESTING_Trait traits[] = { - TALER_TESTING_make_trait_kyc_url ( - (const char **) &kcg->kyc_url), + TALER_TESTING_make_trait_kyc_url (kcg->kyc_url), TALER_TESTING_trait_end () }; diff --git a/src/testing/testing_api_cmd_kyc_proof.c b/src/testing/testing_api_cmd_kyc_proof.c index 52fb65219..b079fffce 100644 --- a/src/testing/testing_api_cmd_kyc_proof.c +++ b/src/testing/testing_api_cmd_kyc_proof.c @@ -44,11 +44,6 @@ struct KycProofGetState const char *code; /** - * State to pass. - */ - const char *state; - - /** * Logic section name to pass to `/kyc-proof/` handler. */ const char *logic; @@ -88,18 +83,13 @@ proof_kyc_cb (void *cls, { struct KycProofGetState *kcg = cls; struct TALER_TESTING_Interpreter *is = kcg->is; - struct TALER_TESTING_Command *cmd = &is->commands[is->ip]; kcg->kph = NULL; if (kcg->expected_response_code != kpr->http_status) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u to command %s in %s:%u\n", - kpr->http_status, - cmd->label, - __FILE__, - __LINE__); - TALER_TESTING_interpreter_fail (is); + TALER_TESTING_unexpected_status (is, + kpr->http_status, + kcg->expected_response_code); return; } switch (kpr->http_status) @@ -136,12 +126,18 @@ proof_kyc_run (void *cls, { struct KycProofGetState *kps = cls; const struct TALER_TESTING_Command *res_cmd; - const char **payto_uri; - struct TALER_PaytoHashP h_payto; + const struct TALER_PaytoHashP *h_payto; char *uargs; + const char *exchange_url; (void) cmd; kps->is = is; + exchange_url = TALER_TESTING_get_exchange_url (is); + if (NULL == exchange_url) + { + GNUNET_break (0); + return; + } res_cmd = TALER_TESTING_interpreter_lookup_command ( kps->is, kps->payment_target_reference); @@ -152,39 +148,27 @@ proof_kyc_run (void *cls, return; } if (GNUNET_OK != - TALER_TESTING_get_trait_payto_uri (res_cmd, - &payto_uri)) + TALER_TESTING_get_trait_h_payto (res_cmd, + &h_payto)) { - const struct TALER_PaytoHashP *hpt; - - if (GNUNET_OK != - TALER_TESTING_get_trait_h_payto (res_cmd, - &hpt)) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (kps->is); - return; - } - h_payto = *hpt; + GNUNET_break (0); + TALER_TESTING_interpreter_fail (kps->is); + return; } + if (NULL == kps->code) + uargs = NULL; else - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Triggering KYC proof for %s\n", - *payto_uri); - TALER_payto_hash (*payto_uri, - &h_payto); - } - GNUNET_asprintf (&uargs, - "?code=%s&state=%s", - kps->code, - kps->state); - kps->kph = TALER_EXCHANGE_kyc_proof (is->exchange, - &h_payto, - kps->logic, - uargs, - &proof_kyc_cb, - kps); + GNUNET_asprintf (&uargs, + "&code=%s", + kps->code); + kps->kph = TALER_EXCHANGE_kyc_proof ( + TALER_TESTING_interpreter_get_context (is), + exchange_url, + h_payto, + kps->logic, + uargs, + &proof_kyc_cb, + kps); GNUNET_free (uargs); GNUNET_assert (NULL != kps->kph); } @@ -205,10 +189,8 @@ proof_kyc_cleanup (void *cls, if (NULL != kps->kph) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - kps->is->ip, - cmd->label); + TALER_TESTING_command_incomplete (kps->is, + cmd->label); TALER_EXCHANGE_kyc_proof_cancel (kps->kph); kps->kph = NULL; } @@ -234,8 +216,7 @@ proof_kyc_traits (void *cls, { struct KycProofGetState *kps = cls; struct TALER_TESTING_Trait traits[] = { - TALER_TESTING_make_trait_web_url ( - (const char **) &kps->redirect_url), + TALER_TESTING_make_trait_web_url (kps->redirect_url), TALER_TESTING_trait_end () }; @@ -252,14 +233,12 @@ TALER_TESTING_cmd_proof_kyc_oauth2 ( const char *payment_target_reference, const char *logic_section, const char *code, - const char *state, unsigned int expected_response_code) { struct KycProofGetState *kps; kps = GNUNET_new (struct KycProofGetState); kps->code = code; - kps->state = state; kps->logic = logic_section; kps->payment_target_reference = payment_target_reference; kps->expected_response_code = expected_response_code; diff --git a/src/testing/testing_api_cmd_kyc_wallet_get.c b/src/testing/testing_api_cmd_kyc_wallet_get.c index d86692f80..ffb143ffb 100644 --- a/src/testing/testing_api_cmd_kyc_wallet_get.c +++ b/src/testing/testing_api_cmd_kyc_wallet_get.c @@ -49,6 +49,11 @@ struct KycWalletGetState char *reserve_payto_uri; /** + * Our command. + */ + const struct TALER_TESTING_Command *cmd; + + /** * Command to get a reserve private key from. */ const char *reserve_reference; @@ -59,10 +64,16 @@ struct KycWalletGetState unsigned int expected_response_code; /** - * Set to the KYC UUID *if* the exchange replied with - * a request for KYC (#MHD_HTTP_ACCEPTED). + * Set to the KYC requirement payto hash *if* the exchange replied with a + * request for KYC (#MHD_HTTP_OK). */ - uint64_t kyc_uuid; + struct TALER_PaytoHashP h_payto; + + /** + * Set to the KYC requirement row *if* the exchange replied with + * a request for KYC (#MHD_HTTP_OK). + */ + uint64_t requirement_row; /** * Handle to the "track transaction" pending operation. @@ -93,33 +104,29 @@ wallet_kyc_cb (void *cls, { struct KycWalletGetState *kwg = cls; struct TALER_TESTING_Interpreter *is = kwg->is; - struct TALER_TESTING_Command *cmd = &is->commands[is->ip]; kwg->kwh = NULL; if (kwg->expected_response_code != wkr->http_status) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u/%d (wanted %u) to command %s in %s:%u\n", - wkr->http_status, - (int) wkr->ec, - kwg->expected_response_code, - cmd->label, - __FILE__, - __LINE__); - TALER_TESTING_interpreter_fail (is); + TALER_TESTING_unexpected_status (is, + wkr->http_status, + kwg->expected_response_code); return; } switch (wkr->http_status) { - case MHD_HTTP_OK: - kwg->kyc_uuid = wkr->payment_target_uuid; - break; case MHD_HTTP_NO_CONTENT: break; case MHD_HTTP_FORBIDDEN: GNUNET_break (0); TALER_TESTING_interpreter_fail (is); return; + case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS: + kwg->requirement_row + = wkr->details.unavailable_for_legal_reasons.requirement_row; + kwg->h_payto + = wkr->details.unavailable_for_legal_reasons.h_payto; + break; default: GNUNET_break (0); break; @@ -141,9 +148,16 @@ wallet_kyc_run (void *cls, struct TALER_TESTING_Interpreter *is) { struct KycWalletGetState *kwg = cls; + const char *exchange_url; - (void) cmd; + kwg->cmd = cmd; kwg->is = is; + exchange_url = TALER_TESTING_get_exchange_url (is); + if (NULL == exchange_url) + { + GNUNET_break (0); + return; + } if (NULL != kwg->reserve_reference) { const struct TALER_TESTING_Command *res_cmd; @@ -175,13 +189,15 @@ wallet_kyc_run (void *cls, GNUNET_CRYPTO_eddsa_key_get_public (&kwg->reserve_priv.eddsa_priv, &kwg->reserve_pub.eddsa_pub); kwg->reserve_payto_uri - = TALER_reserve_make_payto (TALER_EXCHANGE_get_base_url (is->exchange), + = TALER_reserve_make_payto (exchange_url, &kwg->reserve_pub); - kwg->kwh = TALER_EXCHANGE_kyc_wallet (is->exchange, - &kwg->reserve_priv, - &kwg->balance, - &wallet_kyc_cb, - kwg); + kwg->kwh = TALER_EXCHANGE_kyc_wallet ( + TALER_TESTING_interpreter_get_context (is), + exchange_url, + &kwg->reserve_priv, + &kwg->balance, + &wallet_kyc_cb, + kwg); GNUNET_assert (NULL != kwg->kwh); } @@ -201,10 +217,8 @@ wallet_kyc_cleanup (void *cls, if (NULL != kwg->kwh) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - kwg->is->ip, - cmd->label); + TALER_TESTING_command_incomplete (kwg->is, + cmd->label); TALER_EXCHANGE_kyc_wallet_cancel (kwg->kwh); kwg->kwh = NULL; } @@ -232,9 +246,9 @@ wallet_kyc_traits (void *cls, struct TALER_TESTING_Trait traits[] = { TALER_TESTING_make_trait_reserve_priv (&kwg->reserve_priv), TALER_TESTING_make_trait_reserve_pub (&kwg->reserve_pub), - TALER_TESTING_make_trait_payment_target_uuid (&kwg->kyc_uuid), - TALER_TESTING_make_trait_payto_uri ( - (const char **) &kwg->reserve_payto_uri), + TALER_TESTING_make_trait_legi_requirement_row (&kwg->requirement_row), + TALER_TESTING_make_trait_h_payto (&kwg->h_payto), + TALER_TESTING_make_trait_payto_uri (kwg->reserve_payto_uri), TALER_TESTING_trait_end () }; diff --git a/src/testing/testing_api_cmd_oauth.c b/src/testing/testing_api_cmd_oauth.c index 045b5eefa..80d38e4c8 100644 --- a/src/testing/testing_api_cmd_oauth.c +++ b/src/testing/testing_api_cmd_oauth.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2021 Taler Systems SA + Copyright (C) 2021-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 @@ -40,6 +40,11 @@ struct OAuthState struct MHD_Daemon *mhd; /** + * Birthdate that the oauth server should return in a response, may be NULL + */ + const char *birthdate; + + /** * Port to listen on. */ uint16_t port; @@ -172,23 +177,36 @@ handler_cb (void *cls, void **con_cls) { struct RequestCtx *rc = *con_cls; + struct OAuthState *oas = cls; unsigned int hc; json_t *body; - (void) cls; (void) version; if (0 == strcasecmp (method, MHD_HTTP_METHOD_GET)) { + json_t *data = + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("id", + "XXXID12345678"), + GNUNET_JSON_pack_string ("first_name", + "Bob"), + GNUNET_JSON_pack_string ("last_name", + "Builder")); + + if (NULL != oas->birthdate) + GNUNET_assert (0 == + json_object_set_new (data, + "birthdate", + json_string_nocheck ( + oas->birthdate))); + body = GNUNET_JSON_PACK ( GNUNET_JSON_pack_string ( "status", "success"), GNUNET_JSON_pack_object_steal ( - "data", - GNUNET_JSON_PACK ( - GNUNET_JSON_pack_string ("id", - "XXXID12345678")))); + "data", data)); return TALER_MHD_reply_json_steal (connection, body, MHD_HTTP_OK); @@ -305,6 +323,7 @@ cleanup (void *cls, (void) toe; if (NULL == rc) return; + MHD_destroy_post_processor (rc->pp); GNUNET_free (rc->code); GNUNET_free (rc->client_id); GNUNET_free (rc->redirect_uri); @@ -328,12 +347,18 @@ oauth_run (void *cls, struct OAuthState *oas = cls; (void) cmd; - oas->mhd = MHD_start_daemon (MHD_USE_AUTO_INTERNAL_THREAD, + oas->mhd = MHD_start_daemon (MHD_USE_AUTO_INTERNAL_THREAD | MHD_USE_DEBUG, oas->port, NULL, NULL, &handler_cb, oas, MHD_OPTION_NOTIFY_COMPLETED, &cleanup, NULL, NULL); + if (NULL == oas->mhd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } TALER_TESTING_interpreter_next (is); } @@ -362,13 +387,15 @@ oauth_cleanup (void *cls, struct TALER_TESTING_Command -TALER_TESTING_cmd_oauth (const char *label, - uint16_t port) +TALER_TESTING_cmd_oauth_with_birthdate (const char *label, + const char *birthdate, + uint16_t port) { struct OAuthState *oas; oas = GNUNET_new (struct OAuthState); oas->port = port; + oas->birthdate = birthdate; { struct TALER_TESTING_Command cmd = { .cls = oas, diff --git a/src/testing/testing_api_cmd_offline_sign_global_fees.c b/src/testing/testing_api_cmd_offline_sign_global_fees.c index 7c9032255..db3916258 100644 --- a/src/testing/testing_api_cmd_offline_sign_global_fees.c +++ b/src/testing/testing_api_cmd_offline_sign_global_fees.c @@ -52,11 +52,6 @@ struct OfflineSignState const char *history_fee_s; /** - * The KYC fee to sign. - */ - const char *kyc_fee_s; - - /** * The account fee to sign. */ const char *account_fee_s; @@ -72,11 +67,6 @@ struct OfflineSignState struct GNUNET_TIME_Relative purse_timeout; /** - * How long does a user have to complete the KYC? - */ - struct GNUNET_TIME_Relative kyc_timeout; - - /** * How long do we keep the history? */ struct GNUNET_TIME_Relative history_expiration; @@ -104,7 +94,6 @@ offlinesign_run (void *cls, char num_purses[12]; char history_expiration[32]; char purse_timeout[32]; - char kyc_timeout[32]; GNUNET_snprintf (num_purses, sizeof (num_purses), @@ -120,11 +109,6 @@ offlinesign_run (void *cls, "%s", GNUNET_TIME_relative2s (ks->purse_timeout, false)); - GNUNET_snprintf (kyc_timeout, - sizeof (kyc_timeout), - "%s", - GNUNET_TIME_relative2s (ks->kyc_timeout, - false)); ks->offlinesign_proc = GNUNET_OS_start_process ( GNUNET_OS_INHERIT_STD_ALL, @@ -136,11 +120,9 @@ offlinesign_run (void *cls, "global-fee", "now", ks->history_fee_s, - ks->kyc_fee_s, ks->account_fee_s, ks->purse_fee_s, purse_timeout, - kyc_timeout, history_expiration, num_purses, "upload", @@ -215,11 +197,9 @@ TALER_TESTING_cmd_exec_offline_sign_global_fees ( const char *label, const char *config_filename, const char *history_fee, - const char *kyc_fee, const char *account_fee, const char *purse_fee, struct GNUNET_TIME_Relative purse_timeout, - struct GNUNET_TIME_Relative kyc_timeout, struct GNUNET_TIME_Relative history_expiration, unsigned int num_purses) { @@ -228,11 +208,9 @@ TALER_TESTING_cmd_exec_offline_sign_global_fees ( ks = GNUNET_new (struct OfflineSignState); ks->config_filename = config_filename; ks->history_fee_s = history_fee; - ks->kyc_fee_s = kyc_fee; ks->account_fee_s = account_fee; ks->purse_fee_s = purse_fee; ks->purse_timeout = purse_timeout; - ks->kyc_timeout = kyc_timeout; ks->history_expiration = history_expiration; ks->num_purses = num_purses; { diff --git a/src/testing/testing_api_cmd_offline_sign_wire_fees.c b/src/testing/testing_api_cmd_offline_sign_wire_fees.c index 55746ebc5..0fccbcd0a 100644 --- a/src/testing/testing_api_cmd_offline_sign_wire_fees.c +++ b/src/testing/testing_api_cmd_offline_sign_wire_fees.c @@ -52,11 +52,6 @@ struct OfflineSignState const char *wire_fee_s; /** - * The wad fee to sign. - */ - const char *wad_fee_s; - - /** * The closing fee to sign. */ const char *closing_fee_s; @@ -91,7 +86,6 @@ offlinesign_run (void *cls, "x-taler-bank", ks->wire_fee_s, ks->closing_fee_s, - ks->wad_fee_s, "upload", NULL); if (NULL == ks->offlinesign_proc) @@ -163,15 +157,13 @@ struct TALER_TESTING_Command TALER_TESTING_cmd_exec_offline_sign_fees (const char *label, const char *config_filename, const char *wire_fee, - const char *closing_fee, - const char *wad_fee) + const char *closing_fee) { struct OfflineSignState *ks; ks = GNUNET_new (struct OfflineSignState); ks->config_filename = config_filename; ks->wire_fee_s = wire_fee; - ks->wad_fee_s = wad_fee; ks->closing_fee_s = closing_fee; { struct TALER_TESTING_Command cmd = { diff --git a/src/testing/testing_api_cmd_purse_create_deposit.c b/src/testing/testing_api_cmd_purse_create_deposit.c index 200127b77..4740f9801 100644 --- a/src/testing/testing_api_cmd_purse_create_deposit.c +++ b/src/testing/testing_api_cmd_purse_create_deposit.c @@ -44,10 +44,20 @@ struct Coin unsigned int coin_index; /** + * Public key of the deposited coin. + */ + struct TALER_CoinSpendPublicKeyP coin_pub; + + /** * Amount to deposit (with fee). */ struct TALER_Amount deposit_with_fee; + /** + * Entry in the coin's history generated by this operation. + */ + struct TALER_EXCHANGE_CoinHistoryEntry che; + }; @@ -162,22 +172,15 @@ deposit_cb (void *cls, ds->dh = NULL; if (ds->expected_response_code != dr->hr.http_status) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u to command %s in %s:%u\n", - dr->hr.http_status, - ds->is->commands[ds->is->ip].label, - __FILE__, - __LINE__); - json_dumpf (dr->hr.reply, - stderr, - 0); - TALER_TESTING_interpreter_fail (ds->is); + TALER_TESTING_unexpected_status (ds->is, + dr->hr.http_status, + ds->expected_response_code); return; } if (MHD_HTTP_OK == dr->hr.http_status) { - ds->exchange_pub = dr->details.success.exchange_pub; - ds->exchange_sig = dr->details.success.exchange_sig; + ds->exchange_pub = dr->details.ok.exchange_pub; + ds->exchange_sig = dr->details.ok.exchange_sig; } TALER_TESTING_interpreter_next (ds->is); } @@ -200,9 +203,15 @@ deposit_run (void *cls, (void) cmd; ds->is = is; + GNUNET_CRYPTO_eddsa_key_create (&ds->purse_priv.eddsa_priv); + GNUNET_CRYPTO_eddsa_key_create (&ds->merge_priv.eddsa_priv); + GNUNET_CRYPTO_ecdhe_key_create (&ds->contract_priv.ecdhe_priv); + GNUNET_CRYPTO_eddsa_key_get_public (&ds->purse_priv.eddsa_priv, + &ds->purse_pub.eddsa_pub); + for (unsigned int i = 0; i<ds->num_coin_references; i++) { - const struct Coin *cr = &ds->coin_references[i]; + struct Coin *cr = &ds->coin_references[i]; struct TALER_EXCHANGE_PurseDeposit *pd = &deposits[i]; const struct TALER_TESTING_Command *coin_cmd; const struct TALER_CoinSpendPrivateKeyP *coin_priv; @@ -246,14 +255,20 @@ deposit_run (void *cls, pd->coin_priv = *coin_priv; pd->amount = cr->deposit_with_fee; pd->h_denom_pub = denom_pub->h_key; + GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv, + &cr->coin_pub.eddsa_pub); + cr->che.type = TALER_EXCHANGE_CTT_PURSE_DEPOSIT; + cr->che.amount = cr->deposit_with_fee; + GNUNET_CRYPTO_eddsa_key_get_public ( + &ds->purse_priv.eddsa_priv, + &cr->che.details.purse_deposit.purse_pub.eddsa_pub); + cr->che.details.purse_deposit.exchange_base_url + = TALER_TESTING_get_exchange_url (is); + TALER_age_commitment_hash ( + &age_commitment_proof->commitment, + &cr->che.details.purse_deposit.phac); } - GNUNET_CRYPTO_eddsa_key_create (&ds->purse_priv.eddsa_priv); - GNUNET_CRYPTO_eddsa_key_create (&ds->merge_priv.eddsa_priv); - GNUNET_CRYPTO_ecdhe_key_create (&ds->contract_priv.ecdhe_priv); - GNUNET_CRYPTO_eddsa_key_get_public (&ds->purse_priv.eddsa_priv, - &ds->purse_pub.eddsa_pub); - ds->purse_expiration = GNUNET_TIME_absolute_to_timestamp ( GNUNET_TIME_relative_to_absolute (ds->rel_expiration)); @@ -263,7 +278,9 @@ deposit_run (void *cls, "pay_deadline", GNUNET_JSON_from_timestamp (ds->purse_expiration))); ds->dh = TALER_EXCHANGE_purse_create_with_deposit ( - is->exchange, + TALER_TESTING_interpreter_get_context (is), + TALER_TESTING_get_exchange_url (is), + TALER_TESTING_get_keys (is), &ds->purse_priv, &ds->merge_priv, &ds->contract_priv, @@ -299,10 +316,8 @@ deposit_cleanup (void *cls, if (NULL != ds->dh) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - ds->is->ip, - cmd->label); + TALER_TESTING_command_incomplete (ds->is, + cmd->label); TALER_EXCHANGE_purse_create_with_deposit_cancel (ds->dh); ds->dh = NULL; } @@ -330,23 +345,33 @@ deposit_traits (void *cls, unsigned int index) { struct PurseCreateDepositState *ds = cls; - struct TALER_TESTING_Trait traits[] = { - TALER_TESTING_make_trait_merge_priv (&ds->merge_priv), - TALER_TESTING_make_trait_contract_priv (&ds->contract_priv), - TALER_TESTING_make_trait_purse_priv (&ds->purse_priv), - TALER_TESTING_make_trait_purse_pub (&ds->purse_pub), - TALER_TESTING_make_trait_contract_terms (ds->contract_terms), - TALER_TESTING_make_trait_deposit_amount (0, - &ds->target_amount), - TALER_TESTING_make_trait_timestamp (index, - &ds->purse_expiration), - TALER_TESTING_trait_end () - }; - - return TALER_TESTING_get_trait (traits, - ret, - trait, - index); + if (index >= ds->num_coin_references) + return GNUNET_NO; + + { + const struct Coin *co = &ds->coin_references[index]; + struct TALER_TESTING_Trait traits[] = { + TALER_TESTING_make_trait_merge_priv (&ds->merge_priv), + TALER_TESTING_make_trait_contract_priv (&ds->contract_priv), + TALER_TESTING_make_trait_coin_history (index, + &co->che), + TALER_TESTING_make_trait_coin_pub (index, + &co->coin_pub), + TALER_TESTING_make_trait_purse_priv (&ds->purse_priv), + TALER_TESTING_make_trait_purse_pub (&ds->purse_pub), + TALER_TESTING_make_trait_contract_terms (ds->contract_terms), + TALER_TESTING_make_trait_deposit_amount (0, + &ds->target_amount), + TALER_TESTING_make_trait_timestamp (index, + &ds->purse_expiration), + TALER_TESTING_trait_end () + }; + + return TALER_TESTING_get_trait (traits, + ret, + trait, + index); + } } diff --git a/src/testing/testing_api_cmd_purse_delete.c b/src/testing/testing_api_cmd_purse_delete.c new file mode 100644 index 000000000..26037359e --- /dev/null +++ b/src/testing/testing_api_cmd_purse_delete.c @@ -0,0 +1,189 @@ +/* + This file is part of TALER + Copyright (C) 2020 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/testing_api_cmd_purse_delete.c + * @brief command for testing /management/purse/disable. + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_json_lib.h" +#include <gnunet/gnunet_curl_lib.h> +#include "taler_testing_lib.h" +#include "taler_signatures.h" +#include "backoff.h" + + +/** + * State for a "purse_delete" CMD. + */ +struct PurseDeleteState +{ + + /** + * Purse delete handle while operation is running. + */ + struct TALER_EXCHANGE_PurseDeleteHandle *pdh; + + /** + * Our interpreter. + */ + struct TALER_TESTING_Interpreter *is; + + /** + * Expected HTTP response code. + */ + unsigned int expected_response_code; + + /** + * Command that created the purse we now want to + * delete. + */ + const char *purse_cmd; +}; + + +/** + * Callback to analyze the DELETE /purses/$PID response, just used to check if + * the response code is acceptable. + * + * @param cls closure. + * @param pdr HTTP response details + */ +static void +purse_delete_cb (void *cls, + const struct TALER_EXCHANGE_PurseDeleteResponse *pdr) +{ + struct PurseDeleteState *pds = cls; + + pds->pdh = NULL; + if (pds->expected_response_code != pdr->hr.http_status) + { + TALER_TESTING_unexpected_status (pds->is, + pdr->hr.http_status, + pds->expected_response_code); + return; + } + TALER_TESTING_interpreter_next (pds->is); +} + + +/** + * Run the command. + * + * @param cls closure. + * @param cmd the command to execute. + * @param is the interpreter state. + */ +static void +purse_delete_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct PurseDeleteState *pds = cls; + const struct TALER_PurseContractPrivateKeyP *purse_priv; + const struct TALER_TESTING_Command *ref; + const char *exchange_url; + + (void) cmd; + exchange_url = TALER_TESTING_get_exchange_url (is); + if (NULL == exchange_url) + { + GNUNET_break (0); + return; + } + ref = TALER_TESTING_interpreter_lookup_command (is, + pds->purse_cmd); + if (NULL == ref) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + if (GNUNET_OK != + TALER_TESTING_get_trait_purse_priv (ref, + &purse_priv)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + pds->is = is; + pds->pdh = TALER_EXCHANGE_purse_delete ( + TALER_TESTING_interpreter_get_context (is), + exchange_url, + purse_priv, + &purse_delete_cb, + pds); + if (NULL == pds->pdh) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } +} + + +/** + * Free the state of a "purse_delete" CMD, and possibly cancel a + * pending operation thereof. + * + * @param cls closure, must be a `struct PurseDeleteState`. + * @param cmd the command which is being cleaned up. + */ +static void +purse_delete_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct PurseDeleteState *pds = cls; + + if (NULL != pds->pdh) + { + TALER_TESTING_command_incomplete (pds->is, + cmd->label); + TALER_EXCHANGE_purse_delete_cancel (pds->pdh); + pds->pdh = NULL; + } + GNUNET_free (pds); +} + + +struct TALER_TESTING_Command +TALER_TESTING_cmd_purse_delete (const char *label, + unsigned int expected_http_status, + const char *purse_cmd) +{ + struct PurseDeleteState *ds; + + ds = GNUNET_new (struct PurseDeleteState); + ds->expected_response_code = expected_http_status; + ds->purse_cmd = purse_cmd; + { + struct TALER_TESTING_Command cmd = { + .cls = ds, + .label = label, + .run = &purse_delete_run, + .cleanup = &purse_delete_cleanup + }; + + return cmd; + } +} + + +/* end of testing_api_cmd_purse_delete.c */ diff --git a/src/testing/testing_api_cmd_purse_deposit.c b/src/testing/testing_api_cmd_purse_deposit.c index b056497e3..048c6d736 100644 --- a/src/testing/testing_api_cmd_purse_deposit.c +++ b/src/testing/testing_api_cmd_purse_deposit.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2022 Taler Systems SA + Copyright (C) 2022, 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 @@ -39,6 +39,16 @@ struct Coin char *command_ref; /** + * Entry in the coin's history generated by this operation. + */ + struct TALER_EXCHANGE_CoinHistoryEntry che; + + /** + * Public key of the deposited coin. + */ + struct TALER_CoinSpendPublicKeyP coin_pub; + + /** * index of the specific coin in the traits of @e command_ref. */ unsigned int coin_index; @@ -137,23 +147,16 @@ deposit_cb (void *cls, ds->dh = NULL; if (ds->expected_response_code != dr->hr.http_status) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u to command %s in %s:%u\n", - dr->hr.http_status, - ds->is->commands[ds->is->ip].label, - __FILE__, - __LINE__); - json_dumpf (dr->hr.reply, - stderr, - JSON_INDENT (2)); - TALER_TESTING_interpreter_fail (ds->is); + TALER_TESTING_unexpected_status (ds->is, + dr->hr.http_status, + ds->expected_response_code); return; } if (MHD_HTTP_OK == dr->hr.http_status) { if (-1 != - TALER_amount_cmp (&dr->details.success.total_deposited, - &dr->details.success.purse_value_after_fees)) + TALER_amount_cmp (&dr->details.ok.total_deposited, + &dr->details.ok.purse_value_after_fees)) { const struct TALER_TESTING_Command *purse_cmd; const struct TALER_ReserveSignatureP *reserve_sig; @@ -163,7 +166,7 @@ deposit_cb (void *cls, purse_cmd = TALER_TESTING_interpreter_lookup_command (ds->is, ds->purse_ref); - + GNUNET_assert (NULL != purse_cmd); if (GNUNET_OK != TALER_TESTING_get_trait_reserve_sig (purse_cmd, &reserve_sig)) @@ -202,10 +205,10 @@ deposit_cb (void *cls, /* Deposits complete, create trait! */ ds->reserve_history.type = TALER_EXCHANGE_RTT_MERGE; { - const struct TALER_EXCHANGE_Keys *keys; + struct TALER_EXCHANGE_Keys *keys; const struct TALER_EXCHANGE_GlobalFee *gf; - keys = TALER_EXCHANGE_get_keys (ds->is->exchange); + keys = TALER_TESTING_get_keys (ds->is); GNUNET_assert (NULL != keys); gf = TALER_EXCHANGE_get_global_fee (keys, *merge_timestamp); @@ -213,7 +216,7 @@ deposit_cb (void *cls, /* Note: change when flags below changes! */ ds->reserve_history.amount - = dr->details.success.purse_value_after_fees; + = dr->details.ok.purse_value_after_fees; if (true) { ds->reserve_history.details.merge_details.purse_fee = gf->fees.purse; @@ -226,7 +229,7 @@ deposit_cb (void *cls, } } ds->reserve_history.details.merge_details.h_contract_terms - = dr->details.success.h_contract_terms; + = dr->details.ok.h_contract_terms; ds->reserve_history.details.merge_details.merge_pub = *merge_pub; ds->reserve_history.details.merge_details.purse_pub @@ -236,7 +239,7 @@ deposit_cb (void *cls, ds->reserve_history.details.merge_details.merge_timestamp = *merge_timestamp; ds->reserve_history.details.merge_details.purse_expiration - = dr->details.success.purse_expiration; + = dr->details.ok.purse_expiration; ds->reserve_history.details.merge_details.min_age = ds->min_age; ds->reserve_history.details.merge_details.flags @@ -267,9 +270,9 @@ deposit_run (void *cls, (void) cmd; ds->is = is; - purse_cmd = TALER_TESTING_interpreter_lookup_command (is, ds->purse_ref); + GNUNET_assert (NULL != purse_cmd); if (GNUNET_OK != TALER_TESTING_get_trait_purse_pub (purse_cmd, &purse_pub)) @@ -281,7 +284,7 @@ deposit_run (void *cls, ds->purse_pub = *purse_pub; for (unsigned int i = 0; i<ds->num_coin_references; i++) { - const struct Coin *cr = &ds->coin_references[i]; + struct Coin *cr = &ds->coin_references[i]; struct TALER_EXCHANGE_PurseDeposit *pd = &deposits[i]; const struct TALER_TESTING_Command *coin_cmd; const struct TALER_CoinSpendPrivateKeyP *coin_priv; @@ -291,13 +294,7 @@ deposit_run (void *cls, coin_cmd = TALER_TESTING_interpreter_lookup_command (is, cr->command_ref); - if (NULL == coin_cmd) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - + GNUNET_assert (NULL != coin_cmd); if ( (GNUNET_OK != TALER_TESTING_get_trait_coin_priv (coin_cmd, cr->coin_index, @@ -320,6 +317,16 @@ deposit_run (void *cls, TALER_TESTING_interpreter_fail (is); return; } + GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv, + &cr->coin_pub.eddsa_pub); + cr->che.type = TALER_EXCHANGE_CTT_PURSE_DEPOSIT; + cr->che.amount = cr->deposit_with_fee; + cr->che.details.purse_deposit.purse_pub = *purse_pub; + cr->che.details.purse_deposit.exchange_base_url + = TALER_TESTING_get_exchange_url (is); + TALER_age_commitment_hash ( + &age_commitment_proof->commitment, + &cr->che.details.purse_deposit.phac); pd->age_commitment_proof = age_commitment_proof; pd->denom_sig = *denom_pub_sig; pd->coin_priv = *coin_priv; @@ -328,7 +335,9 @@ deposit_run (void *cls, } ds->dh = TALER_EXCHANGE_purse_deposit ( - is->exchange, + TALER_TESTING_interpreter_get_context (is), + TALER_TESTING_get_exchange_url (is), + TALER_TESTING_get_keys (is), NULL, /* FIXME #7271: WADs support: purse exchange URL */ &ds->purse_pub, ds->min_age, @@ -362,10 +371,8 @@ deposit_cleanup (void *cls, if (NULL != ds->dh) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - ds->is->ip, - cmd->label); + TALER_TESTING_command_incomplete (ds->is, + cmd->label); TALER_EXCHANGE_purse_deposit_cancel (ds->dh); ds->dh = NULL; } @@ -392,21 +399,31 @@ deposit_traits (void *cls, unsigned int index) { struct PurseDepositState *ds = cls; - struct TALER_TESTING_Trait traits[] = { - /* history entry MUST be first due to response code logic below! */ - TALER_TESTING_make_trait_reserve_history (0, - &ds->reserve_history), - TALER_TESTING_make_trait_reserve_pub (&ds->reserve_pub), - TALER_TESTING_make_trait_purse_pub (&ds->purse_pub), - TALER_TESTING_trait_end () - }; - - return TALER_TESTING_get_trait (ds->purse_complete - ? &traits[0] /* we have reserve history */ - : &traits[1], /* skip reserve history */ - ret, - trait, - index); + + if (index >= ds->num_coin_references) + return GNUNET_NO; + { + const struct Coin *co = &ds->coin_references[index]; + struct TALER_TESTING_Trait traits[] = { + /* history entry MUST be first due to response code logic below! */ + TALER_TESTING_make_trait_reserve_history (0, + &ds->reserve_history), + TALER_TESTING_make_trait_coin_history (index, + &co->che), + TALER_TESTING_make_trait_coin_pub (index, + &co->coin_pub), + TALER_TESTING_make_trait_reserve_pub (&ds->reserve_pub), + TALER_TESTING_make_trait_purse_pub (&ds->purse_pub), + TALER_TESTING_trait_end () + }; + + return TALER_TESTING_get_trait (ds->purse_complete + ? &traits[0] /* we have reserve history */ + : &traits[1], /* skip reserve history */ + ret, + trait, + index); + } } @@ -444,7 +461,8 @@ TALER_TESTING_cmd_purse_deposit_coins ( { struct Coin *c = &ds->coin_references[i++]; - GNUNET_assert (NULL != (val = va_arg (ap, const char *))); + GNUNET_assert (NULL != (val = va_arg (ap, + const char *))); GNUNET_assert (GNUNET_OK == TALER_TESTING_parse_coin_reference ( ref, diff --git a/src/testing/testing_api_cmd_purse_get.c b/src/testing/testing_api_cmd_purse_get.c index 61873721b..d5246660b 100644 --- a/src/testing/testing_api_cmd_purse_get.c +++ b/src/testing/testing_api_cmd_purse_get.c @@ -147,11 +147,11 @@ purse_status_cb (void *cls, TALER_string_to_amount (ss->expected_balance, &eb)); if (0 != TALER_amount_cmp (&eb, - &rs->details.success.balance)) + &rs->details.ok.balance)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unexpected amount in purse: %s\n", - TALER_amount_to_string (&rs->details.success.balance)); + TALER_amount_to_string (&rs->details.ok.balance)); TALER_TESTING_interpreter_fail (ss->is); return; } @@ -188,13 +188,7 @@ status_run (void *cls, create_purse = TALER_TESTING_interpreter_lookup_command (is, ss->purse_reference); - - if (NULL == create_purse) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } + GNUNET_assert (NULL != create_purse); if (GNUNET_OK != TALER_TESTING_get_trait_purse_pub (create_purse, &ss->purse_pub)) @@ -204,12 +198,15 @@ status_run (void *cls, TALER_TESTING_interpreter_fail (is); return; } - ss->pgh = TALER_EXCHANGE_purse_get (is->exchange, - ss->purse_pub, - ss->timeout, - ss->wait_for_merge, - &purse_status_cb, - ss); + ss->pgh = TALER_EXCHANGE_purse_get ( + TALER_TESTING_interpreter_get_context (is), + TALER_TESTING_get_exchange_url (is), + TALER_TESTING_get_keys (is), + ss->purse_pub, + ss->timeout, + ss->wait_for_merge, + &purse_status_cb, + ss); if (! GNUNET_TIME_relative_is_zero (ss->timeout)) { TALER_TESTING_interpreter_next (is); @@ -233,10 +230,8 @@ status_cleanup (void *cls, if (NULL != ss->pgh) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - ss->is->ip, - cmd->label); + TALER_TESTING_command_incomplete (ss->is, + cmd->label); TALER_EXCHANGE_purse_get_cancel (ss->pgh); ss->pgh = NULL; } @@ -311,6 +306,7 @@ finish_run (void *cls, poll_purse = TALER_TESTING_interpreter_lookup_command (is, ps->poll_reference); + GNUNET_assert (NULL != poll_purse); GNUNET_assert (poll_purse->run == &status_run); ss = poll_purse->cls; if (NULL == ss->pgh) diff --git a/src/testing/testing_api_cmd_purse_merge.c b/src/testing/testing_api_cmd_purse_merge.c index 4d1e8bf4b..cf9d4f996 100644 --- a/src/testing/testing_api_cmd_purse_merge.c +++ b/src/testing/testing_api_cmd_purse_merge.c @@ -72,6 +72,18 @@ struct PurseMergeState struct TALER_TESTING_Interpreter *is; /** + * Hash of the payto://-URI for the reserve we are + * merging into. + */ + struct TALER_PaytoHashP h_payto; + + /** + * Set to the KYC requirement row *if* the exchange replied with + * a request for KYC. + */ + uint64_t requirement_row; + + /** * Reserve history entry that corresponds to this operation. * Will be of type #TALER_EXCHANGE_RTT_MERGE. */ @@ -129,8 +141,9 @@ merge_cb (void *cls, struct PurseMergeState *ds = cls; ds->dh = NULL; - if (MHD_HTTP_OK == dr->hr.http_status) + switch (dr->hr.http_status) { + case MHD_HTTP_OK: ds->reserve_history.type = TALER_EXCHANGE_RTT_MERGE; ds->reserve_history.amount = ds->value_after_fees; GNUNET_assert (GNUNET_OK == @@ -153,21 +166,20 @@ merge_cb (void *cls, = ds->min_age; ds->reserve_history.details.merge_details.flags = TALER_WAMF_MODE_MERGE_FULLY_PAID_PURSE; + break; + case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS: + /* KYC required */ + ds->requirement_row = + dr->details.unavailable_for_legal_reasons.requirement_row; + break; } if (ds->expected_response_code != dr->hr.http_status) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u to command %s in %s:%u\n", - dr->hr.http_status, - ds->is->commands[ds->is->ip].label, - __FILE__, - __LINE__); - json_dumpf (dr->hr.reply, - stderr, - 0); - TALER_TESTING_interpreter_fail (ds->is); + TALER_TESTING_unexpected_status (ds->is, + dr->hr.http_status, + ds->expected_response_code); return; } TALER_TESTING_interpreter_next (ds->is); @@ -281,11 +293,35 @@ merge_run (void *cls, } GNUNET_CRYPTO_eddsa_key_get_public (&ds->reserve_priv.eddsa_priv, &ds->reserve_pub.eddsa_pub); + { + char *payto_uri; + const char *exchange_url; + const struct TALER_TESTING_Command *exchange_cmd; + + exchange_cmd = TALER_TESTING_interpreter_get_command (is, + "exchange"); + if (NULL == exchange_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_exchange_url (exchange_cmd, + &exchange_url)); + payto_uri = TALER_reserve_make_payto (exchange_url, + &ds->reserve_pub); + TALER_payto_hash (payto_uri, + &ds->h_payto); + GNUNET_free (payto_uri); + } GNUNET_CRYPTO_eddsa_key_get_public (&merge_priv->eddsa_priv, &ds->merge_pub.eddsa_pub); ds->merge_timestamp = GNUNET_TIME_timestamp_get (); ds->dh = TALER_EXCHANGE_account_merge ( - is->exchange, + TALER_TESTING_interpreter_get_context (is), + TALER_TESTING_get_exchange_url (is), + TALER_TESTING_get_keys (is), NULL, /* no wad */ &ds->reserve_priv, &ds->purse_pub, @@ -323,10 +359,8 @@ merge_cleanup (void *cls, if (NULL != ds->dh) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - ds->is->ip, - cmd->label); + TALER_TESTING_command_incomplete (ds->is, + cmd->label); TALER_EXCHANGE_account_merge_cancel (ds->dh); ds->dh = NULL; } @@ -357,6 +391,8 @@ merge_traits (void *cls, TALER_TESTING_make_trait_reserve_pub (&ds->reserve_pub), TALER_TESTING_make_trait_timestamp (0, &ds->merge_timestamp), + TALER_TESTING_make_trait_legi_requirement_row (&ds->requirement_row), + TALER_TESTING_make_trait_h_payto (&ds->h_payto), TALER_TESTING_trait_end () }; diff --git a/src/testing/testing_api_cmd_recoup.c b/src/testing/testing_api_cmd_recoup.c index ed8c7eed7..cefcd96bb 100644 --- a/src/testing/testing_api_cmd_recoup.c +++ b/src/testing/testing_api_cmd_recoup.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014-2018 Taler Systems SA + Copyright (C) 2014-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 @@ -59,6 +59,16 @@ struct RecoupState struct TALER_ReservePublicKeyP reserve_pub; /** + * Entry in the coin's history generated by this operation. + */ + struct TALER_EXCHANGE_CoinHistoryEntry che; + + /** + * Public key of the refunded coin. + */ + struct TALER_CoinSpendPublicKeyP coin; + + /** * Reserve history entry, set if this recoup actually filled up a reserve. * Otherwise `reserve_history.type` will be zero. */ @@ -73,17 +83,15 @@ struct RecoupState * was paid back belonged to the right reserve. * * @param cls closure - * @param hr HTTP response details - * @param reserve_pub public key of the reserve receiving the recoup + * @param rr response details */ static void recoup_cb (void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr, - const struct TALER_ReservePublicKeyP *reserve_pub) + const struct TALER_EXCHANGE_RecoupResponse *rr) { struct RecoupState *ps = cls; + const struct TALER_EXCHANGE_HttpResponse *hr = &rr->hr; struct TALER_TESTING_Interpreter *is = ps->is; - struct TALER_TESTING_Command *cmd = &is->commands[is->ip]; const struct TALER_TESTING_Command *reserve_cmd; char *cref; unsigned int idx; @@ -91,18 +99,9 @@ recoup_cb (void *cls, ps->ph = NULL; if (ps->expected_response_code != hr->http_status) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u/%d to command %s in %s:%u\n", - hr->http_status, - (int) hr->ec, - cmd->label, - __FILE__, - __LINE__); - json_dumpf (hr->reply, - stderr, - 0); - fprintf (stderr, "\n"); - TALER_TESTING_interpreter_fail (is); + TALER_TESTING_unexpected_status (is, + hr->http_status, + ps->expected_response_code); return; } @@ -135,12 +134,6 @@ recoup_cb (void *cls, { const struct TALER_ReservePrivateKeyP *reserve_priv; - if (NULL == reserve_pub) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } if (GNUNET_OK != TALER_TESTING_get_trait_reserve_priv (reserve_cmd, &reserve_priv)) @@ -151,7 +144,7 @@ recoup_cb (void *cls, } GNUNET_CRYPTO_eddsa_key_get_public (&reserve_priv->eddsa_priv, &ps->reserve_pub.eddsa_pub); - if (0 != GNUNET_memcmp (reserve_pub, + if (0 != GNUNET_memcmp (&rr->details.ok.reserve_pub, &ps->reserve_pub)) { GNUNET_break (0); @@ -162,6 +155,7 @@ recoup_cb (void *cls, TALER_amount_is_valid (&ps->reserve_history.amount)) ps->reserve_history.type = TALER_EXCHANGE_RTT_RECOUP; /* ps->reserve_history.details.recoup_details.coin_pub; // initialized earlier */ + ps->che.details.recoup.reserve_pub = ps->reserve_pub; } break; case MHD_HTTP_NOT_FOUND: @@ -200,6 +194,7 @@ recoup_run (void *cls, char *cref; unsigned int idx; const struct TALER_ExchangeWithdrawValues *ewv; + struct TALER_DenominationHashP h_denom_pub; ps->is = is; if (GNUNET_OK != @@ -231,6 +226,8 @@ recoup_run (void *cls, TALER_TESTING_interpreter_fail (is); return; } + GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv, + &ps->coin.eddsa_pub); if (GNUNET_OK != TALER_TESTING_get_trait_exchange_wd_value (coin_cmd, idx, @@ -273,13 +270,27 @@ recoup_run (void *cls, GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Trying to recoup denomination '%s'\n", TALER_B2S (&denom_pub->h_key)); - ps->ph = TALER_EXCHANGE_recoup (is->exchange, - denom_pub, - coin_sig, - ewv, - planchet, - &recoup_cb, - ps); + ps->che.type = TALER_EXCHANGE_CTT_RECOUP; + ps->che.amount = ps->reserve_history.amount; + TALER_planchet_blinding_secret_create (planchet, + ewv, + &ps->che.details.recoup.coin_bks); + TALER_denom_pub_hash (&denom_pub->key, + &h_denom_pub); + TALER_wallet_recoup_sign (&h_denom_pub, + &ps->che.details.recoup.coin_bks, + coin_priv, + &ps->che.details.recoup.coin_sig); + ps->ph = TALER_EXCHANGE_recoup ( + TALER_TESTING_interpreter_get_context (is), + TALER_TESTING_get_exchange_url (is), + TALER_TESTING_get_keys (is), + denom_pub, + coin_sig, + ewv, + planchet, + &recoup_cb, + ps); GNUNET_assert (NULL != ps->ph); } @@ -330,6 +341,10 @@ recoup_traits (void *cls, TALER_TESTING_make_trait_reserve_pub (&ps->reserve_pub), TALER_TESTING_make_trait_reserve_history (0, &ps->reserve_history), + TALER_TESTING_make_trait_coin_history (0, + &ps->che), + TALER_TESTING_make_trait_coin_pub (0, + &ps->coin), TALER_TESTING_trait_end () }; diff --git a/src/testing/testing_api_cmd_recoup_refresh.c b/src/testing/testing_api_cmd_recoup_refresh.c index 6081a4ba1..68d267be4 100644 --- a/src/testing/testing_api_cmd_recoup_refresh.c +++ b/src/testing/testing_api_cmd_recoup_refresh.c @@ -44,6 +44,26 @@ struct RecoupRefreshState const char *coin_reference; /** + * Entry in the old coin's history generated by this operation. + */ + struct TALER_EXCHANGE_CoinHistoryEntry che_old; + + /** + * Entry in the recouped coin's history generated by this operation. + */ + struct TALER_EXCHANGE_CoinHistoryEntry che_new; + + /** + * Public key of the refunded coin. + */ + struct TALER_CoinSpendPublicKeyP coin_pub_old; + + /** + * Public key of the refunded coin. + */ + struct TALER_CoinSpendPublicKeyP coin_pub_new; + + /** * Amount to be recouped. */ struct TALER_Amount amount; @@ -73,35 +93,24 @@ struct RecoupRefreshState * was paid back belonged to the right old coin. * * @param cls closure - * @param hr HTTP response details - * @param old_coin_pub public key of the dirty coin + * @param rrr response details */ static void recoup_refresh_cb (void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr, - const struct TALER_CoinSpendPublicKeyP *old_coin_pub) + const struct TALER_EXCHANGE_RecoupRefreshResponse *rrr) { struct RecoupRefreshState *rrs = cls; + const struct TALER_EXCHANGE_HttpResponse *hr = &rrr->hr; struct TALER_TESTING_Interpreter *is = rrs->is; - struct TALER_TESTING_Command *cmd = &is->commands[is->ip]; char *cref; unsigned int idx; rrs->ph = NULL; if (rrs->expected_response_code != hr->http_status) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u/%d to command %s in %s:%u\n", - hr->http_status, - (int) hr->ec, - cmd->label, - __FILE__, - __LINE__); - json_dumpf (hr->reply, - stderr, - 0); - fprintf (stderr, "\n"); - TALER_TESTING_interpreter_fail (is); + TALER_TESTING_unexpected_status (is, + hr->http_status, + rrs->expected_response_code); return; } @@ -150,7 +159,7 @@ recoup_refresh_cb (void *cls, GNUNET_CRYPTO_eddsa_key_get_public (&dirty_priv->eddsa_priv, &oc.eddsa_pub); if (0 != GNUNET_memcmp (&oc, - old_coin_pub)) + &rrr->details.ok.old_coin_pub)) { GNUNET_break (0); TALER_TESTING_interpreter_fail (is); @@ -189,6 +198,7 @@ recoup_refresh_run (void *cls, const struct TALER_TESTING_Command *coin_cmd; const struct TALER_TESTING_Command *melt_cmd; const struct TALER_CoinSpendPrivateKeyP *coin_priv; + const struct TALER_CoinSpendPrivateKeyP *coin_priv_old; const struct TALER_EXCHANGE_DenomPublicKey *denom_pub; const struct TALER_DenominationSignature *coin_sig; const struct TALER_RefreshMasterSecretP *rplanchet; @@ -196,6 +206,7 @@ recoup_refresh_run (void *cls, const struct TALER_ExchangeWithdrawValues *ewv; char *cref; unsigned int idx; + struct TALER_DenominationHashP h_denom_pub; rrs->is = is; if (GNUNET_OK != @@ -235,6 +246,22 @@ recoup_refresh_run (void *cls, return; } if (GNUNET_OK != + TALER_TESTING_get_trait_coin_priv (melt_cmd, + 0, + &coin_priv_old)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + GNUNET_CRYPTO_eddsa_key_get_public ( + &coin_priv->eddsa_priv, + &rrs->coin_pub_new.eddsa_pub); + GNUNET_CRYPTO_eddsa_key_get_public ( + &coin_priv_old->eddsa_priv, + &rrs->coin_pub_old.eddsa_pub); + + if (GNUNET_OK != TALER_TESTING_get_trait_exchange_wd_value (melt_cmd, idx, &ewv)) @@ -281,15 +308,41 @@ recoup_refresh_run (void *cls, GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Trying to recoup_refresh denomination '%s'\n", TALER_B2S (&denom_pub->h_key)); - rrs->ph = TALER_EXCHANGE_recoup_refresh (is->exchange, - denom_pub, - coin_sig, - ewv, - rplanchet, - planchet, - idx, - &recoup_refresh_cb, - rrs); + rrs->che_old.type + = TALER_EXCHANGE_CTT_OLD_COIN_RECOUP; + rrs->che_old.amount + = rrs->amount; + rrs->che_old.details.old_coin_recoup.new_coin_pub + = rrs->coin_pub_new; + rrs->che_new.type + = TALER_EXCHANGE_CTT_RECOUP_REFRESH; + rrs->che_new.amount + = rrs->amount; + rrs->che_new.details.recoup_refresh.old_coin_pub + = rrs->coin_pub_old; + TALER_planchet_blinding_secret_create ( + planchet, + ewv, + &rrs->che_new.details.recoup_refresh.coin_bks); + TALER_denom_pub_hash (&denom_pub->key, + &h_denom_pub); + TALER_wallet_recoup_refresh_sign ( + &h_denom_pub, + &rrs->che_new.details.recoup_refresh.coin_bks, + coin_priv, + &rrs->che_new.details.recoup_refresh.coin_sig); + rrs->ph = TALER_EXCHANGE_recoup_refresh ( + TALER_TESTING_interpreter_get_context (is), + TALER_TESTING_get_exchange_url (is), + TALER_TESTING_get_keys (is), + denom_pub, + coin_sig, + ewv, + rplanchet, + planchet, + idx, + &recoup_refresh_cb, + rrs); GNUNET_assert (NULL != rrs->ph); } @@ -315,6 +368,42 @@ recoup_refresh_cleanup (void *cls, } +/** + * Offer internal data from a "recoup-refresh" CMD state to other + * commands. + * + * @param cls closure + * @param[out] ret result (could be anything) + * @param trait name of the trait + * @param index index number of the object to offer. + * @return #GNUNET_OK on success + */ +static enum GNUNET_GenericReturnValue +recoup_refresh_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + struct RecoupRefreshState *rrs = cls; + struct TALER_TESTING_Trait traits[] = { + TALER_TESTING_make_trait_coin_history (0, + &rrs->che_old), + TALER_TESTING_make_trait_coin_pub (0, + &rrs->coin_pub_old), + TALER_TESTING_make_trait_coin_history (1, + &rrs->che_new), + TALER_TESTING_make_trait_coin_pub (1, + &rrs->coin_pub_new), + TALER_TESTING_trait_end () + }; + + return TALER_TESTING_get_trait (traits, + ret, + trait, + index); +} + + struct TALER_TESTING_Command TALER_TESTING_cmd_recoup_refresh (const char *label, unsigned int expected_response_code, @@ -343,7 +432,8 @@ TALER_TESTING_cmd_recoup_refresh (const char *label, .cls = rrs, .label = label, .run = &recoup_refresh_run, - .cleanup = &recoup_refresh_cleanup + .cleanup = &recoup_refresh_cleanup, + .traits = &recoup_refresh_traits }; return cmd; diff --git a/src/testing/testing_api_cmd_refresh.c b/src/testing/testing_api_cmd_refresh.c index 2aad77ce3..111e9118f 100644 --- a/src/testing/testing_api_cmd_refresh.c +++ b/src/testing/testing_api_cmd_refresh.c @@ -75,12 +75,12 @@ struct TALER_TESTING_FreshCoinData * applicable. */ struct TALER_AgeCommitmentProof *age_commitment_proof; - struct TALER_AgeCommitmentHash *h_age_commitment; + struct TALER_AgeCommitmentHash h_age_commitment; /** * The blinding key (needed for recoup operations). */ - union TALER_DenominationBlindingKeyP blinding_key; + union GNUNET_CRYPTO_BlindingSecretP blinding_key; }; @@ -103,6 +103,11 @@ struct RefreshMeltState struct TALER_EXCHANGE_RefreshData refresh_data; /** + * Our command. + */ + const struct TALER_TESTING_Command *cmd; + + /** * Reference to a previous melt command. */ const char *melt_reference; @@ -113,6 +118,12 @@ struct RefreshMeltState struct TALER_EXCHANGE_MeltHandle *rmh; /** + * Expected entry in the coin history created by this + * operation. + */ + struct TALER_EXCHANGE_CoinHistoryEntry che; + + /** * Interpreter state. */ struct TALER_TESTING_Interpreter *is; @@ -140,6 +151,11 @@ struct RefreshMeltState const struct TALER_CoinSpendPrivateKeyP *melt_priv; /** + * Public key of the dirty coin being melted. + */ + struct TALER_CoinSpendPublicKeyP melt_pub; + + /** * Task scheduled to try later. */ struct GNUNET_SCHEDULER_Task *retry_task; @@ -210,6 +226,11 @@ struct RefreshRevealState struct TALER_EXCHANGE_RefreshesRevealHandle *rrh; /** + * Our command. + */ + const struct TALER_TESTING_Command *cmd; + + /** * Convenience struct to keep in one place all the * data related to one fresh coin, set by the reveal callback * as it comes from the exchange. @@ -273,6 +294,11 @@ struct RefreshLinkState const char *reveal_reference; /** + * Our command. + */ + const struct TALER_TESTING_Command *cmd; + + /** * Handle to the ongoing operation. */ struct TALER_EXCHANGE_LinkHandle *rlh; @@ -334,8 +360,7 @@ do_reveal_retry (void *cls) struct RefreshRevealState *rrs = cls; rrs->retry_task = NULL; - rrs->is->commands[rrs->is->ip].last_req_time - = GNUNET_TIME_absolute_get (); + TALER_TESTING_touch_cmd (rrs->is); refresh_reveal_run (rrs, NULL, rrs->is); @@ -380,24 +405,16 @@ reveal_cb (void *cls, MAX_BACKOFF); rrs->total_backoff = GNUNET_TIME_relative_add (rrs->total_backoff, rrs->backoff); - rrs->is->commands[rrs->is->ip].num_tries++; + TALER_TESTING_inc_tries (rrs->is); rrs->retry_task = GNUNET_SCHEDULER_add_delayed (rrs->backoff, &do_reveal_retry, rrs); return; } } - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u/%d to command %s in %s:%u\n", - hr->http_status, - (int) hr->ec, - rrs->is->commands[rrs->is->ip].label, - __FILE__, - __LINE__); - json_dumpf (hr->reply, - stderr, - 0); - TALER_TESTING_interpreter_fail (rrs->is); + TALER_TESTING_unexpected_status (rrs->is, + hr->http_status, + rrs->expected_response_code); return; } melt_cmd = TALER_TESTING_interpreter_lookup_command (rrs->is, @@ -411,7 +428,7 @@ reveal_cb (void *cls, switch (hr->http_status) { case MHD_HTTP_OK: - rrs->num_fresh_coins = rr->details.success.num_coins; + rrs->num_fresh_coins = rr->details.ok.num_coins; rrs->psa = GNUNET_new_array (rrs->num_fresh_coins, struct TALER_PlanchetMasterSecretP); rrs->fresh_coins = GNUNET_new_array (rrs->num_fresh_coins, @@ -419,7 +436,7 @@ reveal_cb (void *cls, for (unsigned int i = 0; i<rrs->num_fresh_coins; i++) { const struct TALER_EXCHANGE_RevealedCoinInfo *coin - = &rr->details.success.coins[i]; + = &rr->details.ok.coins[i]; struct TALER_TESTING_FreshCoinData *fc = &rrs->fresh_coins[i]; rrs->psa[i] = coin->ps; @@ -434,19 +451,24 @@ reveal_cb (void *cls, return; } fc->coin_priv = coin->coin_priv; - fc->age_commitment_proof = coin->age_commitment_proof; - fc->h_age_commitment = coin->h_age_commitment; - TALER_denom_sig_deep_copy (&fc->sig, - &coin->sig); + if (NULL != coin->age_commitment_proof) + { + fc->age_commitment_proof = + TALER_age_commitment_proof_duplicate (coin->age_commitment_proof); + fc->h_age_commitment = coin->h_age_commitment; + } + + TALER_denom_sig_copy (&fc->sig, + &coin->sig); } if (0 != rrs->total_backoff.rel_value_us) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Total reveal backoff for %s was %s\n", - rrs->is->commands[rrs->is->ip].label, + rrs->cmd->label, GNUNET_STRINGS_relative_time_to_string (rrs->total_backoff, - GNUNET_YES)); + true)); } break; default: @@ -488,6 +510,7 @@ refresh_reveal_run (void *cls, struct RefreshMeltState *rms; const struct TALER_TESTING_Command *melt_cmd; + rrs->cmd = cmd; rrs->is = is; melt_cmd = TALER_TESTING_interpreter_lookup_command (is, rrs->melt_reference); @@ -504,14 +527,16 @@ refresh_reveal_run (void *cls, for (unsigned int i = 0; i<rms->num_fresh_coins; i++) alg_values[i] = rms->mbds[i].alg_value; - rrs->rrh = TALER_EXCHANGE_refreshes_reveal (is->exchange, - &rms->rms, - &rms->refresh_data, - rms->num_fresh_coins, - alg_values, - rms->noreveal_index, - &reveal_cb, - rrs); + rrs->rrh = TALER_EXCHANGE_refreshes_reveal ( + TALER_TESTING_interpreter_get_context (is), + TALER_TESTING_get_exchange_url (is), + &rms->rms, + &rms->refresh_data, + rms->num_fresh_coins, + alg_values, + rms->noreveal_index, + &reveal_cb, + rrs); } if (NULL == rrs->rrh) { @@ -538,10 +563,8 @@ refresh_reveal_cleanup (void *cls, (void) cmd; if (NULL != rrs->rrh) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - rrs->is->ip, - cmd->label); + TALER_TESTING_command_incomplete (rrs->is, + cmd->label); TALER_EXCHANGE_refreshes_reveal_cancel (rrs->rrh); rrs->rrh = NULL; } @@ -552,7 +575,11 @@ refresh_reveal_cleanup (void *cls, } for (unsigned int j = 0; j < rrs->num_fresh_coins; j++) + { TALER_denom_sig_free (&rrs->fresh_coins[j].sig); + TALER_age_commitment_proof_free (rrs->fresh_coins[j].age_commitment_proof); + GNUNET_free (rrs->fresh_coins[j].age_commitment_proof); + } GNUNET_free (rrs->fresh_coins); GNUNET_free (rrs->psa); @@ -585,8 +612,7 @@ do_link_retry (void *cls) struct RefreshLinkState *rls = cls; rls->retry_task = NULL; - rls->is->commands[rls->is->ip].last_req_time - = GNUNET_TIME_absolute_get (); + TALER_TESTING_touch_cmd (rls->is); refresh_link_run (rls, NULL, rls->is); @@ -608,7 +634,6 @@ link_cb (void *cls, struct RefreshLinkState *rls = cls; const struct TALER_EXCHANGE_HttpResponse *hr = &lr->hr; const struct TALER_TESTING_Command *reveal_cmd; - struct TALER_TESTING_Command *link_cmd = &rls->is->commands[rls->is->ip]; unsigned int found; const unsigned int *num_fresh_coins; @@ -634,24 +659,16 @@ link_cb (void *cls, MAX_BACKOFF); rls->total_backoff = GNUNET_TIME_relative_add (rls->total_backoff, rls->backoff); - rls->is->commands[rls->is->ip].num_tries++; + TALER_TESTING_inc_tries (rls->is); rls->retry_task = GNUNET_SCHEDULER_add_delayed (rls->backoff, &do_link_retry, rls); return; } } - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u/%d to command %s in %s:%u\n", - hr->http_status, - (int) hr->ec, - link_cmd->label, - __FILE__, - __LINE__); - json_dumpf (hr->reply, - stderr, - 0); - TALER_TESTING_interpreter_fail (rls->is); + TALER_TESTING_unexpected_status (rls->is, + hr->http_status, + rls->expected_response_code); return; } reveal_cmd = TALER_TESTING_interpreter_lookup_command (rls->is, @@ -675,11 +692,11 @@ link_cb (void *cls, TALER_TESTING_interpreter_fail (rls->is); return; } - if (lr->details.success.num_coins != *num_fresh_coins) + if (lr->details.ok.num_coins != *num_fresh_coins) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unexpected number of fresh coins: %d vs %d in %s:%u\n", - lr->details.success.num_coins, + lr->details.ok.num_coins, *num_fresh_coins, __FILE__, __LINE__); @@ -687,11 +704,11 @@ link_cb (void *cls, return; } /* check that the coins match */ - for (unsigned int i = 0; i<lr->details.success.num_coins; i++) - for (unsigned int j = i + 1; j<lr->details.success.num_coins; j++) + for (unsigned int i = 0; i<lr->details.ok.num_coins; i++) + for (unsigned int j = i + 1; j<lr->details.ok.num_coins; j++) if (0 == - GNUNET_memcmp (&lr->details.success.coins[i].coin_priv, - &lr->details.success.coins[j].coin_priv)) + GNUNET_memcmp (&lr->details.ok.coins[i].coin_priv, + &lr->details.ok.coins[j].coin_priv)) GNUNET_break (0); /* Note: coins might be legitimately permutated in here... */ found = 0; @@ -709,12 +726,12 @@ link_cb (void *cls, return; } - for (unsigned int i = 0; i<lr->details.success.num_coins; i++) + for (unsigned int i = 0; i<lr->details.ok.num_coins; i++) { const struct TALER_EXCHANGE_LinkedCoinInfo *lci_i - = &lr->details.success.coins[i]; + = &lr->details.ok.coins[i]; - for (unsigned int j = 0; j<lr->details.success.num_coins; j++) + for (unsigned int j = 0; j<lr->details.ok.num_coins; j++) { const struct TALER_TESTING_FreshCoinData *fcj = &(*fc)[j]; @@ -735,12 +752,12 @@ link_cb (void *cls, } /* for j*/ } /* for i */ } - if (found != lr->details.success.num_coins) + if (found != lr->details.ok.num_coins) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Only %u/%u coins match expectations\n", found, - lr->details.success.num_coins); + lr->details.ok.num_coins); GNUNET_break (0); TALER_TESTING_interpreter_fail (rls->is); return; @@ -749,9 +766,9 @@ link_cb (void *cls, { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Total link backoff for %s was %s\n", - rls->is->commands[rls->is->ip].label, + rls->cmd->label, GNUNET_STRINGS_relative_time_to_string (rls->total_backoff, - GNUNET_YES)); + true)); } break; default: @@ -782,9 +799,16 @@ refresh_link_run (void *cls, const struct TALER_TESTING_Command *reveal_cmd; const struct TALER_TESTING_Command *melt_cmd; const struct TALER_TESTING_Command *coin_cmd; + const char *exchange_url; - (void) cmd; + rls->cmd = cmd; rls->is = is; + exchange_url = TALER_TESTING_get_exchange_url (is); + if (NULL == exchange_url) + { + GNUNET_break (0); + return; + } reveal_cmd = TALER_TESTING_interpreter_lookup_command (rls->is, rls->reveal_reference); if (NULL == reveal_cmd) @@ -827,11 +851,13 @@ refresh_link_run (void *cls, } /* finally, use private key from withdraw sign command */ - rls->rlh = TALER_EXCHANGE_link (is->exchange, - coin_priv, - rms->refresh_data.melt_age_commitment_proof, - &link_cb, - rls); + rls->rlh = TALER_EXCHANGE_link ( + TALER_TESTING_interpreter_get_context (is), + exchange_url, + coin_priv, + rms->refresh_data.melt_age_commitment_proof, + &link_cb, + rls); if (NULL == rls->rlh) { @@ -857,11 +883,8 @@ refresh_link_cleanup (void *cls, if (NULL != rls->rlh) { - - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - rls->is->ip, - cmd->label); + TALER_TESTING_command_incomplete (rls->is, + cmd->label); TALER_EXCHANGE_link_cancel (rls->rlh); rls->rlh = NULL; } @@ -885,8 +908,7 @@ do_melt_retry (void *cls) struct RefreshMeltState *rms = cls; rms->retry_task = NULL; - rms->is->commands[rms->is->ip].last_req_time - = GNUNET_TIME_absolute_get (); + TALER_TESTING_touch_cmd (rms->is); melt_run (rms, NULL, rms->is); @@ -930,58 +952,56 @@ melt_cb (void *cls, MAX_BACKOFF); rms->total_backoff = GNUNET_TIME_relative_add (rms->total_backoff, rms->backoff); - rms->is->commands[rms->is->ip].num_tries++; + TALER_TESTING_inc_tries (rms->is); rms->retry_task = GNUNET_SCHEDULER_add_delayed (rms->backoff, &do_melt_retry, rms); return; } } - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u/%d to command %s in %s:%u\n", - hr->http_status, - (int) hr->ec, - rms->is->commands[rms->is->ip].label, - __FILE__, - __LINE__); - json_dumpf (hr->reply, - stderr, - 0); - TALER_TESTING_interpreter_fail (rms->is); + TALER_TESTING_unexpected_status_with_body (rms->is, + hr->http_status, + rms->expected_response_code, + hr->reply); return; } if (MHD_HTTP_OK == hr->http_status) { - rms->noreveal_index = mr->details.success.noreveal_index; - if (mr->details.success.num_mbds != rms->num_fresh_coins) + rms->noreveal_index = mr->details.ok.noreveal_index; + if (mr->details.ok.num_mbds != rms->num_fresh_coins) { GNUNET_break (0); TALER_TESTING_interpreter_fail (rms->is); return; } GNUNET_free (rms->mbds); - rms->mbds = GNUNET_memdup (mr->details.success.mbds, - mr->details.success.num_mbds - * sizeof (struct - TALER_EXCHANGE_MeltBlindingDetail)); + rms->mbds = GNUNET_new_array ( + mr->details.ok.num_mbds, + struct TALER_EXCHANGE_MeltBlindingDetail); + for (unsigned int i = 0; i<mr->details.ok.num_mbds; i++) + TALER_denom_ewv_copy (&rms->mbds[i].alg_value, + &mr->details.ok.mbds[i].alg_value); } if (0 != rms->total_backoff.rel_value_us) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Total melt backoff for %s was %s\n", - rms->is->commands[rms->is->ip].label, + rms->cmd->label, GNUNET_STRINGS_relative_time_to_string (rms->total_backoff, - GNUNET_YES)); + true)); } if (rms->double_melt) { TALER_LOG_DEBUG ("Doubling the melt (%s)\n", - rms->is->commands[rms->is->ip].label); - rms->rmh = TALER_EXCHANGE_melt (rms->is->exchange, - &rms->rms, - &rms->refresh_data, - &melt_cb, - rms); + rms->cmd->label); + rms->rmh = TALER_EXCHANGE_melt ( + TALER_TESTING_interpreter_get_context (rms->is), + TALER_TESTING_get_exchange_url (rms->is), + TALER_TESTING_get_keys (rms->is), + &rms->rms, + &rms->refresh_data, + &melt_cb, + rms); rms->double_melt = false; return; } @@ -1009,7 +1029,7 @@ melt_run (void *cls, }; const char **melt_fresh_amounts; - (void) cmd; + rms->cmd = cmd; if (NULL == (melt_fresh_amounts = rms->melt_fresh_amounts)) melt_fresh_amounts = default_melt_fresh_amounts; rms->is = is; @@ -1026,12 +1046,12 @@ melt_run (void *cls, { struct TALER_Amount melt_amount; struct TALER_Amount fresh_amount; - const struct TALER_AgeCommitmentProof *age_commitment_proof; - const struct TALER_AgeCommitmentHash *h_age_commitment; + const struct TALER_AgeCommitmentProof *age_commitment_proof = NULL; + const struct TALER_AgeCommitmentHash *h_age_commitment = NULL; const struct TALER_DenominationSignature *melt_sig; const struct TALER_EXCHANGE_DenomPublicKey *melt_denom_pub; const struct TALER_TESTING_Command *coin_command; - bool age_restricted; + bool age_restricted_denom; if (NULL == (coin_command = TALER_TESTING_interpreter_lookup_command ( @@ -1052,7 +1072,6 @@ melt_run (void *cls, TALER_TESTING_interpreter_fail (rms->is); return; } - if (GNUNET_OK != TALER_TESTING_get_trait_age_commitment_proof (coin_command, 0, @@ -1072,7 +1091,6 @@ melt_run (void *cls, TALER_TESTING_interpreter_fail (rms->is); return; } - if (GNUNET_OK != TALER_TESTING_get_trait_denom_sig (coin_command, 0, @@ -1082,7 +1100,6 @@ melt_run (void *cls, TALER_TESTING_interpreter_fail (rms->is); return; } - if (GNUNET_OK != TALER_TESTING_get_trait_denom_pub (coin_command, 0, @@ -1096,7 +1113,10 @@ melt_run (void *cls, /* Melt amount starts with the melt fee of the old coin; we'll add the values and withdraw fees of the fresh coins next */ melt_amount = melt_denom_pub->fees.refresh; - age_restricted = melt_denom_pub->key.age_mask.bits != 0; + age_restricted_denom = melt_denom_pub->key.age_mask.bits != 0; + GNUNET_assert (age_restricted_denom == (NULL != age_commitment_proof)); + GNUNET_assert ((NULL == age_commitment_proof) || + (0 < age_commitment_proof->commitment.num)); for (unsigned int i = 0; i<num_fresh_coins; i++) { const struct TALER_EXCHANGE_DenomPublicKey *fresh_pk; @@ -1113,9 +1133,9 @@ melt_run (void *cls, TALER_TESTING_interpreter_fail (rms->is); return; } - fresh_pk = TALER_TESTING_find_pk (TALER_EXCHANGE_get_keys (is->exchange), + fresh_pk = TALER_TESTING_find_pk (TALER_TESTING_get_keys (rms->is), &fresh_amount, - age_restricted); + age_restricted_denom); if (NULL == fresh_pk) { GNUNET_break (0); @@ -1133,27 +1153,46 @@ melt_run (void *cls, &fresh_pk->fees.withdraw)); rms->fresh_pks[i] = *fresh_pk; /* Make a deep copy of the RSA key */ - TALER_denom_pub_deep_copy (&rms->fresh_pks[i].key, - &fresh_pk->key); + TALER_denom_pub_copy (&rms->fresh_pks[i].key, + &fresh_pk->key); } /* end for */ rms->refresh_data.melt_priv = *rms->melt_priv; + GNUNET_CRYPTO_eddsa_key_get_public (&rms->melt_priv->eddsa_priv, + &rms->melt_pub.eddsa_pub); rms->refresh_data.melt_amount = melt_amount; rms->refresh_data.melt_sig = *melt_sig; rms->refresh_data.melt_pk = *melt_denom_pub; - rms->refresh_data.melt_age_commitment_proof = age_commitment_proof; - rms->refresh_data.melt_h_age_commitment = h_age_commitment; + + if (NULL != age_commitment_proof) + { + GNUNET_assert (NULL != h_age_commitment); + rms->refresh_data.melt_age_commitment_proof = age_commitment_proof; + rms->refresh_data.melt_h_age_commitment = h_age_commitment; + } rms->refresh_data.fresh_pks = rms->fresh_pks; rms->refresh_data.fresh_pks_len = num_fresh_coins; - GNUNET_assert (age_restricted == + GNUNET_assert (age_restricted_denom == (NULL != age_commitment_proof)); - - rms->rmh = TALER_EXCHANGE_melt (is->exchange, - &rms->rms, - &rms->refresh_data, - &melt_cb, - rms); + GNUNET_assert ((NULL == age_commitment_proof) || + (0 < age_commitment_proof->commitment.num)); + + rms->che.type = TALER_EXCHANGE_CTT_MELT; + rms->che.amount = melt_amount; + if (NULL != age_commitment_proof) + rms->che.details.melt.h_age_commitment = *h_age_commitment; + else + rms->che.details.melt.no_hac = true; + + rms->rmh = TALER_EXCHANGE_melt ( + TALER_TESTING_interpreter_get_context (is), + TALER_TESTING_get_exchange_url (is), + TALER_TESTING_get_keys (is), + &rms->rms, + &rms->refresh_data, + &melt_cb, + rms); if (NULL == rms->rmh) { @@ -1181,10 +1220,8 @@ melt_cleanup (void *cls, (void) cmd; if (NULL != rms->rmh) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - rms->is->ip, - rms->is->commands[rms->is->ip].label); + TALER_TESTING_command_incomplete (rms->is, + cmd->label); TALER_EXCHANGE_melt_cancel (rms->rmh); rms->rmh = NULL; } @@ -1199,7 +1236,12 @@ melt_cleanup (void *cls, TALER_denom_pub_free (&rms->fresh_pks[i].key); GNUNET_free (rms->fresh_pks); } - GNUNET_free (rms->mbds); + if (NULL != rms->mbds) + { + for (unsigned int i = 0; i < rms->num_fresh_coins; i++) + TALER_denom_ewv_free (&rms->mbds[i].alg_value); + GNUNET_free (rms->mbds); + } GNUNET_free (rms->melt_fresh_amounts); GNUNET_free (rms); } @@ -1231,17 +1273,23 @@ melt_traits (void *cls, struct TALER_TESTING_Trait traits[] = { TALER_TESTING_make_trait_denom_pub (index, &rms->fresh_pks[index]), - TALER_TESTING_make_trait_coin_priv (index, + TALER_TESTING_make_trait_coin_priv (0, rms->melt_priv), + TALER_TESTING_make_trait_coin_pub (0, + &rms->melt_pub), + TALER_TESTING_make_trait_coin_history (0, + &rms->che), TALER_TESTING_make_trait_age_commitment_proof ( index, rms->refresh_data.melt_age_commitment_proof), TALER_TESTING_make_trait_h_age_commitment ( index, rms->refresh_data.melt_h_age_commitment), - TALER_TESTING_make_trait_exchange_wd_value (index, - &rms->mbds[index].alg_value), TALER_TESTING_make_trait_refresh_secret (&rms->rms), + (NULL != rms->mbds) + ? TALER_TESTING_make_trait_exchange_wd_value (index, + &rms->mbds[index].alg_value) + : TALER_TESTING_trait_end (), TALER_TESTING_trait_end () }; @@ -1408,7 +1456,7 @@ refresh_reveal_traits (void *cls, rrs->fresh_coins[index].age_commitment_proof), TALER_TESTING_make_trait_h_age_commitment ( index, - rrs->fresh_coins[index].h_age_commitment), + &rrs->fresh_coins[index].h_age_commitment), TALER_TESTING_make_trait_denom_pub ( index, rrs->fresh_coins[index].pk), @@ -1426,6 +1474,7 @@ refresh_reveal_traits (void *cls, &rrs->psa[index]), TALER_TESTING_trait_end () }; + return TALER_TESTING_get_trait (traits, ret, trait, diff --git a/src/testing/testing_api_cmd_refund.c b/src/testing/testing_api_cmd_refund.c index 4be3605a4..29b68ef08 100644 --- a/src/testing/testing_api_cmd_refund.c +++ b/src/testing/testing_api_cmd_refund.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014-2020 Taler Systems SA + Copyright (C) 2014-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 @@ -54,9 +54,14 @@ struct RefundState uint64_t refund_transaction_id; /** - * Connection to the exchange. + * Entry in the coin's history generated by this operation. */ - struct TALER_EXCHANGE_Handle *exchange; + struct TALER_EXCHANGE_CoinHistoryEntry che; + + /** + * Public key of the refunded coin. + */ + struct TALER_CoinSpendPublicKeyP coin; /** * Handle to the refund operation. @@ -75,38 +80,51 @@ struct RefundState * response code is acceptable. * * @param cls closure - * @param hr HTTP response details - * @param exchange_pub public key the exchange - * used for signing @a obj. - * @param exchange_sig actual signature confirming the refund + * @param rr response details */ static void refund_cb (void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr, - const struct TALER_ExchangePublicKeyP *exchange_pub, - const struct TALER_ExchangeSignatureP *exchange_sig) + const struct TALER_EXCHANGE_RefundResponse *rr) { - struct RefundState *rs = cls; - struct TALER_TESTING_Command *refund_cmd; + const struct TALER_EXCHANGE_HttpResponse *hr = &rr->hr; - refund_cmd = &rs->is->commands[rs->is->ip]; rs->rh = NULL; if (rs->expected_response_code != hr->http_status) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u/%d to command %s in %s:%u\n", - hr->http_status, - hr->ec, - refund_cmd->label, - __FILE__, - __LINE__); - json_dumpf (hr->reply, - stderr, - 0); - TALER_TESTING_interpreter_fail (rs->is); + TALER_TESTING_unexpected_status (rs->is, + hr->http_status, + rs->expected_response_code); return; } + if (MHD_HTTP_OK == hr->http_status) + { + struct TALER_Amount refund_amount; + + if (GNUNET_OK != + TALER_string_to_amount (rs->refund_amount, + &refund_amount)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to parse amount `%s'\n", + rs->refund_amount); + TALER_TESTING_interpreter_fail (rs->is); + return; + } + if (0 > + TALER_amount_subtract (&rs->che.amount, + &refund_amount, + &rs->che.details.refund.refund_fee)) + { + GNUNET_break (0); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to subtract %s from %s\n", + TALER_amount2s (&rs->che.details.refund.refund_fee), + rs->refund_amount); + TALER_TESTING_interpreter_fail (rs->is); + return; + } + } TALER_TESTING_interpreter_next (rs->is); } @@ -125,24 +143,21 @@ refund_run (void *cls, { struct RefundState *rs = cls; const struct TALER_CoinSpendPrivateKeyP *coin_priv; - struct TALER_CoinSpendPublicKeyP coin; const json_t *contract_terms; struct TALER_PrivateContractHashP h_contract_terms; struct TALER_Amount refund_amount; const struct TALER_MerchantPrivateKeyP *merchant_priv; const struct TALER_TESTING_Command *coin_cmd; + const struct TALER_EXCHANGE_DenomPublicKey *denom_pub; - rs->exchange = is->exchange; rs->is = is; - if (GNUNET_OK != TALER_string_to_amount (rs->refund_amount, &refund_amount)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to parse amount `%s' at %u/%s\n", + "Failed to parse amount `%s' at %s\n", rs->refund_amount, - is->ip, cmd->label); TALER_TESTING_interpreter_fail (is); return; @@ -168,10 +183,15 @@ refund_run (void *cls, &h_contract_terms)); /* Hunting for a coin .. */ - if (GNUNET_OK != - TALER_TESTING_get_trait_coin_priv (coin_cmd, - 0, - &coin_priv)) + if ( (GNUNET_OK != + TALER_TESTING_get_trait_coin_priv (coin_cmd, + 0, + &coin_priv)) || + (GNUNET_OK != + TALER_TESTING_get_trait_denom_pub (coin_cmd, + 0, + &denom_pub)) ) + { GNUNET_break (0); TALER_TESTING_interpreter_fail (is); @@ -179,7 +199,7 @@ refund_run (void *cls, } GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv, - &coin.eddsa_pub); + &rs->coin.eddsa_pub); if (GNUNET_OK != TALER_TESTING_get_trait_merchant_priv (coin_cmd, &merchant_priv)) @@ -188,19 +208,67 @@ refund_run (void *cls, TALER_TESTING_interpreter_fail (is); return; } - rs->rh = TALER_EXCHANGE_refund (rs->exchange, - &refund_amount, - &h_contract_terms, - &coin, - rs->refund_transaction_id, - merchant_priv, - &refund_cb, - rs); + rs->che.type = TALER_EXCHANGE_CTT_REFUND; + rs->che.details.refund.h_contract_terms = h_contract_terms; + GNUNET_CRYPTO_eddsa_key_get_public ( + &merchant_priv->eddsa_priv, + &rs->che.details.refund.merchant_pub.eddsa_pub); + rs->che.details.refund.refund_fee = denom_pub->fees.refund; + rs->che.details.refund.sig_amount = refund_amount; + rs->che.details.refund.rtransaction_id = rs->refund_transaction_id; + TALER_merchant_refund_sign (&rs->coin, + &h_contract_terms, + rs->refund_transaction_id, + &refund_amount, + merchant_priv, + &rs->che.details.refund.sig); + rs->rh = TALER_EXCHANGE_refund ( + TALER_TESTING_interpreter_get_context (is), + TALER_TESTING_get_exchange_url (is), + TALER_TESTING_get_keys (is), + &refund_amount, + &h_contract_terms, + &rs->coin, + rs->refund_transaction_id, + merchant_priv, + &refund_cb, + rs); GNUNET_assert (NULL != rs->rh); } /** + * Offer internal data from a "refund" CMD, to other commands. + * + * @param cls closure. + * @param[out] ret result. + * @param trait name of the trait. + * @param index index number of the object to offer. + * @return #GNUNET_OK on success. + */ +static enum GNUNET_GenericReturnValue +refund_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + struct RefundState *rs = cls; + struct TALER_TESTING_Trait traits[] = { + TALER_TESTING_make_trait_coin_history (0, + &rs->che), + TALER_TESTING_make_trait_coin_pub (0, + &rs->coin), + TALER_TESTING_trait_end () + }; + + return TALER_TESTING_get_trait (traits, + ret, + trait, + index); +} + + +/** * Free the state from a "refund" CMD, and possibly cancel * a pending operation thereof. * @@ -215,10 +283,8 @@ refund_cleanup (void *cls, if (NULL != rs->rh) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - rs->is->ip, - cmd->label); + TALER_TESTING_command_incomplete (rs->is, + cmd->label); TALER_EXCHANGE_refund_cancel (rs->rh); rs->rh = NULL; } @@ -243,7 +309,8 @@ TALER_TESTING_cmd_refund (const char *label, .cls = rs, .label = label, .run = &refund_run, - .cleanup = &refund_cleanup + .cleanup = &refund_cleanup, + .traits = &refund_traits }; return cmd; @@ -271,7 +338,8 @@ TALER_TESTING_cmd_refund_with_id ( .cls = rs, .label = label, .run = &refund_run, - .cleanup = &refund_cleanup + .cleanup = &refund_cleanup, + .traits = &refund_traits }; return cmd; diff --git a/src/testing/testing_api_cmd_reserve_attest.c b/src/testing/testing_api_cmd_reserve_attest.c new file mode 100644 index 000000000..cf4b3a0c2 --- /dev/null +++ b/src/testing/testing_api_cmd_reserve_attest.c @@ -0,0 +1,263 @@ +/* + This file is part of TALER + Copyright (C) 2014-2022 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/testing_api_cmd_reserve_attest.c + * @brief Implement the /reserve/$RID/attest test command. + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_json_lib.h" +#include <gnunet/gnunet_curl_lib.h> +#include "taler_testing_lib.h" + +/** + * State for a "attest" CMD. + */ +struct AttestState +{ + /** + * Label to the command which created the reserve to check, + * needed to resort the reserve key. + */ + const char *reserve_reference; + + /** + * Handle to the "reserve attest" operation. + */ + struct TALER_EXCHANGE_ReservesAttestHandle *rsh; + + /** + * Private key of the reserve being analyzed. + */ + const struct TALER_ReservePrivateKeyP *reserve_priv; + + /** + * Public key of the reserve being analyzed. + */ + struct TALER_ReservePublicKeyP reserve_pub; + + /** + * Array of attributes to request, of length @e attrs_len. + */ + const char **attrs; + + /** + * Length of the @e attrs array. + */ + unsigned int attrs_len; + + /** + * Expected HTTP response code. + */ + unsigned int expected_response_code; + + /** + * Interpreter state. + */ + struct TALER_TESTING_Interpreter *is; + + /* TODO: expose fields below as traits... */ + + /** + * Attested attributes returned by the exchange. + */ + json_t *attributes; + + /** + * Expiration time of the attested attributes. + */ + struct GNUNET_TIME_Timestamp expiration_time; + + /** + * Signature by the exchange affirming the attributes. + */ + struct TALER_ExchangeSignatureP exchange_sig; + + /** + * Online signing key used by the exchange. + */ + struct TALER_ExchangePublicKeyP exchange_pub; +}; + + +/** + * Check that the reserve balance and HTTP response code are + * both acceptable. + * + * @param cls closure. + * @param rs HTTP response details + */ +static void +reserve_attest_cb ( + void *cls, + const struct TALER_EXCHANGE_ReservePostAttestResult *rs) +{ + struct AttestState *ss = cls; + struct TALER_TESTING_Interpreter *is = ss->is; + + ss->rsh = NULL; + if (ss->expected_response_code != rs->hr.http_status) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected HTTP response code: %d in %s:%u\n", + rs->hr.http_status, + __FILE__, + __LINE__); + json_dumpf (rs->hr.reply, + stderr, + JSON_INDENT (2)); + TALER_TESTING_interpreter_fail (ss->is); + return; + } + if (MHD_HTTP_OK != rs->hr.http_status) + { + TALER_TESTING_interpreter_next (is); + return; + } + ss->attributes = json_incref ((json_t*) rs->details.ok.attributes); + ss->expiration_time = rs->details.ok.expiration_time; + ss->exchange_pub = rs->details.ok.exchange_pub; + ss->exchange_sig = rs->details.ok.exchange_sig; + TALER_TESTING_interpreter_next (is); +} + + +/** + * Run the command. + * + * @param cls closure. + * @param cmd the command being executed. + * @param is the interpreter state. + */ +static void +attest_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct AttestState *ss = cls; + const struct TALER_TESTING_Command *create_reserve; + const char *exchange_url; + + ss->is = is; + exchange_url = TALER_TESTING_get_exchange_url (is); + if (NULL == exchange_url) + { + GNUNET_break (0); + return; + } + create_reserve + = TALER_TESTING_interpreter_lookup_command (is, + ss->reserve_reference); + + if (NULL == create_reserve) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + if (GNUNET_OK != + TALER_TESTING_get_trait_reserve_priv (create_reserve, + &ss->reserve_priv)) + { + GNUNET_break (0); + TALER_LOG_ERROR ("Failed to find reserve_priv for attest query\n"); + TALER_TESTING_interpreter_fail (is); + return; + } + GNUNET_CRYPTO_eddsa_key_get_public (&ss->reserve_priv->eddsa_priv, + &ss->reserve_pub.eddsa_pub); + ss->rsh = TALER_EXCHANGE_reserves_attest ( + TALER_TESTING_interpreter_get_context (is), + exchange_url, + TALER_TESTING_get_keys (is), + ss->reserve_priv, + ss->attrs_len, + ss->attrs, + &reserve_attest_cb, + ss); +} + + +/** + * Cleanup the state from a "reserve attest" CMD, and possibly + * cancel a pending operation thereof. + * + * @param cls closure. + * @param cmd the command which is being cleaned up. + */ +static void +attest_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct AttestState *ss = cls; + + if (NULL != ss->rsh) + { + TALER_TESTING_command_incomplete (ss->is, + cmd->label); + TALER_EXCHANGE_reserves_attest_cancel (ss->rsh); + ss->rsh = NULL; + } + json_decref (ss->attributes); + GNUNET_free (ss->attrs); + GNUNET_free (ss); +} + + +struct TALER_TESTING_Command +TALER_TESTING_cmd_reserve_attest (const char *label, + const char *reserve_reference, + unsigned int expected_response_code, + ...) +{ + struct AttestState *ss; + unsigned int num_args; + const char *ea; + va_list ap; + + num_args = 0; + va_start (ap, expected_response_code); + while (NULL != va_arg (ap, const char *)) + num_args++; + va_end (ap); + + GNUNET_assert (NULL != reserve_reference); + ss = GNUNET_new (struct AttestState); + ss->reserve_reference = reserve_reference; + ss->expected_response_code = expected_response_code; + ss->attrs_len = num_args; + ss->attrs = GNUNET_new_array (num_args, + const char *); + num_args = 0; + va_start (ap, expected_response_code); + while (NULL != (ea = va_arg (ap, const char *))) + ss->attrs[num_args++] = ea; + va_end (ap); + + { + struct TALER_TESTING_Command cmd = { + .cls = ss, + .label = label, + .run = &attest_run, + .cleanup = &attest_cleanup + }; + + return cmd; + } +} diff --git a/src/testing/testing_api_cmd_reserve_close.c b/src/testing/testing_api_cmd_reserve_close.c new file mode 100644 index 000000000..8e272f547 --- /dev/null +++ b/src/testing/testing_api_cmd_reserve_close.c @@ -0,0 +1,260 @@ +/* + This file is part of TALER + Copyright (C) 2014-2022 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/testing_api_cmd_reserve_close.c + * @brief Implement the /reserve/$RID/close test command. + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_json_lib.h" +#include <gnunet/gnunet_curl_lib.h> +#include "taler_testing_lib.h" + + +/** + * State for a "close" CMD. + */ +struct CloseState +{ + /** + * Label to the command which created the reserve to check, + * needed to resort the reserve key. + */ + const char *reserve_reference; + + /** + * Handle to the "reserve close" operation. + */ + struct TALER_EXCHANGE_ReservesCloseHandle *rsh; + + /** + * payto://-URI where to wire the funds. + */ + const char *target_account; + + /** + * Private key of the reserve being analyzed. + */ + const struct TALER_ReservePrivateKeyP *reserve_priv; + + /** + * Public key of the reserve being analyzed. + */ + struct TALER_ReservePublicKeyP reserve_pub; + + /** + * Expected HTTP response code. + */ + unsigned int expected_response_code; + + /** + * Interpreter state. + */ + struct TALER_TESTING_Interpreter *is; + + /** + * Set to the KYC requirement payto hash *if* the exchange replied with a + * request for KYC. + */ + struct TALER_PaytoHashP h_payto; + + /** + * Set to the KYC requirement row *if* the exchange replied with + * a request for KYC. + */ + uint64_t requirement_row; +}; + + +/** + * Check that the reserve balance and HTTP response code are + * both acceptable. + * + * @param cls closure. + * @param rs HTTP response details + */ +static void +reserve_close_cb (void *cls, + const struct TALER_EXCHANGE_ReserveCloseResult *rs) +{ + struct CloseState *ss = cls; + struct TALER_TESTING_Interpreter *is = ss->is; + + ss->rsh = NULL; + if (ss->expected_response_code != rs->hr.http_status) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected HTTP response code: %d in %s:%u\n", + rs->hr.http_status, + __FILE__, + __LINE__); + json_dumpf (rs->hr.reply, + stderr, + JSON_INDENT (2)); + TALER_TESTING_interpreter_fail (ss->is); + return; + } + switch (rs->hr.http_status) + { + case MHD_HTTP_OK: + break; + case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS: + /* nothing to check */ + ss->requirement_row + = rs->details.unavailable_for_legal_reasons.requirement_row; + ss->h_payto + = rs->details.unavailable_for_legal_reasons.h_payto; + break; + default: + break; + } + TALER_TESTING_interpreter_next (is); +} + + +/** + * Run the command. + * + * @param cls closure. + * @param cmd the command being executed. + * @param is the interpreter state. + */ +static void +close_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct CloseState *ss = cls; + const struct TALER_TESTING_Command *create_reserve; + + ss->is = is; + create_reserve + = TALER_TESTING_interpreter_lookup_command (is, + ss->reserve_reference); + + if (NULL == create_reserve) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + if (GNUNET_OK != + TALER_TESTING_get_trait_reserve_priv (create_reserve, + &ss->reserve_priv)) + { + GNUNET_break (0); + TALER_LOG_ERROR ("Failed to find reserve_priv for close query\n"); + TALER_TESTING_interpreter_fail (is); + return; + } + GNUNET_CRYPTO_eddsa_key_get_public (&ss->reserve_priv->eddsa_priv, + &ss->reserve_pub.eddsa_pub); + ss->rsh = TALER_EXCHANGE_reserves_close ( + TALER_TESTING_interpreter_get_context (is), + TALER_TESTING_get_exchange_url (is), + ss->reserve_priv, + ss->target_account, + &reserve_close_cb, + ss); +} + + +/** + * Cleanup the state from a "reserve close" CMD, and possibly + * cancel a pending operation thereof. + * + * @param cls closure. + * @param cmd the command which is being cleaned up. + */ +static void +close_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct CloseState *ss = cls; + + if (NULL != ss->rsh) + { + TALER_TESTING_command_incomplete (ss->is, + cmd->label); + TALER_EXCHANGE_reserves_close_cancel (ss->rsh); + ss->rsh = NULL; + } + GNUNET_free (ss); +} + + +/** + * Offer internal data to a "close" CMD state to other + * commands. + * + * @param cls closure + * @param[out] ret result (could be anything) + * @param trait name of the trait + * @param index index number of the object to offer. + * @return #GNUNET_OK on success + */ +static enum GNUNET_GenericReturnValue +close_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + struct CloseState *cs = cls; + struct TALER_TESTING_Trait traits[] = { + TALER_TESTING_make_trait_legi_requirement_row ( + &cs->requirement_row), + TALER_TESTING_make_trait_h_payto ( + &cs->h_payto), + TALER_TESTING_trait_end () + }; + + if (cs->expected_response_code != MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS) + return GNUNET_NO; + return TALER_TESTING_get_trait (traits, + ret, + trait, + index); +} + + +struct TALER_TESTING_Command +TALER_TESTING_cmd_reserve_close (const char *label, + const char *reserve_reference, + const char *target_account, + unsigned int expected_response_code) +{ + struct CloseState *ss; + + GNUNET_assert (NULL != reserve_reference); + ss = GNUNET_new (struct CloseState); + ss->reserve_reference = reserve_reference; + ss->target_account = target_account; + ss->expected_response_code = expected_response_code; + { + struct TALER_TESTING_Command cmd = { + .cls = ss, + .label = label, + .run = &close_run, + .cleanup = &close_cleanup, + .traits = &close_traits + }; + + return cmd; + } +} diff --git a/src/testing/testing_api_cmd_reserve_get.c b/src/testing/testing_api_cmd_reserve_get.c index f9b8ff6cd..9a938cf82 100644 --- a/src/testing/testing_api_cmd_reserve_get.c +++ b/src/testing/testing_api_cmd_reserve_get.c @@ -178,18 +178,19 @@ status_run (void *cls, { struct StatusState *ss = cls; const struct TALER_TESTING_Command *create_reserve; + const char *exchange_url; ss->is = is; - create_reserve - = TALER_TESTING_interpreter_lookup_command (is, - ss->reserve_reference); - - if (NULL == create_reserve) + exchange_url = TALER_TESTING_get_exchange_url (is); + if (NULL == exchange_url) { GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); return; } + create_reserve + = TALER_TESTING_interpreter_lookup_command (is, + ss->reserve_reference); + GNUNET_assert (NULL != create_reserve); if (GNUNET_OK != TALER_TESTING_get_trait_reserve_pub (create_reserve, &ss->reserve_pubp)) @@ -199,11 +200,13 @@ status_run (void *cls, TALER_TESTING_interpreter_fail (is); return; } - ss->rsh = TALER_EXCHANGE_reserves_get (is->exchange, - ss->reserve_pubp, - ss->timeout, - &reserve_status_cb, - ss); + ss->rsh = TALER_EXCHANGE_reserves_get ( + TALER_TESTING_interpreter_get_context (is), + exchange_url, + ss->reserve_pubp, + ss->timeout, + &reserve_status_cb, + ss); if (! GNUNET_TIME_relative_is_zero (ss->timeout)) { TALER_TESTING_interpreter_next (is); @@ -227,10 +230,8 @@ status_cleanup (void *cls, if (NULL != ss->rsh) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - ss->is->ip, - cmd->label); + TALER_TESTING_command_incomplete (ss->is, + cmd->label); TALER_EXCHANGE_reserves_get_cancel (ss->rsh); ss->rsh = NULL; } @@ -328,6 +329,7 @@ finish_run (void *cls, poll_reserve = TALER_TESTING_interpreter_lookup_command (is, ps->poll_reference); + GNUNET_assert (NULL != poll_reserve); GNUNET_assert (poll_reserve->run == &status_run); ss = poll_reserve->cls; if (NULL == ss->rsh) diff --git a/src/testing/testing_api_cmd_reserve_get_attestable.c b/src/testing/testing_api_cmd_reserve_get_attestable.c new file mode 100644 index 000000000..ed1eb1355 --- /dev/null +++ b/src/testing/testing_api_cmd_reserve_get_attestable.c @@ -0,0 +1,242 @@ +/* + This file is part of TALER + Copyright (C) 2014-2022 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/testing_api_cmd_reserve_get_attestable.c + * @brief Implement the /reserve/$RID/get_attestable test command. + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_json_lib.h" +#include <gnunet/gnunet_curl_lib.h> +#include "taler_testing_lib.h" + + +/** + * State for a "get_attestable" CMD. + */ +struct GetAttestableState +{ + /** + * Label to the command which created the reserve to check, + * needed to resort the reserve key. + */ + const char *reserve_reference; + + /** + * Handle to the "reserve get_attestable" operation. + */ + struct TALER_EXCHANGE_ReservesGetAttestHandle *rgah; + + /** + * Expected attestable attributes. + */ + const char **expected_attestables; + + /** + * Length of the @e expected_attestables array. + */ + unsigned int expected_attestables_length; + + /** + * Public key of the reserve being analyzed. + */ + struct TALER_ReservePublicKeyP reserve_pub; + + /** + * Expected HTTP response code. + */ + unsigned int expected_response_code; + + /** + * Interpreter state. + */ + struct TALER_TESTING_Interpreter *is; +}; + + +/** + * Check that the reserve balance and HTTP response code are + * both acceptable. + * + * @param cls closure. + * @param rs HTTP response details + */ +static void +reserve_get_attestable_cb ( + void *cls, + const struct TALER_EXCHANGE_ReserveGetAttestResult *rs) +{ + struct GetAttestableState *ss = cls; + struct TALER_TESTING_Interpreter *is = ss->is; + + ss->rgah = NULL; + if (ss->expected_response_code != rs->hr.http_status) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected HTTP response code: %d in %s:%u\n", + rs->hr.http_status, + __FILE__, + __LINE__); + json_dumpf (rs->hr.reply, + stderr, + JSON_INDENT (2)); + TALER_TESTING_interpreter_fail (ss->is); + return; + } + if (MHD_HTTP_OK != rs->hr.http_status) + { + TALER_TESTING_interpreter_next (is); + return; + } + // FIXME: check returned list matches expectations! + TALER_TESTING_interpreter_next (is); +} + + +/** + * Run the command. + * + * @param cls closure. + * @param cmd the command being executed. + * @param is the interpreter state. + */ +static void +get_attestable_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct GetAttestableState *ss = cls; + const struct TALER_TESTING_Command *ref_reserve; + const struct TALER_ReservePrivateKeyP *reserve_priv; + const struct TALER_ReservePublicKeyP *reserve_pub; + const char *exchange_url; + + ss->is = is; + exchange_url = TALER_TESTING_get_exchange_url (is); + if (NULL == exchange_url) + { + GNUNET_break (0); + return; + } + ref_reserve + = TALER_TESTING_interpreter_lookup_command (is, + ss->reserve_reference); + + if (NULL == ref_reserve) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + if (GNUNET_OK == + TALER_TESTING_get_trait_reserve_priv (ref_reserve, + &reserve_priv)) + { + GNUNET_CRYPTO_eddsa_key_get_public (&reserve_priv->eddsa_priv, + &ss->reserve_pub.eddsa_pub); + } + else + { + if (GNUNET_OK != + TALER_TESTING_get_trait_reserve_pub (ref_reserve, + &reserve_pub)) + { + GNUNET_break (0); + TALER_LOG_ERROR ( + "Failed to find reserve_priv for get_attestable query\n"); + TALER_TESTING_interpreter_fail (is); + return; + } + ss->reserve_pub = *reserve_pub; + } + ss->rgah = TALER_EXCHANGE_reserves_get_attestable ( + TALER_TESTING_interpreter_get_context (is), + exchange_url, + &ss->reserve_pub, + &reserve_get_attestable_cb, + ss); +} + + +/** + * Cleanup the state from a "reserve get_attestable" CMD, and possibly + * cancel a pending operation thereof. + * + * @param cls closure. + * @param cmd the command which is being cleaned up. + */ +static void +get_attestable_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct GetAttestableState *ss = cls; + + if (NULL != ss->rgah) + { + TALER_TESTING_command_incomplete (ss->is, + cmd->label); + TALER_EXCHANGE_reserves_get_attestable_cancel (ss->rgah); + ss->rgah = NULL; + } + GNUNET_free (ss->expected_attestables); + GNUNET_free (ss); +} + + +struct TALER_TESTING_Command +TALER_TESTING_cmd_reserve_get_attestable (const char *label, + const char *reserve_reference, + unsigned int expected_response_code, + ...) +{ + struct GetAttestableState *ss; + va_list ap; + unsigned int num_expected; + const char *ea; + + num_expected = 0; + va_start (ap, expected_response_code); + while (NULL != va_arg (ap, const char *)) + num_expected++; + va_end (ap); + + GNUNET_assert (NULL != reserve_reference); + ss = GNUNET_new (struct GetAttestableState); + ss->reserve_reference = reserve_reference; + ss->expected_response_code = expected_response_code; + ss->expected_attestables_length = num_expected; + ss->expected_attestables = GNUNET_new_array (num_expected, + const char *); + num_expected = 0; + va_start (ap, expected_response_code); + while (NULL != (ea = va_arg (ap, const char *))) + ss->expected_attestables[num_expected++] = ea; + va_end (ap); + + { + struct TALER_TESTING_Command cmd = { + .cls = ss, + .label = label, + .run = &get_attestable_run, + .cleanup = &get_attestable_cleanup + }; + + return cmd; + } +} diff --git a/src/testing/testing_api_cmd_reserve_history.c b/src/testing/testing_api_cmd_reserve_history.c index beba23f11..ecb236a54 100644 --- a/src/testing/testing_api_cmd_reserve_history.c +++ b/src/testing/testing_api_cmd_reserve_history.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014-2022 Taler Systems SA + Copyright (C) 2014-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 @@ -65,42 +65,223 @@ struct HistoryState struct TALER_TESTING_Interpreter *is; /** - * Reserve history entry that corresponds to this operation. - * Will be of type #TALER_EXCHANGE_RTT_HISTORY. + * Expected HTTP response code. + */ + unsigned int expected_response_code; + +}; + + +/** + * Closure for analysis_cb(). + */ +struct AnalysisContext +{ + /** + * Reserve public key we are looking at. */ - struct TALER_EXCHANGE_ReserveHistoryEntry reserve_history; + const struct TALER_ReservePublicKeyP *reserve_pub; /** - * Expected HTTP response code. + * Length of the @e history array. */ - unsigned int expected_response_code; + unsigned int history_length; + /** + * Array of history items to match. + */ + const struct TALER_EXCHANGE_ReserveHistoryEntry *history; + + /** + * Array of @e history_length of matched entries. + */ + bool *found; + + /** + * Set to true if an entry could not be found. + */ + bool failure; }; /** + * Compare @a h1 and @a h2. + * + * @param h1 a history entry + * @param h2 a history entry + * @return 0 if @a h1 and @a h2 are equal + */ +static int +history_entry_cmp ( + const struct TALER_EXCHANGE_ReserveHistoryEntry *h1, + const struct TALER_EXCHANGE_ReserveHistoryEntry *h2) +{ + if (h1->type != h2->type) + return 1; + switch (h1->type) + { + case TALER_EXCHANGE_RTT_CREDIT: + if ( (0 == + TALER_amount_cmp (&h1->amount, + &h2->amount)) && + (0 == strcasecmp (h1->details.in_details.sender_url, + h2->details.in_details.sender_url)) && + (h1->details.in_details.wire_reference == + h2->details.in_details.wire_reference) && + (GNUNET_TIME_timestamp_cmp (h1->details.in_details.timestamp, + ==, + h2->details.in_details.timestamp)) ) + return 0; + return 1; + case TALER_EXCHANGE_RTT_WITHDRAWAL: + if ( (0 == + TALER_amount_cmp (&h1->amount, + &h2->amount)) && + (0 == + TALER_amount_cmp (&h1->details.withdraw.fee, + &h2->details.withdraw.fee)) ) + /* testing_api_cmd_withdraw doesn't set the out_authorization_sig, + so we cannot test for it here. but if the amount matches, + that should be good enough. */ + return 0; + return 1; + case TALER_EXCHANGE_RTT_AGEWITHDRAWAL: + /* testing_api_cmd_age_withdraw doesn't set the out_authorization_sig, + so we cannot test for it here. but if the amount matches, + that should be good enough. */ + if ( (0 == + TALER_amount_cmp (&h1->amount, + &h2->amount)) && + (0 == + TALER_amount_cmp (&h1->details.age_withdraw.fee, + &h2->details.age_withdraw.fee)) && + (h1->details.age_withdraw.max_age == + h2->details.age_withdraw.max_age)) + return 0; + return 1; + case TALER_EXCHANGE_RTT_RECOUP: + /* exchange_sig, exchange_pub and timestamp are NOT available + from the original recoup response, hence here NOT check(able/ed) */ + if ( (0 == + TALER_amount_cmp (&h1->amount, + &h2->amount)) && + (0 == + GNUNET_memcmp (&h1->details.recoup_details.coin_pub, + &h2->details.recoup_details.coin_pub)) ) + return 0; + return 1; + case TALER_EXCHANGE_RTT_CLOSING: + /* testing_api_cmd_exec_closer doesn't set the + receiver_account_details, exchange_sig, exchange_pub or wtid or timestamp + so we cannot test for it here. but if the amount matches, + that should be good enough. */ + if ( (0 == + TALER_amount_cmp (&h1->amount, + &h2->amount)) && + (0 == + TALER_amount_cmp (&h1->details.close_details.fee, + &h2->details.close_details.fee)) ) + return 0; + return 1; + case TALER_EXCHANGE_RTT_MERGE: + if ( (0 == + TALER_amount_cmp (&h1->amount, + &h2->amount)) && + (0 == + TALER_amount_cmp (&h1->details.merge_details.purse_fee, + &h2->details.merge_details.purse_fee)) && + (GNUNET_TIME_timestamp_cmp (h1->details.merge_details.merge_timestamp, + ==, + h2->details.merge_details.merge_timestamp)) + && + (GNUNET_TIME_timestamp_cmp (h1->details.merge_details.purse_expiration, + ==, + h2->details.merge_details.purse_expiration)) + && + (0 == + GNUNET_memcmp (&h1->details.merge_details.merge_pub, + &h2->details.merge_details.merge_pub)) && + (0 == + GNUNET_memcmp (&h1->details.merge_details.h_contract_terms, + &h2->details.merge_details.h_contract_terms)) && + (0 == + GNUNET_memcmp (&h1->details.merge_details.purse_pub, + &h2->details.merge_details.purse_pub)) && + (0 == + GNUNET_memcmp (&h1->details.merge_details.reserve_sig, + &h2->details.merge_details.reserve_sig)) && + (h1->details.merge_details.min_age == + h2->details.merge_details.min_age) && + (h1->details.merge_details.flags == + h2->details.merge_details.flags) ) + return 0; + return 1; + case TALER_EXCHANGE_RTT_OPEN: + if ( (0 == + TALER_amount_cmp (&h1->amount, + &h2->amount)) && + (GNUNET_TIME_timestamp_cmp ( + h1->details.open_request.request_timestamp, + ==, + h2->details.open_request.request_timestamp)) && + (GNUNET_TIME_timestamp_cmp ( + h1->details.open_request.reserve_expiration, + ==, + h2->details.open_request.reserve_expiration)) && + (h1->details.open_request.purse_limit == + h2->details.open_request.purse_limit) && + (0 == + TALER_amount_cmp (&h1->details.open_request.reserve_payment, + &h2->details.open_request.reserve_payment)) && + (0 == + GNUNET_memcmp (&h1->details.open_request.reserve_sig, + &h2->details.open_request.reserve_sig)) ) + return 0; + return 1; + case TALER_EXCHANGE_RTT_CLOSE: + if ( (0 == + TALER_amount_cmp (&h1->amount, + &h2->amount)) && + (GNUNET_TIME_timestamp_cmp ( + h1->details.close_request.request_timestamp, + ==, + h2->details.close_request.request_timestamp)) && + (0 == + GNUNET_memcmp (&h1->details.close_request.target_account_h_payto, + &h2->details.close_request.target_account_h_payto)) && + (0 == + GNUNET_memcmp (&h1->details.close_request.reserve_sig, + &h2->details.close_request.reserve_sig)) ) + return 0; + return 1; + } + GNUNET_assert (0); + return 1; +} + + +/** * Check if @a cmd changed the reserve, if so, find the - * entry in @a history and set the respective index in @a found - * to #GNUNET_YES. If the entry is not found, return #GNUNET_SYSERR. + * entry in our history and set the respective index in found + * to true. If the entry is not found, set failure. * - * @param reserve_pub public key of the reserve for which we have the @a history + * @param cls our `struct AnalysisContext *` * @param cmd command to analyze for impact on history - * @param history_length number of entries in @a history and @a found - * @param history history to check - * @param[in,out] found array to update - * @return #GNUNET_OK if @a cmd action on reserve was found in @a history */ -static enum GNUNET_GenericReturnValue -analyze_command (const struct TALER_ReservePublicKeyP *reserve_pub, - const struct TALER_TESTING_Command *cmd, - unsigned int history_length, - const struct TALER_EXCHANGE_ReserveHistoryEntry *history, - bool *found) +static void +analyze_command (void *cls, + const struct TALER_TESTING_Command *cmd) { + struct AnalysisContext *ac = cls; + const struct TALER_ReservePublicKeyP *reserve_pub = ac->reserve_pub; + const struct TALER_EXCHANGE_ReserveHistoryEntry *history = ac->history; + unsigned int history_length = ac->history_length; + bool *found = ac->found; + if (TALER_TESTING_cmd_is_batch (cmd)) { struct TALER_TESTING_Command *cur; - struct TALER_TESTING_Command **bcmd; + struct TALER_TESTING_Command *bcmd; cur = TALER_TESTING_cmd_batch_get_current (cmd); if (GNUNET_OK != @@ -108,28 +289,26 @@ analyze_command (const struct TALER_ReservePublicKeyP *reserve_pub, &bcmd)) { GNUNET_break (0); - return GNUNET_SYSERR; + ac->failure = true; + return; } - for (unsigned int i = 0; NULL != (*bcmd)[i].label; i++) + for (unsigned int i = 0; NULL != bcmd[i].label; i++) { - struct TALER_TESTING_Command *step = &(*bcmd)[i]; + struct TALER_TESTING_Command *step = &bcmd[i]; - if (GNUNET_OK != - analyze_command (reserve_pub, - step, - history_length, - history, - found)) + analyze_command (ac, + step); + if (ac->failure) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Entry for batch step `%s' missing in history\n", step->label); - return GNUNET_SYSERR; + return; } if (step == cur) break; /* if *we* are in a batch, make sure not to analyze commands past 'now' */ } - return GNUNET_OK; + return; } { @@ -138,11 +317,11 @@ analyze_command (const struct TALER_ReservePublicKeyP *reserve_pub, if (GNUNET_OK != TALER_TESTING_get_trait_reserve_pub (cmd, &rp)) - return GNUNET_OK; /* command does nothing for reserves */ + return; /* command does nothing for reserves */ if (0 != GNUNET_memcmp (rp, reserve_pub)) - return GNUNET_OK; /* command affects some _other_ reserve */ + return; /* command affects some _other_ reserve */ for (unsigned int j = 0; true; j++) { const struct TALER_EXCHANGE_ReserveHistoryEntry *he; @@ -156,17 +335,17 @@ analyze_command (const struct TALER_ReservePublicKeyP *reserve_pub, /* NOTE: only for debugging... */ if (0 == j) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Command `%s' has the reserve_pub trait, but does not reserve history trait\n", + "Command `%s' has the reserve_pub, but lacks reserve history trait\n", cmd->label); - return GNUNET_OK; /* command does nothing for reserves */ + return; /* command does nothing for reserves */ } for (unsigned int i = 0; i<history_length; i++) { if (found[i]) continue; /* already found, skip */ if (0 == - TALER_TESTING_history_entry_cmp (he, - &history[i])) + history_entry_cmp (he, + &history[i])) { found[i] = true; matched = true; @@ -179,7 +358,8 @@ analyze_command (const struct TALER_ReservePublicKeyP *reserve_pub, "Command `%s' reserve history entry #%u not found\n", cmd->label, j); - return GNUNET_SYSERR; + ac->failure = true; + return; } } } @@ -202,21 +382,6 @@ reserve_history_cb (void *cls, struct TALER_Amount eb; ss->rsh = NULL; - if (MHD_HTTP_OK == rs->hr.http_status) - { - const struct TALER_EXCHANGE_Keys *keys; - const struct TALER_EXCHANGE_GlobalFee *gf; - - ss->reserve_history.type = TALER_EXCHANGE_RTT_HISTORY; - keys = TALER_EXCHANGE_get_keys (ss->is->exchange); - GNUNET_assert (NULL != keys); - gf = TALER_EXCHANGE_get_global_fee (keys, - rs->ts); - GNUNET_assert (NULL != gf); - ss->reserve_history.amount = gf->fees.history; - ss->reserve_history.details.history_details.request_timestamp = rs->ts; - ss->reserve_history.details.history_details.reserve_sig = *rs->reserve_sig; - } if (ss->expected_response_code != rs->hr.http_status) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, @@ -254,44 +419,42 @@ reserve_history_cb (void *cls, } { bool found[rs->details.ok.history_len]; + struct AnalysisContext ac = { + .reserve_pub = &ss->reserve_pub, + .history = rs->details.ok.history, + .history_length = rs->details.ok.history_len, + .found = found + }; memset (found, 0, sizeof (found)); - for (unsigned int i = 0; i<= (unsigned int) is->ip; i++) + TALER_TESTING_iterate (is, + true, + &analyze_command, + &ac); + if (ac.failure) { - struct TALER_TESTING_Command *cmd = &is->commands[i]; - - if (GNUNET_OK != - analyze_command (&ss->reserve_pub, - cmd, - rs->details.ok.history_len, - rs->details.ok.history, - found)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Entry for command `%s' missing in history\n", - cmd->label); - json_dumpf (rs->hr.reply, - stderr, - JSON_INDENT (2)); - TALER_TESTING_interpreter_fail (ss->is); - return; - } + json_dumpf (rs->hr.reply, + stderr, + JSON_INDENT (2)); + TALER_TESTING_interpreter_fail (ss->is); + return; } for (unsigned int i = 0; i<rs->details.ok.history_len; i++) - if (! found[i]) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "History entry at index %u of type %d not justified by command history\n", - i, - rs->details.ok.history[i].type); - json_dumpf (rs->hr.reply, - stderr, - JSON_INDENT (2)); - TALER_TESTING_interpreter_fail (ss->is); - return; - } + { + if (found[i]) + continue; + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "History entry at index %u of type %d not justified by command history\n", + i, + rs->details.ok.history[i].type); + json_dumpf (rs->hr.reply, + stderr, + JSON_INDENT (2)); + TALER_TESTING_interpreter_fail (ss->is); + return; + } } TALER_TESTING_interpreter_next (is); } @@ -333,10 +496,14 @@ history_run (void *cls, } GNUNET_CRYPTO_eddsa_key_get_public (&ss->reserve_priv->eddsa_priv, &ss->reserve_pub.eddsa_pub); - ss->rsh = TALER_EXCHANGE_reserves_history (is->exchange, - ss->reserve_priv, - &reserve_history_cb, - ss); + ss->rsh = TALER_EXCHANGE_reserves_history ( + TALER_TESTING_interpreter_get_context (is), + TALER_TESTING_get_exchange_url (is), + TALER_TESTING_get_keys (is), + ss->reserve_priv, + 0, + &reserve_history_cb, + ss); } @@ -357,16 +524,11 @@ history_traits (void *cls, { struct HistoryState *hs = cls; struct TALER_TESTING_Trait traits[] = { - /* history entry MUST be first due to response code logic below! */ - TALER_TESTING_make_trait_reserve_history (0, - &hs->reserve_history), TALER_TESTING_make_trait_reserve_pub (&hs->reserve_pub), TALER_TESTING_trait_end () }; - return TALER_TESTING_get_trait ((hs->expected_response_code == MHD_HTTP_OK) - ? &traits[0] /* we have reserve history */ - : &traits[1], /* skip reserve history */ + return TALER_TESTING_get_trait (traits, ret, trait, index); @@ -388,10 +550,8 @@ history_cleanup (void *cls, if (NULL != ss->rsh) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - ss->is->ip, - cmd->label); + TALER_TESTING_command_incomplete (ss->is, + cmd->label); TALER_EXCHANGE_reserves_history_cancel (ss->rsh); ss->rsh = NULL; } diff --git a/src/testing/testing_api_cmd_reserve_open.c b/src/testing/testing_api_cmd_reserve_open.c new file mode 100644 index 000000000..189d06b26 --- /dev/null +++ b/src/testing/testing_api_cmd_reserve_open.c @@ -0,0 +1,349 @@ +/* + This file is part of TALER + Copyright (C) 2014-2022 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/testing_api_cmd_reserve_open.c + * @brief Implement the /reserve/$RID/open test command. + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_json_lib.h" +#include <gnunet/gnunet_curl_lib.h> +#include "taler_testing_lib.h" + + +/** + * Information we track per coin used to pay for opening the + * reserve. + */ +struct CoinDetail +{ + /** + * Name of the command and index of the coin to use. + */ + const char *name; + + /** + * Amount to charge to this coin. + */ + struct TALER_Amount amount; +}; + + +/** + * State for a "open" CMD. + */ +struct OpenState +{ + /** + * Label to the command which created the reserve to check, + * needed to resort the reserve key. + */ + const char *reserve_reference; + + /** + * Requested expiration time. + */ + struct GNUNET_TIME_Relative req_expiration_time; + + /** + * Requested minimum number of purses. + */ + uint32_t min_purses; + + /** + * Amount to pay for the opening from the reserve balance. + */ + struct TALER_Amount reserve_pay; + + /** + * Handle to the "reserve open" operation. + */ + struct TALER_EXCHANGE_ReservesOpenHandle *rsh; + + /** + * Expected reserve balance. + */ + const char *expected_balance; + + /** + * Length of the @e cd array. + */ + unsigned int cpl; + + /** + * Coin details, array of length @e cpl. + */ + struct CoinDetail *cd; + + /** + * Private key of the reserve being analyzed. + */ + const struct TALER_ReservePrivateKeyP *reserve_priv; + + /** + * Public key of the reserve being analyzed. + */ + struct TALER_ReservePublicKeyP reserve_pub; + + /** + * Expected HTTP response code. + */ + unsigned int expected_response_code; + + /** + * Interpreter state. + */ + struct TALER_TESTING_Interpreter *is; +}; + + +/** + * Check that the reserve balance and HTTP response code are + * both acceptable. + * + * @param cls closure. + * @param rs HTTP response details + */ +static void +reserve_open_cb (void *cls, + const struct TALER_EXCHANGE_ReserveOpenResult *rs) +{ + struct OpenState *ss = cls; + struct TALER_TESTING_Interpreter *is = ss->is; + + ss->rsh = NULL; + if (ss->expected_response_code != rs->hr.http_status) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected HTTP response code: %d in %s:%u\n", + rs->hr.http_status, + __FILE__, + __LINE__); + json_dumpf (rs->hr.reply, + stderr, + JSON_INDENT (2)); + TALER_TESTING_interpreter_fail (ss->is); + return; + } + if (MHD_HTTP_OK != rs->hr.http_status) + { + TALER_TESTING_interpreter_next (is); + return; + } + TALER_TESTING_interpreter_next (is); +} + + +/** + * Run the command. + * + * @param cls closure. + * @param cmd the command being executed. + * @param is the interpreter state. + */ +static void +open_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct OpenState *ss = cls; + const struct TALER_TESTING_Command *create_reserve; + struct TALER_EXCHANGE_PurseDeposit cp[GNUNET_NZL (ss->cpl)]; + + ss->is = is; + create_reserve + = TALER_TESTING_interpreter_lookup_command (is, + ss->reserve_reference); + + if (NULL == create_reserve) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + if (GNUNET_OK != + TALER_TESTING_get_trait_reserve_priv (create_reserve, + &ss->reserve_priv)) + { + GNUNET_break (0); + TALER_LOG_ERROR ("Failed to find reserve_priv for open query\n"); + TALER_TESTING_interpreter_fail (is); + return; + } + GNUNET_CRYPTO_eddsa_key_get_public (&ss->reserve_priv->eddsa_priv, + &ss->reserve_pub.eddsa_pub); + for (unsigned int i = 0; i<ss->cpl; i++) + { + struct TALER_EXCHANGE_PurseDeposit *cpi = &cp[i]; + const struct TALER_TESTING_Command *cmdi; + const struct TALER_AgeCommitmentProof *age_commitment_proof; + const struct TALER_CoinSpendPrivateKeyP *coin_priv; + const struct TALER_DenominationSignature *denom_sig; + const struct TALER_EXCHANGE_DenomPublicKey *denom_pub; + char *cref; + unsigned int cidx; + + if (GNUNET_OK != + TALER_TESTING_parse_coin_reference (ss->cd[i].name, + &cref, + &cidx)) + { + GNUNET_break (0); + TALER_LOG_ERROR ("Failed to parse coin reference `%s'\n", + ss->cd[i].name); + TALER_TESTING_interpreter_fail (is); + return; + } + cmdi = TALER_TESTING_interpreter_lookup_command (is, + cref); + GNUNET_free (cref); + if (NULL == cmdi) + { + GNUNET_break (0); + TALER_LOG_ERROR ("Command `%s' not found\n", + ss->cd[i].name); + TALER_TESTING_interpreter_fail (is); + return; + } + if ( (GNUNET_OK != + TALER_TESTING_get_trait_age_commitment_proof (cmdi, + cidx, + &age_commitment_proof)) + || + (GNUNET_OK != + TALER_TESTING_get_trait_coin_priv (cmdi, + cidx, + &coin_priv)) || + (GNUNET_OK != + TALER_TESTING_get_trait_denom_sig (cmdi, + cidx, + &denom_sig)) || + (GNUNET_OK != + TALER_TESTING_get_trait_denom_pub (cmdi, + cidx, + &denom_pub)) ) + { + GNUNET_break (0); + TALER_LOG_ERROR ("Coin trait not found in `%s'\n", + ss->cd[i].name); + TALER_TESTING_interpreter_fail (is); + return; + } + cpi->age_commitment_proof = age_commitment_proof; + cpi->coin_priv = *coin_priv; + cpi->denom_sig = *denom_sig; + cpi->amount = ss->cd[i].amount; + cpi->h_denom_pub = denom_pub->h_key; + } + ss->rsh = TALER_EXCHANGE_reserves_open ( + TALER_TESTING_interpreter_get_context (is), + TALER_TESTING_get_exchange_url (is), + TALER_TESTING_get_keys (is), + ss->reserve_priv, + &ss->reserve_pay, + ss->cpl, + cp, + GNUNET_TIME_relative_to_timestamp (ss->req_expiration_time), + ss->min_purses, + &reserve_open_cb, + ss); +} + + +/** + * Cleanup the state from a "reserve open" CMD, and possibly + * cancel a pending operation thereof. + * + * @param cls closure. + * @param cmd the command which is being cleaned up. + */ +static void +open_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct OpenState *ss = cls; + + if (NULL != ss->rsh) + { + TALER_TESTING_command_incomplete (ss->is, + cmd->label); + TALER_EXCHANGE_reserves_open_cancel (ss->rsh); + ss->rsh = NULL; + } + GNUNET_free (ss); +} + + +struct TALER_TESTING_Command +TALER_TESTING_cmd_reserve_open (const char *label, + const char *reserve_reference, + const char *reserve_pay, + struct GNUNET_TIME_Relative expiration_time, + uint32_t min_purses, + unsigned int expected_response_code, + ...) +{ + struct OpenState *ss; + va_list ap; + const char *name; + unsigned int i; + + GNUNET_assert (NULL != reserve_reference); + ss = GNUNET_new (struct OpenState); + ss->reserve_reference = reserve_reference; + ss->req_expiration_time = expiration_time; + ss->min_purses = min_purses; + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (reserve_pay, + &ss->reserve_pay)); + ss->expected_response_code = expected_response_code; + va_start (ap, + expected_response_code); + while (NULL != (name = va_arg (ap, const char *))) + ss->cpl++; + va_end (ap); + GNUNET_assert (0 == (ss->cpl % 2)); + ss->cpl /= 2; /* name and amount per coin */ + ss->cd = GNUNET_new_array (ss->cpl, + struct CoinDetail); + i = 0; + va_start (ap, + expected_response_code); + while (NULL != (name = va_arg (ap, const char *))) + { + struct CoinDetail *cd = &ss->cd[i]; + cd->name = name; + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (va_arg (ap, + const char *), + &cd->amount)); + i++; + } + va_end (ap); + { + struct TALER_TESTING_Command cmd = { + .cls = ss, + .label = label, + .run = &open_run, + .cleanup = &open_cleanup + }; + + return cmd; + } +} diff --git a/src/testing/testing_api_cmd_reserve_purse.c b/src/testing/testing_api_cmd_reserve_purse.c index 915118eb7..ef6964f26 100644 --- a/src/testing/testing_api_cmd_reserve_purse.c +++ b/src/testing/testing_api_cmd_reserve_purse.c @@ -98,6 +98,18 @@ struct ReservePurseState struct GNUNET_TIME_Timestamp purse_expiration; /** + * Hash of the payto://-URI for the reserve we are + * merging into. + */ + struct TALER_PaytoHashP h_payto; + + /** + * Set to the KYC requirement row *if* the exchange replied with + * a request for KYC. + */ + uint64_t requirement_row; + + /** * Contract terms for the purse. */ json_t *contract_terms; @@ -117,6 +129,10 @@ struct ReservePurseState */ unsigned int expected_response_code; + /** + * True to pay the purse fee. + */ + bool pay_purse_fee; }; @@ -137,18 +153,19 @@ purse_cb (void *cls, ds->reserve_sig = *dr->reserve_sig; if (ds->expected_response_code != dr->hr.http_status) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u to command %s in %s:%u\n", - dr->hr.http_status, - ds->is->commands[ds->is->ip].label, - __FILE__, - __LINE__); - json_dumpf (dr->hr.reply, - stderr, - 0); - TALER_TESTING_interpreter_fail (ds->is); + TALER_TESTING_unexpected_status (ds->is, + dr->hr.http_status, + ds->expected_response_code); return; } + switch (dr->hr.http_status) + { + case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS: + /* KYC required */ + ds->requirement_row = + dr->details.unavailable_for_legal_reasons.requirement_row; + break; + } TALER_TESTING_interpreter_next (ds->is); } @@ -194,6 +211,30 @@ purse_run (void *cls, GNUNET_CRYPTO_ecdhe_key_create (&ds->contract_priv.ecdhe_priv); ds->purse_expiration = GNUNET_TIME_absolute_to_timestamp ( GNUNET_TIME_relative_to_absolute (ds->expiration_rel)); + + { + char *payto_uri; + const char *exchange_url; + const struct TALER_TESTING_Command *exchange_cmd; + + exchange_cmd = TALER_TESTING_interpreter_get_command (is, + "exchange"); + if (NULL == exchange_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_exchange_url (exchange_cmd, + &exchange_url)); + payto_uri = TALER_reserve_make_payto (exchange_url, + &ds->reserve_pub); + TALER_payto_hash (payto_uri, + &ds->h_payto); + GNUNET_free (payto_uri); + } + GNUNET_assert (0 == json_object_set_new ( ds->contract_terms, @@ -201,14 +242,16 @@ purse_run (void *cls, GNUNET_JSON_from_timestamp (ds->purse_expiration))); ds->merge_timestamp = GNUNET_TIME_timestamp_get (); ds->dh = TALER_EXCHANGE_purse_create_with_merge ( - is->exchange, + TALER_TESTING_interpreter_get_context (is), + TALER_TESTING_get_exchange_url (is), + TALER_TESTING_get_keys (is), &ds->reserve_priv, &ds->purse_priv, &ds->merge_priv, &ds->contract_priv, ds->contract_terms, true /* upload contract */, - true /* do pay purse fee -- FIXME #7274: make this a choice to test this case; then update testing_api_cmd_purse_deposit flags logic to match! */, + ds->pay_purse_fee, ds->merge_timestamp, &purse_cb, ds); @@ -238,10 +281,8 @@ purse_cleanup (void *cls, if (NULL != ds->dh) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - ds->is->ip, - cmd->label); + TALER_TESTING_command_incomplete (ds->is, + cmd->label); TALER_EXCHANGE_purse_create_with_merge_cancel (ds->dh); ds->dh = NULL; } @@ -278,6 +319,8 @@ purse_traits (void *cls, TALER_TESTING_make_trait_reserve_priv (&ds->reserve_priv), TALER_TESTING_make_trait_reserve_pub (&ds->reserve_pub), TALER_TESTING_make_trait_reserve_sig (&ds->reserve_sig), + TALER_TESTING_make_trait_legi_requirement_row (&ds->requirement_row), + TALER_TESTING_make_trait_h_payto (&ds->h_payto), TALER_TESTING_trait_end () }; @@ -294,6 +337,7 @@ TALER_TESTING_cmd_purse_create_with_reserve ( unsigned int expected_http_status, const char *contract_terms, bool upload_contract, + bool pay_purse_fee, struct GNUNET_TIME_Relative expiration, const char *reserve_ref) { @@ -306,6 +350,7 @@ TALER_TESTING_cmd_purse_create_with_reserve ( 0 /* flags */, &err); GNUNET_assert (NULL != ds->contract_terms); + ds->pay_purse_fee = pay_purse_fee; ds->reserve_ref = reserve_ref; ds->expected_response_code = expected_http_status; diff --git a/src/testing/testing_api_cmd_reserve_status.c b/src/testing/testing_api_cmd_reserve_status.c deleted file mode 100644 index a1b7aaefd..000000000 --- a/src/testing/testing_api_cmd_reserve_status.c +++ /dev/null @@ -1,369 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014-2020 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/testing_api_cmd_reserve_status.c - * @brief Implement the /reserve/$RID/status test command. - * @author Marcello Stanisci - */ -#include "platform.h" -#include "taler_json_lib.h" -#include <gnunet/gnunet_curl_lib.h> -#include "taler_testing_lib.h" - - -/** - * State for a "status" CMD. - */ -struct StatusState -{ - /** - * Label to the command which created the reserve to check, - * needed to resort the reserve key. - */ - const char *reserve_reference; - - /** - * Handle to the "reserve status" operation. - */ - struct TALER_EXCHANGE_ReservesStatusHandle *rsh; - - /** - * Expected reserve balance. - */ - const char *expected_balance; - - /** - * Private key of the reserve being analyzed. - */ - const struct TALER_ReservePrivateKeyP *reserve_priv; - - /** - * Public key of the reserve being analyzed. - */ - struct TALER_ReservePublicKeyP reserve_pub; - - /** - * Expected HTTP response code. - */ - unsigned int expected_response_code; - - /** - * Interpreter state. - */ - struct TALER_TESTING_Interpreter *is; -}; - - -/** - * Check if @a cmd changed the reserve, if so, find the - * entry in @a history and set the respective index in @a found - * to #GNUNET_YES. If the entry is not found, return #GNUNET_SYSERR. - * - * @param reserve_pub public key of the reserve for which we have the @a history - * @param cmd command to analyze for impact on history - * @param history_length number of entries in @a history and @a found - * @param history history to check - * @param[in,out] found array to update - * @return #GNUNET_OK if @a cmd action on reserve was found in @a history - */ -static enum GNUNET_GenericReturnValue -analyze_command (const struct TALER_ReservePublicKeyP *reserve_pub, - const struct TALER_TESTING_Command *cmd, - unsigned int history_length, - const struct TALER_EXCHANGE_ReserveHistoryEntry *history, - bool *found) -{ - if (TALER_TESTING_cmd_is_batch (cmd)) - { - struct TALER_TESTING_Command *cur; - struct TALER_TESTING_Command **bcmd; - - cur = TALER_TESTING_cmd_batch_get_current (cmd); - if (GNUNET_OK != - TALER_TESTING_get_trait_batch_cmds (cmd, - &bcmd)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - for (unsigned int i = 0; NULL != (*bcmd)[i].label; i++) - { - struct TALER_TESTING_Command *step = &(*bcmd)[i]; - - if (step == cur) - break; /* if *we* are in a batch, make sure not to analyze commands past 'now' */ - if (GNUNET_OK != - analyze_command (reserve_pub, - step, - history_length, - history, - found)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Entry for batch step `%s' missing in history\n", - step->label); - return GNUNET_SYSERR; - } - } - return GNUNET_OK; - } - else - { - const struct TALER_ReservePublicKeyP *rp; - - if (GNUNET_OK != - TALER_TESTING_get_trait_reserve_pub (cmd, - &rp)) - return GNUNET_OK; /* command does nothing for reserves */ - if (0 != - GNUNET_memcmp (rp, - reserve_pub)) - return GNUNET_OK; /* command affects some _other_ reserve */ - for (unsigned int j = 0; true; j++) - { - const struct TALER_EXCHANGE_ReserveHistoryEntry *he; - bool matched = false; - - if (GNUNET_OK != - TALER_TESTING_get_trait_reserve_history (cmd, - j, - &he)) - { - /* NOTE: only for debugging... */ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Command `%s' has the reserve_pub trait, but does not reserve history trait\n", - cmd->label); - return GNUNET_OK; /* command does nothing for reserves */ - } - for (unsigned int i = 0; i<history_length; i++) - { - if (found[i]) - continue; /* already found, skip */ - if (0 == - TALER_TESTING_history_entry_cmp (he, - &history[i])) - { - found[i] = true; - matched = true; - break; - } - } - if (! matched) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Command `%s' reserve history entry #%u not found\n", - cmd->label, - j); - return GNUNET_SYSERR; - } - } - } -} - - -/** - * Check that the reserve balance and HTTP response code are - * both acceptable. - * - * @param cls closure. - * @param rs HTTP response details - */ -static void -reserve_status_cb (void *cls, - const struct TALER_EXCHANGE_ReserveStatus *rs) -{ - struct StatusState *ss = cls; - struct TALER_TESTING_Interpreter *is = ss->is; - struct TALER_Amount eb; - - ss->rsh = NULL; - if (ss->expected_response_code != rs->hr.http_status) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected HTTP response code: %d in %s:%u\n", - rs->hr.http_status, - __FILE__, - __LINE__); - json_dumpf (rs->hr.reply, - stderr, - JSON_INDENT (2)); - TALER_TESTING_interpreter_fail (ss->is); - return; - } - if (MHD_HTTP_OK != rs->hr.http_status) - { - TALER_TESTING_interpreter_next (is); - return; - } - GNUNET_assert (GNUNET_OK == - TALER_string_to_amount (ss->expected_balance, - &eb)); - - if (0 != TALER_amount_cmp (&eb, - &rs->details.ok.balance)) - { - GNUNET_break (0); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected amount in reserve: %s\n", - TALER_amount_to_string (&rs->details.ok.balance)); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Expected balance of: %s\n", - TALER_amount_to_string (&eb)); - TALER_TESTING_interpreter_fail (ss->is); - return; - } - { - bool found[rs->details.ok.history_len]; - - memset (found, - 0, - sizeof (found)); - for (unsigned int i = 0; i<= (unsigned int) is->ip; i++) - { - struct TALER_TESTING_Command *cmd = &is->commands[i]; - - if (GNUNET_OK != - analyze_command (&ss->reserve_pub, - cmd, - rs->details.ok.history_len, - rs->details.ok.history, - found)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Entry for command `%s' missing in history\n", - cmd->label); - json_dumpf (rs->hr.reply, - stderr, - JSON_INDENT (2)); - TALER_TESTING_interpreter_fail (ss->is); - return; - } - } - for (unsigned int i = 0; i<rs->details.ok.history_len; i++) - if (! found[i]) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "History entry at index %u of type %d not justified by command status\n", - i, - rs->details.ok.history[i].type); - json_dumpf (rs->hr.reply, - stderr, - JSON_INDENT (2)); - TALER_TESTING_interpreter_fail (ss->is); - return; - } - } - TALER_TESTING_interpreter_next (is); -} - - -/** - * Run the command. - * - * @param cls closure. - * @param cmd the command being executed. - * @param is the interpreter state. - */ -static void -status_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - struct StatusState *ss = cls; - const struct TALER_TESTING_Command *create_reserve; - - ss->is = is; - create_reserve - = TALER_TESTING_interpreter_lookup_command (is, - ss->reserve_reference); - - if (NULL == create_reserve) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - if (GNUNET_OK != - TALER_TESTING_get_trait_reserve_priv (create_reserve, - &ss->reserve_priv)) - { - GNUNET_break (0); - TALER_LOG_ERROR ("Failed to find reserve_priv for status query\n"); - TALER_TESTING_interpreter_fail (is); - return; - } - GNUNET_CRYPTO_eddsa_key_get_public (&ss->reserve_priv->eddsa_priv, - &ss->reserve_pub.eddsa_pub); - ss->rsh = TALER_EXCHANGE_reserves_status (is->exchange, - ss->reserve_priv, - &reserve_status_cb, - ss); -} - - -/** - * Cleanup the state from a "reserve status" CMD, and possibly - * cancel a pending operation thereof. - * - * @param cls closure. - * @param cmd the command which is being cleaned up. - */ -static void -status_cleanup (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - struct StatusState *ss = cls; - - if (NULL != ss->rsh) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - ss->is->ip, - cmd->label); - TALER_EXCHANGE_reserves_status_cancel (ss->rsh); - ss->rsh = NULL; - } - GNUNET_free (ss); -} - - -struct TALER_TESTING_Command -TALER_TESTING_cmd_reserve_status (const char *label, - const char *reserve_reference, - const char *expected_balance, - unsigned int expected_response_code) -{ - struct StatusState *ss; - - GNUNET_assert (NULL != reserve_reference); - ss = GNUNET_new (struct StatusState); - ss->reserve_reference = reserve_reference; - ss->expected_balance = expected_balance; - ss->expected_response_code = expected_response_code; - { - struct TALER_TESTING_Command cmd = { - .cls = ss, - .label = label, - .run = &status_run, - .cleanup = &status_cleanup - }; - - return cmd; - } -} diff --git a/src/testing/testing_api_cmd_revoke.c b/src/testing/testing_api_cmd_revoke.c index 4522dede1..f734be1a4 100644 --- a/src/testing/testing_api_cmd_revoke.c +++ b/src/testing/testing_api_cmd_revoke.c @@ -141,14 +141,12 @@ revoke_run (void *cls, /* Get denom pub from trait */ coin_cmd = TALER_TESTING_interpreter_lookup_command (is, rs->coin_reference); - if (NULL == coin_cmd) { GNUNET_break (0); TALER_TESTING_interpreter_fail (is); return; } - GNUNET_assert (GNUNET_OK == TALER_TESTING_get_trait_denom_pub (coin_cmd, 0, diff --git a/src/testing/testing_api_cmd_revoke_denom_key.c b/src/testing/testing_api_cmd_revoke_denom_key.c index 7c77c3566..2663c538f 100644 --- a/src/testing/testing_api_cmd_revoke_denom_key.c +++ b/src/testing/testing_api_cmd_revoke_denom_key.c @@ -65,28 +65,22 @@ struct RevokeState * Function called with information about the post revocation operation result. * * @param cls closure with a `struct RevokeState *` - * @param hr HTTP response data + * @param rdr response data */ static void success_cb ( void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr) + const struct TALER_EXCHANGE_ManagementRevokeDenominationResponse *rdr) { struct RevokeState *rs = cls; + const struct TALER_EXCHANGE_HttpResponse *hr = &rdr->hr; rs->kh = NULL; if (rs->expected_response_code != hr->http_status) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u to command %s in %s:%u\n", - hr->http_status, - rs->is->commands[rs->is->ip].label, - __FILE__, - __LINE__); - json_dumpf (hr->reply, - stderr, - 0); - TALER_TESTING_interpreter_fail (rs->is); + TALER_TESTING_unexpected_status (rs->is, + hr->http_status, + rs->expected_response_code); return; } TALER_TESTING_interpreter_next (rs->is); @@ -158,7 +152,23 @@ revoke_run (void *cls, const struct TALER_TESTING_Command *coin_cmd; const struct TALER_EXCHANGE_DenomPublicKey *denom_pub; struct TALER_MasterSignatureP master_sig; + const char *exchange_url; + { + const struct TALER_TESTING_Command *exchange_cmd; + + exchange_cmd = TALER_TESTING_interpreter_get_command (is, + "exchange"); + if (NULL == exchange_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_exchange_url (exchange_cmd, + &exchange_url)); + } rs->is = is; /* Get denom pub from trait */ coin_cmd = TALER_TESTING_interpreter_lookup_command (is, @@ -185,13 +195,27 @@ revoke_run (void *cls, } else { + const struct TALER_TESTING_Command *exchange_cmd; + const struct TALER_MasterPrivateKeyP *master_priv; + + exchange_cmd = TALER_TESTING_interpreter_get_command (is, + "exchange"); + if (NULL == exchange_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_master_priv (exchange_cmd, + &master_priv)); TALER_exchange_offline_denomination_revoke_sign (&denom_pub->h_key, - &is->master_priv, + master_priv, &master_sig); } rs->kh = TALER_EXCHANGE_management_revoke_denomination_key ( - is->ctx, - is->exchange_url, + TALER_TESTING_interpreter_get_context (is), + exchange_url, &denom_pub->h_key, &master_sig, &success_cb, diff --git a/src/testing/testing_api_cmd_revoke_sign_key.c b/src/testing/testing_api_cmd_revoke_sign_key.c index 9745d728d..65b80b4c9 100644 --- a/src/testing/testing_api_cmd_revoke_sign_key.c +++ b/src/testing/testing_api_cmd_revoke_sign_key.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014-2020 Taler Systems SA + Copyright (C) 2014-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 @@ -65,28 +65,22 @@ struct RevokeState * Function called with information about the post revocation operation result. * * @param cls closure with a `struct RevokeState *` - * @param hr HTTP response data + * @param rsr response data */ static void success_cb ( void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr) + const struct TALER_EXCHANGE_ManagementRevokeSigningKeyResponse *rsr) { struct RevokeState *rs = cls; + const struct TALER_EXCHANGE_HttpResponse *hr = &rsr->hr; rs->kh = NULL; if (rs->expected_response_code != hr->http_status) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u to command %s in %s:%u\n", - hr->http_status, - rs->is->commands[rs->is->ip].label, - __FILE__, - __LINE__); - json_dumpf (hr->reply, - stderr, - 0); - TALER_TESTING_interpreter_fail (rs->is); + TALER_TESTING_unexpected_status (rs->is, + hr->http_status, + rs->expected_response_code); return; } TALER_TESTING_interpreter_next (rs->is); @@ -158,7 +152,23 @@ revoke_run (void *cls, const struct TALER_TESTING_Command *coin_cmd; const struct TALER_ExchangePublicKeyP *exchange_pub; struct TALER_MasterSignatureP master_sig; + const char *exchange_url; + { + const struct TALER_TESTING_Command *exchange_cmd; + + exchange_cmd = TALER_TESTING_interpreter_get_command (is, + "exchange"); + if (NULL == exchange_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_exchange_url (exchange_cmd, + &exchange_url)); + } rs->is = is; /* Get sign pub from trait */ coin_cmd = TALER_TESTING_interpreter_lookup_command (is, @@ -185,13 +195,27 @@ revoke_run (void *cls, } else { + const struct TALER_TESTING_Command *exchange_cmd; + const struct TALER_MasterPrivateKeyP *master_priv; + + exchange_cmd = TALER_TESTING_interpreter_get_command (is, + "exchange"); + if (NULL == exchange_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_master_priv (exchange_cmd, + &master_priv)); TALER_exchange_offline_signkey_revoke_sign (exchange_pub, - &is->master_priv, + master_priv, &master_sig); } rs->kh = TALER_EXCHANGE_management_revoke_signing_key ( - is->ctx, - is->exchange_url, + TALER_TESTING_interpreter_get_context (is), + exchange_url, exchange_pub, &master_sig, &success_cb, diff --git a/src/testing/testing_api_cmd_rewind.c b/src/testing/testing_api_cmd_rewind.c deleted file mode 100644 index 93b38d3c3..000000000 --- a/src/testing/testing_api_cmd_rewind.c +++ /dev/null @@ -1,197 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014-2020 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/testing_api_cmd_rewind.c - * @brief command to rewind the instruction pointer. - * @author Marcello Stanisci - * @author Christian Grothoff - */ -#include "platform.h" -#include "taler_exchange_service.h" -#include "taler_testing_lib.h" - - -/** - * State for a "rewind" CMD. - */ -struct RewindIpState -{ - /** - * Instruction pointer to set into the interpreter. - */ - const char *target_label; - - /** - * How many times this set should take place. However, this value lives at - * the calling process, and this CMD is only in charge of checking and - * decremeting it. - */ - unsigned int counter; -}; - - -/** - * Seek for the @a target command in @a batch (and rewind to it - * if successful). - * - * @param is the interpreter state (for failures) - * @param cmd batch to search for @a target - * @param target command to search for - * @return #GNUNET_OK on success, #GNUNET_NO if target was not found, - * #GNUNET_SYSERR if target is in the future and we failed - */ -static enum GNUNET_GenericReturnValue -seek_batch (struct TALER_TESTING_Interpreter *is, - const struct TALER_TESTING_Command *cmd, - const struct TALER_TESTING_Command *target) -{ - unsigned int new_ip; - struct TALER_TESTING_Command **batch; - struct TALER_TESTING_Command *current; - struct TALER_TESTING_Command *icmd; - struct TALER_TESTING_Command *match; - - current = TALER_TESTING_cmd_batch_get_current (cmd); - GNUNET_assert (GNUNET_OK == - TALER_TESTING_get_trait_batch_cmds (cmd, - &batch)); - match = NULL; - for (new_ip = 0; - NULL != (icmd = &(*batch)[new_ip]); - new_ip++) - { - if (current == target) - current = NULL; - if (icmd == target) - { - match = icmd; - break; - } - if (TALER_TESTING_cmd_is_batch (icmd)) - { - int ret = seek_batch (is, - icmd, - target); - if (GNUNET_SYSERR == ret) - return GNUNET_SYSERR; /* failure! */ - if (GNUNET_OK == ret) - { - match = icmd; - break; - } - } - } - if (NULL == current) - { - /* refuse to jump forward */ - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return GNUNET_SYSERR; - } - if (NULL == match) - return GNUNET_NO; /* not found */ - TALER_TESTING_cmd_batch_set_current (cmd, - new_ip); - return GNUNET_OK; -} - - -/** - * Run the "rewind" CMD. - * - * @param cls closure. - * @param cmd command being executed now. - * @param is the interpreter state. - */ -static void -rewind_ip_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - struct RewindIpState *ris = cls; - const struct TALER_TESTING_Command *target; - unsigned int new_ip; - - (void) cmd; - if (0 == ris->counter) - { - TALER_TESTING_interpreter_next (is); - return; - } - target - = TALER_TESTING_interpreter_lookup_command (is, - ris->target_label); - if (NULL == target) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - ris->counter--; - for (new_ip = 0; - NULL != is->commands[new_ip].label; - new_ip++) - { - const struct TALER_TESTING_Command *cmd = &is->commands[new_ip]; - - if (cmd == target) - break; - if (TALER_TESTING_cmd_is_batch (cmd)) - { - int ret = seek_batch (is, - cmd, - target); - if (GNUNET_SYSERR == ret) - return; /* failure! */ - if (GNUNET_OK == ret) - break; - } - } - if (new_ip > (unsigned int) is->ip) - { - /* refuse to jump forward */ - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - is->ip = new_ip - 1; /* -1 because the next function will advance by one */ - TALER_TESTING_interpreter_next (is); -} - - -struct TALER_TESTING_Command -TALER_TESTING_cmd_rewind_ip (const char *label, - const char *target_label, - unsigned int counter) -{ - struct RewindIpState *ris; - - ris = GNUNET_new (struct RewindIpState); - ris->target_label = target_label; - ris->counter = counter; - { - struct TALER_TESTING_Command cmd = { - .cls = ris, - .label = label, - .run = &rewind_ip_run - }; - - return cmd; - } -} diff --git a/src/testing/testing_api_cmd_run_fakebank.c b/src/testing/testing_api_cmd_run_fakebank.c new file mode 100644 index 000000000..7739d3c0c --- /dev/null +++ b/src/testing/testing_api_cmd_run_fakebank.c @@ -0,0 +1,214 @@ +/* + This file is part of TALER + (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/testing_api_cmd_run_fakebank.c + * @brief Command to run fakebank in-process + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_json_lib.h" +#include <gnunet/gnunet_curl_lib.h> +#include "taler_testing_lib.h" + +/** + * State for a "run fakebank" CMD. + */ +struct RunFakebankState +{ + + /** + * Our interpreter state. + */ + struct TALER_TESTING_Interpreter *is; + + /** + * Handle to the fakebank we are running. + */ + struct TALER_FAKEBANK_Handle *fakebank; + + /** + * URL of the bank. + */ + char *bank_url; + + /** + * Currency to use. + */ + char *currency; + + /** + * Data for access control. + */ + struct TALER_BANK_AuthenticationData ba; + + /** + * Port to use. + */ + uint16_t port; +}; + + +/** + * Run the "get_exchange" command. + * + * @param cls closure. + * @param cmd the command currently being executed. + * @param is the interpreter state. + */ +static void +run_fakebank_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct RunFakebankState *rfs = cls; + + (void) cmd; + rfs->fakebank = TALER_FAKEBANK_start (rfs->port, + rfs->currency); + if (NULL == rfs->fakebank) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + TALER_TESTING_interpreter_next (is); +} + + +/** + * Cleanup the state. + * + * @param cls closure. + * @param cmd the command which is being cleaned up. + */ +static void +run_fakebank_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct RunFakebankState *rfs = cls; + + if (NULL != rfs->fakebank) + { + TALER_FAKEBANK_stop (rfs->fakebank); + rfs->fakebank = NULL; + } + GNUNET_free (rfs->ba.wire_gateway_url); + GNUNET_free (rfs->bank_url); + GNUNET_free (rfs->currency); + GNUNET_free (rfs); +} + + +/** + * Offer internal data to a "run_fakebank" CMD state to other commands. + * + * @param cls closure + * @param[out] ret result (could be anything) + * @param trait name of the trait + * @param index index number of the object to offer. + * @return #GNUNET_OK on success + */ +static enum GNUNET_GenericReturnValue +run_fakebank_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + struct RunFakebankState *rfs = cls; + struct TALER_TESTING_Trait traits[] = { + TALER_TESTING_make_trait_bank_auth_data (&rfs->ba), + TALER_TESTING_make_trait_fakebank (rfs->fakebank), + TALER_TESTING_trait_end () + }; + + return TALER_TESTING_get_trait (traits, + ret, + trait, + index); +} + + +struct TALER_TESTING_Command +TALER_TESTING_cmd_run_fakebank ( + const char *label, + const struct GNUNET_CONFIGURATION_Handle *cfg, + const char *exchange_account_section) +{ + struct RunFakebankState *rfs; + unsigned long long fakebank_port; + char *exchange_payto_uri; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cfg, + "BANK", + "HTTP_PORT", + &fakebank_port)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "BANK", + "HTTP_PORT"); + GNUNET_assert (0); + } + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, + exchange_account_section, + "PAYTO_URI", + &exchange_payto_uri)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + exchange_account_section, + "PAYTO_URI"); + GNUNET_assert (0); + } + rfs = GNUNET_new (struct RunFakebankState); + rfs->port = (uint16_t) fakebank_port; + GNUNET_asprintf (&rfs->bank_url, + "http://localhost:%u/", + (unsigned int) rfs->port); + GNUNET_assert (GNUNET_OK == + TALER_config_get_currency (cfg, + &rfs->currency)); + { + char *exchange_xtalerbank_account; + + exchange_xtalerbank_account + = TALER_xtalerbank_account_from_payto (exchange_payto_uri); + GNUNET_assert (NULL != exchange_xtalerbank_account); + GNUNET_asprintf (&rfs->ba.wire_gateway_url, + "http://localhost:%u/%s/", + (unsigned int) fakebank_port, + exchange_xtalerbank_account); + GNUNET_free (exchange_xtalerbank_account); + GNUNET_free (exchange_payto_uri); + } + GNUNET_free (exchange_payto_uri); + rfs->ba.method = TALER_BANK_AUTH_NONE; + { + struct TALER_TESTING_Command cmd = { + .cls = rfs, + .label = label, + .run = &run_fakebank_run, + .cleanup = &run_fakebank_cleanup, + .traits = &run_fakebank_traits, + .name = "fakebank" + }; + + return cmd; + } +} diff --git a/src/testing/testing_api_cmd_serialize_keys.c b/src/testing/testing_api_cmd_serialize_keys.c deleted file mode 100644 index ef912bf51..000000000 --- a/src/testing/testing_api_cmd_serialize_keys.c +++ /dev/null @@ -1,275 +0,0 @@ -/* - This file is part of TALER - (C) 2018 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 3, or - (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - <http://www.gnu.org/licenses/> -*/ -/** - * @file testing/testing_api_cmd_serialize_keys.c - * @brief Lets tests use the keys serialization API. - * @author Marcello Stanisci - */ -#include "platform.h" -#include <jansson.h> -#include "taler_testing_lib.h" - - -/** - * Internal state for a serialize-keys CMD. - */ -struct SerializeKeysState -{ - /** - * Serialized keys. - */ - json_t *keys; - - /** - * Exchange URL. Needed because the exchange gets disconnected - * from, after keys serialization. This value is then needed by - * subsequent commands that have to reconnect to the exchange. - */ - char *exchange_url; -}; - - -/** - * Internal state for a connect-with-state CMD. - */ -struct ConnectWithStateState -{ - - /** - * Reference to a CMD that offers a serialized key-state - * that will be used in the reconnection. - */ - const char *state_reference; - - /** - * If set to GNUNET_YES, then the /keys callback has already - * been passed the control to the next CMD. This is necessary - * because it is not uncommon that the /keys callback gets - * invoked multiple times, and without this flag, we would keep - * going "next" CMD upon every invocation (causing impredictable - * behaviour as for the instruction pointer.) - */ - unsigned int consumed; - - /** - * Interpreter state. - */ - struct TALER_TESTING_Interpreter *is; -}; - - -/** - * Run the command. - * - * @param cls closure. - * @param cmd the command to execute. - * @param is the interpreter state. - */ -static void -serialize_keys_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - struct SerializeKeysState *sks = cls; - - sks->keys = TALER_EXCHANGE_serialize_data (is->exchange); - if (NULL == sks->keys) - TALER_TESTING_interpreter_fail (is); - - sks->exchange_url = GNUNET_strdup - (TALER_EXCHANGE_get_base_url (is->exchange)); - TALER_EXCHANGE_disconnect (is->exchange); - is->exchange = NULL; - is->working = GNUNET_NO; - TALER_TESTING_interpreter_next (is); -} - - -/** - * Cleanup the state of a "serialize keys" CMD. - * - * @param cls closure. - * @param cmd the command which is being cleaned up. - */ -static void -serialize_keys_cleanup (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - struct SerializeKeysState *sks = cls; - - if (NULL != sks->keys) - { - json_decref (sks->keys); - } - GNUNET_free (sks->exchange_url); - GNUNET_free (sks); -} - - -/** - * Offer serialized keys as trait. - * - * @param cls closure. - * @param[out] ret result. - * @param trait name of the trait. - * @param index index number of the object to offer. - * @return #GNUNET_OK on success. - */ -static enum GNUNET_GenericReturnValue -serialize_keys_traits (void *cls, - const void **ret, - const char *trait, - unsigned int index) -{ - struct SerializeKeysState *sks = cls; - struct TALER_TESTING_Trait traits[] = { - TALER_TESTING_make_trait_exchange_keys (sks->keys), - TALER_TESTING_make_trait_exchange_url ( - (const char **) &sks->exchange_url), - TALER_TESTING_trait_end () - }; - - return TALER_TESTING_get_trait (traits, - ret, - trait, - index); -} - - -/** - * Run the command. - * - * @param cls closure. - * @param cmd the command to execute. - * @param is the interpreter state. - */ -static void -connect_with_state_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - struct ConnectWithStateState *cwss = cls; - const struct TALER_TESTING_Command *state_cmd; - const json_t *serialized_keys; - const char **exchange_url; - - /* This command usually gets rescheduled after serialized - * reconnection. */ - if (GNUNET_YES == cwss->consumed) - { - TALER_TESTING_interpreter_next (is); - return; - } - - cwss->is = is; - state_cmd = TALER_TESTING_interpreter_lookup_command (is, - cwss->state_reference); - - /* Command providing serialized keys not found. */ - if (NULL == state_cmd) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - - GNUNET_assert (GNUNET_OK == - TALER_TESTING_get_trait_exchange_keys (state_cmd, - &serialized_keys)); - { - char *dump; - - dump = json_dumps (serialized_keys, - JSON_INDENT (1)); - TALER_LOG_DEBUG ("Serialized key-state: %s\n", - dump); - free (dump); - } - - GNUNET_assert (GNUNET_OK == - TALER_TESTING_get_trait_exchange_url (state_cmd, - &exchange_url)); - is->exchange = TALER_EXCHANGE_connect (is->ctx, - *exchange_url, - &TALER_TESTING_cert_cb, - cwss, - TALER_EXCHANGE_OPTION_DATA, - serialized_keys, - TALER_EXCHANGE_OPTION_END); - cwss->consumed = GNUNET_YES; -} - - -/** - * Cleanup the state of a "connect with state" CMD. Just - * a placeholder to avoid jumping on an invalid address. - * - * @param cls closure. - * @param cmd the command which is being cleaned up. - */ -static void -connect_with_state_cleanup (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - struct ConnectWithStateState *cwss = cls; - - GNUNET_free (cwss); -} - - -struct TALER_TESTING_Command -TALER_TESTING_cmd_serialize_keys (const char *label) -{ - struct SerializeKeysState *sks; - - sks = GNUNET_new (struct SerializeKeysState); - { - struct TALER_TESTING_Command cmd = { - .cls = sks, - .label = label, - .run = serialize_keys_run, - .cleanup = serialize_keys_cleanup, - .traits = serialize_keys_traits - }; - - return cmd; - } -} - - -struct TALER_TESTING_Command -TALER_TESTING_cmd_connect_with_state (const char *label, - const char *state_reference) -{ - struct ConnectWithStateState *cwss; - - cwss = GNUNET_new (struct ConnectWithStateState); - cwss->state_reference = state_reference; - cwss->consumed = GNUNET_NO; - { - struct TALER_TESTING_Command cmd = { - .cls = cwss, - .label = label, - .run = connect_with_state_run, - .cleanup = connect_with_state_cleanup - }; - - return cmd; - } -} diff --git a/src/testing/testing_api_cmd_set_officer.c b/src/testing/testing_api_cmd_set_officer.c new file mode 100644 index 000000000..4fbe5e368 --- /dev/null +++ b/src/testing/testing_api_cmd_set_officer.c @@ -0,0 +1,301 @@ +/* + 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/testing_api_cmd_set_officer.c + * @brief command for testing /management/aml-officers + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_json_lib.h" +#include <gnunet/gnunet_curl_lib.h> +#include "taler_testing_lib.h" +#include "taler_signatures.h" +#include "backoff.h" + + +/** + * State for a "set_officer" CMD. + */ +struct SetOfficerState +{ + + /** + * Update AML officer handle while operation is running. + */ + struct TALER_EXCHANGE_ManagementUpdateAmlOfficer *dh; + + /** + * Our interpreter. + */ + struct TALER_TESTING_Interpreter *is; + + /** + * Reference to command to previous set officer + * to update, or NULL. + */ + const char *ref_cmd; + + /** + * Name to use for the officer. + */ + const char *name; + + /** + * Private key of the AML officer. + */ + struct TALER_AmlOfficerPrivateKeyP officer_priv; + + /** + * Public key of the AML officer. + */ + struct TALER_AmlOfficerPublicKeyP officer_pub; + + /** + * Is the officer supposed to be enabled? + */ + bool is_active; + + /** + * Is access supposed to be read-only? + */ + bool read_only; + +}; + + +/** + * Callback to analyze the /management/XXX response, just used to check + * if the response code is acceptable. + * + * @param cls closure. + * @param ar response details + */ +static void +set_officer_cb (void *cls, + const struct + TALER_EXCHANGE_ManagementUpdateAmlOfficerResponse *ar) +{ + struct SetOfficerState *ds = cls; + const struct TALER_EXCHANGE_HttpResponse *hr = &ar->hr; + + ds->dh = NULL; + if (MHD_HTTP_NO_CONTENT != hr->http_status) + { + TALER_TESTING_unexpected_status (ds->is, + hr->http_status, + MHD_HTTP_NO_CONTENT); + return; + } + TALER_TESTING_interpreter_next (ds->is); +} + + +/** + * Run the command. + * + * @param cls closure. + * @param cmd the command to execute. + * @param is the interpreter state. + */ +static void +set_officer_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct SetOfficerState *ds = cls; + struct GNUNET_TIME_Timestamp now; + struct TALER_MasterSignatureP master_sig; + const char *exchange_url; + + (void) cmd; + { + const struct TALER_TESTING_Command *exchange_cmd; + + exchange_cmd = TALER_TESTING_interpreter_get_command (is, + "exchange"); + if (NULL == exchange_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_exchange_url (exchange_cmd, + &exchange_url)); + } + now = GNUNET_TIME_timestamp_get (); + ds->is = is; + if (NULL == ds->ref_cmd) + { + GNUNET_CRYPTO_eddsa_key_create (&ds->officer_priv.eddsa_priv); + GNUNET_CRYPTO_eddsa_key_get_public (&ds->officer_priv.eddsa_priv, + &ds->officer_pub.eddsa_pub); + } + else + { + const struct TALER_TESTING_Command *ref; + const struct TALER_AmlOfficerPrivateKeyP *officer_priv; + const struct TALER_AmlOfficerPublicKeyP *officer_pub; + + ref = TALER_TESTING_interpreter_lookup_command (is, + ds->ref_cmd); + if (NULL == ref) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_officer_pub (ref, + &officer_pub)); + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_officer_priv (ref, + &officer_priv)); + ds->officer_pub = *officer_pub; + ds->officer_priv = *officer_priv; + } + { + const struct TALER_TESTING_Command *exchange_cmd; + const struct TALER_MasterPrivateKeyP *master_priv; + + exchange_cmd = TALER_TESTING_interpreter_get_command (is, + "exchange"); + if (NULL == exchange_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_master_priv (exchange_cmd, + &master_priv)); + + TALER_exchange_offline_aml_officer_status_sign (&ds->officer_pub, + ds->name, + now, + ds->is_active, + ds->read_only, + master_priv, + &master_sig); + } + ds->dh = TALER_EXCHANGE_management_update_aml_officer ( + TALER_TESTING_interpreter_get_context (is), + exchange_url, + &ds->officer_pub, + ds->name, + now, + ds->is_active, + ds->read_only, + &master_sig, + &set_officer_cb, + ds); + if (NULL == ds->dh) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } +} + + +/** + * Free the state of a "set_officer" CMD, and possibly cancel a + * pending operation thereof. + * + * @param cls closure, must be a `struct SetOfficerState`. + * @param cmd the command which is being cleaned up. + */ +static void +set_officer_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct SetOfficerState *ds = cls; + + if (NULL != ds->dh) + { + TALER_TESTING_command_incomplete (ds->is, + cmd->label); + TALER_EXCHANGE_management_update_aml_officer_cancel (ds->dh); + ds->dh = NULL; + } + GNUNET_free (ds); +} + + +/** + * Offer internal data of a "set officer" CMD state to other + * commands. + * + * @param cls closure + * @param[out] ret result (could be anything) + * @param trait name of the trait + * @param index index number of the object to offer. + * @return #GNUNET_OK on success + */ +static enum GNUNET_GenericReturnValue +set_officer_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + struct SetOfficerState *ws = cls; + struct TALER_TESTING_Trait traits[] = { + TALER_TESTING_make_trait_officer_pub (&ws->officer_pub), + TALER_TESTING_make_trait_officer_priv (&ws->officer_priv), + TALER_TESTING_make_trait_officer_name (ws->name), + TALER_TESTING_trait_end () + }; + + return TALER_TESTING_get_trait (traits, + ret, + trait, + index); +} + + +struct TALER_TESTING_Command +TALER_TESTING_cmd_set_officer ( + const char *label, + const char *ref_cmd, + const char *name, + bool is_active, + bool read_only) +{ + struct SetOfficerState *ds; + + ds = GNUNET_new (struct SetOfficerState); + ds->ref_cmd = ref_cmd; + ds->name = name; + ds->is_active = is_active; + ds->read_only = read_only; + { + struct TALER_TESTING_Command cmd = { + .cls = ds, + .label = label, + .run = &set_officer_run, + .cleanup = &set_officer_cleanup, + .traits = &set_officer_traits + }; + + return cmd; + } +} + + +/* end of testing_api_cmd_set_officer.c */ diff --git a/src/testing/testing_api_cmd_set_wire_fee.c b/src/testing/testing_api_cmd_set_wire_fee.c index 8eb993878..460a71e40 100644 --- a/src/testing/testing_api_cmd_set_wire_fee.c +++ b/src/testing/testing_api_cmd_set_wire_fee.c @@ -61,11 +61,6 @@ struct WireFeeState const char *closing_fee; /** - * Wad fee amount to use. - */ - const char *wad_fee; - - /** * Expected HTTP response code. */ unsigned int expected_response_code; @@ -82,27 +77,21 @@ struct WireFeeState * if the response code is acceptable. * * @param cls closure. - * @param hr HTTP response details + * @param sfr response details */ static void wire_add_cb (void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr) + const struct TALER_EXCHANGE_ManagementSetWireFeeResponse *sfr) { struct WireFeeState *ds = cls; + const struct TALER_EXCHANGE_HttpResponse *hr = &sfr->hr; ds->dh = NULL; if (ds->expected_response_code != hr->http_status) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u to command %s in %s:%u\n", - hr->http_status, - ds->is->commands[ds->is->ip].label, - __FILE__, - __LINE__); - json_dumpf (hr->reply, - stderr, - 0); - TALER_TESTING_interpreter_fail (ds->is); + TALER_TESTING_unexpected_status (ds->is, + hr->http_status, + ds->expected_response_code); return; } TALER_TESTING_interpreter_next (ds->is); @@ -127,8 +116,24 @@ wire_add_run (void *cls, struct GNUNET_TIME_Timestamp start_time; struct GNUNET_TIME_Timestamp end_time; struct TALER_WireFeeSet fees; + const char *exchange_url; (void) cmd; + { + const struct TALER_TESTING_Command *exchange_cmd; + + exchange_cmd = TALER_TESTING_interpreter_get_command (is, + "exchange"); + if (NULL == exchange_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_exchange_url (exchange_cmd, + &exchange_url)); + } ds->is = is; now = GNUNET_TIME_absolute_get (); start_time = GNUNET_TIME_absolute_to_timestamp ( @@ -141,9 +146,6 @@ wire_add_run (void *cls, TALER_string_to_amount (ds->closing_fee, &fees.closing)) || (GNUNET_OK != - TALER_string_to_amount (ds->wad_fee, - &fees.wad)) || - (GNUNET_OK != TALER_string_to_amount (ds->wire_fee, &fees.wire)) ) { @@ -160,16 +162,30 @@ wire_add_run (void *cls, } else { + const struct TALER_TESTING_Command *exchange_cmd; + const struct TALER_MasterPrivateKeyP *master_priv; + + exchange_cmd = TALER_TESTING_interpreter_get_command (is, + "exchange"); + if (NULL == exchange_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_master_priv (exchange_cmd, + &master_priv)); TALER_exchange_offline_wire_fee_sign (ds->wire_method, start_time, end_time, &fees, - &is->master_priv, + master_priv, &master_sig); } ds->dh = TALER_EXCHANGE_management_set_wire_fees ( - is->ctx, - is->exchange_url, + TALER_TESTING_interpreter_get_context (is), + exchange_url, ds->wire_method, start_time, end_time, @@ -201,10 +217,8 @@ wire_add_cleanup (void *cls, if (NULL != ds->dh) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - ds->is->ip, - cmd->label); + TALER_TESTING_command_incomplete (ds->is, + cmd->label); TALER_EXCHANGE_management_set_wire_fees_cancel (ds->dh); ds->dh = NULL; } @@ -217,7 +231,6 @@ TALER_TESTING_cmd_set_wire_fee (const char *label, const char *wire_method, const char *wire_fee, const char *closing_fee, - const char *wad_fee, unsigned int expected_http_status, bool bad_sig) { @@ -229,7 +242,6 @@ TALER_TESTING_cmd_set_wire_fee (const char *label, ds->wire_method = wire_method; ds->wire_fee = wire_fee; ds->closing_fee = closing_fee; - ds->wad_fee = wad_fee; { struct TALER_TESTING_Command cmd = { .cls = ds, diff --git a/src/testing/testing_api_cmd_signal.c b/src/testing/testing_api_cmd_signal.c index b2116ebf6..be3a58bdd 100644 --- a/src/testing/testing_api_cmd_signal.c +++ b/src/testing/testing_api_cmd_signal.c @@ -62,7 +62,6 @@ signal_run (void *cls, GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Signaling '%d'..\n", ss->signal); - sleep (6); TALER_TESTING_interpreter_next (is); } diff --git a/src/testing/testing_api_cmd_stat.c b/src/testing/testing_api_cmd_stat.c index 5d41c05c9..8723aac0d 100644 --- a/src/testing/testing_api_cmd_stat.c +++ b/src/testing/testing_api_cmd_stat.c @@ -28,6 +28,19 @@ /** + * Run a "stat" CMD. + * + * @param cls closure. + * @param cmd the command being run. + * @param is the interpreter state. + */ +static void +stat_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is); + + +/** * Add the time @a cmd took to the respective duration in @a timings. * * @param timings where to add up times @@ -40,9 +53,20 @@ stat_cmd (struct TALER_TESTING_Timer *timings, struct GNUNET_TIME_Relative duration; struct GNUNET_TIME_Relative lat; - if (cmd->start_time.abs_value_us > cmd->finish_time.abs_value_us) + if (GNUNET_TIME_absolute_cmp (cmd->start_time, + >, + cmd->finish_time)) { - GNUNET_break (0); + /* This is a problem, except of course for + this command itself, as we clearly did not yet + finish... */ + if (cmd->run != &stat_run) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Bad timings for `%s'\n", + cmd->label); + GNUNET_break (0); + } return; } duration = GNUNET_TIME_absolute_get_difference (cmd->start_time, @@ -74,16 +98,18 @@ stat_cmd (struct TALER_TESTING_Timer *timings, /** * Obtain statistics for @a timings of @a cmd * - * @param timings what timings to get + * @param[in,out] cls what timings to get * @param cmd command to process */ static void -do_stat (struct TALER_TESTING_Timer *timings, +do_stat (void *cls, const struct TALER_TESTING_Command *cmd) { + struct TALER_TESTING_Timer *timings = cls; + if (TALER_TESTING_cmd_is_batch (cmd)) { - struct TALER_TESTING_Command **bcmd; + struct TALER_TESTING_Command *bcmd; if (GNUNET_OK != TALER_TESTING_get_trait_batch_cmds (cmd, @@ -92,18 +118,15 @@ do_stat (struct TALER_TESTING_Timer *timings, GNUNET_break (0); return; } - for (unsigned int j = 0; - NULL != (*bcmd)[j].label; + NULL != bcmd[j].label; j++) do_stat (timings, - &(*bcmd)[j]); - } - else - { - stat_cmd (timings, - cmd); + &bcmd[j]); + return; } + stat_cmd (timings, + cmd); } @@ -121,13 +144,10 @@ stat_run (void *cls, { struct TALER_TESTING_Timer *timings = cls; - for (unsigned int i = 0; NULL != is->commands[i].label; i++) - { - if (cmd == &is->commands[i]) - break; /* skip at our current command */ - do_stat (timings, - &is->commands[i]); - } + TALER_TESTING_iterate (is, + true, + &do_stat, + timings); TALER_TESTING_interpreter_next (is); } @@ -137,7 +157,7 @@ TALER_TESTING_cmd_stat (struct TALER_TESTING_Timer *timers) { struct TALER_TESTING_Command cmd = { .label = "stat", - .run = stat_run, + .run = &stat_run, .cls = (void *) timers }; @@ -145,4 +165,4 @@ TALER_TESTING_cmd_stat (struct TALER_TESTING_Timer *timers) } -/* end of testing_api_cmd_sleep.c */ +/* end of testing_api_cmd_stat.c */ diff --git a/src/testing/testing_api_cmd_system_start.c b/src/testing/testing_api_cmd_system_start.c new file mode 100644 index 000000000..541ad75c1 --- /dev/null +++ b/src/testing/testing_api_cmd_system_start.c @@ -0,0 +1,395 @@ +/* + 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/testing_api_cmd_system_start.c + * @brief run taler-benchmark-setup.sh command + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_json_lib.h" +#include <gnunet/gnunet_curl_lib.h> +#include "taler_signatures.h" +#include "taler_testing_lib.h" + + +/** + * State for a "system" CMD. + */ +struct SystemState +{ + + /** + * System process. + */ + struct GNUNET_OS_Process *system_proc; + + /** + * Input pipe to @e system_proc, used to keep the + * process alive until we are done. + */ + struct GNUNET_DISK_PipeHandle *pipe_in; + + /** + * Output pipe to @e system_proc, used to find out + * when the services are ready. + */ + struct GNUNET_DISK_PipeHandle *pipe_out; + + /** + * Task reading from @e pipe_in. + */ + struct GNUNET_SCHEDULER_Task *reader; + + /** + * Waiting for child to die. + */ + struct GNUNET_ChildWaitHandle *cwh; + + /** + * Our interpreter state. + */ + struct TALER_TESTING_Interpreter *is; + + /** + * NULL-terminated array of command-line arguments. + */ + char **args; + + /** + * Current input buffer, 0-terminated. Contains the last 15 bytes of input + * so we can search them again for the "<<READY>>" tag. + */ + char ibuf[16]; + + /** + * Did we find the ready tag? + */ + bool ready; + + /** + * Is the child process still running? + */ + bool active; +}; + + +/** + * Defines a GNUNET_ChildCompletedCallback which is sent back + * upon death or completion of a child process. + * + * @param cls our `struct SystemState *` + * @param type type of the process + * @param exit_code status code of the process + */ +static void +setup_terminated (void *cls, + enum GNUNET_OS_ProcessStatusType type, + long unsigned int exit_code) +{ + struct SystemState *as = cls; + + as->cwh = NULL; + as->active = false; + if (NULL != as->reader) + { + GNUNET_SCHEDULER_cancel (as->reader); + as->reader = NULL; + } + if (! as->ready) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Launching Taler system failed: %d/%llu\n", + (int) type, + (unsigned long long) exit_code); + TALER_TESTING_interpreter_fail (as->is); + return; + } +} + + +/** + * Start helper to read from stdout of child. + * + * @param as our system state + */ +static void +start_reader (struct SystemState *as); + + +static void +read_stdout (void *cls) +{ + struct SystemState *as = cls; + const struct GNUNET_DISK_FileHandle *fh; + char buf[1024 * 10]; + ssize_t ret; + size_t off = 0; + + as->reader = NULL; + strcpy (buf, + as->ibuf); + off = strlen (buf); + fh = GNUNET_DISK_pipe_handle (as->pipe_out, + GNUNET_DISK_PIPE_END_READ); + ret = GNUNET_DISK_file_read (fh, + &buf[off], + sizeof (buf) - off); + if (-1 == ret) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, + "read"); + TALER_TESTING_interpreter_fail (as->is); + return; + } + if (0 == ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Child closed stdout\n"); + return; + } + /* forward log, except single '.' outputs */ + if ( (1 != ret) || + ('.' != buf[off]) ) + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "TUS: %.*s\n", + (int) ret, + &buf[off]); + start_reader (as); + off += ret; + if (as->ready) + { + /* already done */ + return; + } + if (NULL != + memmem (buf, + off, + "\n<<READY>>\n", + strlen ("\n<<READY>>\n"))) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Taler system UP\n"); + as->ready = true; + TALER_TESTING_interpreter_next (as->is); + return; + } + + { + size_t mcpy; + + mcpy = GNUNET_MIN (off, + sizeof (as->ibuf) - 1); + memcpy (as->ibuf, + &buf[off - mcpy], + mcpy); + as->ibuf[mcpy] = '\0'; + } +} + + +static void +start_reader (struct SystemState *as) +{ + const struct GNUNET_DISK_FileHandle *fh; + + GNUNET_assert (NULL == as->reader); + fh = GNUNET_DISK_pipe_handle (as->pipe_out, + GNUNET_DISK_PIPE_END_READ); + as->reader = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, + fh, + &read_stdout, + as); +} + + +/** + * Run the command. Use the `taler-exchange-system' program. + * + * @param cls closure. + * @param cmd command being run. + * @param is interpreter state. + */ +static void +system_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct SystemState *as = cls; + + (void) cmd; + as->is = is; + as->pipe_in = GNUNET_DISK_pipe (GNUNET_DISK_PF_BLOCKING_READ); + GNUNET_assert (NULL != as->pipe_in); + as->pipe_out = GNUNET_DISK_pipe (GNUNET_DISK_PF_NONE); + GNUNET_assert (NULL != as->pipe_out); + as->system_proc + = GNUNET_OS_start_process_vap ( + GNUNET_OS_INHERIT_STD_ERR, + as->pipe_in, as->pipe_out, NULL, + "taler-unified-setup.sh", + as->args); + if (NULL == as->system_proc) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + as->active = true; + start_reader (as); + as->cwh = GNUNET_wait_child (as->system_proc, + &setup_terminated, + as); +} + + +/** + * Free the state of a "system" CMD, and possibly kill its + * process if it did not terminate correctly. + * + * @param cls closure. + * @param cmd the command being freed. + */ +static void +system_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct SystemState *as = cls; + + (void) cmd; + if (NULL != as->cwh) + { + GNUNET_wait_child_cancel (as->cwh); + as->cwh = NULL; + } + if (NULL != as->reader) + { + GNUNET_SCHEDULER_cancel (as->reader); + as->reader = NULL; + } + if (NULL != as->system_proc) + { + if (as->active) + { + GNUNET_break (0 == + GNUNET_OS_process_kill (as->system_proc, + SIGTERM)); + GNUNET_OS_process_wait (as->system_proc); + } + GNUNET_OS_process_destroy (as->system_proc); + as->system_proc = NULL; + } + if (NULL != as->pipe_in) + { + GNUNET_break (GNUNET_OK == + GNUNET_DISK_pipe_close (as->pipe_in)); + as->pipe_in = NULL; + } + if (NULL != as->pipe_out) + { + GNUNET_break (GNUNET_OK == + GNUNET_DISK_pipe_close (as->pipe_out)); + as->pipe_out = NULL; + } + + for (unsigned int i = 0; NULL != as->args[i]; i++) + GNUNET_free (as->args[i]); + GNUNET_free (as->args); + GNUNET_free (as); +} + + +/** + * Offer "system" CMD internal data to other commands. + * + * @param cls closure. + * @param[out] ret result. + * @param trait name of the trait. + * @param index index number of the object to offer. + * @return #GNUNET_OK on success + */ +static enum GNUNET_GenericReturnValue +system_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + struct SystemState *as = cls; + struct TALER_TESTING_Trait traits[] = { + TALER_TESTING_make_trait_process (&as->system_proc), + TALER_TESTING_trait_end () + }; + + return TALER_TESTING_get_trait (traits, + ret, + trait, + index); +} + + +struct TALER_TESTING_Command +TALER_TESTING_cmd_system_start ( + const char *label, + const char *config_file, + ...) +{ + struct SystemState *as; + va_list ap; + const char *arg; + unsigned int cnt; + + as = GNUNET_new (struct SystemState); + cnt = 4; /* 0-2 reserved, +1 for NULL termination */ + va_start (ap, + config_file); + while (NULL != (arg = va_arg (ap, + const char *))) + { + cnt++; + } + va_end (ap); + as->args = GNUNET_new_array (cnt, + char *); + as->args[0] = GNUNET_strdup ("taler-unified-setup"); + as->args[1] = GNUNET_strdup ("-c"); + as->args[2] = GNUNET_strdup (config_file); + cnt = 3; + va_start (ap, + config_file); + while (NULL != (arg = va_arg (ap, + const char *))) + { + as->args[cnt++] = GNUNET_strdup (arg); + } + va_end (ap); + + { + struct TALER_TESTING_Command cmd = { + .cls = as, + .label = label, + .run = &system_run, + .cleanup = &system_cleanup, + .traits = &system_traits + }; + + return cmd; + } +} + + +/* end of testing_api_cmd_system_start.c */ diff --git a/src/testing/testing_api_cmd_take_aml_decision.c b/src/testing/testing_api_cmd_take_aml_decision.c new file mode 100644 index 000000000..c0e23de22 --- /dev/null +++ b/src/testing/testing_api_cmd_take_aml_decision.c @@ -0,0 +1,321 @@ +/* + 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/testing_api_cmd_take_aml_decision.c + * @brief command for testing /aml/$OFFICER_PUB/decision + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_json_lib.h" +#include <gnunet/gnunet_curl_lib.h> +#include "taler_testing_lib.h" +#include "taler_signatures.h" +#include "backoff.h" + + +/** + * State for a "take_aml_decision" CMD. + */ +struct AmlDecisionState +{ + + /** + * Auditor enable handle while operation is running. + */ + struct TALER_EXCHANGE_AddAmlDecision *dh; + + /** + * Our interpreter. + */ + struct TALER_TESTING_Interpreter *is; + + /** + * Reference to command to previous set officer command that gives + * us an officer_priv trait. + */ + const char *officer_ref_cmd; + + /** + * Reference to command to previous AML-triggering event that gives + * us a payto-hash trait. + */ + const char *account_ref_cmd; + + /** + * Payto hash of the account we are manipulating the AML settings for. + */ + struct TALER_PaytoHashP h_payto; + + /** + * New AML state to use. + */ + enum TALER_AmlDecisionState new_state; + + /** + * Justification given. + */ + const char *justification; + + /** + * KYC requirement to add. + */ + const char *kyc_requirement; + + /** + * Threshold transaction amount. + */ + struct TALER_Amount new_threshold; + + /** + * Expected response code. + */ + unsigned int expected_response; +}; + + +/** + * Callback to analyze the /aml-decision/$OFFICER_PUB response, just used to check + * if the response code is acceptable. + * + * @param cls closure. + * @param adr response details + */ +static void +take_aml_decision_cb ( + void *cls, + const struct TALER_EXCHANGE_AddAmlDecisionResponse *adr) +{ + struct AmlDecisionState *ds = cls; + const struct TALER_EXCHANGE_HttpResponse *hr = &adr->hr; + + ds->dh = NULL; + if (ds->expected_response != hr->http_status) + { + TALER_TESTING_unexpected_status (ds->is, + hr->http_status, + ds->expected_response); + return; + } + TALER_TESTING_interpreter_next (ds->is); +} + + +/** + * Run the command. + * + * @param cls closure. + * @param cmd the command to execute. + * @param is the interpreter state. + */ +static void +take_aml_decision_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct AmlDecisionState *ds = cls; + struct GNUNET_TIME_Timestamp now; + const struct TALER_PaytoHashP *h_payto; + const struct TALER_AmlOfficerPrivateKeyP *officer_priv; + const struct TALER_TESTING_Command *ref; + json_t *kyc_requirements = NULL; + const char *exchange_url; + + (void) cmd; + { + const struct TALER_TESTING_Command *exchange_cmd; + + exchange_cmd = TALER_TESTING_interpreter_get_command (is, + "exchange"); + if (NULL == exchange_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_exchange_url (exchange_cmd, + &exchange_url)); + } + now = GNUNET_TIME_timestamp_get (); + ds->is = is; + ref = TALER_TESTING_interpreter_lookup_command (is, + ds->account_ref_cmd); + if (NULL == ref) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + if (GNUNET_OK != + TALER_TESTING_get_trait_h_payto (ref, + &h_payto)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + ref = TALER_TESTING_interpreter_lookup_command (is, + ds->officer_ref_cmd); + if (NULL == ref) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + if (GNUNET_OK != + TALER_TESTING_get_trait_officer_priv (ref, + &officer_priv)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + ds->h_payto = *h_payto; + if (NULL != ds->kyc_requirement) + { + kyc_requirements = json_array (); + GNUNET_assert (NULL != kyc_requirements); + GNUNET_assert (0 == + json_array_append (kyc_requirements, + json_string (ds->kyc_requirement))); + } + + ds->dh = TALER_EXCHANGE_add_aml_decision ( + TALER_TESTING_interpreter_get_context (is), + exchange_url, + ds->justification, + now, + &ds->new_threshold, + h_payto, + ds->new_state, + kyc_requirements, + officer_priv, + &take_aml_decision_cb, + ds); + json_decref (kyc_requirements); + if (NULL == ds->dh) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } +} + + +/** + * Free the state of a "take_aml_decision" CMD, and possibly cancel a + * pending operation thereof. + * + * @param cls closure, must be a `struct AmlDecisionState`. + * @param cmd the command which is being cleaned up. + */ +static void +take_aml_decision_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct AmlDecisionState *ds = cls; + + if (NULL != ds->dh) + { + TALER_TESTING_command_incomplete (ds->is, + cmd->label); + TALER_EXCHANGE_add_aml_decision_cancel (ds->dh); + ds->dh = NULL; + } + GNUNET_free (ds); +} + + +/** + * Offer internal data of a "AML decision" CMD state to other + * commands. + * + * @param cls closure + * @param[out] ret result (could be anything) + * @param trait name of the trait + * @param index index number of the object to offer. + * @return #GNUNET_OK on success + */ +static enum GNUNET_GenericReturnValue +take_aml_decision_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + struct AmlDecisionState *ws = cls; + struct TALER_TESTING_Trait traits[] = { + TALER_TESTING_make_trait_h_payto (&ws->h_payto), + TALER_TESTING_make_trait_aml_justification (ws->justification), + TALER_TESTING_make_trait_aml_decision (&ws->new_state), + TALER_TESTING_make_trait_amount (&ws->new_threshold), + TALER_TESTING_trait_end () + }; + + return TALER_TESTING_get_trait (traits, + ret, + trait, + index); +} + + +struct TALER_TESTING_Command +TALER_TESTING_cmd_take_aml_decision ( + const char *label, + const char *ref_officer, + const char *ref_operation, + const char *new_threshold, + const char *justification, + enum TALER_AmlDecisionState new_state, + const char *kyc_requirement, + unsigned int expected_response) +{ + struct AmlDecisionState *ds; + + ds = GNUNET_new (struct AmlDecisionState); + ds->officer_ref_cmd = ref_officer; + ds->account_ref_cmd = ref_operation; + ds->kyc_requirement = kyc_requirement; + if (GNUNET_OK != + TALER_string_to_amount (new_threshold, + &ds->new_threshold)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to parse amount `%s' at %s\n", + new_threshold, + label); + GNUNET_assert (0); + } + ds->new_state = new_state; + ds->justification = justification; + ds->expected_response = expected_response; + { + struct TALER_TESTING_Command cmd = { + .cls = ds, + .label = label, + .run = &take_aml_decision_run, + .cleanup = &take_aml_decision_cleanup, + .traits = &take_aml_decision_traits + }; + + return cmd; + } +} + + +/* end of testing_api_cmd_take_aml_decision.c */ diff --git a/src/testing/testing_api_cmd_transfer_get.c b/src/testing/testing_api_cmd_transfer_get.c index 3c467e6da..405c8b7f9 100644 --- a/src/testing/testing_api_cmd_transfer_get.c +++ b/src/testing/testing_api_cmd_transfer_get.c @@ -44,6 +44,11 @@ struct TrackTransferState const char *expected_wire_fee; /** + * Our command. + */ + const struct TALER_TESTING_Command *cmd; + + /** * Reference to any operation that can provide a WTID. * Will be the WTID to track. */ @@ -98,10 +103,8 @@ track_transfer_cleanup (void *cls, if (NULL != tts->tth) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - tts->is->ip, - cmd->label); + TALER_TESTING_command_incomplete (tts->is, + cmd->label); TALER_EXCHANGE_transfers_get_cancel (tts->tth); tts->tth = NULL; } @@ -115,180 +118,178 @@ track_transfer_cleanup (void *cls, * wire fees and hashed wire details as well. * * @param cls closure. - * @param hr HTTP response details - * @param ta transfer data returned by the exchange + * @param tgr response details */ static void track_transfer_cb (void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr, - const struct TALER_EXCHANGE_TransferData *ta) + const struct TALER_EXCHANGE_TransfersGetResponse *tgr) { struct TrackTransferState *tts = cls; + const struct TALER_EXCHANGE_HttpResponse *hr = &tgr->hr; struct TALER_TESTING_Interpreter *is = tts->is; - struct TALER_TESTING_Command *cmd = &is->commands[is->ip]; struct TALER_Amount expected_amount; tts->tth = NULL; if (tts->expected_response_code != hr->http_status) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u/%d to command %s in %s:%u\n", - hr->http_status, - (int) hr->ec, - cmd->label, - __FILE__, - __LINE__); - json_dumpf (hr->reply, - stderr, - 0); - TALER_TESTING_interpreter_fail (is); + TALER_TESTING_unexpected_status (is, + hr->http_status, + tts->expected_response_code); return; } switch (hr->http_status) { case MHD_HTTP_OK: - if (NULL == tts->expected_total_amount) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - if (NULL == tts->expected_wire_fee) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - - if (GNUNET_OK != - TALER_string_to_amount (tts->expected_total_amount, - &expected_amount)) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - if (0 != TALER_amount_cmp (&ta->total_amount, - &expected_amount)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Total amount mismatch to command %s - " - "%s vs %s\n", - cmd->label, - TALER_amount_to_string (&ta->total_amount), - TALER_amount_to_string (&expected_amount)); - json_dumpf (hr->reply, - stderr, - 0); - fprintf (stderr, "\n"); - TALER_TESTING_interpreter_fail (is); - return; - } - - if (GNUNET_OK != - TALER_string_to_amount (tts->expected_wire_fee, - &expected_amount)) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - - if (0 != TALER_amount_cmp (&ta->wire_fee, - &expected_amount)) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Wire fee mismatch to command %s\n", - cmd->label); - json_dumpf (hr->reply, - stderr, - 0); - TALER_TESTING_interpreter_fail (is); - return; - } + const struct TALER_EXCHANGE_TransferData *ta + = &tgr->details.ok.td; - /** - * Optionally checking: (1) wire-details for this transfer - * match the ones from a referenced "deposit" operation - - * or any operation that could provide wire-details. (2) - * Total amount for this transfer matches the one from any - * referenced command that could provide one. - */ - if (NULL != tts->wire_details_reference) - { - const struct TALER_TESTING_Command *wire_details_cmd; - const char **payto_uri; - struct TALER_PaytoHashP h_payto; - - wire_details_cmd - = TALER_TESTING_interpreter_lookup_command (is, - tts->wire_details_reference); - if (NULL == wire_details_cmd) + if (NULL == tts->expected_total_amount) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + if (NULL == tts->expected_wire_fee) { GNUNET_break (0); TALER_TESTING_interpreter_fail (is); return; } + if (GNUNET_OK != - TALER_TESTING_get_trait_payto_uri (wire_details_cmd, - &payto_uri)) + TALER_string_to_amount (tts->expected_total_amount, + &expected_amount)) { GNUNET_break (0); TALER_TESTING_interpreter_fail (is); return; } - TALER_payto_hash (*payto_uri, - &h_payto); - if (0 != GNUNET_memcmp (&h_payto, - &ta->h_payto)) + if (0 != TALER_amount_cmp (&ta->total_amount, + &expected_amount)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Wire hash missmath to command %s\n", - cmd->label); + "Total amount mismatch to command %s - " + "%s vs %s\n", + tts->cmd->label, + TALER_amount_to_string (&ta->total_amount), + TALER_amount_to_string (&expected_amount)); json_dumpf (hr->reply, stderr, 0); + fprintf (stderr, "\n"); TALER_TESTING_interpreter_fail (is); return; } - } - if (NULL != tts->total_amount_reference) - { - const struct TALER_TESTING_Command *total_amount_cmd; - const struct TALER_Amount *total_amount_from_reference; - total_amount_cmd - = TALER_TESTING_interpreter_lookup_command (is, - tts->total_amount_reference); - if (NULL == total_amount_cmd) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } if (GNUNET_OK != - TALER_TESTING_get_trait_amount (total_amount_cmd, - &total_amount_from_reference)) + TALER_string_to_amount (tts->expected_wire_fee, + &expected_amount)) { GNUNET_break (0); TALER_TESTING_interpreter_fail (is); return; } - if (0 != TALER_amount_cmp (&ta->total_amount, - total_amount_from_reference)) + + if (0 != TALER_amount_cmp (&ta->wire_fee, + &expected_amount)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Amount missmath to command %s\n", - cmd->label); + "Wire fee mismatch to command %s\n", + tts->cmd->label); json_dumpf (hr->reply, stderr, 0); TALER_TESTING_interpreter_fail (is); return; } - } - } + + /** + * Optionally checking: (1) wire-details for this transfer + * match the ones from a referenced "deposit" operation - + * or any operation that could provide wire-details. (2) + * Total amount for this transfer matches the one from any + * referenced command that could provide one. + */ + if (NULL != tts->wire_details_reference) + { + const struct TALER_TESTING_Command *wire_details_cmd; + const char *payto_uri; + struct TALER_PaytoHashP h_payto; + + wire_details_cmd + = TALER_TESTING_interpreter_lookup_command (is, + tts-> + wire_details_reference); + if (NULL == wire_details_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + if (GNUNET_OK != + TALER_TESTING_get_trait_payto_uri (wire_details_cmd, + &payto_uri)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + TALER_payto_hash (payto_uri, + &h_payto); + if (0 != GNUNET_memcmp (&h_payto, + &ta->h_payto)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Wire hash missmath to command %s\n", + tts->cmd->label); + json_dumpf (hr->reply, + stderr, + 0); + TALER_TESTING_interpreter_fail (is); + return; + } + } + if (NULL != tts->total_amount_reference) + { + const struct TALER_TESTING_Command *total_amount_cmd; + const struct TALER_Amount *total_amount_from_reference; + + total_amount_cmd + = TALER_TESTING_interpreter_lookup_command (is, + tts-> + total_amount_reference); + if (NULL == total_amount_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + if (GNUNET_OK != + TALER_TESTING_get_trait_amount (total_amount_cmd, + &total_amount_from_reference)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + if (0 != TALER_amount_cmp (&ta->total_amount, + total_amount_from_reference)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Amount mismatch in command %s\n", + tts->cmd->label); + json_dumpf (hr->reply, + stderr, + 0); + TALER_TESTING_interpreter_fail (is); + return; + } + } + break; + } /* case OK */ + } /* switch on status */ TALER_TESTING_interpreter_next (is); } @@ -310,13 +311,13 @@ track_transfer_run (void *cls, struct TALER_WireTransferIdentifierRawP wtid; const struct TALER_WireTransferIdentifierRawP *wtid_ptr; + tts->cmd = cmd; /* If no reference is given, we'll use a all-zeros * WTID */ memset (&wtid, 0, sizeof (wtid)); wtid_ptr = &wtid; - tts->is = is; if (NULL != tts->wtid_reference) { @@ -341,10 +342,13 @@ track_transfer_run (void *cls, } GNUNET_assert (NULL != wtid_ptr); } - tts->tth = TALER_EXCHANGE_transfers_get (is->exchange, - wtid_ptr, - &track_transfer_cb, - tts); + tts->tth = TALER_EXCHANGE_transfers_get ( + TALER_TESTING_interpreter_get_context (is), + TALER_TESTING_get_exchange_url (is), + TALER_TESTING_get_keys (is), + wtid_ptr, + &track_transfer_cb, + tts); GNUNET_assert (NULL != tts->tth); } diff --git a/src/testing/testing_api_cmd_twister_exec_client.c b/src/testing/testing_api_cmd_twister_exec_client.c index d1d781f5a..bf83c1f80 100644 --- a/src/testing/testing_api_cmd_twister_exec_client.c +++ b/src/testing/testing_api_cmd_twister_exec_client.c @@ -572,7 +572,7 @@ flip_object_cleanup * @param index index number of the object to offer. * @return #GNUNET_OK on success */ -static int +static enum GNUNET_GenericReturnValue flip_object_traits (void *cls, const void **ret, const char *trait, diff --git a/src/testing/testing_api_cmd_wire.c b/src/testing/testing_api_cmd_wire.c index 4b0a177b5..41ff7a978 100644 --- a/src/testing/testing_api_cmd_wire.c +++ b/src/testing/testing_api_cmd_wire.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2018 Taler Systems SA + Copyright (C) 2018, 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 @@ -39,6 +39,11 @@ struct WireState struct TALER_EXCHANGE_WireHandle *wh; /** + * Our command. + */ + const struct TALER_TESTING_Command *cmd; + + /** * Which wire-method we expect is offered by the exchange. */ const char *expected_method; @@ -72,19 +77,14 @@ struct WireState * that the wire fee is acceptable too. * * @param cls closure. - * @param hr HTTP response details - * @param accounts_len length of the @a accounts array. - * @param accounts list of wire accounts of the exchange, - * NULL on error. + * @param wr response details */ static void wire_cb (void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr, - unsigned int accounts_len, - const struct TALER_EXCHANGE_WireAccount *accounts) + const struct TALER_EXCHANGE_WireResponse *wr) { struct WireState *ws = cls; - struct TALER_TESTING_Command *cmd = &ws->is->commands[ws->is->ip]; + const struct TALER_EXCHANGE_HttpResponse *hr = &wr->hr; struct TALER_Amount expected_fee; TALER_LOG_DEBUG ("Checking parsed /wire response\n"); @@ -100,41 +100,70 @@ wire_cb (void *cls, if (MHD_HTTP_OK == hr->http_status) { + unsigned int accounts_len + = wr->details.ok.accounts_len; + unsigned int fees_len + = wr->details.ok.fees_len; + const struct TALER_EXCHANGE_WireAccount *accounts + = wr->details.ok.accounts; + const struct TALER_EXCHANGE_WireFeesByMethod *fees + = wr->details.ok.fees; + for (unsigned int i = 0; i<accounts_len; i++) { char *method; method = TALER_payto_get_method (accounts[i].payto_uri); + if (NULL == method) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (ws->is); + return; + } if (0 == strcmp (ws->expected_method, method)) { ws->method_found = GNUNET_OK; - if (NULL != ws->expected_fee) + } + GNUNET_free (method); + } + if (NULL != ws->expected_fee) + { + bool fee_found = false; + + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (ws->expected_fee, + &expected_fee)); + for (unsigned int i = 0; i<fees_len; i++) + { + if (0 != strcmp (fees[i].method, + ws->expected_method)) + continue; + for (const struct TALER_EXCHANGE_WireAggregateFees *waf + = fees[i].fees_head; + NULL != waf; + waf = waf->next) { - GNUNET_assert (GNUNET_OK == - TALER_string_to_amount (ws->expected_fee, - &expected_fee)); - for (const struct TALER_EXCHANGE_WireAggregateFees *waf - = accounts[i].fees; - NULL != waf; - waf = waf->next) + if (0 != TALER_amount_cmp (&waf->fees.wire, + &expected_fee)) { - if (0 != TALER_amount_cmp (&waf->fees.wire, - &expected_fee)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Wire fee mismatch to command %s\n", - cmd->label); - TALER_TESTING_interpreter_fail (ws->is); - GNUNET_free (method); - return; - } + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Wire fee mismatch to command %s\n", + ws->cmd->label); + TALER_TESTING_interpreter_fail (ws->is); + return; } + fee_found = true; } } - TALER_LOG_DEBUG ("Freeing method '%s'\n", - method); - GNUNET_free (method); + if (! fee_found) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "/wire does not contain expected fee '%s'\n", + ws->expected_fee); + TALER_TESTING_interpreter_fail (ws->is); + return; + } } if (GNUNET_OK != ws->method_found) { @@ -163,11 +192,14 @@ wire_run (void *cls, { struct WireState *ws = cls; - (void) cmd; + ws->cmd = cmd; ws->is = is; - ws->wh = TALER_EXCHANGE_wire (is->exchange, - &wire_cb, - ws); + ws->wh = TALER_EXCHANGE_wire ( + TALER_TESTING_interpreter_get_context (is), + TALER_TESTING_get_exchange_url (is), + TALER_TESTING_get_keys (is), + &wire_cb, + ws); } @@ -186,10 +218,8 @@ wire_cleanup (void *cls, if (NULL != ws->wh) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - ws->is->ip, - cmd->label); + TALER_TESTING_command_incomplete (ws->is, + cmd->label); TALER_EXCHANGE_wire_cancel (ws->wh); ws->wh = NULL; } @@ -197,17 +227,6 @@ wire_cleanup (void *cls, } -/** - * Create a "wire" command. - * - * @param label the command label. - * @param expected_method which wire-transfer method is expected - * to be offered by the exchange. - * @param expected_fee the fee the exchange should charge. - * @param expected_response_code the HTTP response the exchange - * should return. - * @return the command. - */ struct TALER_TESTING_Command TALER_TESTING_cmd_wire (const char *label, const char *expected_method, diff --git a/src/testing/testing_api_cmd_wire_add.c b/src/testing/testing_api_cmd_wire_add.c index c07e9bba6..d2a15894a 100644 --- a/src/testing/testing_api_cmd_wire_add.c +++ b/src/testing/testing_api_cmd_wire_add.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2020 Taler Systems SA + Copyright (C) 2020-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 @@ -67,27 +67,21 @@ struct WireAddState * if the response code is acceptable. * * @param cls closure. - * @param hr HTTP response details + * @param wer response details */ static void wire_add_cb (void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr) + const struct TALER_EXCHANGE_ManagementWireEnableResponse *wer) { struct WireAddState *ds = cls; + const struct TALER_EXCHANGE_HttpResponse *hr = &wer->hr; ds->dh = NULL; if (ds->expected_response_code != hr->http_status) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u to command %s in %s:%u\n", - hr->http_status, - ds->is->commands[ds->is->ip].label, - __FILE__, - __LINE__); - json_dumpf (hr->reply, - stderr, - 0); - TALER_TESTING_interpreter_fail (ds->is); + TALER_TESTING_unexpected_status (ds->is, + hr->http_status, + ds->expected_response_code); return; } TALER_TESTING_interpreter_next (ds->is); @@ -110,10 +104,30 @@ wire_add_run (void *cls, struct TALER_MasterSignatureP master_sig1; struct TALER_MasterSignatureP master_sig2; struct GNUNET_TIME_Timestamp now; + json_t *credit_rest; + json_t *debit_rest; + const char *exchange_url; (void) cmd; + { + const struct TALER_TESTING_Command *exchange_cmd; + + exchange_cmd = TALER_TESTING_interpreter_get_command (is, + "exchange"); + if (NULL == exchange_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_exchange_url (exchange_cmd, + &exchange_url)); + } now = GNUNET_TIME_timestamp_get (); ds->is = is; + debit_rest = json_array (); + credit_rest = json_array (); if (ds->bad_sig) { memset (&master_sig1, @@ -125,23 +139,50 @@ wire_add_run (void *cls, } else { + const struct TALER_TESTING_Command *exchange_cmd; + const struct TALER_MasterPrivateKeyP *master_priv; + + exchange_cmd = TALER_TESTING_interpreter_get_command (is, + "exchange"); + if (NULL == exchange_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_master_priv (exchange_cmd, + &master_priv)); TALER_exchange_offline_wire_add_sign (ds->payto_uri, + NULL, + debit_rest, + credit_rest, now, - &is->master_priv, + master_priv, &master_sig1); TALER_exchange_wire_signature_make (ds->payto_uri, - &is->master_priv, + NULL, + debit_rest, + credit_rest, + master_priv, &master_sig2); } ds->dh = TALER_EXCHANGE_management_enable_wire ( - is->ctx, - is->exchange_url, + TALER_TESTING_interpreter_get_context (is), + exchange_url, ds->payto_uri, + NULL, + debit_rest, + credit_rest, now, &master_sig1, &master_sig2, + NULL, + 0LL, &wire_add_cb, ds); + json_decref (debit_rest); + json_decref (credit_rest); if (NULL == ds->dh) { GNUNET_break (0); @@ -166,10 +207,8 @@ wire_add_cleanup (void *cls, if (NULL != ds->dh) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - ds->is->ip, - cmd->label); + TALER_TESTING_command_incomplete (ds->is, + cmd->label); TALER_EXCHANGE_management_enable_wire_cancel (ds->dh); ds->dh = NULL; } diff --git a/src/testing/testing_api_cmd_wire_del.c b/src/testing/testing_api_cmd_wire_del.c index 15d29d727..50ebfc7cb 100644 --- a/src/testing/testing_api_cmd_wire_del.c +++ b/src/testing/testing_api_cmd_wire_del.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2020 Taler Systems SA + Copyright (C) 2020, 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 @@ -67,27 +67,22 @@ struct WireDelState * if the response code is acceptable. * * @param cls closure. - * @param hr HTTP response details + * @param wdr response details */ static void wire_del_cb (void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr) + const struct TALER_EXCHANGE_ManagementWireDisableResponse *wdr) { struct WireDelState *ds = cls; + const struct TALER_EXCHANGE_HttpResponse *hr = &wdr->hr; ds->dh = NULL; if (ds->expected_response_code != hr->http_status) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u to command %s in %s:%u\n", - hr->http_status, - ds->is->commands[ds->is->ip].label, - __FILE__, - __LINE__); - json_dumpf (hr->reply, - stderr, - 0); - TALER_TESTING_interpreter_fail (ds->is); + TALER_TESTING_unexpected_status (ds->is, + hr->http_status, + ds->expected_response_code); + return; } TALER_TESTING_interpreter_next (ds->is); @@ -109,8 +104,24 @@ wire_del_run (void *cls, struct WireDelState *ds = cls; struct TALER_MasterSignatureP master_sig; struct GNUNET_TIME_Timestamp now; + const char *exchange_url; (void) cmd; + { + const struct TALER_TESTING_Command *exchange_cmd; + + exchange_cmd = TALER_TESTING_interpreter_get_command (is, + "exchange"); + if (NULL == exchange_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_exchange_url (exchange_cmd, + &exchange_url)); + } now = GNUNET_TIME_timestamp_get (); ds->is = is; if (ds->bad_sig) @@ -121,14 +132,28 @@ wire_del_run (void *cls, } else { + const struct TALER_TESTING_Command *exchange_cmd; + const struct TALER_MasterPrivateKeyP *master_priv; + + exchange_cmd = TALER_TESTING_interpreter_get_command (is, + "exchange"); + if (NULL == exchange_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_master_priv (exchange_cmd, + &master_priv)); TALER_exchange_offline_wire_del_sign (ds->payto_uri, now, - &is->master_priv, + master_priv, &master_sig); } ds->dh = TALER_EXCHANGE_management_disable_wire ( - is->ctx, - is->exchange_url, + TALER_TESTING_interpreter_get_context (is), + exchange_url, ds->payto_uri, now, &master_sig, @@ -158,10 +183,8 @@ wire_del_cleanup (void *cls, if (NULL != ds->dh) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - ds->is->ip, - cmd->label); + TALER_TESTING_command_incomplete (ds->is, + cmd->label); TALER_EXCHANGE_management_disable_wire_cancel (ds->dh); ds->dh = NULL; } diff --git a/src/testing/testing_api_cmd_withdraw.c b/src/testing/testing_api_cmd_withdraw.c index 6b77a35e7..f8ff0205b 100644 --- a/src/testing/testing_api_cmd_withdraw.c +++ b/src/testing/testing_api_cmd_withdraw.c @@ -62,11 +62,16 @@ struct WithdrawState /** * Reference to a withdraw or reveal operation from which we should - * re-use the private coin key, or NULL for regular withdrawal. + * reuse the private coin key, or NULL for regular withdrawal. */ const char *reuse_coin_key_ref; /** + * Our command. + */ + const struct TALER_TESTING_Command *cmd; + + /** * 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. @@ -108,7 +113,7 @@ struct WithdrawState /** * Blinding key used during the operation. */ - union TALER_DenominationBlindingKeyP bks; + union GNUNET_CRYPTO_BlindingSecretP bks; /** * Values contributed from the exchange during the @@ -139,10 +144,10 @@ struct WithdrawState /** * If age > 0, put here the corresponding age commitment with its proof and - * its hash, respectivelly, NULL otherwise. + * its hash, respectively. */ - struct TALER_AgeCommitmentProof *age_commitment_proof; - struct TALER_AgeCommitmentHash *h_age_commitment; + struct TALER_AgeCommitmentProof age_commitment_proof; + struct TALER_AgeCommitmentHash h_age_commitment; /** * Reserve history entry that corresponds to this operation. @@ -153,7 +158,7 @@ struct WithdrawState /** * Withdraw handle (while operation is running). */ - struct TALER_EXCHANGE_WithdrawHandle *wsh; + struct TALER_EXCHANGE_BatchWithdrawHandle *wsh; /** * Task scheduled to try later. @@ -171,10 +176,16 @@ struct WithdrawState struct GNUNET_TIME_Relative total_backoff; /** - * Set to the KYC UUID *if* the exchange replied with + * Set to the KYC requirement payto hash *if* the exchange replied with a + * request for KYC. + */ + struct TALER_PaytoHashP h_payto; + + /** + * Set to the KYC requirement row *if* the exchange replied with * a request for KYC. */ - uint64_t kyc_uuid; + uint64_t requirement_row; /** * Expected HTTP response code to the request. @@ -214,8 +225,7 @@ do_retry (void *cls) struct WithdrawState *ws = cls; ws->retry_task = NULL; - ws->is->commands[ws->is->ip].last_req_time - = GNUNET_TIME_absolute_get (); + TALER_TESTING_touch_cmd (ws->is); withdraw_run (ws, NULL, ws->is); @@ -232,7 +242,7 @@ do_retry (void *cls) */ static void reserve_withdraw_cb (void *cls, - const struct TALER_EXCHANGE_WithdrawResponse *wr) + const struct TALER_EXCHANGE_BatchWithdrawResponse *wr) { struct WithdrawState *ws = cls; struct TALER_TESTING_Interpreter *is = ws->is; @@ -266,48 +276,38 @@ reserve_withdraw_cb (void *cls, UNKNOWN_MAX_BACKOFF); ws->total_backoff = GNUNET_TIME_relative_add (ws->total_backoff, ws->backoff); - ws->is->commands[ws->is->ip].num_tries++; + TALER_TESTING_inc_tries (ws->is); ws->retry_task = GNUNET_SCHEDULER_add_delayed (ws->backoff, &do_retry, ws); return; } } - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u/%d to command %s in %s:%u\n", - wr->hr.http_status, - (int) wr->hr.ec, - TALER_TESTING_interpreter_get_current_label (is), - __FILE__, - __LINE__); - json_dumpf (wr->hr.reply, - stderr, - 0); - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); + TALER_TESTING_unexpected_status_with_body (is, + wr->hr.http_status, + ws->expected_response_code, + wr->hr.reply); return; } switch (wr->hr.http_status) { case MHD_HTTP_OK: - TALER_denom_sig_deep_copy (&ws->sig, - &wr->details.success.sig); - ws->coin_priv = wr->details.success.coin_priv; - ws->bks = wr->details.success.bks; - ws->exchange_vals = wr->details.success.exchange_vals; + GNUNET_assert (1 == wr->details.ok.num_coins); + TALER_denom_sig_copy (&ws->sig, + &wr->details.ok.coins[0].sig); + ws->coin_priv = wr->details.ok.coins[0].coin_priv; + ws->bks = wr->details.ok.coins[0].bks; + TALER_denom_ewv_copy (&ws->exchange_vals, + &wr->details.ok.coins[0].exchange_vals); if (0 != ws->total_backoff.rel_value_us) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Total withdraw backoff for %s was %s\n", - is->commands[is->ip].label, + ws->cmd->label, GNUNET_STRINGS_relative_time_to_string (ws->total_backoff, - GNUNET_YES)); + true)); } break; - case MHD_HTTP_ACCEPTED: - /* nothing to check */ - ws->kyc_uuid = wr->details.accepted.payment_target_uuid; - break; case MHD_HTTP_FORBIDDEN: /* nothing to check */ break; @@ -322,6 +322,10 @@ reserve_withdraw_cb (void *cls, break; case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS: /* KYC required */ + ws->requirement_row = + wr->details.unavailable_for_legal_reasons.requirement_row; + ws->h_payto + = wr->details.unavailable_for_legal_reasons.h_payto; break; default: /* Unsupported status code (by test harness) */ @@ -348,20 +352,19 @@ withdraw_run (void *cls, const struct TALER_TESTING_Command *create_reserve; const struct TALER_EXCHANGE_DenomPublicKey *dpk; - (void) cmd; + if (NULL != cmd) + ws->cmd = cmd; ws->is = is; create_reserve = TALER_TESTING_interpreter_lookup_command ( is, ws->reserve_reference); - if (NULL == create_reserve) { GNUNET_break (0); TALER_TESTING_interpreter_fail (is); return; } - if (GNUNET_OK != TALER_TESTING_get_trait_reserve_priv (create_reserve, &rp)) @@ -370,10 +373,9 @@ withdraw_run (void *cls, TALER_TESTING_interpreter_fail (is); return; } - if (NULL == ws->exchange_url) ws->exchange_url - = GNUNET_strdup (TALER_EXCHANGE_get_base_url (is->exchange)); + = GNUNET_strdup (TALER_TESTING_get_exchange_url (is)); ws->reserve_priv = *rp; GNUNET_CRYPTO_eddsa_key_get_public (&ws->reserve_priv.eddsa_priv, &ws->reserve_pub.eddsa_pub); @@ -409,7 +411,7 @@ withdraw_run (void *cls, if (NULL == ws->pk) { - dpk = TALER_TESTING_find_pk (TALER_EXCHANGE_get_keys (is->exchange), + dpk = TALER_TESTING_find_pk (TALER_TESTING_get_keys (is), &ws->amount, ws->age > 0); if (NULL == dpk) @@ -440,13 +442,18 @@ withdraw_run (void *cls, struct TALER_EXCHANGE_WithdrawCoinInput wci = { .pk = ws->pk, .ps = &ws->ps, - .ach = ws->h_age_commitment + .ach = 0 < ws->age ? &ws->h_age_commitment : NULL }; - ws->wsh = TALER_EXCHANGE_withdraw (is->exchange, - rp, - &wci, - &reserve_withdraw_cb, - ws); + + ws->wsh = TALER_EXCHANGE_batch_withdraw ( + TALER_TESTING_interpreter_get_context (is), + TALER_TESTING_get_exchange_url (is), + TALER_TESTING_get_keys (is), + rp, + 1, + &wci, + &reserve_withdraw_cb, + ws); } if (NULL == ws->wsh) { @@ -472,10 +479,9 @@ withdraw_cleanup (void *cls, if (NULL != ws->wsh) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %s did not complete\n", - cmd->label); - TALER_EXCHANGE_withdraw_cancel (ws->wsh); + TALER_TESTING_command_incomplete (ws->is, + cmd->label); + TALER_EXCHANGE_batch_withdraw_cancel (ws->wsh); ws->wsh = NULL; } if (NULL != ws->retry_task) @@ -484,21 +490,14 @@ withdraw_cleanup (void *cls, ws->retry_task = NULL; } TALER_denom_sig_free (&ws->sig); + TALER_denom_ewv_free (&ws->exchange_vals); if (NULL != ws->pk) { TALER_EXCHANGE_destroy_denomination_key (ws->pk); ws->pk = NULL; } - if (NULL != ws->age_commitment_proof) - { - TALER_age_commitment_proof_free (ws->age_commitment_proof); - ws->age_commitment_proof = NULL; - } - if (NULL != ws->h_age_commitment) - { - GNUNET_free (ws->h_age_commitment); - ws->h_age_commitment = NULL; - } + if (ws->age > 0) + TALER_age_commitment_proof_free (&ws->age_commitment_proof); GNUNET_free (ws->exchange_url); GNUNET_free (ws->reserve_payto_uri); GNUNET_free (ws); @@ -540,13 +539,18 @@ withdraw_traits (void *cls, TALER_TESTING_make_trait_reserve_priv (&ws->reserve_priv), TALER_TESTING_make_trait_reserve_pub (&ws->reserve_pub), TALER_TESTING_make_trait_amount (&ws->amount), - TALER_TESTING_make_trait_payment_target_uuid (&ws->kyc_uuid), - TALER_TESTING_make_trait_payto_uri ( - (const char **) &ws->reserve_payto_uri), - TALER_TESTING_make_trait_exchange_url ( - (const char **) &ws->exchange_url), - TALER_TESTING_make_trait_age_commitment_proof (0, ws->age_commitment_proof), - TALER_TESTING_make_trait_h_age_commitment (0, ws->h_age_commitment), + TALER_TESTING_make_trait_legi_requirement_row (&ws->requirement_row), + TALER_TESTING_make_trait_h_payto (&ws->h_payto), + TALER_TESTING_make_trait_payto_uri (ws->reserve_payto_uri), + TALER_TESTING_make_trait_exchange_url (ws->exchange_url), + TALER_TESTING_make_trait_age_commitment_proof (0, + 0 < ws->age + ? &ws->age_commitment_proof + : NULL), + TALER_TESTING_make_trait_h_age_commitment (0, + 0 < ws->age + ? &ws->h_age_commitment + : NULL), TALER_TESTING_trait_end () }; @@ -563,45 +567,28 @@ struct TALER_TESTING_Command TALER_TESTING_cmd_withdraw_amount (const char *label, const char *reserve_reference, const char *amount, - const uint8_t age, + uint8_t age, unsigned int expected_response_code) { struct WithdrawState *ws; ws = GNUNET_new (struct WithdrawState); - ws->age = age; if (0 < age) { - struct TALER_AgeCommitmentProof *acp; - struct TALER_AgeCommitmentHash *hac; struct GNUNET_HashCode seed; struct TALER_AgeMask mask; - acp = GNUNET_new (struct TALER_AgeCommitmentProof); - hac = GNUNET_new (struct TALER_AgeCommitmentHash); - mask = TALER_extensions_age_restriction_ageMask (); + mask = TALER_extensions_get_age_restriction_mask (); GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, &seed, sizeof(seed)); - - if (GNUNET_OK != - TALER_age_restriction_commit ( - &mask, - age, - &seed, - acp)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to generate age commitment for age %d at %s\n", - age, - label); - GNUNET_assert (0); - } - - TALER_age_commitment_hash (&acp->commitment,hac); - ws->age_commitment_proof = acp; - ws->h_age_commitment = hac; + TALER_age_restriction_commit (&mask, + age, + &seed, + &ws->age_commitment_proof); + TALER_age_commitment_hash (&ws->age_commitment_proof.commitment, + &ws->h_age_commitment); } ws->reserve_reference = reserve_reference; diff --git a/src/testing/testing_api_helpers_auditor.c b/src/testing/testing_api_helpers_auditor.c deleted file mode 100644 index b74258004..000000000 --- a/src/testing/testing_api_helpers_auditor.c +++ /dev/null @@ -1,231 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2018 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 3, or - (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - <http://www.gnu.org/licenses/> -*/ -/** - * @file testing/testing_api_helpers_auditor.c - * @brief helper functions - * @author Christian Grothoff - */ -#include "platform.h" -#include "taler_json_lib.h" -#include <gnunet/gnunet_curl_lib.h> -#include "taler_testing_lib.h" -#include "taler_auditor_service.h" - - -/** - * Closure for #cleanup_auditor. - */ -struct CleanupContext -{ - /** - * Where we find the state to clean up. - */ - struct TALER_TESTING_Interpreter *is; - - /** - * Next cleanup routine to call, NULL for none. - */ - GNUNET_SCHEDULER_TaskCallback fcb; - - /** - * Closure for @e fcb - */ - void *fcb_cls; -}; - - -/** - * Function to clean up the auditor connection. - * - * @param cls a `struct CleanupContext` - */ -static void -cleanup_auditor (void *cls) -{ - struct CleanupContext *cc = cls; - struct TALER_TESTING_Interpreter *is = cc->is; - - TALER_AUDITOR_disconnect (is->auditor); - is->auditor = NULL; - if (NULL != cc->fcb) - cc->fcb (cc->fcb_cls); - GNUNET_free (cc); -} - - -/** - * Closure for #auditor_main_wrapper() - */ -struct MainWrapperContext -{ - /** - * Main function to launch. - */ - TALER_TESTING_Main main_cb; - - /** - * Closure for @e main_cb. - */ - void *main_cb_cls; - - /** - * Configuration we use. - */ - const struct GNUNET_CONFIGURATION_Handle *cfg; - - /** - * Name of the configuration file. - */ - const char *config_filename; - -}; - - -/** - * Function called with information about the auditor. - * - * @param cls closure - * @param hr http response details - * @param vi basic information about the auditor - * @param compat protocol compatibility information - */ -static void -auditor_version_cb (void *cls, - const struct TALER_AUDITOR_HttpResponse *hr, - const struct TALER_AUDITOR_VersionInformation *vi, - enum TALER_AUDITOR_VersionCompatibility compat) -{ - struct TALER_TESTING_Interpreter *is = cls; - - (void) hr; - if (TALER_AUDITOR_VC_MATCH != compat) - { - TALER_TESTING_interpreter_fail (is); - return; - } - is->auditor_working = GNUNET_YES; -} - - -/** - * Setup the @a is 'auditor' member before running the main test loop. - * - * @param cls must be a `struct MainWrapperContext *` - * @param[in,out] is interpreter state to setup - */ -static void -auditor_main_wrapper (void *cls, - struct TALER_TESTING_Interpreter *is) -{ - struct MainWrapperContext *mwc = cls; - struct CleanupContext *cc; - char *auditor_base_url; - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (mwc->cfg, - "auditor", - "BASE_URL", - &auditor_base_url)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "auditor", - "BASE_URL"); - return; - } - - is->auditor = TALER_AUDITOR_connect (is->ctx, - auditor_base_url, - &auditor_version_cb, - is); - GNUNET_free (auditor_base_url); - - if (NULL == is->auditor) - { - GNUNET_break (0); - return; - } - - cc = GNUNET_new (struct CleanupContext); - cc->is = is; - cc->fcb = is->final_cleanup_cb; - cc->fcb_cls = is->final_cleanup_cb_cls; - is->final_cleanup_cb = cleanup_auditor; - is->final_cleanup_cb_cls = cc; - mwc->main_cb (mwc->main_cb_cls, - is); -} - - -/** - * Install signal handlers plus schedules the main wrapper - * around the "run" method. - * - * @param cls our `struct MainWrapperContext` - * @param cfg configuration we use - * @return #GNUNET_OK if all is okay, != #GNUNET_OK otherwise. - * non-GNUNET_OK codes are #GNUNET_SYSERR most of the - * times. - */ -static int -setup_with_cfg (void *cls, - const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - struct MainWrapperContext *mwc = cls; - struct TALER_TESTING_SetupContext setup_ctx = { - .config_filename = mwc->config_filename, - .main_cb = &auditor_main_wrapper, - .main_cb_cls = mwc - }; - - mwc->cfg = cfg; - return TALER_TESTING_setup_with_auditor_and_exchange_cfg (&setup_ctx, - cfg); -} - - -/** - * Install signal handlers plus schedules the main wrapper - * around the "run" method. - * - * @param main_cb the "run" method which contains all the - * commands. - * @param main_cb_cls a closure for "run", typically NULL. - * @param config_filename configuration filename. - * @return #GNUNET_OK if all is okay, != #GNUNET_OK otherwise. - * non-GNUNET_OK codes are #GNUNET_SYSERR most of the - * times. - */ -int -TALER_TESTING_auditor_setup (TALER_TESTING_Main main_cb, - void *main_cb_cls, - const char *config_filename) -{ - struct MainWrapperContext mwc = { - .main_cb = main_cb, - .main_cb_cls = main_cb_cls, - .config_filename = config_filename - }; - - return GNUNET_CONFIGURATION_parse_and_run (config_filename, - &setup_with_cfg, - &mwc); -} - - -/* end of testing_auditor_api_helpers.c */ diff --git a/src/testing/testing_api_helpers_bank.c b/src/testing/testing_api_helpers_bank.c deleted file mode 100644 index eccd45723..000000000 --- a/src/testing/testing_api_helpers_bank.c +++ /dev/null @@ -1,703 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2018-2021 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/testing_api_helpers_bank.c - * @brief convenience functions for bank tests. - * @author Marcello Stanisci - * @author Christian Grothoff - */ -#include "platform.h" -#include <gnunet/gnunet_util_lib.h> -#include "taler_testing_lib.h" -#include "taler_fakebank_lib.h" - -#define BANK_FAIL() \ - do {GNUNET_break (0); return NULL; } while (0) - - -struct TALER_FAKEBANK_Handle * -TALER_TESTING_run_fakebank (const char *bank_url, - const char *currency) -{ - const char *port; - long pnum; - struct TALER_FAKEBANK_Handle *fakebankd; - - port = strrchr (bank_url, - (unsigned char) ':'); - if (NULL == port) - pnum = 80; - else - pnum = strtol (port + 1, NULL, 10); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Starting Fakebank on port %u (%s)\n", - (unsigned int) pnum, - bank_url); - fakebankd = TALER_FAKEBANK_start ((uint16_t) pnum, - currency); - if (NULL == fakebankd) - { - GNUNET_break (0); - return NULL; - } - return fakebankd; -} - - -int -TALER_TESTING_has_in_name (const char *prog, - const char *marker) -{ - size_t name_pos; - size_t pos; - - if (! prog || ! marker) - return GNUNET_NO; - - pos = 0; - name_pos = 0; - while (prog[pos]) - { - if ('/' == prog[pos]) - name_pos = pos + 1; - pos++; - } - if (name_pos == pos) - return GNUNET_YES; - return (NULL != strstr (prog + name_pos, marker)); -} - - -struct TALER_TESTING_LibeufinServices -TALER_TESTING_run_libeufin (const struct TALER_TESTING_BankConfiguration *bc) -{ - struct GNUNET_OS_Process *nexus_proc; - struct GNUNET_OS_Process *sandbox_proc; - struct TALER_TESTING_LibeufinServices ret = { 0 }; - unsigned int iter; - char *curl_check_cmd; - const char *db_conn = "jdbc:sqlite:/tmp/libeufin-exchange-test.sqlite3"; - - setenv ( - "LIBEUFIN_NEXUS_DB_CONNECTION", - db_conn, - 1); // not overwriting any potentially existing DB. - - nexus_proc = GNUNET_OS_start_process ( - GNUNET_OS_INHERIT_STD_ERR, - NULL, NULL, NULL, - "libeufin-nexus", - "libeufin-nexus", - "serve", - NULL); - if (NULL == nexus_proc) - { - GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, - "exec", - "libeufin-nexus"); - return ret; - } - GNUNET_asprintf (&curl_check_cmd, - "curl -s %s", - bc->exchange_auth.wire_gateway_url); - /* give child time to start and bind against the socket */ - fprintf (stderr, - "Waiting for `nexus' to be ready (via %s)\n", curl_check_cmd); - iter = 0; - do - { - if (10 == iter) - { - fprintf ( - stderr, - "Failed to launch `nexus'\n"); - GNUNET_OS_process_kill (nexus_proc, - SIGTERM); - GNUNET_OS_process_wait (nexus_proc); - GNUNET_OS_process_destroy (nexus_proc); - GNUNET_free (curl_check_cmd); - GNUNET_break (0); - return ret; - } - fprintf (stderr, "."); - sleep (1); - iter++; - } - while (0 != system (curl_check_cmd)); - - // start sandbox. - GNUNET_free (curl_check_cmd); - fprintf (stderr, "\n"); - setenv ( - "LIBEUFIN_SANDBOX_DB_CONNECTION", - db_conn, - 1); // not overwriting existing any potentially existing DB. - setenv ( - "LIBEUFIN_SANDBOX_ADMIN_PASSWORD", - "secret", - 1); - if (0 != system ("libeufin-sandbox config --currency=KUDOS default")) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Could not create the default demobank.\n"); - return ret; - } - sandbox_proc = GNUNET_OS_start_process ( - GNUNET_OS_INHERIT_STD_ERR, - NULL, NULL, NULL, - "libeufin-sandbox", - "libeufin-sandbox", - "serve", - NULL); - if (NULL == sandbox_proc) - { - GNUNET_break (0); - return ret; - } - - /* give child time to start and bind against the socket */ - fprintf (stderr, - "Waiting for `sandbox' to be ready.\n"); - iter = 0; - do - { - if (10 == iter) - { - fprintf ( - stderr, - "Failed to launch `sandbox'\n"); - GNUNET_OS_process_kill (sandbox_proc, - SIGTERM); - GNUNET_OS_process_wait (sandbox_proc); - GNUNET_OS_process_destroy (sandbox_proc); - GNUNET_break (0); - return ret; - } - fprintf (stderr, "."); - sleep (1); - iter++; - } - while (0 != system ("curl -s http://localhost:5000/")); - fprintf (stderr, "\n"); - - // Creates nexus user + bank loopback connection + Taler facade. - if (0 != system ("taler-nexus-prepare")) - { - GNUNET_OS_process_kill (nexus_proc, SIGTERM); - GNUNET_OS_process_wait (nexus_proc); - GNUNET_OS_process_destroy (nexus_proc); - GNUNET_OS_process_kill (sandbox_proc, SIGTERM); - GNUNET_OS_process_wait (sandbox_proc); - GNUNET_OS_process_destroy (sandbox_proc); - TALER_LOG_ERROR ("Could not prepare nexus\n"); - GNUNET_break (0); - return ret; - } - ret.nexus = nexus_proc; - ret.sandbox = sandbox_proc; - return ret; -} - - -struct GNUNET_OS_Process * -TALER_TESTING_run_bank (const char *config_filename, - const char *bank_url) -{ - struct GNUNET_OS_Process *bank_proc; - unsigned int iter; - char *wget_cmd; - char *database; - struct GNUNET_CONFIGURATION_Handle *cfg; - - cfg = GNUNET_CONFIGURATION_create (); - if (GNUNET_OK != - GNUNET_CONFIGURATION_load (cfg, - config_filename)) - { - GNUNET_break (0); - GNUNET_CONFIGURATION_destroy (cfg); - exit (77); - } - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - "bank", - "database", - &database)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, - "bank", - "database"); - GNUNET_break (0); - GNUNET_CONFIGURATION_destroy (cfg); - exit (77); - } - GNUNET_CONFIGURATION_destroy (cfg); - bank_proc = GNUNET_OS_start_process ( - GNUNET_OS_INHERIT_STD_ERR, - NULL, NULL, NULL, - "taler-bank-manage-testing", - "taler-bank-manage-testing", - config_filename, - database, - "serve", NULL); - GNUNET_free (database); - if (NULL == bank_proc) - { - BANK_FAIL (); - } - - GNUNET_asprintf (&wget_cmd, - "wget -q -t 2 -T 1 %s -o /dev/null -O /dev/null", - bank_url); - - /* give child time to start and bind against the socket */ - fprintf (stderr, - "Waiting for `taler-bank-manage' to be ready (via %s)\n", wget_cmd); - iter = 0; - do - { - if (10 == iter) - { - fprintf ( - stderr, - "Failed to launch `taler-bank-manage' (or `wget')\n"); - GNUNET_OS_process_kill (bank_proc, - SIGTERM); - GNUNET_OS_process_wait (bank_proc); - GNUNET_OS_process_destroy (bank_proc); - GNUNET_free (wget_cmd); - BANK_FAIL (); - } - fprintf (stderr, "."); - sleep (1); - iter++; - } - while (0 != system (wget_cmd)); - GNUNET_free (wget_cmd); - fprintf (stderr, "\n"); - - return bank_proc; - -} - - -enum GNUNET_GenericReturnValue -TALER_TESTING_prepare_nexus (const char *config_filename, - int reset_db, - const char *config_section, - struct TALER_TESTING_BankConfiguration *bc) -{ - struct GNUNET_CONFIGURATION_Handle *cfg; - unsigned long long port; - char *database = NULL; // silence compiler - char *exchange_payto_uri; - - GNUNET_assert (0 == - strncasecmp (config_section, - "exchange-account-", - strlen ("exchange-account-"))); - cfg = GNUNET_CONFIGURATION_create (); - if (GNUNET_OK != - GNUNET_CONFIGURATION_load (cfg, - config_filename)) - { - GNUNET_CONFIGURATION_destroy (cfg); - GNUNET_break (0); - return GNUNET_SYSERR; - } - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - config_section, - "PAYTO_URI", - &exchange_payto_uri)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, - config_section, - "PAYTO_URI"); - GNUNET_CONFIGURATION_destroy (cfg); - return GNUNET_SYSERR; - } - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (cfg, - "bank", - "HTTP_PORT", - &port)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "bank", - "HTTP_PORT"); - GNUNET_CONFIGURATION_destroy (cfg); - GNUNET_free (database); - GNUNET_break (0); - return GNUNET_SYSERR; - } - - if (GNUNET_OK != - GNUNET_NETWORK_test_port_free (IPPROTO_TCP, - (uint16_t) port)) - { - fprintf (stderr, - "Required port %llu not available, skipping.\n", - port); - GNUNET_break (0); - GNUNET_free (database); - GNUNET_CONFIGURATION_destroy (cfg); - return GNUNET_SYSERR; - } - - /* DB preparation */ - if (GNUNET_YES == reset_db) - { - if (0 != system ("rm -f /tmp/libeufin-exchange-test.sqlite3")) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to invoke db-removal command.\n"); - GNUNET_free (database); - GNUNET_CONFIGURATION_destroy (cfg); - return GNUNET_SYSERR; - } - } - - { - char *csn; - - GNUNET_asprintf (&csn, - "exchange-accountcredentials-%s", - &config_section[strlen ("exchange-account-")]); - - - if (GNUNET_OK != - TALER_BANK_auth_parse_cfg (cfg, - csn, - &bc->exchange_auth)) - { - GNUNET_break (0); - GNUNET_CONFIGURATION_destroy (cfg); - GNUNET_free (csn); - return GNUNET_SYSERR; - } - GNUNET_free (csn); - } - GNUNET_CONFIGURATION_destroy (cfg); - bc->exchange_payto = exchange_payto_uri; - bc->user42_payto = - "payto://iban/SANDBOXX/FR7630006000011234567890189?receiver-name=User42"; - bc->user43_payto = - "payto://iban/SANDBOXX/GB33BUKB20201555555555?receiver-name=User43"; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Relying on nexus %s on port %u\n", - bc->exchange_auth.wire_gateway_url, - (unsigned int) port); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "exchange payto: %s\n", - bc->exchange_payto); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "user42_payto: %s\n", - bc->user42_payto); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "user42_payto: %s\n", - bc->user43_payto); - return GNUNET_OK; -} - - -enum GNUNET_GenericReturnValue -TALER_TESTING_prepare_bank (const char *config_filename, - int reset_db, - const char *config_section, - struct TALER_TESTING_BankConfiguration *bc) -{ - struct GNUNET_CONFIGURATION_Handle *cfg; - unsigned long long port; - struct GNUNET_OS_Process *dbreset_proc; - enum GNUNET_OS_ProcessStatusType type; - unsigned long code; - char *database; - char *exchange_payto_uri; - - GNUNET_assert (0 == - strncasecmp (config_section, - "exchange-account-", - strlen ("exchange-account-"))); - cfg = GNUNET_CONFIGURATION_create (); - - if (GNUNET_OK != - GNUNET_CONFIGURATION_load (cfg, - config_filename)) - { - GNUNET_CONFIGURATION_destroy (cfg); - GNUNET_break (0); - return GNUNET_SYSERR; - } - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - "bank", - "DATABASE", - &database)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "bank", - "DATABASE"); - GNUNET_CONFIGURATION_destroy (cfg); - GNUNET_break (0); - return GNUNET_SYSERR; - } - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - config_section, - "PAYTO_URI", - &exchange_payto_uri)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, - config_section, - "PAYTO_URI"); - GNUNET_CONFIGURATION_destroy (cfg); - return GNUNET_SYSERR; - } - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (cfg, - "bank", - "HTTP_PORT", - &port)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "bank", - "HTTP_PORT"); - GNUNET_CONFIGURATION_destroy (cfg); - GNUNET_free (database); - GNUNET_break (0); - return GNUNET_SYSERR; - } - - if (GNUNET_OK != - GNUNET_NETWORK_test_port_free (IPPROTO_TCP, - (uint16_t) port)) - { - fprintf (stderr, - "Required port %llu not available, skipping.\n", - port); - GNUNET_break (0); - GNUNET_free (database); - GNUNET_CONFIGURATION_destroy (cfg); - return GNUNET_SYSERR; - } - - /* DB preparation */ - if (GNUNET_YES == reset_db) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Flushing bank database\n"); - if (NULL == - (dbreset_proc = GNUNET_OS_start_process ( - GNUNET_OS_INHERIT_STD_ERR, - NULL, NULL, NULL, - "taler-bank-manage", - "taler-bank-manage", - "-c", config_filename, - "--with-db", database, - "django", - "flush", - "--no-input", NULL))) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to flush the bank db.\n"); - GNUNET_free (database); - GNUNET_CONFIGURATION_destroy (cfg); - return GNUNET_SYSERR; - } - - if (GNUNET_SYSERR == - GNUNET_OS_process_wait_status (dbreset_proc, - &type, - &code)) - { - GNUNET_OS_process_destroy (dbreset_proc); - GNUNET_break (0); - GNUNET_CONFIGURATION_destroy (cfg); - GNUNET_free (database); - return GNUNET_SYSERR; - } - if ( (type == GNUNET_OS_PROCESS_EXITED) && - (0 != code) ) - { - fprintf (stderr, - "Failed to setup database `%s'\n", - database); - GNUNET_break (0); - GNUNET_CONFIGURATION_destroy (cfg); - GNUNET_free (database); - return GNUNET_SYSERR; - } - GNUNET_free (database); - if ( (type != GNUNET_OS_PROCESS_EXITED) || - (0 != code) ) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected error running `taler-bank-manage django flush'!\n"); - GNUNET_break (0); - GNUNET_CONFIGURATION_destroy (cfg); - return GNUNET_SYSERR; - } - GNUNET_OS_process_destroy (dbreset_proc); - } - { - char *csn; - - GNUNET_asprintf (&csn, - "exchange-accountcredentials-%s", - &config_section[strlen ("exchange-account-")]); - - if (GNUNET_OK != - TALER_BANK_auth_parse_cfg (cfg, - csn, - &bc->exchange_auth)) - { - GNUNET_break (0); - GNUNET_free (csn); - GNUNET_CONFIGURATION_destroy (cfg); - return GNUNET_SYSERR; - } - GNUNET_free (csn); - } - GNUNET_CONFIGURATION_destroy (cfg); - bc->exchange_payto = exchange_payto_uri; - bc->user42_payto = "payto://x-taler-bank/localhost/42?receiver-name=42"; - bc->user43_payto = "payto://x-taler-bank/localhost/43?receiver-name=43"; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Using pybank %s on port %u\n", - bc->exchange_auth.wire_gateway_url, - (unsigned int) port); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "exchange payto: %s\n", - bc->exchange_payto); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "user42_payto: %s\n", - bc->user42_payto); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "user43_payto: %s\n", - bc->user43_payto); - return GNUNET_OK; -} - - -enum GNUNET_GenericReturnValue -TALER_TESTING_prepare_fakebank (const char *config_filename, - const char *config_section, - struct TALER_TESTING_BankConfiguration *bc) -{ - struct GNUNET_CONFIGURATION_Handle *cfg; - unsigned long long fakebank_port; - char *exchange_payto_uri; - - cfg = GNUNET_CONFIGURATION_create (); - if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, - config_filename)) - return GNUNET_SYSERR; - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (cfg, - "BANK", - "HTTP_PORT", - &fakebank_port)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, - "BANK", - "HTTP_PORT"); - GNUNET_CONFIGURATION_destroy (cfg); - return GNUNET_SYSERR; - } - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - config_section, - "PAYTO_URI", - &exchange_payto_uri)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, - config_section, - "PAYTO_URI"); - GNUNET_CONFIGURATION_destroy (cfg); - return GNUNET_SYSERR; - } - { - char *exchange_xtalerbank_account; - - exchange_xtalerbank_account - = TALER_xtalerbank_account_from_payto (exchange_payto_uri); - if (NULL == exchange_xtalerbank_account) - { - GNUNET_break (0); - GNUNET_free (exchange_payto_uri); - return GNUNET_SYSERR; - } - GNUNET_asprintf (&bc->exchange_auth.wire_gateway_url, - "http://localhost:%u/%s/", - (unsigned int) fakebank_port, - exchange_xtalerbank_account); - GNUNET_free (exchange_xtalerbank_account); - } - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Using fakebank %s on port %u\n", - bc->exchange_auth.wire_gateway_url, - (unsigned int) fakebank_port); - - GNUNET_CONFIGURATION_destroy (cfg); - if (GNUNET_OK != - TALER_TESTING_url_port_free (bc->exchange_auth.wire_gateway_url)) - { - GNUNET_free (bc->exchange_auth.wire_gateway_url); - bc->exchange_auth.wire_gateway_url = NULL; - GNUNET_free (exchange_payto_uri); - return GNUNET_SYSERR; - } - /* Now we know it's the fake bank, for purpose of authentication, we - * don't have any auth. */ - bc->exchange_auth.method = TALER_BANK_AUTH_NONE; - bc->exchange_payto = exchange_payto_uri; - bc->user42_payto = "payto://x-taler-bank/localhost/42?receiver-name=42"; - bc->user43_payto = "payto://x-taler-bank/localhost/43?receiver-name=43"; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "exchange payto: %s\n", - bc->exchange_payto); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "user42_payto: %s\n", - bc->user42_payto); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "user43_payto: %s\n", - bc->user43_payto); - return GNUNET_OK; -} - - -json_t * -TALER_TESTING_make_wire_details (const char *payto) -{ - struct TALER_WireSaltP salt; - - /* salt must be constant for aggregation tests! */ - memset (&salt, - 47, - sizeof (salt)); - return GNUNET_JSON_PACK ( - GNUNET_JSON_pack_string ("payto_uri", - payto), - GNUNET_JSON_pack_data_auto ("salt", - &salt)); -} - - -/* end of testing_api_helpers_bank.c */ diff --git a/src/testing/testing_api_helpers_exchange.c b/src/testing/testing_api_helpers_exchange.c deleted file mode 100644 index d813021bd..000000000 --- a/src/testing/testing_api_helpers_exchange.c +++ /dev/null @@ -1,983 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2018-2020 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/testing_api_helpers_exchange.c - * @brief helper functions - * @author Christian Grothoff - * @author Marcello Stanisci - */ -#include "platform.h" -#include "taler_json_lib.h" -#include <gnunet/gnunet_curl_lib.h> -#include "taler_signatures.h" -#include "taler_extensions.h" -#include "taler_testing_lib.h" - -/** - * Run multiple taler-exchange-httpd processes in - * parallel using GNU parallel? - */ -#define GNU_PARALLEL 0 - - -void -TALER_TESTING_cleanup_files (const char *config_name) -{ - if (GNUNET_OK != - GNUNET_CONFIGURATION_parse_and_run (config_name, - &TALER_TESTING_cleanup_files_cfg, - NULL)) - exit (77); -} - - -/** - * Remove @a option directory from @a section in @a cfg. - * - * @return #GNUNET_OK on success - */ -static enum GNUNET_GenericReturnValue -remove_dir (const struct GNUNET_CONFIGURATION_Handle *cfg, - const char *section, - const char *option) -{ - char *dir; - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_filename (cfg, - section, - option, - &dir)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - section, - option); - return GNUNET_SYSERR; - } - if (GNUNET_YES == - GNUNET_DISK_directory_test (dir, - GNUNET_NO)) - GNUNET_break (GNUNET_OK == - GNUNET_DISK_directory_remove (dir)); - GNUNET_free (dir); - return GNUNET_OK; -} - - -enum GNUNET_GenericReturnValue -TALER_TESTING_cleanup_files_cfg (void *cls, - const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - char *dir; - - (void) cls; - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_filename (cfg, - "exchange-offline", - "SECM_TOFU_FILE", - &dir)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "exchange-offline", - "SECM_TOFU_FILE"); - return GNUNET_SYSERR; - } - if ( (0 != unlink (dir)) && - (ENOENT != errno) ) - { - GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, - "unlink", - dir); - GNUNET_free (dir); - return GNUNET_SYSERR; - } - GNUNET_free (dir); - if (GNUNET_OK != - remove_dir (cfg, - "taler-exchange-secmod-eddsa", - "KEY_DIR")) - return GNUNET_SYSERR; - if (GNUNET_OK != - remove_dir (cfg, - "taler-exchange-secmod-rsa", - "KEY_DIR")) - return GNUNET_SYSERR; - return GNUNET_OK; -} - - -enum GNUNET_GenericReturnValue -TALER_TESTING_run_auditor_exchange (const char *config_filename, - const char *exchange_master_pub, - const char *exchange_base_url, - int do_remove) -{ - struct GNUNET_OS_Process *proc; - enum GNUNET_OS_ProcessStatusType type; - unsigned long code; - - TALER_LOG_DEBUG ("Add exchange (%s,%s) to the auditor\n", - exchange_base_url, - exchange_master_pub); - - proc = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL, - NULL, NULL, NULL, - "taler-auditor-exchange", - "taler-auditor-exchange", - "-c", config_filename, - "-u", exchange_base_url, - "-m", exchange_master_pub, - (GNUNET_YES == do_remove) - ? "-r" - : NULL, - NULL); - if (NULL == proc) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to run `taler-auditor-exchange`, is your PATH correct?\n"); - return GNUNET_SYSERR; - } - GNUNET_assert (GNUNET_OK == - GNUNET_OS_process_wait_status (proc, - &type, - &code)); - GNUNET_OS_process_destroy (proc); - if ( (0 != code) || - (GNUNET_OS_PROCESS_EXITED != type) ) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "taler-auditor-exchange terminated with error (%d/%d)\n", - (int) type, - (int) code); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -enum GNUNET_GenericReturnValue -TALER_TESTING_exchange_db_reset (const char *config_filename) -{ - struct GNUNET_OS_Process *proc; - enum GNUNET_OS_ProcessStatusType type; - unsigned long code; - - proc = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL, - NULL, NULL, NULL, - "taler-exchange-dbinit", - "taler-exchange-dbinit", - "-c", config_filename, - "-L", "WARNING", - "-r", - NULL); - if (NULL == proc) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to run `taler-exchange-dbinit`, is your PATH correct?\n"); - return GNUNET_NO; - } - if (GNUNET_SYSERR == - GNUNET_OS_process_wait_status (proc, - &type, - &code)) - { - GNUNET_break (0); - GNUNET_OS_process_destroy (proc); - return GNUNET_SYSERR; - } - GNUNET_OS_process_destroy (proc); - if ( (type == GNUNET_OS_PROCESS_EXITED) && - (0 != code) ) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to setup (exchange) database, exit code %d\n", - (int) code); - return GNUNET_NO; - } - if ( (type != GNUNET_OS_PROCESS_EXITED) || - (0 != code) ) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected error (%d/%d) running `taler-exchange-dbinit'!\n", - (int) type, - (int) code); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -enum GNUNET_GenericReturnValue -TALER_TESTING_auditor_db_reset (const char *config_filename) -{ - struct GNUNET_OS_Process *proc; - enum GNUNET_OS_ProcessStatusType type; - unsigned long code; - - proc = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL, - NULL, NULL, NULL, - "taler-auditor-dbinit", - "taler-auditor-dbinit", - "-c", config_filename, - "-R", - NULL); - if (NULL == proc) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to run `taler-auditor-dbinit`, is your PATH correct?\n"); - return GNUNET_NO; - } - if (GNUNET_SYSERR == - GNUNET_OS_process_wait_status (proc, - &type, - &code)) - { - GNUNET_break (0); - GNUNET_OS_process_destroy (proc); - return GNUNET_SYSERR; - } - GNUNET_OS_process_destroy (proc); - if ( (type == GNUNET_OS_PROCESS_EXITED) && - (0 != code) ) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to setup (auditor) database, exit code %d\n", - (int) code); - return GNUNET_NO; - } - if ( (type != GNUNET_OS_PROCESS_EXITED) || - (0 != code) ) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected error (%d/%d) running `taler-auditor-dbinit'!\n", - (int) type, - (int) code); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/** - * Type of closure for - * #sign_keys_for_exchange. - */ -struct SignInfo -{ - /** - * Members will be set to the exchange configuration. - */ - struct TALER_TESTING_ExchangeConfiguration *ec; - - /** - * Name of the configuration file to use. - */ - const char *config_filename; - - /** - * Did we reset the database? - */ - int db_reset; -}; - - -/** - * Sign the keys for an exchange given configuration @a cfg. - * The information to be signed must be in a file "auditor.in". - * - * @param[in,out] cls a `struct SignInfo` with further parameters - * @param cfg configuration to use - * @return #GNUNET_OK on success - */ -static enum GNUNET_GenericReturnValue -sign_keys_for_exchange (void *cls, - const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - struct SignInfo *si = cls; - char *exchange_master_pub; - int ret; - - /* Load the age restriction mask from the configuration */ - TALER_extensions_load_taler_config (cfg); - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - "exchange", - "BASE_URL", - &si->ec->exchange_url)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, - "exchange", - "BASE_URL"); - si->ec->exchange_url = NULL; - return GNUNET_NO; - } - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - "auditor", - "BASE_URL", - &si->ec->auditor_url)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, - "auditor", - "BASE_URL"); - GNUNET_free (si->ec->exchange_url); - si->ec->exchange_url = NULL; - si->ec->auditor_url = NULL; - return GNUNET_SYSERR; - } - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - "exchange", - "MASTER_PUBLIC_KEY", - &exchange_master_pub)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "exchange", - "MASTER_PUBLIC_KEY"); - ret = GNUNET_SYSERR; - goto fail; - } - if ( (GNUNET_OK != - TALER_TESTING_run_auditor_exchange (si->config_filename, - exchange_master_pub, - si->ec->exchange_url, - GNUNET_NO)) && - (GNUNET_YES == si->db_reset) ) - { - ret = GNUNET_NO; - goto fail; - } - GNUNET_free (exchange_master_pub); - return GNUNET_OK; -fail: - GNUNET_free (si->ec->exchange_url); - GNUNET_free (si->ec->auditor_url); - si->ec->exchange_url = NULL; - si->ec->auditor_url = NULL; - return ret; -} - - -enum GNUNET_GenericReturnValue -TALER_TESTING_prepare_exchange (const char *config_filename, - int reset_db, - struct TALER_TESTING_ExchangeConfiguration *ec) -{ - struct SignInfo si = { - .config_filename = config_filename, - .ec = ec, - .db_reset = reset_db - }; - - if (GNUNET_YES == reset_db) - { - if (GNUNET_OK != - TALER_TESTING_exchange_db_reset (config_filename)) - return GNUNET_NO; - if (GNUNET_OK != - TALER_TESTING_auditor_db_reset (config_filename)) - return GNUNET_NO; - } - if (GNUNET_OK != - GNUNET_CONFIGURATION_parse_and_run (config_filename, - &sign_keys_for_exchange, - &si)) - return GNUNET_NO; - return GNUNET_OK; -} - - -const struct TALER_EXCHANGE_DenomPublicKey * -TALER_TESTING_find_pk (const struct TALER_EXCHANGE_Keys *keys, - const struct TALER_Amount *amount, - bool age_restricted) -{ - struct GNUNET_TIME_Timestamp now; - struct TALER_EXCHANGE_DenomPublicKey *pk; - char *str; - - now = GNUNET_TIME_timestamp_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)) && - (GNUNET_TIME_timestamp_cmp (now, - >=, - pk->valid_from)) && - (GNUNET_TIME_timestamp_cmp (now, - <, - pk->withdraw_valid_until)) && - (age_restricted == (0 != pk->key.age_mask.bits)) ) - 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)) && - (GNUNET_TIME_timestamp_cmp (now, - <, - pk->valid_from) || - GNUNET_TIME_timestamp_cmp (now, - >, - pk->withdraw_valid_until) ) && - (age_restricted == (0 != pk->key.age_mask.bits)) ) - { - 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_time.abs_value_us, - (unsigned long long) pk->valid_from.abs_time.abs_value_us, - (unsigned long long) pk->withdraw_valid_until.abs_time.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; -} - - -int -TALER_TESTING_wait_exchange_ready (const char *base_url) -{ - char *wget_cmd; - unsigned int iter; - - GNUNET_asprintf (&wget_cmd, - "wget -q -t 1 -T 1 %sseed -o /dev/null -O /dev/null", - base_url); // make sure ends with '/' - /* give child time to start and bind against the socket */ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Waiting for `taler-exchange-httpd` service to be ready (check with: %s)\n", - wget_cmd); - iter = 0; - do - { - if (10 == iter) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to launch `taler-exchange-httpd` service (or `wget')\n"); - GNUNET_free (wget_cmd); - return 77; - } - sleep (1); - iter++; - } - while (0 != system (wget_cmd)); - GNUNET_free (wget_cmd); - return 0; -} - - -int -TALER_TESTING_wait_httpd_ready (const char *base_url) -{ - char *wget_cmd; - unsigned int iter; - - GNUNET_asprintf (&wget_cmd, - "wget -q -t 1 -T 1 %s -o /dev/null -O /dev/null", - base_url); // make sure ends with '/' - /* give child time to start and bind against the socket */ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Waiting for HTTP service to be ready (check with: %s)\n", - wget_cmd); - iter = 0; - do - { - if (10 == iter) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to launch HTTP service (or `wget')\n"); - GNUNET_free (wget_cmd); - return 77; - } - sleep (1); - iter++; - } - while (0 != system (wget_cmd)); - GNUNET_free (wget_cmd); - return 0; -} - - -/** - * Wait for the auditor to have started. Waits for at - * most 10s, after that returns 77 to indicate an error. - * - * @param base_url what URL should we expect the auditor - * to be running at - * @return 0 on success - */ -int -TALER_TESTING_wait_auditor_ready (const char *base_url) -{ - char *wget_cmd; - unsigned int iter; - - GNUNET_asprintf (&wget_cmd, - "wget -q -t 1 -T 1 %sversion -o /dev/null -O /dev/null", - base_url); // make sure ends with '/' - /* give child time to start and bind against the socket */ - fprintf (stderr, - "Waiting for `taler-auditor-httpd' to be ready at %s\n", - base_url); - iter = 0; - do - { - if (10 == iter) - { - fprintf (stderr, - "Failed to launch `taler-auditor-httpd' (or `wget')\n"); - GNUNET_free (wget_cmd); - return 77; - } - fprintf (stderr, ".\n"); - sleep (1); - iter++; - } - while (0 != system (wget_cmd)); - GNUNET_free (wget_cmd); - return 0; -} - - -enum GNUNET_GenericReturnValue -TALER_TESTING_setup_with_exchange (TALER_TESTING_Main main_cb, - void *main_cb_cls, - const char *config_file) -{ - struct TALER_TESTING_SetupContext setup_ctx = { - .config_filename = config_file, - .main_cb = main_cb, - .main_cb_cls = main_cb_cls - }; - enum GNUNET_GenericReturnValue result; - - result = - GNUNET_CONFIGURATION_parse_and_run (config_file, - &TALER_TESTING_setup_with_exchange_cfg, - &setup_ctx); - if (GNUNET_OK != result) - return result; - return GNUNET_OK; -} - - -/** - * Stop taler-exchange-crypto helpers. - * - * @param[in] helpers the process handles. - */ -static void -stop_helpers (struct GNUNET_OS_Process *helpers[3]) -{ - for (unsigned int i = 0; i<3; i++) - { - if (NULL == helpers[i]) - continue; - GNUNET_break (0 == - GNUNET_OS_process_kill (helpers[i], - SIGTERM)); - GNUNET_break (GNUNET_OK == - GNUNET_OS_process_wait (helpers[i])); - GNUNET_OS_process_destroy (helpers[i]); - } -} - - -/** - * Start taler-exchange-crypto helpers. - * - * @param config_filename configuration file to use - * @param[out] helpers where to store the process handles. - */ -static enum GNUNET_GenericReturnValue -start_helpers (const char *config_filename, - struct GNUNET_OS_Process *helpers[3]) -{ - char *dir; - const struct GNUNET_OS_ProjectData *pd; - - pd = GNUNET_OS_project_data_get (); - GNUNET_OS_init (TALER_project_data_default ()); - dir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_BINDIR); - GNUNET_OS_init (pd); - if (NULL == dir) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - { - char *fn; - - GNUNET_asprintf (&fn, - "%s/%s", - dir, - "taler-exchange-secmod-eddsa"); - helpers[0] = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL, - NULL, NULL, NULL, - fn, - "taler-exchange-secmod-eddsa", - "-c", config_filename, - "-L", "INFO", - NULL); - GNUNET_free (fn); - } - { - char *fn; - - GNUNET_asprintf (&fn, - "%s/%s", - dir, - "taler-exchange-secmod-rsa"); - helpers[1] = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL, - NULL, NULL, NULL, - fn, - "taler-exchange-secmod-rsa", - "-c", config_filename, - "-L", "INFO", - NULL); - GNUNET_free (fn); - } - { - char *fn; - - GNUNET_asprintf (&fn, - "%s/%s", - dir, - "taler-exchange-secmod-cs"); - helpers[2] = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL, - NULL, NULL, NULL, - fn, - "taler-exchange-secmod-cs", - "-c", config_filename, - "-L", "INFO", - NULL); - GNUNET_free (fn); - } - GNUNET_free (dir); - if ( (NULL == helpers[0]) || - (NULL == helpers[1]) || - (NULL == helpers[2]) ) - { - stop_helpers (helpers); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -enum GNUNET_GenericReturnValue -TALER_TESTING_setup_with_exchange_cfg ( - void *cls, - const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - const struct TALER_TESTING_SetupContext *setup_ctx = cls; - struct GNUNET_OS_Process *exchanged; - struct GNUNET_OS_Process *helpers[3]; - unsigned long long port; - char *serve; - char *base_url; - int result; - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - "exchange", - "SERVE", - &serve)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "exchange", - "SERVE"); - return GNUNET_NO; - } - - if (0 == strcmp ("tcp", - serve)) - { - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (cfg, - "exchange", - "PORT", - &port)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "exchange", - "PORT"); - GNUNET_free (serve); - return GNUNET_NO; - } - - if (GNUNET_OK != - GNUNET_NETWORK_test_port_free (IPPROTO_TCP, - (uint16_t) port)) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Required port %llu not available, skipping.\n", - port); - GNUNET_free (serve); - return GNUNET_NO; - } - } - GNUNET_free (serve); - if (GNUNET_OK != - start_helpers (setup_ctx->config_filename, - helpers)) - { - GNUNET_break (0); - return 77; - } - exchanged = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL, - NULL, NULL, NULL, -#if GNU_PARALLEL - "parallel", -#endif - "taler-exchange-httpd", - "taler-exchange-httpd", - "-L", "INFO", - "-a", /* some tests may need timetravel */ - "-c", setup_ctx->config_filename, -#if GNU_PARALLEL - "-r", - ":::", - "-", - "-", - "-", - "-", -#endif - NULL); - if (NULL == exchanged) - { - GNUNET_break (0); - stop_helpers (helpers); - return 77; - } - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - "exchange", - "BASE_URL", - &base_url)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "exchange", - "BASE_URL"); - stop_helpers (helpers); - return GNUNET_NO; - } - - if (0 != TALER_TESTING_wait_exchange_ready (base_url)) - { - GNUNET_free (base_url); - stop_helpers (helpers); - GNUNET_break (0 == - GNUNET_OS_process_kill (exchanged, - SIGTERM)); -#if GNU_PARALLEL - /* GNU Parallel kills on 2nd SIGTERM, need to give it a - chance to process the 1st signal first... */ - sleep (1); - GNUNET_break (0 == - GNUNET_OS_process_kill (exchanged, - SIGTERM)); -#endif - GNUNET_break (GNUNET_OK == - GNUNET_OS_process_wait (exchanged)); - GNUNET_OS_process_destroy (exchanged); - return 77; - } - GNUNET_free (base_url); - - /* NOTE: this call blocks. */ - result = TALER_TESTING_setup (setup_ctx->main_cb, - setup_ctx->main_cb_cls, - cfg, - exchanged, - GNUNET_YES); - GNUNET_break (0 == - GNUNET_OS_process_kill (exchanged, - SIGTERM)); -#if GNU_PARALLEL - /* GNU Parallel kills on 2nd SIGTERM, need to give it a - chance to process the 1st signal first... */ - sleep (1); - GNUNET_break (0 == - GNUNET_OS_process_kill (exchanged, - SIGTERM)); -#endif - GNUNET_break (GNUNET_OK == - GNUNET_OS_process_wait (exchanged)); - GNUNET_OS_process_destroy (exchanged); - stop_helpers (helpers); - return result; -} - - -enum GNUNET_GenericReturnValue -TALER_TESTING_setup_with_auditor_and_exchange_cfg ( - void *cls, - const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - const struct TALER_TESTING_SetupContext *setup_ctx = cls; - struct GNUNET_OS_Process *auditord; - unsigned long long port; - char *serve; - char *base_url; - int result; - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - "auditor", - "SERVE", - &serve)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "auditor", - "SERVE"); - return GNUNET_NO; - } - - if (0 == strcmp ("tcp", serve)) - { - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (cfg, - "auditor", - "PORT", - &port)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "auditor", - "PORT"); - GNUNET_free (serve); - return GNUNET_NO; - } - - if (GNUNET_OK != - GNUNET_NETWORK_test_port_free (IPPROTO_TCP, - (uint16_t) port)) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Required port %llu not available, skipping.\n", - port); - GNUNET_free (serve); - return GNUNET_NO; - } - } - GNUNET_free (serve); - auditord = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL, - NULL, NULL, NULL, - "taler-auditor-httpd", - "taler-auditor-httpd", - "-c", setup_ctx->config_filename, - NULL); - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - "auditor", - "BASE_URL", - &base_url)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "auditor", - "BASE_URL"); - return GNUNET_NO; - } - - if (0 != TALER_TESTING_wait_auditor_ready (base_url)) - { - GNUNET_free (base_url); - GNUNET_break (0 == - GNUNET_OS_process_kill (auditord, - SIGTERM)); - GNUNET_break (GNUNET_OK == - GNUNET_OS_process_wait (auditord)); - GNUNET_OS_process_destroy (auditord); - return 77; - } - GNUNET_free (base_url); - - /* NOTE: this call blocks. */ - result = TALER_TESTING_setup_with_exchange_cfg ((void *) setup_ctx, - cfg); - GNUNET_break (0 == - GNUNET_OS_process_kill (auditord, - SIGTERM)); - GNUNET_break (GNUNET_OK == - GNUNET_OS_process_wait (auditord)); - GNUNET_OS_process_destroy (auditord); - return result; -} - - -enum GNUNET_GenericReturnValue -TALER_TESTING_setup_with_auditor_and_exchange (TALER_TESTING_Main main_cb, - void *main_cb_cls, - const char *config_file) -{ - struct TALER_TESTING_SetupContext setup_ctx = { - .config_filename = config_file, - .main_cb = main_cb, - .main_cb_cls = main_cb_cls - }; - - return GNUNET_CONFIGURATION_parse_and_run ( - config_file, - &TALER_TESTING_setup_with_auditor_and_exchange_cfg, - &setup_ctx); -} - - -enum GNUNET_GenericReturnValue -TALER_TESTING_url_port_free (const char *url) -{ - const char *port; - long pnum; - - port = strrchr (url, - (unsigned char) ':'); - if (NULL == port) - pnum = 80; - else - pnum = strtol (port + 1, NULL, 10); - if (GNUNET_OK != - GNUNET_NETWORK_test_port_free (IPPROTO_TCP, - pnum)) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Port %u not available.\n", - (unsigned int) pnum); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/* end of testing_api_helpers_exchange.c */ diff --git a/src/testing/testing_api_loop.c b/src/testing/testing_api_loop.c index 190e20928..0f242f7f1 100644 --- a/src/testing/testing_api_loop.c +++ b/src/testing/testing_api_loop.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2018 Taler Systems SA + Copyright (C) 2018-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 @@ -26,15 +26,65 @@ #include "platform.h" #include "taler_json_lib.h" #include <gnunet/gnunet_curl_lib.h> +#include "taler_extensions.h" #include "taler_signatures.h" #include "taler_testing_lib.h" -#include "taler_fakebank_lib.h" + /** - * Pipe used to communicate child death via signal. - * Must be global, as used in signal handler! + * The interpreter and its state */ -static struct GNUNET_DISK_PipeHandle *sigpipe; +struct TALER_TESTING_Interpreter +{ + + /** + * Commands the interpreter will run. + */ + struct TALER_TESTING_Command *commands; + + /** + * Interpreter task (if one is scheduled). + */ + struct GNUNET_SCHEDULER_Task *task; + + /** + * Handle for the child management. + */ + struct GNUNET_ChildWaitHandle *cwh; + + /** + * Main execution context for the main loop. + */ + struct GNUNET_CURL_Context *ctx; + + /** + * Context for running the CURL event loop. + */ + struct GNUNET_CURL_RescheduleContext *rc; + + /** + * Hash map mapping variable names to commands. + */ + struct GNUNET_CONTAINER_MultiHashMap *vars; + + /** + * Task run on timeout. + */ + struct GNUNET_SCHEDULER_Task *timeout_task; + + /** + * Instruction pointer. Tells #interpreter_run() which instruction to run + * next. Need (signed) int because it gets -1 when rewinding the + * interpreter to the first CMD. + */ + int ip; + + /** + * Result of the testcases, #GNUNET_OK on success + */ + enum GNUNET_GenericReturnValue result; + +}; const struct TALER_TESTING_Command * @@ -60,7 +110,7 @@ TALER_TESTING_interpreter_lookup_command (struct TALER_TESTING_Interpreter *is, if (TALER_TESTING_cmd_is_batch (cmd)) { - struct TALER_TESTING_Command **batch; + struct TALER_TESTING_Command *batch; struct TALER_TESTING_Command *current; struct TALER_TESTING_Command *icmd; const struct TALER_TESTING_Command *match; @@ -72,7 +122,7 @@ TALER_TESTING_interpreter_lookup_command (struct TALER_TESTING_Interpreter *is, /* We must do the loop forward, but we can find the last match */ match = NULL; for (unsigned int j = 0; - NULL != (icmd = &(*batch)[j])->label; + NULL != (icmd = &batch[j])->label; j++) { if (current == icmd) @@ -90,13 +140,29 @@ TALER_TESTING_interpreter_lookup_command (struct TALER_TESTING_Interpreter *is, "Command not found: %s\n", label); return NULL; +} + +const struct TALER_TESTING_Command * +TALER_TESTING_interpreter_get_command (struct TALER_TESTING_Interpreter *is, + const char *name) +{ + const struct TALER_TESTING_Command *cmd; + struct GNUNET_HashCode h_name; + + GNUNET_CRYPTO_hash (name, + strlen (name), + &h_name); + cmd = GNUNET_CONTAINER_multihashmap_get (is->vars, + &h_name); + if (NULL == cmd) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Command not found by name: %s\n", + name); + return cmd; } -/** - * Obtain main execution context for the main loop. - */ struct GNUNET_CURL_Context * TALER_TESTING_interpreter_get_context (struct TALER_TESTING_Interpreter *is) { @@ -104,38 +170,18 @@ TALER_TESTING_interpreter_get_context (struct TALER_TESTING_Interpreter *is) } -struct TALER_FAKEBANK_Handle * -TALER_TESTING_interpreter_get_fakebank (struct TALER_TESTING_Interpreter *is) +void +TALER_TESTING_touch_cmd (struct TALER_TESTING_Interpreter *is) { - return is->fakebank; + is->commands[is->ip].last_req_time + = GNUNET_TIME_absolute_get (); } void -TALER_TESTING_run_with_fakebank (struct TALER_TESTING_Interpreter *is, - struct TALER_TESTING_Command *commands, - const char *bank_url) +TALER_TESTING_inc_tries (struct TALER_TESTING_Interpreter *is) { - char *currency; - - if (GNUNET_OK != - TALER_config_get_currency (is->cfg, - ¤cy)) - { - is->result = GNUNET_SYSERR; - return; - } - is->fakebank = TALER_TESTING_run_fakebank (bank_url, - currency); - GNUNET_free (currency); - if (NULL == is->fakebank) - { - GNUNET_break (0); - is->result = GNUNET_SYSERR; - return; - } - TALER_TESTING_run (is, - commands); + is->commands[is->ip].num_tries++; } @@ -159,7 +205,13 @@ TALER_TESTING_interpreter_next (struct TALER_TESTING_Interpreter *is) return; /* ignore, we already failed! */ if (TALER_TESTING_cmd_is_batch (cmd)) { - TALER_TESTING_cmd_batch_next (is); + if (TALER_TESTING_cmd_batch_next (is, + cmd->cls)) + { + /* batch is done */ + cmd->finish_time = GNUNET_TIME_absolute_get (); + is->ip++; + } } else { @@ -173,7 +225,7 @@ TALER_TESTING_interpreter_next (struct TALER_TESTING_Interpreter *is) "Interpreter executed 1000 instructions in %s\n", GNUNET_STRINGS_relative_time_to_string ( GNUNET_TIME_absolute_get_duration (last_report), - GNUNET_YES)); + true)); last_report = GNUNET_TIME_absolute_get (); } ipc++; @@ -202,19 +254,9 @@ TALER_TESTING_interpreter_fail (struct TALER_TESTING_Interpreter *is) } -struct TALER_TESTING_Command -TALER_TESTING_cmd_end (void) -{ - static struct TALER_TESTING_Command cmd; - cmd.label = NULL; - - return cmd; -} - - const char * -TALER_TESTING_interpreter_get_current_label (struct - TALER_TESTING_Interpreter *is) +TALER_TESTING_interpreter_get_current_label ( + struct TALER_TESTING_Interpreter *is) { struct TALER_TESTING_Command *cmd = &is->commands[is->ip]; @@ -246,6 +288,19 @@ interpreter_run (void *cls) = cmd->last_req_time = GNUNET_TIME_absolute_get (); cmd->num_tries = 1; + if (NULL != cmd->name) + { + struct GNUNET_HashCode h_name; + + GNUNET_CRYPTO_hash (cmd->name, + strlen (cmd->name), + &h_name); + (void) GNUNET_CONTAINER_multihashmap_put ( + is->vars, + &h_name, + cmd, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE); + } cmd->run (cmd->cls, cmd, is); @@ -277,22 +332,11 @@ do_shutdown (void *cls) if (NULL != cmd->cleanup) cmd->cleanup (cmd->cls, cmd); - if (NULL != is->exchange) - { - TALER_LOG_DEBUG ("Disconnecting the exchange\n"); - TALER_EXCHANGE_disconnect (is->exchange); - is->exchange = NULL; - } if (NULL != is->task) { GNUNET_SCHEDULER_cancel (is->task); is->task = NULL; } - if (NULL != is->fakebank) - { - TALER_FAKEBANK_stop (is->fakebank); - is->fakebank = NULL; - } if (NULL != is->ctx) { GNUNET_CURL_fini (is->ctx); @@ -303,15 +347,20 @@ do_shutdown (void *cls) GNUNET_CURL_gnunet_rc_destroy (is->rc); is->rc = NULL; } + if (NULL != is->vars) + { + GNUNET_CONTAINER_multihashmap_destroy (is->vars); + is->vars = NULL; + } if (NULL != is->timeout_task) { GNUNET_SCHEDULER_cancel (is->timeout_task); is->timeout_task = NULL; } - if (NULL != is->child_death_task) + if (NULL != is->cwh) { - GNUNET_SCHEDULER_cancel (is->child_death_task); - is->child_death_task = NULL; + GNUNET_wait_child_cancel (is->cwh); + is->cwh = NULL; } GNUNET_free (is->commands); } @@ -339,30 +388,24 @@ do_timeout (void *cls) * process died). * * @param cls the `struct TALER_TESTING_Interpreter *` + * @param type type of the process + * @param code status code of the process */ static void -maint_child_death (void *cls) +maint_child_death (void *cls, + enum GNUNET_OS_ProcessStatusType type, + long unsigned int code) { struct TALER_TESTING_Interpreter *is = cls; struct TALER_TESTING_Command *cmd = &is->commands[is->ip]; - const struct GNUNET_DISK_FileHandle *pr; struct GNUNET_OS_Process **processp; - char c[16]; - enum GNUNET_OS_ProcessStatusType type; - unsigned long code; + is->cwh = NULL; while (TALER_TESTING_cmd_is_batch (cmd)) cmd = TALER_TESTING_cmd_batch_get_current (cmd); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got SIGCHLD for `%s'.\n", cmd->label); - is->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))); if (GNUNET_OK != TALER_TESTING_get_trait_process (cmd, &processp)) @@ -371,13 +414,8 @@ maint_child_death (void *cls) TALER_TESTING_interpreter_fail (is); return; } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got the dead child process handle, waiting for termination ...\n"); - GNUNET_assert (GNUNET_OK == - GNUNET_OS_process_wait_status (*processp, - &type, - &code)); GNUNET_OS_process_destroy (*processp); *processp = NULL; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, @@ -411,7 +449,6 @@ maint_child_death (void *cls) TALER_TESTING_interpreter_fail (is); return; } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Dead child, go on with next command.\n"); TALER_TESTING_interpreter_next (is); @@ -421,16 +458,24 @@ maint_child_death (void *cls) void TALER_TESTING_wait_for_sigchld (struct TALER_TESTING_Interpreter *is) { - const struct GNUNET_DISK_FileHandle *pr; + struct GNUNET_OS_Process **processp; + struct TALER_TESTING_Command *cmd = &is->commands[is->ip]; - GNUNET_assert (NULL == is->child_death_task); - pr = GNUNET_DISK_pipe_handle (sigpipe, - GNUNET_DISK_PIPE_END_READ); - is->child_death_task - = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, - pr, - &maint_child_death, - is); + while (TALER_TESTING_cmd_is_batch (cmd)) + cmd = TALER_TESTING_cmd_batch_get_current (cmd); + if (GNUNET_OK != + TALER_TESTING_get_trait_process (cmd, + &processp)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + GNUNET_assert (NULL == is->cwh); + is->cwh + = GNUNET_wait_child (*processp, + &maint_child_death, + is); } @@ -452,9 +497,9 @@ TALER_TESTING_run2 (struct TALER_TESTING_Interpreter *is, is->commands = GNUNET_malloc_large ( (i + 1) * sizeof (struct TALER_TESTING_Command)); GNUNET_assert (NULL != is->commands); - memcpy (is->commands, - commands, - sizeof (struct TALER_TESTING_Command) * i); + GNUNET_memcpy (is->commands, + commands, + sizeof (struct TALER_TESTING_Command) * i); is->timeout_task = GNUNET_SCHEDULER_add_delayed ( timeout, &do_timeout, @@ -466,14 +511,19 @@ TALER_TESTING_run2 (struct TALER_TESTING_Interpreter *is, } +#include "valgrind.h" + void TALER_TESTING_run (struct TALER_TESTING_Interpreter *is, struct TALER_TESTING_Command *commands) { TALER_TESTING_run2 (is, commands, - GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, - 5)); + 0 == RUNNING_ON_VALGRIND + ? GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, + 5) + : GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, + 50)); } @@ -507,352 +557,446 @@ struct MainContext /** - * Signal handler called for SIGCHLD. Triggers the - * respective handler by writing to the trigger pipe. + * Initialize scheduler loop and curl context for the testcase, + * and responsible to run the "run" method. + * + * @param cls closure, typically the "run" method, the + * interpreter state and a closure for "run". */ static void -sighandler_child_death (void) +main_wrapper (void *cls) +{ + struct MainContext *main_ctx = cls; + + main_ctx->main_cb (main_ctx->main_cb_cls, + main_ctx->is); +} + + +enum GNUNET_GenericReturnValue +TALER_TESTING_loop (TALER_TESTING_Main main_cb, + void *main_cb_cls) +{ + struct TALER_TESTING_Interpreter is; + struct MainContext main_ctx = { + .main_cb = main_cb, + .main_cb_cls = main_cb_cls, + /* needed to init the curl ctx */ + .is = &is, + }; + + memset (&is, + 0, + sizeof (is)); + is.ctx = GNUNET_CURL_init ( + &GNUNET_CURL_gnunet_scheduler_reschedule, + &is.rc); + GNUNET_CURL_enable_async_scope_header (is.ctx, + "Taler-Correlation-Id"); + GNUNET_assert (NULL != is.ctx); + is.rc = GNUNET_CURL_gnunet_rc_create (is.ctx); + is.vars = GNUNET_CONTAINER_multihashmap_create (1024, + false); + /* Blocking */ + GNUNET_SCHEDULER_run (&main_wrapper, + &main_ctx); + return is.result; +} + + +int +TALER_TESTING_main (char *const *argv, + const char *loglevel, + const char *cfg_file, + const char *exchange_account_section, + enum TALER_TESTING_BankSystem bs, + struct TALER_TESTING_Credentials *cred, + TALER_TESTING_Main main_cb, + void *main_cb_cls) { - static char c; - int old_errno = errno; /* back-up errno */ + enum GNUNET_GenericReturnValue ret; - 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 */ + unsetenv ("XDG_DATA_HOME"); + unsetenv ("XDG_CONFIG_HOME"); + GNUNET_log_setup (argv[0], + loglevel, + NULL); + if (GNUNET_OK != + TALER_TESTING_get_credentials (cfg_file, + exchange_account_section, + bs, + cred)) + { + GNUNET_break (0); + return 77; + } + if (GNUNET_OK != + TALER_TESTING_cleanup_files_cfg (NULL, + cred->cfg)) + { + GNUNET_break (0); + return 77; + } + if (GNUNET_OK != + TALER_extensions_init (cred->cfg)) + { + GNUNET_break (0); + return 77; + } + ret = TALER_TESTING_loop (main_cb, + main_cb_cls); + /* TODO: should we free 'cred' resources here? */ + return (GNUNET_OK == ret) ? 0 : 1; } +/* ************** iterate over commands ********* */ + + void -TALER_TESTING_cert_cb (void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr, - const struct TALER_EXCHANGE_Keys *keys, - enum TALER_EXCHANGE_VersionCompatibility compat) +TALER_TESTING_iterate (struct TALER_TESTING_Interpreter *is, + bool asc, + TALER_TESTING_CommandIterator cb, + void *cb_cls) { - struct MainContext *main_ctx = cls; - struct TALER_TESTING_Interpreter *is = main_ctx->is; + unsigned int start; + unsigned int end; + int inc; - (void) compat; - if (NULL == keys) + if (asc) { - if (GNUNET_NO == is->working) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Got NULL response for /keys during startup (%u/%d), retrying!\n", - hr->http_status, - (int) hr->ec); - TALER_EXCHANGE_disconnect (is->exchange); - GNUNET_assert ( - NULL != (is->exchange - = TALER_EXCHANGE_connect (is->ctx, - main_ctx->exchange_url, - &TALER_TESTING_cert_cb, - main_ctx, - TALER_EXCHANGE_OPTION_END))); - return; - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Got NULL response for /keys during execution (%u/%d)!\n", - hr->http_status, - (int) hr->ec); - } + inc = 1; + start = 0; + end = is->ip; } else { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Got %d DK from /keys in generation %u\n", - keys->num_denom_keys, - is->key_generation + 1); + inc = -1; + start = is->ip; + end = 0; + } + for (unsigned int off = start; off != end + inc; off += inc) + { + const struct TALER_TESTING_Command *cmd = &is->commands[off]; + + cb (cb_cls, + cmd); } - is->key_generation++; - is->keys = keys; +} - /* /keys has been called for some reason and - * the interpreter is already running. */ - if (GNUNET_YES == is->working) - return; - is->working = GNUNET_YES; - /* Trigger the next command. */ - TALER_LOG_DEBUG ("Cert_cb, scheduling CMD (ip: %d)\n", - is->ip); - GNUNET_SCHEDULER_add_now (&interpreter_run, - is); + +/* ************** special commands ********* */ + + +struct TALER_TESTING_Command +TALER_TESTING_cmd_end (void) +{ + static struct TALER_TESTING_Command cmd; + cmd.label = NULL; + + return cmd; +} + + +struct TALER_TESTING_Command +TALER_TESTING_cmd_set_var (const char *name, + struct TALER_TESTING_Command cmd) +{ + cmd.name = name; + return cmd; } /** - * Initialize scheduler loop and curl context for the testcase, - * and responsible to run the "run" method. + * State for a "rewind" CMD. + */ +struct RewindIpState +{ + /** + * Instruction pointer to set into the interpreter. + */ + const char *target_label; + + /** + * How many times this set should take place. However, this value lives at + * the calling process, and this CMD is only in charge of checking and + * decremeting it. + */ + unsigned int counter; +}; + + +/** + * Seek for the @a target command in @a batch (and rewind to it + * if successful). * - * @param cls closure, typically the "run" method, the - * interpreter state and a closure for "run". + * @param is the interpreter state (for failures) + * @param cmd batch to search for @a target + * @param target command to search for + * @return #GNUNET_OK on success, #GNUNET_NO if target was not found, + * #GNUNET_SYSERR if target is in the future and we failed */ -static void -main_wrapper_exchange_agnostic (void *cls) +static enum GNUNET_GenericReturnValue +seek_batch (struct TALER_TESTING_Interpreter *is, + const struct TALER_TESTING_Command *cmd, + const struct TALER_TESTING_Command *target) { - struct MainContext *main_ctx = cls; + unsigned int new_ip; + struct TALER_TESTING_Command *batch; + struct TALER_TESTING_Command *current; + struct TALER_TESTING_Command *icmd; + struct TALER_TESTING_Command *match; - main_ctx->main_cb (main_ctx->main_cb_cls, - main_ctx->is); + current = TALER_TESTING_cmd_batch_get_current (cmd); + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_batch_cmds (cmd, + &batch)); + match = NULL; + for (new_ip = 0; + NULL != (icmd = &batch[new_ip]); + new_ip++) + { + if (current == target) + current = NULL; + if (icmd == target) + { + match = icmd; + break; + } + if (TALER_TESTING_cmd_is_batch (icmd)) + { + int ret = seek_batch (is, + icmd, + target); + if (GNUNET_SYSERR == ret) + return GNUNET_SYSERR; /* failure! */ + if (GNUNET_OK == ret) + { + match = icmd; + break; + } + } + } + if (NULL == current) + { + /* refuse to jump forward */ + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return GNUNET_SYSERR; + } + if (NULL == match) + return GNUNET_NO; /* not found */ + TALER_TESTING_cmd_batch_set_current (cmd, + new_ip); + return GNUNET_OK; } /** - * Function run when the test is aborted before we launch the actual - * interpreter. Cleans up our state. + * Run the "rewind" CMD. * - * @param cls the main context + * @param cls closure. + * @param cmd command being executed now. + * @param is the interpreter state. */ static void -do_abort (void *cls) +rewind_ip_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) { - struct MainContext *main_ctx = cls; - struct TALER_TESTING_Interpreter *is = main_ctx->is; + struct RewindIpState *ris = cls; + const struct TALER_TESTING_Command *target; + unsigned int new_ip; - is->timeout_task = NULL; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Executing abort prior to interpreter launch\n"); - if (NULL != is->exchange) + (void) cmd; + if (0 == ris->counter) { - TALER_EXCHANGE_disconnect (is->exchange); - is->exchange = NULL; + TALER_TESTING_interpreter_next (is); + return; } - if (NULL != is->fakebank) + target + = TALER_TESTING_interpreter_lookup_command (is, + ris->target_label); + if (NULL == target) { - TALER_FAKEBANK_stop (is->fakebank); - is->fakebank = NULL; + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; } - if (NULL != is->ctx) + ris->counter--; + for (new_ip = 0; + NULL != is->commands[new_ip].label; + new_ip++) { - GNUNET_CURL_fini (is->ctx); - is->ctx = NULL; + const struct TALER_TESTING_Command *cmd = &is->commands[new_ip]; + + if (cmd == target) + break; + if (TALER_TESTING_cmd_is_batch (cmd)) + { + int ret = seek_batch (is, + cmd, + target); + if (GNUNET_SYSERR == ret) + return; /* failure! */ + if (GNUNET_OK == ret) + break; + } } - if (NULL != is->rc) + if (new_ip > (unsigned int) is->ip) { - GNUNET_CURL_gnunet_rc_destroy (is->rc); - is->rc = NULL; + /* refuse to jump forward */ + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; } + is->ip = new_ip - 1; /* -1 because the next function will advance by one */ + TALER_TESTING_interpreter_next (is); } -/** - * Initialize scheduler loop and curl context for the testcase, - * and responsible to run the "run" method. - * - * @param cls a `struct MainContext *` - */ -static void -main_wrapper_exchange_connect (void *cls) +struct TALER_TESTING_Command +TALER_TESTING_cmd_rewind_ip (const char *label, + const char *target_label, + unsigned int counter) { - struct MainContext *main_ctx = cls; - struct TALER_TESTING_Interpreter *is = main_ctx->is; - char *exchange_url; + struct RewindIpState *ris; - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (is->cfg, - "exchange", - "BASE_URL", - &exchange_url)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "exchange", - "BASE_URL"); - return; + ris = GNUNET_new (struct RewindIpState); + ris->target_label = target_label; + ris->counter = counter; + { + struct TALER_TESTING_Command cmd = { + .cls = ris, + .label = label, + .run = &rewind_ip_run + }; + + return cmd; } - main_ctx->exchange_url = exchange_url; - is->timeout_task = GNUNET_SCHEDULER_add_shutdown (&do_abort, - main_ctx); - is->working = GNUNET_YES; - GNUNET_assert (NULL == is->exchange); - GNUNET_break ( - NULL != (is->exchange = - TALER_EXCHANGE_connect (is->ctx, - exchange_url, - &TALER_TESTING_cert_cb, - main_ctx, - TALER_EXCHANGE_OPTION_END))); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Starting main test loop\n"); - main_ctx->main_cb (main_ctx->main_cb_cls, - is); } /** - * Load the exchange and auditor key material into @a is. + * State for a "authchange" CMD. + */ +struct AuthchangeState +{ + + /** + * What is the new authorization token to send? + */ + const char *auth_token; + + /** + * Old context, clean up on termination. + */ + struct GNUNET_CURL_Context *old_ctx; +}; + + +/** + * Run the command. * - * @param[in,out] is state to initialize + * @param cls closure. + * @param cmd the command to execute. + * @param is the interpreter state. */ -static enum GNUNET_GenericReturnValue -load_keys (struct TALER_TESTING_Interpreter *is) +static void +authchange_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) { - char *fn; + struct AuthchangeState *ss = cls; - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_filename (is->cfg, - "exchange-offline", - "MASTER_PRIV_FILE", - &fn)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "exchange-offline", - "MASTER_PRIV_FILE"); - return GNUNET_SYSERR; - } - if (GNUNET_SYSERR == - GNUNET_DISK_directory_create_for_file (fn)) + (void) cmd; + ss->old_ctx = is->ctx; + if (NULL != is->rc) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Could not setup directory for master private key file `%s'\n", - fn); - GNUNET_free (fn); - return GNUNET_SYSERR; + GNUNET_CURL_gnunet_rc_destroy (is->rc); + is->rc = NULL; } - if (GNUNET_SYSERR == - GNUNET_CRYPTO_eddsa_key_from_file (fn, - GNUNET_YES, - &is->master_priv.eddsa_priv)) + is->ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule, + &is->rc); + GNUNET_CURL_enable_async_scope_header (is->ctx, + "Taler-Correlation-Id"); + GNUNET_assert (NULL != is->ctx); + is->rc = GNUNET_CURL_gnunet_rc_create (is->ctx); + if (NULL != ss->auth_token) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Could not load master private key from `%s'\n", - fn); - GNUNET_free (fn); - return GNUNET_SYSERR; - } - GNUNET_free (fn); - GNUNET_CRYPTO_eddsa_key_get_public (&is->master_priv.eddsa_priv, - &is->master_pub.eddsa_pub); + char *authorization; - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_filename (is->cfg, - "auditor", - "AUDITOR_PRIV_FILE", - &fn)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "auditor", - "AUDITOR_PRIV_FILE"); - return GNUNET_SYSERR; - } - if (GNUNET_SYSERR == - GNUNET_DISK_directory_create_for_file (fn)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Could not setup directory for auditor private key file `%s'\n", - fn); - GNUNET_free (fn); - return GNUNET_SYSERR; - } - if (GNUNET_SYSERR == - GNUNET_CRYPTO_eddsa_key_from_file (fn, - GNUNET_YES, - &is->auditor_priv.eddsa_priv)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Could not load auditor private key from `%s'\n", - fn); - GNUNET_free (fn); - return GNUNET_SYSERR; + GNUNET_asprintf (&authorization, + "%s: %s", + MHD_HTTP_HEADER_AUTHORIZATION, + ss->auth_token); + GNUNET_assert (GNUNET_OK == + GNUNET_CURL_append_header (is->ctx, + authorization)); + GNUNET_free (authorization); } - GNUNET_free (fn); - GNUNET_CRYPTO_eddsa_key_get_public (&is->auditor_priv.eddsa_priv, - &is->auditor_pub.eddsa_pub); - return GNUNET_OK; + TALER_TESTING_interpreter_next (is); } /** - * Load the exchange and auditor URLs from the configuration into @a is. + * Call GNUNET_CURL_fini(). Done as a separate task to + * ensure that all of the command's cleanups have been + * executed first. See #7151. * - * @param[in,out] is state to initialize + * @param cls a `struct GNUNET_CURL_Context *` to clean up. */ -static enum GNUNET_GenericReturnValue -load_urls (struct TALER_TESTING_Interpreter *is) +static void +deferred_cleanup_cb (void *cls) { - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (is->cfg, - "auditor", - "BASE_URL", - &is->auditor_url)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "auditor", - "BASE_URL"); - return GNUNET_SYSERR; - } - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (is->cfg, - "exchange", - "BASE_URL", - &is->exchange_url)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "exchange", - "BASE_URL"); - GNUNET_free (is->auditor_url); - return GNUNET_SYSERR; + struct GNUNET_CURL_Context *ctx = cls; + + GNUNET_CURL_fini (ctx); +} + + +/** + * Cleanup the state from a "authchange" CMD. + * + * @param cls closure. + * @param cmd the command which is being cleaned up. + */ +static void +authchange_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct AuthchangeState *ss = cls; + + (void) cmd; + if (NULL != ss->old_ctx) + { + (void) GNUNET_SCHEDULER_add_now (&deferred_cleanup_cb, + ss->old_ctx); + ss->old_ctx = NULL; } - return GNUNET_OK; + GNUNET_free (ss); } -enum GNUNET_GenericReturnValue -TALER_TESTING_setup (TALER_TESTING_Main main_cb, - void *main_cb_cls, - const struct GNUNET_CONFIGURATION_Handle *cfg, - struct GNUNET_OS_Process *exchanged, - int exchange_connect) -{ - struct TALER_TESTING_Interpreter is = { - .cfg = cfg, - .exchanged = exchanged - }; - struct MainContext main_ctx = { - .main_cb = main_cb, - .main_cb_cls = main_cb_cls, - /* needed to init the curl ctx */ - .is = &is, - }; - struct GNUNET_SIGNAL_Context *shc_chld; +struct TALER_TESTING_Command +TALER_TESTING_cmd_set_authorization (const char *label, + const char *auth_token) +{ + struct AuthchangeState *ss; - if (GNUNET_OK != - load_keys (&is)) - return GNUNET_SYSERR; - if (GNUNET_OK != - load_urls (&is)) - return GNUNET_SYSERR; - sigpipe = GNUNET_DISK_pipe (GNUNET_DISK_PF_NONE); - GNUNET_assert (NULL != sigpipe); - shc_chld = GNUNET_SIGNAL_handler_install ( - GNUNET_SIGCHLD, - &sighandler_child_death); - is.ctx = GNUNET_CURL_init ( - &GNUNET_CURL_gnunet_scheduler_reschedule, - &is.rc); - GNUNET_CURL_enable_async_scope_header (is.ctx, - "Taler-Correlation-Id"); - GNUNET_assert (NULL != is.ctx); - is.rc = GNUNET_CURL_gnunet_rc_create (is.ctx); + ss = GNUNET_new (struct AuthchangeState); + ss->auth_token = auth_token; - /* Blocking */ - if (GNUNET_YES == exchange_connect) - GNUNET_SCHEDULER_run (&main_wrapper_exchange_connect, - &main_ctx); - else - GNUNET_SCHEDULER_run (&main_wrapper_exchange_agnostic, - &main_ctx); - if (NULL != is.final_cleanup_cb) - is.final_cleanup_cb (is.final_cleanup_cb_cls); - GNUNET_free (main_ctx.exchange_url); - GNUNET_SIGNAL_handler_uninstall (shc_chld); - GNUNET_DISK_pipe_close (sigpipe); - sigpipe = NULL; - GNUNET_free (is.auditor_url); - GNUNET_free (is.exchange_url); - return is.result; + { + struct TALER_TESTING_Command cmd = { + .cls = ss, + .label = label, + .run = &authchange_run, + .cleanup = &authchange_cleanup + }; + + return cmd; + } } diff --git a/src/testing/testing_api_misc.c b/src/testing/testing_api_misc.c new file mode 100644 index 000000000..80ff0b6c8 --- /dev/null +++ b/src/testing/testing_api_misc.c @@ -0,0 +1,394 @@ +/* + This file is part of TALER + Copyright (C) 2018-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/testing_api_misc.c + * @brief non-command functions useful for writing tests + * @author Christian Grothoff + */ +#include "platform.h" +#include <gnunet/gnunet_util_lib.h> +#include "taler_testing_lib.h" +#include "taler_fakebank_lib.h" + + +bool +TALER_TESTING_has_in_name (const char *prog, + const char *marker) +{ + size_t name_pos; + size_t pos; + + if (! prog || ! marker) + return false; + + pos = 0; + name_pos = 0; + while (prog[pos]) + { + if ('/' == prog[pos]) + name_pos = pos + 1; + pos++; + } + if (name_pos == pos) + return true; + return (NULL != strstr (prog + name_pos, + marker)); +} + + +enum GNUNET_GenericReturnValue +TALER_TESTING_get_credentials ( + const char *cfg_file, + const char *exchange_account_section, + enum TALER_TESTING_BankSystem bs, + struct TALER_TESTING_Credentials *ua) +{ + unsigned long long port; + char *exchange_payto_uri; + + ua->cfg = GNUNET_CONFIGURATION_create (); + if (GNUNET_OK != + GNUNET_CONFIGURATION_load (ua->cfg, + cfg_file)) + { + GNUNET_break (0); + GNUNET_CONFIGURATION_destroy (ua->cfg); + return GNUNET_SYSERR; + } + if (0 != + strncasecmp (exchange_account_section, + "exchange-account-", + strlen ("exchange-account-"))) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (ua->cfg, + exchange_account_section, + "PAYTO_URI", + &exchange_payto_uri)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + exchange_account_section, + "PAYTO_URI"); + return GNUNET_SYSERR; + } + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (ua->cfg, + "bank", + "HTTP_PORT", + &port)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "bank", + "HTTP_PORT"); + return GNUNET_SYSERR; + } + { + char *csn; + + GNUNET_asprintf (&csn, + "exchange-accountcredentials-%s", + &exchange_account_section[strlen ("exchange-account-")]); + if (GNUNET_OK != + TALER_BANK_auth_parse_cfg (ua->cfg, + csn, + &ua->ba)) + { + GNUNET_break (0); + GNUNET_free (csn); + return GNUNET_SYSERR; + } + GNUNET_free (csn); + } + { + char *csn; + + GNUNET_asprintf (&csn, + "admin-accountcredentials-%s", + &exchange_account_section[strlen ("exchange-account-")]); + if (GNUNET_OK != + TALER_BANK_auth_parse_cfg (ua->cfg, + csn, + &ua->ba_admin)) + { + GNUNET_break (0); + GNUNET_free (csn); + return GNUNET_SYSERR; + } + GNUNET_free (csn); + } + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (ua->cfg, + "exchange", + "BASE_URL", + &ua->exchange_url)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "exchange", + "BASE_URL"); + return GNUNET_SYSERR; + } + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (ua->cfg, + "auditor", + "BASE_URL", + &ua->auditor_url)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "auditor", + "BASE_URL"); + return GNUNET_SYSERR; + } + + switch (bs) + { + case TALER_TESTING_BS_FAKEBANK: + ua->exchange_payto + = exchange_payto_uri; + ua->user42_payto + = GNUNET_strdup ("payto://x-taler-bank/localhost/42?receiver-name=42"); + ua->user43_payto + = GNUNET_strdup ("payto://x-taler-bank/localhost/43?receiver-name=43"); + break; + case TALER_TESTING_BS_IBAN: + ua->exchange_payto + = exchange_payto_uri; + ua->user42_payto + = GNUNET_strdup ( + "payto://iban/SANDBOXX/FR7630006000011234567890189?receiver-name=User42"); + ua->user43_payto + = GNUNET_strdup ( + "payto://iban/SANDBOXX/GB33BUKB20201555555555?receiver-name=User43"); + break; + } + return GNUNET_OK; +} + + +json_t * +TALER_TESTING_make_wire_details (const char *payto) +{ + struct TALER_WireSaltP salt; + + /* salt must be constant for aggregation tests! */ + memset (&salt, + 47, + sizeof (salt)); + return GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("payto_uri", + payto), + GNUNET_JSON_pack_data_auto ("salt", + &salt)); +} + + +/** + * Remove @a option directory from @a section in @a cfg. + * + * @return #GNUNET_OK on success + */ +static enum GNUNET_GenericReturnValue +remove_dir (const struct GNUNET_CONFIGURATION_Handle *cfg, + const char *section, + const char *option) +{ + char *dir; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (cfg, + section, + option, + &dir)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + section, + option); + return GNUNET_SYSERR; + } + if (GNUNET_YES == + GNUNET_DISK_directory_test (dir, + GNUNET_NO)) + GNUNET_break (GNUNET_OK == + GNUNET_DISK_directory_remove (dir)); + GNUNET_free (dir); + return GNUNET_OK; +} + + +enum GNUNET_GenericReturnValue +TALER_TESTING_cleanup_files_cfg ( + void *cls, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + char *dir; + + (void) cls; + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (cfg, + "exchange-offline", + "SECM_TOFU_FILE", + &dir)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "exchange-offline", + "SECM_TOFU_FILE"); + return GNUNET_SYSERR; + } + if ( (0 != unlink (dir)) && + (ENOENT != errno) ) + { + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, + "unlink", + dir); + GNUNET_free (dir); + return GNUNET_SYSERR; + } + GNUNET_free (dir); + if (GNUNET_OK != + remove_dir (cfg, + "taler-exchange-secmod-eddsa", + "KEY_DIR")) + return GNUNET_SYSERR; + if (GNUNET_OK != + remove_dir (cfg, + "taler-exchange-secmod-rsa", + "KEY_DIR")) + return GNUNET_SYSERR; + return GNUNET_OK; +} + + +const struct TALER_EXCHANGE_DenomPublicKey * +TALER_TESTING_find_pk ( + const struct TALER_EXCHANGE_Keys *keys, + const struct TALER_Amount *amount, + bool age_restricted) +{ + struct GNUNET_TIME_Timestamp now; + struct TALER_EXCHANGE_DenomPublicKey *pk; + char *str; + + now = GNUNET_TIME_timestamp_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)) && + (GNUNET_TIME_timestamp_cmp (now, + >=, + pk->valid_from)) && + (GNUNET_TIME_timestamp_cmp (now, + <, + pk->withdraw_valid_until)) && + (age_restricted == (0 != pk->key.age_mask.bits)) ) + 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)) && + (GNUNET_TIME_timestamp_cmp (now, + <, + pk->valid_from) || + GNUNET_TIME_timestamp_cmp (now, + >, + pk->withdraw_valid_until) ) && + (age_restricted == (0 != pk->key.age_mask.bits)) ) + { + 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_time.abs_value_us, + (unsigned long long) pk->valid_from.abs_time.abs_value_us, + (unsigned long long) pk->withdraw_valid_until.abs_time.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; +} + + +int +TALER_TESTING_wait_httpd_ready (const char *base_url) +{ + char *wget_cmd; + unsigned int iter; + + GNUNET_asprintf (&wget_cmd, + "wget -q -t 1 -T 1 %s -o /dev/null -O /dev/null", + base_url); // make sure ends with '/' + /* give child time to start and bind against the socket */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Waiting for HTTP service to be ready (check with: %s)\n", + wget_cmd); + iter = 0; + do + { + if (10 == iter) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to launch HTTP service (or `wget')\n"); + GNUNET_free (wget_cmd); + return 77; + } + sleep (1); + iter++; + } + while (0 != system (wget_cmd)); + GNUNET_free (wget_cmd); + return 0; +} + + +enum GNUNET_GenericReturnValue +TALER_TESTING_url_port_free (const char *url) +{ + const char *port; + long pnum; + + port = strrchr (url, + (unsigned char) ':'); + if (NULL == port) + pnum = 80; + else + pnum = strtol (port + 1, NULL, 10); + if (GNUNET_OK != + GNUNET_NETWORK_test_port_free (IPPROTO_TCP, + pnum)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Port %u not available.\n", + (unsigned int) pnum); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} diff --git a/src/testing/testing_api_traits.c b/src/testing/testing_api_traits.c index db94e81a5..799ae6718 100644 --- a/src/testing/testing_api_traits.c +++ b/src/testing/testing_api_traits.c @@ -67,7 +67,7 @@ TALER_TESTING_get_trait (const struct TALER_TESTING_Trait *traits, return GNUNET_OK; } } - GNUNET_log (GNUNET_ERROR_TYPE_INFO, + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trait %s/%u not found.\n", trait, index); @@ -75,4 +75,59 @@ TALER_TESTING_get_trait (const struct TALER_TESTING_Trait *traits, } +const char * +TALER_TESTING_get_exchange_url (struct TALER_TESTING_Interpreter *is) +{ + const char *exchange_url; + const struct TALER_TESTING_Command *exchange_cmd; + + exchange_cmd + = TALER_TESTING_interpreter_get_command (is, + "exchange"); + if (NULL == exchange_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return NULL; + } + if (GNUNET_OK != + TALER_TESTING_get_trait_exchange_url (exchange_cmd, + &exchange_url)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return NULL; + } + return exchange_url; +} + + +struct TALER_EXCHANGE_Keys * +TALER_TESTING_get_keys ( + struct TALER_TESTING_Interpreter *is) +{ + struct TALER_EXCHANGE_Keys *keys; + const struct TALER_TESTING_Command *exchange_cmd; + + exchange_cmd + = TALER_TESTING_interpreter_get_command (is, + "exchange"); + if (NULL == exchange_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return NULL; + } + if (GNUNET_OK != + TALER_TESTING_get_trait_keys (exchange_cmd, + &keys)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return NULL; + } + return keys; +} + + /* end of testing_api_traits.c */ diff --git a/src/testing/testing_api_twister_helpers.c b/src/testing/testing_api_twister_helpers.c index 935d8bcc1..68fbf0082 100644 --- a/src/testing/testing_api_twister_helpers.c +++ b/src/testing/testing_api_twister_helpers.c @@ -116,7 +116,9 @@ TALER_TWISTER_run_twister (const char *config_filename) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not start the taler-twister client\n"); - GNUNET_OS_process_kill (proc, SIGTERM); + GNUNET_break (0 == + GNUNET_OS_process_kill (proc, + SIGTERM)); GNUNET_OS_process_wait (proc); GNUNET_OS_process_destroy (proc); TWISTER_FAIL (); @@ -129,7 +131,9 @@ TALER_TWISTER_run_twister (const char *config_filename) &code)) { GNUNET_OS_process_destroy (client_proc); - GNUNET_OS_process_kill (proc, SIGTERM); + GNUNET_break (0 == + GNUNET_OS_process_kill (proc, + SIGTERM)); GNUNET_OS_process_wait (proc); GNUNET_OS_process_destroy (proc); TWISTER_FAIL (); @@ -140,7 +144,9 @@ TALER_TWISTER_run_twister (const char *config_filename) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to check twister works.\n"); GNUNET_OS_process_destroy (client_proc); - GNUNET_OS_process_kill (proc, SIGTERM); + GNUNET_break (0 == + GNUNET_OS_process_kill (proc, + SIGTERM)); GNUNET_OS_process_wait (proc); GNUNET_OS_process_destroy (proc); TWISTER_FAIL (); @@ -151,7 +157,9 @@ TALER_TWISTER_run_twister (const char *config_filename) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unexpected error running `taler-twister'!\n"); GNUNET_OS_process_destroy (client_proc); - GNUNET_OS_process_kill (proc, SIGTERM); + GNUNET_break (0 == + GNUNET_OS_process_kill (proc, + SIGTERM)); GNUNET_OS_process_wait (proc); GNUNET_OS_process_destroy (proc); TWISTER_FAIL (); diff --git a/src/testing/valgrind.h b/src/testing/valgrind.h new file mode 100644 index 000000000..eaf1632e1 --- /dev/null +++ b/src/testing/valgrind.h @@ -0,0 +1,7165 @@ +/* -*- c -*- + ---------------------------------------------------------------- + + Notice that the following BSD-style license applies to this one + file (valgrind.h) only. The rest of Valgrind is licensed under the + terms of the GNU General Public License, version 2, unless + otherwise indicated. See the COPYING file in the source + distribution for details. + + ---------------------------------------------------------------- + + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2017 Julian Seward. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 3. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + + 4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + ---------------------------------------------------------------- + + Notice that the above BSD-style license applies to this one file + (valgrind.h) only. The entire rest of Valgrind is licensed under + the terms of the GNU General Public License, version 2. See the + COPYING file in the source distribution for details. + + ---------------------------------------------------------------- +*/ + + +/* This file is for inclusion into client (your!) code. + + You can use these macros to manipulate and query Valgrind's + execution inside your own programs. + + The resulting executables will still run without Valgrind, just a + little bit more slowly than they otherwise would, but otherwise + unchanged. When not running on valgrind, each client request + consumes very few (eg. 7) instructions, so the resulting performance + loss is negligible unless you plan to execute client requests + millions of times per second. Nevertheless, if that is still a + problem, you can compile with the NVALGRIND symbol defined (gcc + -DNVALGRIND) so that client requests are not even compiled in. */ + +#ifndef __VALGRIND_H +#define __VALGRIND_H + + +/* ------------------------------------------------------------------ */ +/* VERSION NUMBER OF VALGRIND */ +/* ------------------------------------------------------------------ */ + +/* Specify Valgrind's version number, so that user code can + conditionally compile based on our version number. Note that these + were introduced at version 3.6 and so do not exist in version 3.5 + or earlier. The recommended way to use them to check for "version + X.Y or later" is (eg) + +#if defined(__VALGRIND_MAJOR__) && defined(__VALGRIND_MINOR__) \ + && (__VALGRIND_MAJOR__ > 3 \ + || (__VALGRIND_MAJOR__ == 3 && __VALGRIND_MINOR__ >= 6)) +*/ +#define __VALGRIND_MAJOR__ 3 +#define __VALGRIND_MINOR__ 19 + + +#include <stdarg.h> + +/* Nb: this file might be included in a file compiled with -ansi. So + we can't use C++ style "//" comments nor the "asm" keyword (instead + use "__asm__"). */ + +/* Derive some tags indicating what the target platform is. Note + that in this file we're using the compiler's CPP symbols for + identifying architectures, which are different to the ones we use + within the rest of Valgrind. Note, __powerpc__ is active for both + 32 and 64-bit PPC, whereas __powerpc64__ is only active for the + latter (on Linux, that is). + + Misc note: how to find out what's predefined in gcc by default: + gcc -Wp,-dM somefile.c +*/ +#undef PLAT_x86_darwin +#undef PLAT_amd64_darwin +#undef PLAT_x86_freebsd +#undef PLAT_amd64_freebsd +#undef PLAT_x86_win32 +#undef PLAT_amd64_win64 +#undef PLAT_x86_linux +#undef PLAT_amd64_linux +#undef PLAT_ppc32_linux +#undef PLAT_ppc64be_linux +#undef PLAT_ppc64le_linux +#undef PLAT_arm_linux +#undef PLAT_arm64_linux +#undef PLAT_s390x_linux +#undef PLAT_mips32_linux +#undef PLAT_mips64_linux +#undef PLAT_nanomips_linux +#undef PLAT_x86_solaris +#undef PLAT_amd64_solaris + + +#if defined(__APPLE__) && defined(__i386__) +# define PLAT_x86_darwin 1 +#elif defined(__APPLE__) && defined(__x86_64__) +# define PLAT_amd64_darwin 1 +#elif defined(__FreeBSD__) && defined(__i386__) +# define PLAT_x86_freebsd 1 +#elif defined(__FreeBSD__) && defined(__amd64__) +# define PLAT_amd64_freebsd 1 +#elif (defined(__MINGW32__) && defined(__i386__)) \ + || defined(__CYGWIN32__) \ + || (defined(_WIN32) && defined(_M_IX86)) +# define PLAT_x86_win32 1 +#elif (defined(__MINGW32__) && defined(__x86_64__)) \ + || (defined(_WIN32) && defined(_M_X64)) +/* __MINGW32__ and _WIN32 are defined in 64 bit mode as well. */ +# define PLAT_amd64_win64 1 +#elif defined(__linux__) && defined(__i386__) +# define PLAT_x86_linux 1 +#elif defined(__linux__) && defined(__x86_64__) && !defined(__ILP32__) +# define PLAT_amd64_linux 1 +#elif defined(__linux__) && defined(__powerpc__) && !defined(__powerpc64__) +# define PLAT_ppc32_linux 1 +#elif defined(__linux__) && defined(__powerpc__) && defined(__powerpc64__) && _CALL_ELF != 2 +/* Big Endian uses ELF version 1 */ +# define PLAT_ppc64be_linux 1 +#elif defined(__linux__) && defined(__powerpc__) && defined(__powerpc64__) && _CALL_ELF == 2 +/* Little Endian uses ELF version 2 */ +# define PLAT_ppc64le_linux 1 +#elif defined(__linux__) && defined(__arm__) && !defined(__aarch64__) +# define PLAT_arm_linux 1 +#elif defined(__linux__) && defined(__aarch64__) && !defined(__arm__) +# define PLAT_arm64_linux 1 +#elif defined(__linux__) && defined(__s390__) && defined(__s390x__) +# define PLAT_s390x_linux 1 +#elif defined(__linux__) && defined(__mips__) && (__mips==64) +# define PLAT_mips64_linux 1 +#elif defined(__linux__) && defined(__mips__) && (__mips==32) +# define PLAT_mips32_linux 1 +#elif defined(__linux__) && defined(__nanomips__) +# define PLAT_nanomips_linux 1 +#elif defined(__sun) && defined(__i386__) +# define PLAT_x86_solaris 1 +#elif defined(__sun) && defined(__x86_64__) +# define PLAT_amd64_solaris 1 +#else +/* If we're not compiling for our target platform, don't generate + any inline asms. */ +# if !defined(NVALGRIND) +# define NVALGRIND 1 +# endif +#endif + + +/* ------------------------------------------------------------------ */ +/* ARCHITECTURE SPECIFICS for SPECIAL INSTRUCTIONS. There is nothing */ +/* in here of use to end-users -- skip to the next section. */ +/* ------------------------------------------------------------------ */ + +/* + * VALGRIND_DO_CLIENT_REQUEST(): a statement that invokes a Valgrind client + * request. Accepts both pointers and integers as arguments. + * + * VALGRIND_DO_CLIENT_REQUEST_STMT(): a statement that invokes a Valgrind + * client request that does not return a value. + + * VALGRIND_DO_CLIENT_REQUEST_EXPR(): a C expression that invokes a Valgrind + * client request and whose value equals the client request result. Accepts + * both pointers and integers as arguments. Note that such calls are not + * necessarily pure functions -- they may have side effects. + */ + +#define VALGRIND_DO_CLIENT_REQUEST(_zzq_rlval, _zzq_default, \ + _zzq_request, _zzq_arg1, _zzq_arg2, \ + _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + do { (_zzq_rlval) = VALGRIND_DO_CLIENT_REQUEST_EXPR((_zzq_default), \ + (_zzq_request), (_zzq_arg1), (_zzq_arg2), \ + (_zzq_arg3), (_zzq_arg4), (_zzq_arg5)); } while (0) + +#define VALGRIND_DO_CLIENT_REQUEST_STMT(_zzq_request, _zzq_arg1, \ + _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + do { (void) VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ + (_zzq_request), (_zzq_arg1), (_zzq_arg2), \ + (_zzq_arg3), (_zzq_arg4), (_zzq_arg5)); } while (0) + +#if defined(NVALGRIND) + +/* Define NVALGRIND to completely remove the Valgrind magic sequence + from the compiled code (analogous to NDEBUG's effects on + assert()) */ +#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ + _zzq_default, _zzq_request, \ + _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + (_zzq_default) + +#else /* ! NVALGRIND */ + +/* The following defines the magic code sequences which the JITter + spots and handles magically. Don't look too closely at them as + they will rot your brain. + + The assembly code sequences for all architectures is in this one + file. This is because this file must be stand-alone, and we don't + want to have multiple files. + + For VALGRIND_DO_CLIENT_REQUEST, we must ensure that the default + value gets put in the return slot, so that everything works when + this is executed not under Valgrind. Args are passed in a memory + block, and so there's no intrinsic limit to the number that could + be passed, but it's currently five. + + The macro args are: + _zzq_rlval result lvalue + _zzq_default default value (result returned when running on real CPU) + _zzq_request request code + _zzq_arg1..5 request params + + The other two macros are used to support function wrapping, and are + a lot simpler. VALGRIND_GET_NR_CONTEXT returns the value of the + guest's NRADDR pseudo-register and whatever other information is + needed to safely run the call original from the wrapper: on + ppc64-linux, the R2 value at the divert point is also needed. This + information is abstracted into a user-visible type, OrigFn. + + VALGRIND_CALL_NOREDIR_* behaves the same as the following on the + guest, but guarantees that the branch instruction will not be + redirected: x86: call *%eax, amd64: call *%rax, ppc32/ppc64: + branch-and-link-to-r11. VALGRIND_CALL_NOREDIR is just text, not a + complete inline asm, since it needs to be combined with more magic + inline asm stuff to be useful. +*/ + +/* ----------------- x86-{linux,darwin,solaris} ---------------- */ + +#if defined(PLAT_x86_linux) || defined(PLAT_x86_darwin) \ + || (defined(PLAT_x86_win32) && defined(__GNUC__)) \ + || defined(PLAT_x86_solaris) || defined(PLAT_x86_freebsd) + +typedef + struct { + unsigned int nraddr; /* where's the code? */ + } + OrigFn; + +#define __SPECIAL_INSTRUCTION_PREAMBLE \ + "roll $3, %%edi ; roll $13, %%edi\n\t" \ + "roll $29, %%edi ; roll $19, %%edi\n\t" + +#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ + _zzq_default, _zzq_request, \ + _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + __extension__ \ + ({volatile unsigned int _zzq_args[6]; \ + volatile unsigned int _zzq_result; \ + _zzq_args[0] = (unsigned int)(_zzq_request); \ + _zzq_args[1] = (unsigned int)(_zzq_arg1); \ + _zzq_args[2] = (unsigned int)(_zzq_arg2); \ + _zzq_args[3] = (unsigned int)(_zzq_arg3); \ + _zzq_args[4] = (unsigned int)(_zzq_arg4); \ + _zzq_args[5] = (unsigned int)(_zzq_arg5); \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + /* %EDX = client_request ( %EAX ) */ \ + "xchgl %%ebx,%%ebx" \ + : "=d" (_zzq_result) \ + : "a" (&_zzq_args[0]), "0" (_zzq_default) \ + : "cc", "memory" \ + ); \ + _zzq_result; \ + }) + +#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ + { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ + volatile unsigned int __addr; \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + /* %EAX = guest_NRADDR */ \ + "xchgl %%ecx,%%ecx" \ + : "=a" (__addr) \ + : \ + : "cc", "memory" \ + ); \ + _zzq_orig->nraddr = __addr; \ + } + +#define VALGRIND_CALL_NOREDIR_EAX \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + /* call-noredir *%EAX */ \ + "xchgl %%edx,%%edx\n\t" + +#define VALGRIND_VEX_INJECT_IR() \ + do { \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + "xchgl %%edi,%%edi\n\t" \ + : : : "cc", "memory" \ + ); \ + } while (0) + +#endif /* PLAT_x86_linux || PLAT_x86_darwin || (PLAT_x86_win32 && __GNUC__) + || PLAT_x86_solaris */ + +/* ------------------------- x86-Win32 ------------------------- */ + +#if defined(PLAT_x86_win32) && !defined(__GNUC__) + +typedef + struct { + unsigned int nraddr; /* where's the code? */ + } + OrigFn; + +#if defined(_MSC_VER) + +#define __SPECIAL_INSTRUCTION_PREAMBLE \ + __asm rol edi, 3 __asm rol edi, 13 \ + __asm rol edi, 29 __asm rol edi, 19 + +#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ + _zzq_default, _zzq_request, \ + _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + valgrind_do_client_request_expr((uintptr_t)(_zzq_default), \ + (uintptr_t)(_zzq_request), (uintptr_t)(_zzq_arg1), \ + (uintptr_t)(_zzq_arg2), (uintptr_t)(_zzq_arg3), \ + (uintptr_t)(_zzq_arg4), (uintptr_t)(_zzq_arg5)) + +static __inline uintptr_t +valgrind_do_client_request_expr(uintptr_t _zzq_default, uintptr_t _zzq_request, + uintptr_t _zzq_arg1, uintptr_t _zzq_arg2, + uintptr_t _zzq_arg3, uintptr_t _zzq_arg4, + uintptr_t _zzq_arg5) +{ + volatile uintptr_t _zzq_args[6]; + volatile unsigned int _zzq_result; + _zzq_args[0] = (uintptr_t)(_zzq_request); + _zzq_args[1] = (uintptr_t)(_zzq_arg1); + _zzq_args[2] = (uintptr_t)(_zzq_arg2); + _zzq_args[3] = (uintptr_t)(_zzq_arg3); + _zzq_args[4] = (uintptr_t)(_zzq_arg4); + _zzq_args[5] = (uintptr_t)(_zzq_arg5); + __asm { __asm lea eax, _zzq_args __asm mov edx, _zzq_default + __SPECIAL_INSTRUCTION_PREAMBLE + /* %EDX = client_request ( %EAX ) */ + __asm xchg ebx,ebx + __asm mov _zzq_result, edx + } + return _zzq_result; +} + +#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ + { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ + volatile unsigned int __addr; \ + __asm { __SPECIAL_INSTRUCTION_PREAMBLE \ + /* %EAX = guest_NRADDR */ \ + __asm xchg ecx,ecx \ + __asm mov __addr, eax \ + } \ + _zzq_orig->nraddr = __addr; \ + } + +#define VALGRIND_CALL_NOREDIR_EAX ERROR + +#define VALGRIND_VEX_INJECT_IR() \ + do { \ + __asm { __SPECIAL_INSTRUCTION_PREAMBLE \ + __asm xchg edi,edi \ + } \ + } while (0) + +#else +#error Unsupported compiler. +#endif + +#endif /* PLAT_x86_win32 */ + +/* ----------------- amd64-{linux,darwin,solaris} --------------- */ + +#if defined(PLAT_amd64_linux) || defined(PLAT_amd64_darwin) \ + || defined(PLAT_amd64_solaris) \ + || defined(PLAT_amd64_freebsd) \ + || (defined(PLAT_amd64_win64) && defined(__GNUC__)) + +typedef + struct { + unsigned long int nraddr; /* where's the code? */ + } + OrigFn; + +#define __SPECIAL_INSTRUCTION_PREAMBLE \ + "rolq $3, %%rdi ; rolq $13, %%rdi\n\t" \ + "rolq $61, %%rdi ; rolq $51, %%rdi\n\t" + +#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ + _zzq_default, _zzq_request, \ + _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + __extension__ \ + ({ volatile unsigned long int _zzq_args[6]; \ + volatile unsigned long int _zzq_result; \ + _zzq_args[0] = (unsigned long int)(_zzq_request); \ + _zzq_args[1] = (unsigned long int)(_zzq_arg1); \ + _zzq_args[2] = (unsigned long int)(_zzq_arg2); \ + _zzq_args[3] = (unsigned long int)(_zzq_arg3); \ + _zzq_args[4] = (unsigned long int)(_zzq_arg4); \ + _zzq_args[5] = (unsigned long int)(_zzq_arg5); \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + /* %RDX = client_request ( %RAX ) */ \ + "xchgq %%rbx,%%rbx" \ + : "=d" (_zzq_result) \ + : "a" (&_zzq_args[0]), "0" (_zzq_default) \ + : "cc", "memory" \ + ); \ + _zzq_result; \ + }) + +#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ + { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ + volatile unsigned long int __addr; \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + /* %RAX = guest_NRADDR */ \ + "xchgq %%rcx,%%rcx" \ + : "=a" (__addr) \ + : \ + : "cc", "memory" \ + ); \ + _zzq_orig->nraddr = __addr; \ + } + +#define VALGRIND_CALL_NOREDIR_RAX \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + /* call-noredir *%RAX */ \ + "xchgq %%rdx,%%rdx\n\t" + +#define VALGRIND_VEX_INJECT_IR() \ + do { \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + "xchgq %%rdi,%%rdi\n\t" \ + : : : "cc", "memory" \ + ); \ + } while (0) + +#endif /* PLAT_amd64_linux || PLAT_amd64_darwin || PLAT_amd64_solaris */ + +/* ------------------------- amd64-Win64 ------------------------- */ + +#if defined(PLAT_amd64_win64) && !defined(__GNUC__) + +#error Unsupported compiler. + +#endif /* PLAT_amd64_win64 */ + +/* ------------------------ ppc32-linux ------------------------ */ + +#if defined(PLAT_ppc32_linux) + +typedef + struct { + unsigned int nraddr; /* where's the code? */ + } + OrigFn; + +#define __SPECIAL_INSTRUCTION_PREAMBLE \ + "rlwinm 0,0,3,0,31 ; rlwinm 0,0,13,0,31\n\t" \ + "rlwinm 0,0,29,0,31 ; rlwinm 0,0,19,0,31\n\t" + +#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ + _zzq_default, _zzq_request, \ + _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + \ + __extension__ \ + ({ unsigned int _zzq_args[6]; \ + unsigned int _zzq_result; \ + unsigned int* _zzq_ptr; \ + _zzq_args[0] = (unsigned int)(_zzq_request); \ + _zzq_args[1] = (unsigned int)(_zzq_arg1); \ + _zzq_args[2] = (unsigned int)(_zzq_arg2); \ + _zzq_args[3] = (unsigned int)(_zzq_arg3); \ + _zzq_args[4] = (unsigned int)(_zzq_arg4); \ + _zzq_args[5] = (unsigned int)(_zzq_arg5); \ + _zzq_ptr = _zzq_args; \ + __asm__ volatile("mr 3,%1\n\t" /*default*/ \ + "mr 4,%2\n\t" /*ptr*/ \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + /* %R3 = client_request ( %R4 ) */ \ + "or 1,1,1\n\t" \ + "mr %0,3" /*result*/ \ + : "=b" (_zzq_result) \ + : "b" (_zzq_default), "b" (_zzq_ptr) \ + : "cc", "memory", "r3", "r4"); \ + _zzq_result; \ + }) + +#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ + { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ + unsigned int __addr; \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + /* %R3 = guest_NRADDR */ \ + "or 2,2,2\n\t" \ + "mr %0,3" \ + : "=b" (__addr) \ + : \ + : "cc", "memory", "r3" \ + ); \ + _zzq_orig->nraddr = __addr; \ + } + +#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + /* branch-and-link-to-noredir *%R11 */ \ + "or 3,3,3\n\t" + +#define VALGRIND_VEX_INJECT_IR() \ + do { \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + "or 5,5,5\n\t" \ + ); \ + } while (0) + +#endif /* PLAT_ppc32_linux */ + +/* ------------------------ ppc64-linux ------------------------ */ + +#if defined(PLAT_ppc64be_linux) + +typedef + struct { + unsigned long int nraddr; /* where's the code? */ + unsigned long int r2; /* what tocptr do we need? */ + } + OrigFn; + +#define __SPECIAL_INSTRUCTION_PREAMBLE \ + "rotldi 0,0,3 ; rotldi 0,0,13\n\t" \ + "rotldi 0,0,61 ; rotldi 0,0,51\n\t" + +#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ + _zzq_default, _zzq_request, \ + _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + \ + __extension__ \ + ({ unsigned long int _zzq_args[6]; \ + unsigned long int _zzq_result; \ + unsigned long int* _zzq_ptr; \ + _zzq_args[0] = (unsigned long int)(_zzq_request); \ + _zzq_args[1] = (unsigned long int)(_zzq_arg1); \ + _zzq_args[2] = (unsigned long int)(_zzq_arg2); \ + _zzq_args[3] = (unsigned long int)(_zzq_arg3); \ + _zzq_args[4] = (unsigned long int)(_zzq_arg4); \ + _zzq_args[5] = (unsigned long int)(_zzq_arg5); \ + _zzq_ptr = _zzq_args; \ + __asm__ volatile("mr 3,%1\n\t" /*default*/ \ + "mr 4,%2\n\t" /*ptr*/ \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + /* %R3 = client_request ( %R4 ) */ \ + "or 1,1,1\n\t" \ + "mr %0,3" /*result*/ \ + : "=b" (_zzq_result) \ + : "b" (_zzq_default), "b" (_zzq_ptr) \ + : "cc", "memory", "r3", "r4"); \ + _zzq_result; \ + }) + +#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ + { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ + unsigned long int __addr; \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + /* %R3 = guest_NRADDR */ \ + "or 2,2,2\n\t" \ + "mr %0,3" \ + : "=b" (__addr) \ + : \ + : "cc", "memory", "r3" \ + ); \ + _zzq_orig->nraddr = __addr; \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + /* %R3 = guest_NRADDR_GPR2 */ \ + "or 4,4,4\n\t" \ + "mr %0,3" \ + : "=b" (__addr) \ + : \ + : "cc", "memory", "r3" \ + ); \ + _zzq_orig->r2 = __addr; \ + } + +#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + /* branch-and-link-to-noredir *%R11 */ \ + "or 3,3,3\n\t" + +#define VALGRIND_VEX_INJECT_IR() \ + do { \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + "or 5,5,5\n\t" \ + ); \ + } while (0) + +#endif /* PLAT_ppc64be_linux */ + +#if defined(PLAT_ppc64le_linux) + +typedef + struct { + unsigned long int nraddr; /* where's the code? */ + unsigned long int r2; /* what tocptr do we need? */ + } + OrigFn; + +#define __SPECIAL_INSTRUCTION_PREAMBLE \ + "rotldi 0,0,3 ; rotldi 0,0,13\n\t" \ + "rotldi 0,0,61 ; rotldi 0,0,51\n\t" + +#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ + _zzq_default, _zzq_request, \ + _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + \ + __extension__ \ + ({ unsigned long int _zzq_args[6]; \ + unsigned long int _zzq_result; \ + unsigned long int* _zzq_ptr; \ + _zzq_args[0] = (unsigned long int)(_zzq_request); \ + _zzq_args[1] = (unsigned long int)(_zzq_arg1); \ + _zzq_args[2] = (unsigned long int)(_zzq_arg2); \ + _zzq_args[3] = (unsigned long int)(_zzq_arg3); \ + _zzq_args[4] = (unsigned long int)(_zzq_arg4); \ + _zzq_args[5] = (unsigned long int)(_zzq_arg5); \ + _zzq_ptr = _zzq_args; \ + __asm__ volatile("mr 3,%1\n\t" /*default*/ \ + "mr 4,%2\n\t" /*ptr*/ \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + /* %R3 = client_request ( %R4 ) */ \ + "or 1,1,1\n\t" \ + "mr %0,3" /*result*/ \ + : "=b" (_zzq_result) \ + : "b" (_zzq_default), "b" (_zzq_ptr) \ + : "cc", "memory", "r3", "r4"); \ + _zzq_result; \ + }) + +#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ + { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ + unsigned long int __addr; \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + /* %R3 = guest_NRADDR */ \ + "or 2,2,2\n\t" \ + "mr %0,3" \ + : "=b" (__addr) \ + : \ + : "cc", "memory", "r3" \ + ); \ + _zzq_orig->nraddr = __addr; \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + /* %R3 = guest_NRADDR_GPR2 */ \ + "or 4,4,4\n\t" \ + "mr %0,3" \ + : "=b" (__addr) \ + : \ + : "cc", "memory", "r3" \ + ); \ + _zzq_orig->r2 = __addr; \ + } + +#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + /* branch-and-link-to-noredir *%R12 */ \ + "or 3,3,3\n\t" + +#define VALGRIND_VEX_INJECT_IR() \ + do { \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + "or 5,5,5\n\t" \ + ); \ + } while (0) + +#endif /* PLAT_ppc64le_linux */ + +/* ------------------------- arm-linux ------------------------- */ + +#if defined(PLAT_arm_linux) + +typedef + struct { + unsigned int nraddr; /* where's the code? */ + } + OrigFn; + +#define __SPECIAL_INSTRUCTION_PREAMBLE \ + "mov r12, r12, ror #3 ; mov r12, r12, ror #13 \n\t" \ + "mov r12, r12, ror #29 ; mov r12, r12, ror #19 \n\t" + +#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ + _zzq_default, _zzq_request, \ + _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + \ + __extension__ \ + ({volatile unsigned int _zzq_args[6]; \ + volatile unsigned int _zzq_result; \ + _zzq_args[0] = (unsigned int)(_zzq_request); \ + _zzq_args[1] = (unsigned int)(_zzq_arg1); \ + _zzq_args[2] = (unsigned int)(_zzq_arg2); \ + _zzq_args[3] = (unsigned int)(_zzq_arg3); \ + _zzq_args[4] = (unsigned int)(_zzq_arg4); \ + _zzq_args[5] = (unsigned int)(_zzq_arg5); \ + __asm__ volatile("mov r3, %1\n\t" /*default*/ \ + "mov r4, %2\n\t" /*ptr*/ \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + /* R3 = client_request ( R4 ) */ \ + "orr r10, r10, r10\n\t" \ + "mov %0, r3" /*result*/ \ + : "=r" (_zzq_result) \ + : "r" (_zzq_default), "r" (&_zzq_args[0]) \ + : "cc","memory", "r3", "r4"); \ + _zzq_result; \ + }) + +#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ + { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ + unsigned int __addr; \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + /* R3 = guest_NRADDR */ \ + "orr r11, r11, r11\n\t" \ + "mov %0, r3" \ + : "=r" (__addr) \ + : \ + : "cc", "memory", "r3" \ + ); \ + _zzq_orig->nraddr = __addr; \ + } + +#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + /* branch-and-link-to-noredir *%R4 */ \ + "orr r12, r12, r12\n\t" + +#define VALGRIND_VEX_INJECT_IR() \ + do { \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + "orr r9, r9, r9\n\t" \ + : : : "cc", "memory" \ + ); \ + } while (0) + +#endif /* PLAT_arm_linux */ + +/* ------------------------ arm64-linux ------------------------- */ + +#if defined(PLAT_arm64_linux) + +typedef + struct { + unsigned long int nraddr; /* where's the code? */ + } + OrigFn; + +#define __SPECIAL_INSTRUCTION_PREAMBLE \ + "ror x12, x12, #3 ; ror x12, x12, #13 \n\t" \ + "ror x12, x12, #51 ; ror x12, x12, #61 \n\t" + +#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ + _zzq_default, _zzq_request, \ + _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + \ + __extension__ \ + ({volatile unsigned long int _zzq_args[6]; \ + volatile unsigned long int _zzq_result; \ + _zzq_args[0] = (unsigned long int)(_zzq_request); \ + _zzq_args[1] = (unsigned long int)(_zzq_arg1); \ + _zzq_args[2] = (unsigned long int)(_zzq_arg2); \ + _zzq_args[3] = (unsigned long int)(_zzq_arg3); \ + _zzq_args[4] = (unsigned long int)(_zzq_arg4); \ + _zzq_args[5] = (unsigned long int)(_zzq_arg5); \ + __asm__ volatile("mov x3, %1\n\t" /*default*/ \ + "mov x4, %2\n\t" /*ptr*/ \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + /* X3 = client_request ( X4 ) */ \ + "orr x10, x10, x10\n\t" \ + "mov %0, x3" /*result*/ \ + : "=r" (_zzq_result) \ + : "r" ((unsigned long int)(_zzq_default)), \ + "r" (&_zzq_args[0]) \ + : "cc","memory", "x3", "x4"); \ + _zzq_result; \ + }) + +#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ + { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ + unsigned long int __addr; \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + /* X3 = guest_NRADDR */ \ + "orr x11, x11, x11\n\t" \ + "mov %0, x3" \ + : "=r" (__addr) \ + : \ + : "cc", "memory", "x3" \ + ); \ + _zzq_orig->nraddr = __addr; \ + } + +#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + /* branch-and-link-to-noredir X8 */ \ + "orr x12, x12, x12\n\t" + +#define VALGRIND_VEX_INJECT_IR() \ + do { \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + "orr x9, x9, x9\n\t" \ + : : : "cc", "memory" \ + ); \ + } while (0) + +#endif /* PLAT_arm64_linux */ + +/* ------------------------ s390x-linux ------------------------ */ + +#if defined(PLAT_s390x_linux) + +typedef + struct { + unsigned long int nraddr; /* where's the code? */ + } + OrigFn; + +/* __SPECIAL_INSTRUCTION_PREAMBLE will be used to identify Valgrind specific + * code. This detection is implemented in platform specific toIR.c + * (e.g. VEX/priv/guest_s390_decoder.c). + */ +#define __SPECIAL_INSTRUCTION_PREAMBLE \ + "lr 15,15\n\t" \ + "lr 1,1\n\t" \ + "lr 2,2\n\t" \ + "lr 3,3\n\t" + +#define __CLIENT_REQUEST_CODE "lr 2,2\n\t" +#define __GET_NR_CONTEXT_CODE "lr 3,3\n\t" +#define __CALL_NO_REDIR_CODE "lr 4,4\n\t" +#define __VEX_INJECT_IR_CODE "lr 5,5\n\t" + +#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ + _zzq_default, _zzq_request, \ + _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + __extension__ \ + ({volatile unsigned long int _zzq_args[6]; \ + volatile unsigned long int _zzq_result; \ + _zzq_args[0] = (unsigned long int)(_zzq_request); \ + _zzq_args[1] = (unsigned long int)(_zzq_arg1); \ + _zzq_args[2] = (unsigned long int)(_zzq_arg2); \ + _zzq_args[3] = (unsigned long int)(_zzq_arg3); \ + _zzq_args[4] = (unsigned long int)(_zzq_arg4); \ + _zzq_args[5] = (unsigned long int)(_zzq_arg5); \ + __asm__ volatile(/* r2 = args */ \ + "lgr 2,%1\n\t" \ + /* r3 = default */ \ + "lgr 3,%2\n\t" \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + __CLIENT_REQUEST_CODE \ + /* results = r3 */ \ + "lgr %0, 3\n\t" \ + : "=d" (_zzq_result) \ + : "a" (&_zzq_args[0]), \ + "0" ((unsigned long int)_zzq_default) \ + : "cc", "2", "3", "memory" \ + ); \ + _zzq_result; \ + }) + +#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ + { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ + volatile unsigned long int __addr; \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + __GET_NR_CONTEXT_CODE \ + "lgr %0, 3\n\t" \ + : "=a" (__addr) \ + : \ + : "cc", "3", "memory" \ + ); \ + _zzq_orig->nraddr = __addr; \ + } + +#define VALGRIND_CALL_NOREDIR_R1 \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + __CALL_NO_REDIR_CODE + +#define VALGRIND_VEX_INJECT_IR() \ + do { \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + __VEX_INJECT_IR_CODE); \ + } while (0) + +#endif /* PLAT_s390x_linux */ + +/* ------------------------- mips32-linux ---------------- */ + +#if defined(PLAT_mips32_linux) + +typedef + struct { + unsigned int nraddr; /* where's the code? */ + } + OrigFn; + +/* .word 0x342 + * .word 0x742 + * .word 0xC2 + * .word 0x4C2*/ +#define __SPECIAL_INSTRUCTION_PREAMBLE \ + "srl $0, $0, 13\n\t" \ + "srl $0, $0, 29\n\t" \ + "srl $0, $0, 3\n\t" \ + "srl $0, $0, 19\n\t" + +#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ + _zzq_default, _zzq_request, \ + _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + __extension__ \ + ({ volatile unsigned int _zzq_args[6]; \ + volatile unsigned int _zzq_result; \ + _zzq_args[0] = (unsigned int)(_zzq_request); \ + _zzq_args[1] = (unsigned int)(_zzq_arg1); \ + _zzq_args[2] = (unsigned int)(_zzq_arg2); \ + _zzq_args[3] = (unsigned int)(_zzq_arg3); \ + _zzq_args[4] = (unsigned int)(_zzq_arg4); \ + _zzq_args[5] = (unsigned int)(_zzq_arg5); \ + __asm__ volatile("move $11, %1\n\t" /*default*/ \ + "move $12, %2\n\t" /*ptr*/ \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + /* T3 = client_request ( T4 ) */ \ + "or $13, $13, $13\n\t" \ + "move %0, $11\n\t" /*result*/ \ + : "=r" (_zzq_result) \ + : "r" (_zzq_default), "r" (&_zzq_args[0]) \ + : "$11", "$12", "memory"); \ + _zzq_result; \ + }) + +#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ + { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ + volatile unsigned int __addr; \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + /* %t9 = guest_NRADDR */ \ + "or $14, $14, $14\n\t" \ + "move %0, $11" /*result*/ \ + : "=r" (__addr) \ + : \ + : "$11" \ + ); \ + _zzq_orig->nraddr = __addr; \ + } + +#define VALGRIND_CALL_NOREDIR_T9 \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + /* call-noredir *%t9 */ \ + "or $15, $15, $15\n\t" + +#define VALGRIND_VEX_INJECT_IR() \ + do { \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + "or $11, $11, $11\n\t" \ + ); \ + } while (0) + + +#endif /* PLAT_mips32_linux */ + +/* ------------------------- mips64-linux ---------------- */ + +#if defined(PLAT_mips64_linux) + +typedef + struct { + unsigned long nraddr; /* where's the code? */ + } + OrigFn; + +/* dsll $0,$0, 3 + * dsll $0,$0, 13 + * dsll $0,$0, 29 + * dsll $0,$0, 19*/ +#define __SPECIAL_INSTRUCTION_PREAMBLE \ + "dsll $0,$0, 3 ; dsll $0,$0,13\n\t" \ + "dsll $0,$0,29 ; dsll $0,$0,19\n\t" + +#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ + _zzq_default, _zzq_request, \ + _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + __extension__ \ + ({ volatile unsigned long int _zzq_args[6]; \ + volatile unsigned long int _zzq_result; \ + _zzq_args[0] = (unsigned long int)(_zzq_request); \ + _zzq_args[1] = (unsigned long int)(_zzq_arg1); \ + _zzq_args[2] = (unsigned long int)(_zzq_arg2); \ + _zzq_args[3] = (unsigned long int)(_zzq_arg3); \ + _zzq_args[4] = (unsigned long int)(_zzq_arg4); \ + _zzq_args[5] = (unsigned long int)(_zzq_arg5); \ + __asm__ volatile("move $11, %1\n\t" /*default*/ \ + "move $12, %2\n\t" /*ptr*/ \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + /* $11 = client_request ( $12 ) */ \ + "or $13, $13, $13\n\t" \ + "move %0, $11\n\t" /*result*/ \ + : "=r" (_zzq_result) \ + : "r" (_zzq_default), "r" (&_zzq_args[0]) \ + : "$11", "$12", "memory"); \ + _zzq_result; \ + }) + +#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ + { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ + volatile unsigned long int __addr; \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + /* $11 = guest_NRADDR */ \ + "or $14, $14, $14\n\t" \ + "move %0, $11" /*result*/ \ + : "=r" (__addr) \ + : \ + : "$11"); \ + _zzq_orig->nraddr = __addr; \ + } + +#define VALGRIND_CALL_NOREDIR_T9 \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + /* call-noredir $25 */ \ + "or $15, $15, $15\n\t" + +#define VALGRIND_VEX_INJECT_IR() \ + do { \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + "or $11, $11, $11\n\t" \ + ); \ + } while (0) + +#endif /* PLAT_mips64_linux */ + +#if defined(PLAT_nanomips_linux) + +typedef + struct { + unsigned int nraddr; /* where's the code? */ + } + OrigFn; +/* + 8000 c04d srl zero, zero, 13 + 8000 c05d srl zero, zero, 29 + 8000 c043 srl zero, zero, 3 + 8000 c053 srl zero, zero, 19 +*/ + +#define __SPECIAL_INSTRUCTION_PREAMBLE "srl[32] $zero, $zero, 13 \n\t" \ + "srl[32] $zero, $zero, 29 \n\t" \ + "srl[32] $zero, $zero, 3 \n\t" \ + "srl[32] $zero, $zero, 19 \n\t" + +#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ + _zzq_default, _zzq_request, \ + _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + __extension__ \ + ({ volatile unsigned int _zzq_args[6]; \ + volatile unsigned int _zzq_result; \ + _zzq_args[0] = (unsigned int)(_zzq_request); \ + _zzq_args[1] = (unsigned int)(_zzq_arg1); \ + _zzq_args[2] = (unsigned int)(_zzq_arg2); \ + _zzq_args[3] = (unsigned int)(_zzq_arg3); \ + _zzq_args[4] = (unsigned int)(_zzq_arg4); \ + _zzq_args[5] = (unsigned int)(_zzq_arg5); \ + __asm__ volatile("move $a7, %1\n\t" /* default */ \ + "move $t0, %2\n\t" /* ptr */ \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + /* $a7 = client_request( $t0 ) */ \ + "or[32] $t0, $t0, $t0\n\t" \ + "move %0, $a7\n\t" /* result */ \ + : "=r" (_zzq_result) \ + : "r" (_zzq_default), "r" (&_zzq_args[0]) \ + : "$a7", "$t0", "memory"); \ + _zzq_result; \ + }) + +#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ + { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ + volatile unsigned long int __addr; \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + /* $a7 = guest_NRADDR */ \ + "or[32] $t1, $t1, $t1\n\t" \ + "move %0, $a7" /*result*/ \ + : "=r" (__addr) \ + : \ + : "$a7"); \ + _zzq_orig->nraddr = __addr; \ + } + +#define VALGRIND_CALL_NOREDIR_T9 \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + /* call-noredir $25 */ \ + "or[32] $t2, $t2, $t2\n\t" + +#define VALGRIND_VEX_INJECT_IR() \ + do { \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + "or[32] $t3, $t3, $t3\n\t" \ + ); \ + } while (0) + +#endif +/* Insert assembly code for other platforms here... */ + +#endif /* NVALGRIND */ + + +/* ------------------------------------------------------------------ */ +/* PLATFORM SPECIFICS for FUNCTION WRAPPING. This is all very */ +/* ugly. It's the least-worst tradeoff I can think of. */ +/* ------------------------------------------------------------------ */ + +/* This section defines magic (a.k.a appalling-hack) macros for doing + guaranteed-no-redirection macros, so as to get from function + wrappers to the functions they are wrapping. The whole point is to + construct standard call sequences, but to do the call itself with a + special no-redirect call pseudo-instruction that the JIT + understands and handles specially. This section is long and + repetitious, and I can't see a way to make it shorter. + + The naming scheme is as follows: + + CALL_FN_{W,v}_{v,W,WW,WWW,WWWW,5W,6W,7W,etc} + + 'W' stands for "word" and 'v' for "void". Hence there are + different macros for calling arity 0, 1, 2, 3, 4, etc, functions, + and for each, the possibility of returning a word-typed result, or + no result. +*/ + +/* Use these to write the name of your wrapper. NOTE: duplicates + VG_WRAP_FUNCTION_Z{U,Z} in pub_tool_redir.h. NOTE also: inserts + the default behaviour equivalance class tag "0000" into the name. + See pub_tool_redir.h for details -- normally you don't need to + think about this, though. */ + +/* Use an extra level of macroisation so as to ensure the soname/fnname + args are fully macro-expanded before pasting them together. */ +#define VG_CONCAT4(_aa,_bb,_cc,_dd) _aa##_bb##_cc##_dd + +#define I_WRAP_SONAME_FNNAME_ZU(soname,fnname) \ + VG_CONCAT4(_vgw00000ZU_,soname,_,fnname) + +#define I_WRAP_SONAME_FNNAME_ZZ(soname,fnname) \ + VG_CONCAT4(_vgw00000ZZ_,soname,_,fnname) + +/* Use this macro from within a wrapper function to collect the + context (address and possibly other info) of the original function. + Once you have that you can then use it in one of the CALL_FN_ + macros. The type of the argument _lval is OrigFn. */ +#define VALGRIND_GET_ORIG_FN(_lval) VALGRIND_GET_NR_CONTEXT(_lval) + +/* Also provide end-user facilities for function replacement, rather + than wrapping. A replacement function differs from a wrapper in + that it has no way to get hold of the original function being + called, and hence no way to call onwards to it. In a replacement + function, VALGRIND_GET_ORIG_FN always returns zero. */ + +#define I_REPLACE_SONAME_FNNAME_ZU(soname,fnname) \ + VG_CONCAT4(_vgr00000ZU_,soname,_,fnname) + +#define I_REPLACE_SONAME_FNNAME_ZZ(soname,fnname) \ + VG_CONCAT4(_vgr00000ZZ_,soname,_,fnname) + +/* Derivatives of the main macros below, for calling functions + returning void. */ + +#define CALL_FN_v_v(fnptr) \ + do { volatile unsigned long _junk; \ + CALL_FN_W_v(_junk,fnptr); } while (0) + +#define CALL_FN_v_W(fnptr, arg1) \ + do { volatile unsigned long _junk; \ + CALL_FN_W_W(_junk,fnptr,arg1); } while (0) + +#define CALL_FN_v_WW(fnptr, arg1,arg2) \ + do { volatile unsigned long _junk; \ + CALL_FN_W_WW(_junk,fnptr,arg1,arg2); } while (0) + +#define CALL_FN_v_WWW(fnptr, arg1,arg2,arg3) \ + do { volatile unsigned long _junk; \ + CALL_FN_W_WWW(_junk,fnptr,arg1,arg2,arg3); } while (0) + +#define CALL_FN_v_WWWW(fnptr, arg1,arg2,arg3,arg4) \ + do { volatile unsigned long _junk; \ + CALL_FN_W_WWWW(_junk,fnptr,arg1,arg2,arg3,arg4); } while (0) + +#define CALL_FN_v_5W(fnptr, arg1,arg2,arg3,arg4,arg5) \ + do { volatile unsigned long _junk; \ + CALL_FN_W_5W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5); } while (0) + +#define CALL_FN_v_6W(fnptr, arg1,arg2,arg3,arg4,arg5,arg6) \ + do { volatile unsigned long _junk; \ + CALL_FN_W_6W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5,arg6); } while (0) + +#define CALL_FN_v_7W(fnptr, arg1,arg2,arg3,arg4,arg5,arg6,arg7) \ + do { volatile unsigned long _junk; \ + CALL_FN_W_7W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5,arg6,arg7); } while (0) + +/* ----------------- x86-{linux,darwin,solaris} ---------------- */ + +#if defined(PLAT_x86_linux) || defined(PLAT_x86_darwin) \ + || defined(PLAT_x86_solaris) || defined(PLAT_x86_freebsd) + +/* These regs are trashed by the hidden call. No need to mention eax + as gcc can already see that, plus causes gcc to bomb. */ +#define __CALLER_SAVED_REGS /*"eax"*/ "ecx", "edx" + +/* Macros to save and align the stack before making a function + call and restore it afterwards as gcc may not keep the stack + pointer aligned if it doesn't realise calls are being made + to other functions. */ + +#define VALGRIND_ALIGN_STACK \ + "movl %%esp,%%edi\n\t" \ + "andl $0xfffffff0,%%esp\n\t" +#define VALGRIND_RESTORE_STACK \ + "movl %%edi,%%esp\n\t" + +/* These CALL_FN_ macros assume that on x86-linux, sizeof(unsigned + long) == 4. */ + +#define CALL_FN_W_v(lval, orig) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[1]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "movl (%%eax), %%eax\n\t" /* target->%eax */ \ + VALGRIND_CALL_NOREDIR_EAX \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_W(lval, orig, arg1) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[2]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "subl $12, %%esp\n\t" \ + "pushl 4(%%eax)\n\t" \ + "movl (%%eax), %%eax\n\t" /* target->%eax */ \ + VALGRIND_CALL_NOREDIR_EAX \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "subl $8, %%esp\n\t" \ + "pushl 8(%%eax)\n\t" \ + "pushl 4(%%eax)\n\t" \ + "movl (%%eax), %%eax\n\t" /* target->%eax */ \ + VALGRIND_CALL_NOREDIR_EAX \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[4]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "subl $4, %%esp\n\t" \ + "pushl 12(%%eax)\n\t" \ + "pushl 8(%%eax)\n\t" \ + "pushl 4(%%eax)\n\t" \ + "movl (%%eax), %%eax\n\t" /* target->%eax */ \ + VALGRIND_CALL_NOREDIR_EAX \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[5]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "pushl 16(%%eax)\n\t" \ + "pushl 12(%%eax)\n\t" \ + "pushl 8(%%eax)\n\t" \ + "pushl 4(%%eax)\n\t" \ + "movl (%%eax), %%eax\n\t" /* target->%eax */ \ + VALGRIND_CALL_NOREDIR_EAX \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[6]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "subl $12, %%esp\n\t" \ + "pushl 20(%%eax)\n\t" \ + "pushl 16(%%eax)\n\t" \ + "pushl 12(%%eax)\n\t" \ + "pushl 8(%%eax)\n\t" \ + "pushl 4(%%eax)\n\t" \ + "movl (%%eax), %%eax\n\t" /* target->%eax */ \ + VALGRIND_CALL_NOREDIR_EAX \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[7]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "subl $8, %%esp\n\t" \ + "pushl 24(%%eax)\n\t" \ + "pushl 20(%%eax)\n\t" \ + "pushl 16(%%eax)\n\t" \ + "pushl 12(%%eax)\n\t" \ + "pushl 8(%%eax)\n\t" \ + "pushl 4(%%eax)\n\t" \ + "movl (%%eax), %%eax\n\t" /* target->%eax */ \ + VALGRIND_CALL_NOREDIR_EAX \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[8]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "subl $4, %%esp\n\t" \ + "pushl 28(%%eax)\n\t" \ + "pushl 24(%%eax)\n\t" \ + "pushl 20(%%eax)\n\t" \ + "pushl 16(%%eax)\n\t" \ + "pushl 12(%%eax)\n\t" \ + "pushl 8(%%eax)\n\t" \ + "pushl 4(%%eax)\n\t" \ + "movl (%%eax), %%eax\n\t" /* target->%eax */ \ + VALGRIND_CALL_NOREDIR_EAX \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[9]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "pushl 32(%%eax)\n\t" \ + "pushl 28(%%eax)\n\t" \ + "pushl 24(%%eax)\n\t" \ + "pushl 20(%%eax)\n\t" \ + "pushl 16(%%eax)\n\t" \ + "pushl 12(%%eax)\n\t" \ + "pushl 8(%%eax)\n\t" \ + "pushl 4(%%eax)\n\t" \ + "movl (%%eax), %%eax\n\t" /* target->%eax */ \ + VALGRIND_CALL_NOREDIR_EAX \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[10]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "subl $12, %%esp\n\t" \ + "pushl 36(%%eax)\n\t" \ + "pushl 32(%%eax)\n\t" \ + "pushl 28(%%eax)\n\t" \ + "pushl 24(%%eax)\n\t" \ + "pushl 20(%%eax)\n\t" \ + "pushl 16(%%eax)\n\t" \ + "pushl 12(%%eax)\n\t" \ + "pushl 8(%%eax)\n\t" \ + "pushl 4(%%eax)\n\t" \ + "movl (%%eax), %%eax\n\t" /* target->%eax */ \ + VALGRIND_CALL_NOREDIR_EAX \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[11]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + _argvec[10] = (unsigned long)(arg10); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "subl $8, %%esp\n\t" \ + "pushl 40(%%eax)\n\t" \ + "pushl 36(%%eax)\n\t" \ + "pushl 32(%%eax)\n\t" \ + "pushl 28(%%eax)\n\t" \ + "pushl 24(%%eax)\n\t" \ + "pushl 20(%%eax)\n\t" \ + "pushl 16(%%eax)\n\t" \ + "pushl 12(%%eax)\n\t" \ + "pushl 8(%%eax)\n\t" \ + "pushl 4(%%eax)\n\t" \ + "movl (%%eax), %%eax\n\t" /* target->%eax */ \ + VALGRIND_CALL_NOREDIR_EAX \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ + arg6,arg7,arg8,arg9,arg10, \ + arg11) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[12]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + _argvec[10] = (unsigned long)(arg10); \ + _argvec[11] = (unsigned long)(arg11); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "subl $4, %%esp\n\t" \ + "pushl 44(%%eax)\n\t" \ + "pushl 40(%%eax)\n\t" \ + "pushl 36(%%eax)\n\t" \ + "pushl 32(%%eax)\n\t" \ + "pushl 28(%%eax)\n\t" \ + "pushl 24(%%eax)\n\t" \ + "pushl 20(%%eax)\n\t" \ + "pushl 16(%%eax)\n\t" \ + "pushl 12(%%eax)\n\t" \ + "pushl 8(%%eax)\n\t" \ + "pushl 4(%%eax)\n\t" \ + "movl (%%eax), %%eax\n\t" /* target->%eax */ \ + VALGRIND_CALL_NOREDIR_EAX \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ + arg6,arg7,arg8,arg9,arg10, \ + arg11,arg12) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[13]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + _argvec[10] = (unsigned long)(arg10); \ + _argvec[11] = (unsigned long)(arg11); \ + _argvec[12] = (unsigned long)(arg12); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "pushl 48(%%eax)\n\t" \ + "pushl 44(%%eax)\n\t" \ + "pushl 40(%%eax)\n\t" \ + "pushl 36(%%eax)\n\t" \ + "pushl 32(%%eax)\n\t" \ + "pushl 28(%%eax)\n\t" \ + "pushl 24(%%eax)\n\t" \ + "pushl 20(%%eax)\n\t" \ + "pushl 16(%%eax)\n\t" \ + "pushl 12(%%eax)\n\t" \ + "pushl 8(%%eax)\n\t" \ + "pushl 4(%%eax)\n\t" \ + "movl (%%eax), %%eax\n\t" /* target->%eax */ \ + VALGRIND_CALL_NOREDIR_EAX \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#endif /* PLAT_x86_linux || PLAT_x86_darwin || PLAT_x86_solaris */ + +/* ---------------- amd64-{linux,darwin,solaris} --------------- */ + +#if defined(PLAT_amd64_linux) || defined(PLAT_amd64_darwin) \ + || defined(PLAT_amd64_solaris) || defined(PLAT_amd64_freebsd) + +/* ARGREGS: rdi rsi rdx rcx r8 r9 (the rest on stack in R-to-L order) */ + +/* These regs are trashed by the hidden call. */ +#define __CALLER_SAVED_REGS /*"rax",*/ "rcx", "rdx", "rsi", \ + "rdi", "r8", "r9", "r10", "r11" + +/* This is all pretty complex. It's so as to make stack unwinding + work reliably. See bug 243270. The basic problem is the sub and + add of 128 of %rsp in all of the following macros. If gcc believes + the CFA is in %rsp, then unwinding may fail, because what's at the + CFA is not what gcc "expected" when it constructs the CFIs for the + places where the macros are instantiated. + + But we can't just add a CFI annotation to increase the CFA offset + by 128, to match the sub of 128 from %rsp, because we don't know + whether gcc has chosen %rsp as the CFA at that point, or whether it + has chosen some other register (eg, %rbp). In the latter case, + adding a CFI annotation to change the CFA offset is simply wrong. + + So the solution is to get hold of the CFA using + __builtin_dwarf_cfa(), put it in a known register, and add a + CFI annotation to say what the register is. We choose %rbp for + this (perhaps perversely), because: + + (1) %rbp is already subject to unwinding. If a new register was + chosen then the unwinder would have to unwind it in all stack + traces, which is expensive, and + + (2) %rbp is already subject to precise exception updates in the + JIT. If a new register was chosen, we'd have to have precise + exceptions for it too, which reduces performance of the + generated code. + + However .. one extra complication. We can't just whack the result + of __builtin_dwarf_cfa() into %rbp and then add %rbp to the + list of trashed registers at the end of the inline assembly + fragments; gcc won't allow %rbp to appear in that list. Hence + instead we need to stash %rbp in %r15 for the duration of the asm, + and say that %r15 is trashed instead. gcc seems happy to go with + that. + + Oh .. and this all needs to be conditionalised so that it is + unchanged from before this commit, when compiled with older gccs + that don't support __builtin_dwarf_cfa. Furthermore, since + this header file is freestanding, it has to be independent of + config.h, and so the following conditionalisation cannot depend on + configure time checks. + + Although it's not clear from + 'defined(__GNUC__) && defined(__GCC_HAVE_DWARF2_CFI_ASM)', + this expression excludes Darwin. + .cfi directives in Darwin assembly appear to be completely + different and I haven't investigated how they work. + + For even more entertainment value, note we have to use the + completely undocumented __builtin_dwarf_cfa(), which appears to + really compute the CFA, whereas __builtin_frame_address(0) claims + to but actually doesn't. See + https://bugs.kde.org/show_bug.cgi?id=243270#c47 +*/ +#if defined(__GNUC__) && defined(__GCC_HAVE_DWARF2_CFI_ASM) +# define __FRAME_POINTER \ + ,"r"(__builtin_dwarf_cfa()) +# define VALGRIND_CFI_PROLOGUE \ + "movq %%rbp, %%r15\n\t" \ + "movq %2, %%rbp\n\t" \ + ".cfi_remember_state\n\t" \ + ".cfi_def_cfa rbp, 0\n\t" +# define VALGRIND_CFI_EPILOGUE \ + "movq %%r15, %%rbp\n\t" \ + ".cfi_restore_state\n\t" +#else +# define __FRAME_POINTER +# define VALGRIND_CFI_PROLOGUE +# define VALGRIND_CFI_EPILOGUE +#endif + +/* Macros to save and align the stack before making a function + call and restore it afterwards as gcc may not keep the stack + pointer aligned if it doesn't realise calls are being made + to other functions. */ + +#define VALGRIND_ALIGN_STACK \ + "movq %%rsp,%%r14\n\t" \ + "andq $0xfffffffffffffff0,%%rsp\n\t" +#define VALGRIND_RESTORE_STACK \ + "movq %%r14,%%rsp\n\t" + +/* These CALL_FN_ macros assume that on amd64-linux, sizeof(unsigned + long) == 8. */ + +/* NB 9 Sept 07. There is a nasty kludge here in all these CALL_FN_ + macros. In order not to trash the stack redzone, we need to drop + %rsp by 128 before the hidden call, and restore afterwards. The + nastyness is that it is only by luck that the stack still appears + to be unwindable during the hidden call - since then the behaviour + of any routine using this macro does not match what the CFI data + says. Sigh. + + Why is this important? Imagine that a wrapper has a stack + allocated local, and passes to the hidden call, a pointer to it. + Because gcc does not know about the hidden call, it may allocate + that local in the redzone. Unfortunately the hidden call may then + trash it before it comes to use it. So we must step clear of the + redzone, for the duration of the hidden call, to make it safe. + + Probably the same problem afflicts the other redzone-style ABIs too + (ppc64-linux); but for those, the stack is + self describing (none of this CFI nonsense) so at least messing + with the stack pointer doesn't give a danger of non-unwindable + stack. */ + +#define CALL_FN_W_v(lval, orig) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[1]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + VALGRIND_ALIGN_STACK \ + "subq $128,%%rsp\n\t" \ + "movq (%%rax), %%rax\n\t" /* target->%rax */ \ + VALGRIND_CALL_NOREDIR_RAX \ + VALGRIND_RESTORE_STACK \ + VALGRIND_CFI_EPILOGUE \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_W(lval, orig, arg1) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[2]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + VALGRIND_ALIGN_STACK \ + "subq $128,%%rsp\n\t" \ + "movq 8(%%rax), %%rdi\n\t" \ + "movq (%%rax), %%rax\n\t" /* target->%rax */ \ + VALGRIND_CALL_NOREDIR_RAX \ + VALGRIND_RESTORE_STACK \ + VALGRIND_CFI_EPILOGUE \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + VALGRIND_ALIGN_STACK \ + "subq $128,%%rsp\n\t" \ + "movq 16(%%rax), %%rsi\n\t" \ + "movq 8(%%rax), %%rdi\n\t" \ + "movq (%%rax), %%rax\n\t" /* target->%rax */ \ + VALGRIND_CALL_NOREDIR_RAX \ + VALGRIND_RESTORE_STACK \ + VALGRIND_CFI_EPILOGUE \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[4]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + VALGRIND_ALIGN_STACK \ + "subq $128,%%rsp\n\t" \ + "movq 24(%%rax), %%rdx\n\t" \ + "movq 16(%%rax), %%rsi\n\t" \ + "movq 8(%%rax), %%rdi\n\t" \ + "movq (%%rax), %%rax\n\t" /* target->%rax */ \ + VALGRIND_CALL_NOREDIR_RAX \ + VALGRIND_RESTORE_STACK \ + VALGRIND_CFI_EPILOGUE \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[5]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + VALGRIND_ALIGN_STACK \ + "subq $128,%%rsp\n\t" \ + "movq 32(%%rax), %%rcx\n\t" \ + "movq 24(%%rax), %%rdx\n\t" \ + "movq 16(%%rax), %%rsi\n\t" \ + "movq 8(%%rax), %%rdi\n\t" \ + "movq (%%rax), %%rax\n\t" /* target->%rax */ \ + VALGRIND_CALL_NOREDIR_RAX \ + VALGRIND_RESTORE_STACK \ + VALGRIND_CFI_EPILOGUE \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[6]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + VALGRIND_ALIGN_STACK \ + "subq $128,%%rsp\n\t" \ + "movq 40(%%rax), %%r8\n\t" \ + "movq 32(%%rax), %%rcx\n\t" \ + "movq 24(%%rax), %%rdx\n\t" \ + "movq 16(%%rax), %%rsi\n\t" \ + "movq 8(%%rax), %%rdi\n\t" \ + "movq (%%rax), %%rax\n\t" /* target->%rax */ \ + VALGRIND_CALL_NOREDIR_RAX \ + VALGRIND_RESTORE_STACK \ + VALGRIND_CFI_EPILOGUE \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[7]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + VALGRIND_ALIGN_STACK \ + "subq $128,%%rsp\n\t" \ + "movq 48(%%rax), %%r9\n\t" \ + "movq 40(%%rax), %%r8\n\t" \ + "movq 32(%%rax), %%rcx\n\t" \ + "movq 24(%%rax), %%rdx\n\t" \ + "movq 16(%%rax), %%rsi\n\t" \ + "movq 8(%%rax), %%rdi\n\t" \ + "movq (%%rax), %%rax\n\t" /* target->%rax */ \ + VALGRIND_CALL_NOREDIR_RAX \ + VALGRIND_RESTORE_STACK \ + VALGRIND_CFI_EPILOGUE \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[8]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + VALGRIND_ALIGN_STACK \ + "subq $136,%%rsp\n\t" \ + "pushq 56(%%rax)\n\t" \ + "movq 48(%%rax), %%r9\n\t" \ + "movq 40(%%rax), %%r8\n\t" \ + "movq 32(%%rax), %%rcx\n\t" \ + "movq 24(%%rax), %%rdx\n\t" \ + "movq 16(%%rax), %%rsi\n\t" \ + "movq 8(%%rax), %%rdi\n\t" \ + "movq (%%rax), %%rax\n\t" /* target->%rax */ \ + VALGRIND_CALL_NOREDIR_RAX \ + VALGRIND_RESTORE_STACK \ + VALGRIND_CFI_EPILOGUE \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[9]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + VALGRIND_ALIGN_STACK \ + "subq $128,%%rsp\n\t" \ + "pushq 64(%%rax)\n\t" \ + "pushq 56(%%rax)\n\t" \ + "movq 48(%%rax), %%r9\n\t" \ + "movq 40(%%rax), %%r8\n\t" \ + "movq 32(%%rax), %%rcx\n\t" \ + "movq 24(%%rax), %%rdx\n\t" \ + "movq 16(%%rax), %%rsi\n\t" \ + "movq 8(%%rax), %%rdi\n\t" \ + "movq (%%rax), %%rax\n\t" /* target->%rax */ \ + VALGRIND_CALL_NOREDIR_RAX \ + VALGRIND_RESTORE_STACK \ + VALGRIND_CFI_EPILOGUE \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[10]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + VALGRIND_ALIGN_STACK \ + "subq $136,%%rsp\n\t" \ + "pushq 72(%%rax)\n\t" \ + "pushq 64(%%rax)\n\t" \ + "pushq 56(%%rax)\n\t" \ + "movq 48(%%rax), %%r9\n\t" \ + "movq 40(%%rax), %%r8\n\t" \ + "movq 32(%%rax), %%rcx\n\t" \ + "movq 24(%%rax), %%rdx\n\t" \ + "movq 16(%%rax), %%rsi\n\t" \ + "movq 8(%%rax), %%rdi\n\t" \ + "movq (%%rax), %%rax\n\t" /* target->%rax */ \ + VALGRIND_CALL_NOREDIR_RAX \ + VALGRIND_RESTORE_STACK \ + VALGRIND_CFI_EPILOGUE \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[11]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + _argvec[10] = (unsigned long)(arg10); \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + VALGRIND_ALIGN_STACK \ + "subq $128,%%rsp\n\t" \ + "pushq 80(%%rax)\n\t" \ + "pushq 72(%%rax)\n\t" \ + "pushq 64(%%rax)\n\t" \ + "pushq 56(%%rax)\n\t" \ + "movq 48(%%rax), %%r9\n\t" \ + "movq 40(%%rax), %%r8\n\t" \ + "movq 32(%%rax), %%rcx\n\t" \ + "movq 24(%%rax), %%rdx\n\t" \ + "movq 16(%%rax), %%rsi\n\t" \ + "movq 8(%%rax), %%rdi\n\t" \ + "movq (%%rax), %%rax\n\t" /* target->%rax */ \ + VALGRIND_CALL_NOREDIR_RAX \ + VALGRIND_RESTORE_STACK \ + VALGRIND_CFI_EPILOGUE \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10,arg11) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[12]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + _argvec[10] = (unsigned long)(arg10); \ + _argvec[11] = (unsigned long)(arg11); \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + VALGRIND_ALIGN_STACK \ + "subq $136,%%rsp\n\t" \ + "pushq 88(%%rax)\n\t" \ + "pushq 80(%%rax)\n\t" \ + "pushq 72(%%rax)\n\t" \ + "pushq 64(%%rax)\n\t" \ + "pushq 56(%%rax)\n\t" \ + "movq 48(%%rax), %%r9\n\t" \ + "movq 40(%%rax), %%r8\n\t" \ + "movq 32(%%rax), %%rcx\n\t" \ + "movq 24(%%rax), %%rdx\n\t" \ + "movq 16(%%rax), %%rsi\n\t" \ + "movq 8(%%rax), %%rdi\n\t" \ + "movq (%%rax), %%rax\n\t" /* target->%rax */ \ + VALGRIND_CALL_NOREDIR_RAX \ + VALGRIND_RESTORE_STACK \ + VALGRIND_CFI_EPILOGUE \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10,arg11,arg12) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[13]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + _argvec[10] = (unsigned long)(arg10); \ + _argvec[11] = (unsigned long)(arg11); \ + _argvec[12] = (unsigned long)(arg12); \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + VALGRIND_ALIGN_STACK \ + "subq $128,%%rsp\n\t" \ + "pushq 96(%%rax)\n\t" \ + "pushq 88(%%rax)\n\t" \ + "pushq 80(%%rax)\n\t" \ + "pushq 72(%%rax)\n\t" \ + "pushq 64(%%rax)\n\t" \ + "pushq 56(%%rax)\n\t" \ + "movq 48(%%rax), %%r9\n\t" \ + "movq 40(%%rax), %%r8\n\t" \ + "movq 32(%%rax), %%rcx\n\t" \ + "movq 24(%%rax), %%rdx\n\t" \ + "movq 16(%%rax), %%rsi\n\t" \ + "movq 8(%%rax), %%rdi\n\t" \ + "movq (%%rax), %%rax\n\t" /* target->%rax */ \ + VALGRIND_CALL_NOREDIR_RAX \ + VALGRIND_RESTORE_STACK \ + VALGRIND_CFI_EPILOGUE \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#endif /* PLAT_amd64_linux || PLAT_amd64_darwin || PLAT_amd64_solaris */ + +/* ------------------------ ppc32-linux ------------------------ */ + +#if defined(PLAT_ppc32_linux) + +/* This is useful for finding out about the on-stack stuff: + + extern int f9 ( int,int,int,int,int,int,int,int,int ); + extern int f10 ( int,int,int,int,int,int,int,int,int,int ); + extern int f11 ( int,int,int,int,int,int,int,int,int,int,int ); + extern int f12 ( int,int,int,int,int,int,int,int,int,int,int,int ); + + int g9 ( void ) { + return f9(11,22,33,44,55,66,77,88,99); + } + int g10 ( void ) { + return f10(11,22,33,44,55,66,77,88,99,110); + } + int g11 ( void ) { + return f11(11,22,33,44,55,66,77,88,99,110,121); + } + int g12 ( void ) { + return f12(11,22,33,44,55,66,77,88,99,110,121,132); + } +*/ + +/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */ + +/* These regs are trashed by the hidden call. */ +#define __CALLER_SAVED_REGS \ + "lr", "ctr", "xer", \ + "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \ + "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \ + "r11", "r12", "r13" + +/* Macros to save and align the stack before making a function + call and restore it afterwards as gcc may not keep the stack + pointer aligned if it doesn't realise calls are being made + to other functions. */ + +#define VALGRIND_ALIGN_STACK \ + "mr 28,1\n\t" \ + "rlwinm 1,1,0,0,27\n\t" +#define VALGRIND_RESTORE_STACK \ + "mr 1,28\n\t" + +/* These CALL_FN_ macros assume that on ppc32-linux, + sizeof(unsigned long) == 4. */ + +#define CALL_FN_W_v(lval, orig) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[1]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "lwz 11,0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + VALGRIND_RESTORE_STACK \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_W(lval, orig, arg1) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[2]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "lwz 3,4(11)\n\t" /* arg1->r3 */ \ + "lwz 11,0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + VALGRIND_RESTORE_STACK \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "lwz 3,4(11)\n\t" /* arg1->r3 */ \ + "lwz 4,8(11)\n\t" \ + "lwz 11,0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + VALGRIND_RESTORE_STACK \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[4]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "lwz 3,4(11)\n\t" /* arg1->r3 */ \ + "lwz 4,8(11)\n\t" \ + "lwz 5,12(11)\n\t" \ + "lwz 11,0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + VALGRIND_RESTORE_STACK \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[5]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + _argvec[4] = (unsigned long)arg4; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "lwz 3,4(11)\n\t" /* arg1->r3 */ \ + "lwz 4,8(11)\n\t" \ + "lwz 5,12(11)\n\t" \ + "lwz 6,16(11)\n\t" /* arg4->r6 */ \ + "lwz 11,0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + VALGRIND_RESTORE_STACK \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[6]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + _argvec[4] = (unsigned long)arg4; \ + _argvec[5] = (unsigned long)arg5; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "lwz 3,4(11)\n\t" /* arg1->r3 */ \ + "lwz 4,8(11)\n\t" \ + "lwz 5,12(11)\n\t" \ + "lwz 6,16(11)\n\t" /* arg4->r6 */ \ + "lwz 7,20(11)\n\t" \ + "lwz 11,0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + VALGRIND_RESTORE_STACK \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[7]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + _argvec[4] = (unsigned long)arg4; \ + _argvec[5] = (unsigned long)arg5; \ + _argvec[6] = (unsigned long)arg6; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "lwz 3,4(11)\n\t" /* arg1->r3 */ \ + "lwz 4,8(11)\n\t" \ + "lwz 5,12(11)\n\t" \ + "lwz 6,16(11)\n\t" /* arg4->r6 */ \ + "lwz 7,20(11)\n\t" \ + "lwz 8,24(11)\n\t" \ + "lwz 11,0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + VALGRIND_RESTORE_STACK \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[8]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + _argvec[4] = (unsigned long)arg4; \ + _argvec[5] = (unsigned long)arg5; \ + _argvec[6] = (unsigned long)arg6; \ + _argvec[7] = (unsigned long)arg7; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "lwz 3,4(11)\n\t" /* arg1->r3 */ \ + "lwz 4,8(11)\n\t" \ + "lwz 5,12(11)\n\t" \ + "lwz 6,16(11)\n\t" /* arg4->r6 */ \ + "lwz 7,20(11)\n\t" \ + "lwz 8,24(11)\n\t" \ + "lwz 9,28(11)\n\t" \ + "lwz 11,0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + VALGRIND_RESTORE_STACK \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[9]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + _argvec[4] = (unsigned long)arg4; \ + _argvec[5] = (unsigned long)arg5; \ + _argvec[6] = (unsigned long)arg6; \ + _argvec[7] = (unsigned long)arg7; \ + _argvec[8] = (unsigned long)arg8; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "lwz 3,4(11)\n\t" /* arg1->r3 */ \ + "lwz 4,8(11)\n\t" \ + "lwz 5,12(11)\n\t" \ + "lwz 6,16(11)\n\t" /* arg4->r6 */ \ + "lwz 7,20(11)\n\t" \ + "lwz 8,24(11)\n\t" \ + "lwz 9,28(11)\n\t" \ + "lwz 10,32(11)\n\t" /* arg8->r10 */ \ + "lwz 11,0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + VALGRIND_RESTORE_STACK \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[10]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + _argvec[4] = (unsigned long)arg4; \ + _argvec[5] = (unsigned long)arg5; \ + _argvec[6] = (unsigned long)arg6; \ + _argvec[7] = (unsigned long)arg7; \ + _argvec[8] = (unsigned long)arg8; \ + _argvec[9] = (unsigned long)arg9; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "addi 1,1,-16\n\t" \ + /* arg9 */ \ + "lwz 3,36(11)\n\t" \ + "stw 3,8(1)\n\t" \ + /* args1-8 */ \ + "lwz 3,4(11)\n\t" /* arg1->r3 */ \ + "lwz 4,8(11)\n\t" \ + "lwz 5,12(11)\n\t" \ + "lwz 6,16(11)\n\t" /* arg4->r6 */ \ + "lwz 7,20(11)\n\t" \ + "lwz 8,24(11)\n\t" \ + "lwz 9,28(11)\n\t" \ + "lwz 10,32(11)\n\t" /* arg8->r10 */ \ + "lwz 11,0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + VALGRIND_RESTORE_STACK \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[11]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + _argvec[4] = (unsigned long)arg4; \ + _argvec[5] = (unsigned long)arg5; \ + _argvec[6] = (unsigned long)arg6; \ + _argvec[7] = (unsigned long)arg7; \ + _argvec[8] = (unsigned long)arg8; \ + _argvec[9] = (unsigned long)arg9; \ + _argvec[10] = (unsigned long)arg10; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "addi 1,1,-16\n\t" \ + /* arg10 */ \ + "lwz 3,40(11)\n\t" \ + "stw 3,12(1)\n\t" \ + /* arg9 */ \ + "lwz 3,36(11)\n\t" \ + "stw 3,8(1)\n\t" \ + /* args1-8 */ \ + "lwz 3,4(11)\n\t" /* arg1->r3 */ \ + "lwz 4,8(11)\n\t" \ + "lwz 5,12(11)\n\t" \ + "lwz 6,16(11)\n\t" /* arg4->r6 */ \ + "lwz 7,20(11)\n\t" \ + "lwz 8,24(11)\n\t" \ + "lwz 9,28(11)\n\t" \ + "lwz 10,32(11)\n\t" /* arg8->r10 */ \ + "lwz 11,0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + VALGRIND_RESTORE_STACK \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10,arg11) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[12]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + _argvec[4] = (unsigned long)arg4; \ + _argvec[5] = (unsigned long)arg5; \ + _argvec[6] = (unsigned long)arg6; \ + _argvec[7] = (unsigned long)arg7; \ + _argvec[8] = (unsigned long)arg8; \ + _argvec[9] = (unsigned long)arg9; \ + _argvec[10] = (unsigned long)arg10; \ + _argvec[11] = (unsigned long)arg11; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "addi 1,1,-32\n\t" \ + /* arg11 */ \ + "lwz 3,44(11)\n\t" \ + "stw 3,16(1)\n\t" \ + /* arg10 */ \ + "lwz 3,40(11)\n\t" \ + "stw 3,12(1)\n\t" \ + /* arg9 */ \ + "lwz 3,36(11)\n\t" \ + "stw 3,8(1)\n\t" \ + /* args1-8 */ \ + "lwz 3,4(11)\n\t" /* arg1->r3 */ \ + "lwz 4,8(11)\n\t" \ + "lwz 5,12(11)\n\t" \ + "lwz 6,16(11)\n\t" /* arg4->r6 */ \ + "lwz 7,20(11)\n\t" \ + "lwz 8,24(11)\n\t" \ + "lwz 9,28(11)\n\t" \ + "lwz 10,32(11)\n\t" /* arg8->r10 */ \ + "lwz 11,0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + VALGRIND_RESTORE_STACK \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10,arg11,arg12) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[13]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + _argvec[4] = (unsigned long)arg4; \ + _argvec[5] = (unsigned long)arg5; \ + _argvec[6] = (unsigned long)arg6; \ + _argvec[7] = (unsigned long)arg7; \ + _argvec[8] = (unsigned long)arg8; \ + _argvec[9] = (unsigned long)arg9; \ + _argvec[10] = (unsigned long)arg10; \ + _argvec[11] = (unsigned long)arg11; \ + _argvec[12] = (unsigned long)arg12; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "addi 1,1,-32\n\t" \ + /* arg12 */ \ + "lwz 3,48(11)\n\t" \ + "stw 3,20(1)\n\t" \ + /* arg11 */ \ + "lwz 3,44(11)\n\t" \ + "stw 3,16(1)\n\t" \ + /* arg10 */ \ + "lwz 3,40(11)\n\t" \ + "stw 3,12(1)\n\t" \ + /* arg9 */ \ + "lwz 3,36(11)\n\t" \ + "stw 3,8(1)\n\t" \ + /* args1-8 */ \ + "lwz 3,4(11)\n\t" /* arg1->r3 */ \ + "lwz 4,8(11)\n\t" \ + "lwz 5,12(11)\n\t" \ + "lwz 6,16(11)\n\t" /* arg4->r6 */ \ + "lwz 7,20(11)\n\t" \ + "lwz 8,24(11)\n\t" \ + "lwz 9,28(11)\n\t" \ + "lwz 10,32(11)\n\t" /* arg8->r10 */ \ + "lwz 11,0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + VALGRIND_RESTORE_STACK \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#endif /* PLAT_ppc32_linux */ + +/* ------------------------ ppc64-linux ------------------------ */ + +#if defined(PLAT_ppc64be_linux) + +/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */ + +/* These regs are trashed by the hidden call. */ +#define __CALLER_SAVED_REGS \ + "lr", "ctr", "xer", \ + "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \ + "r0", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \ + "r11", "r12", "r13" + +/* Macros to save and align the stack before making a function + call and restore it afterwards as gcc may not keep the stack + pointer aligned if it doesn't realise calls are being made + to other functions. */ + +#define VALGRIND_ALIGN_STACK \ + "mr 28,1\n\t" \ + "rldicr 1,1,0,59\n\t" +#define VALGRIND_RESTORE_STACK \ + "mr 1,28\n\t" + +/* These CALL_FN_ macros assume that on ppc64-linux, sizeof(unsigned + long) == 8. */ + +#define CALL_FN_W_v(lval, orig) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+0]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_W(lval, orig, arg1) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+1]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + "ld 3, 8(11)\n\t" /* arg1->r3 */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+2]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + "ld 3, 8(11)\n\t" /* arg1->r3 */ \ + "ld 4, 16(11)\n\t" /* arg2->r4 */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+3]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + "ld 3, 8(11)\n\t" /* arg1->r3 */ \ + "ld 4, 16(11)\n\t" /* arg2->r4 */ \ + "ld 5, 24(11)\n\t" /* arg3->r5 */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+4]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + "ld 3, 8(11)\n\t" /* arg1->r3 */ \ + "ld 4, 16(11)\n\t" /* arg2->r4 */ \ + "ld 5, 24(11)\n\t" /* arg3->r5 */ \ + "ld 6, 32(11)\n\t" /* arg4->r6 */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+5]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + "ld 3, 8(11)\n\t" /* arg1->r3 */ \ + "ld 4, 16(11)\n\t" /* arg2->r4 */ \ + "ld 5, 24(11)\n\t" /* arg3->r5 */ \ + "ld 6, 32(11)\n\t" /* arg4->r6 */ \ + "ld 7, 40(11)\n\t" /* arg5->r7 */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+6]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + _argvec[2+6] = (unsigned long)arg6; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + "ld 3, 8(11)\n\t" /* arg1->r3 */ \ + "ld 4, 16(11)\n\t" /* arg2->r4 */ \ + "ld 5, 24(11)\n\t" /* arg3->r5 */ \ + "ld 6, 32(11)\n\t" /* arg4->r6 */ \ + "ld 7, 40(11)\n\t" /* arg5->r7 */ \ + "ld 8, 48(11)\n\t" /* arg6->r8 */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+7]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + _argvec[2+6] = (unsigned long)arg6; \ + _argvec[2+7] = (unsigned long)arg7; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + "ld 3, 8(11)\n\t" /* arg1->r3 */ \ + "ld 4, 16(11)\n\t" /* arg2->r4 */ \ + "ld 5, 24(11)\n\t" /* arg3->r5 */ \ + "ld 6, 32(11)\n\t" /* arg4->r6 */ \ + "ld 7, 40(11)\n\t" /* arg5->r7 */ \ + "ld 8, 48(11)\n\t" /* arg6->r8 */ \ + "ld 9, 56(11)\n\t" /* arg7->r9 */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+8]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + _argvec[2+6] = (unsigned long)arg6; \ + _argvec[2+7] = (unsigned long)arg7; \ + _argvec[2+8] = (unsigned long)arg8; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + "ld 3, 8(11)\n\t" /* arg1->r3 */ \ + "ld 4, 16(11)\n\t" /* arg2->r4 */ \ + "ld 5, 24(11)\n\t" /* arg3->r5 */ \ + "ld 6, 32(11)\n\t" /* arg4->r6 */ \ + "ld 7, 40(11)\n\t" /* arg5->r7 */ \ + "ld 8, 48(11)\n\t" /* arg6->r8 */ \ + "ld 9, 56(11)\n\t" /* arg7->r9 */ \ + "ld 10, 64(11)\n\t" /* arg8->r10 */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+9]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + _argvec[2+6] = (unsigned long)arg6; \ + _argvec[2+7] = (unsigned long)arg7; \ + _argvec[2+8] = (unsigned long)arg8; \ + _argvec[2+9] = (unsigned long)arg9; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + "addi 1,1,-128\n\t" /* expand stack frame */ \ + /* arg9 */ \ + "ld 3,72(11)\n\t" \ + "std 3,112(1)\n\t" \ + /* args1-8 */ \ + "ld 3, 8(11)\n\t" /* arg1->r3 */ \ + "ld 4, 16(11)\n\t" /* arg2->r4 */ \ + "ld 5, 24(11)\n\t" /* arg3->r5 */ \ + "ld 6, 32(11)\n\t" /* arg4->r6 */ \ + "ld 7, 40(11)\n\t" /* arg5->r7 */ \ + "ld 8, 48(11)\n\t" /* arg6->r8 */ \ + "ld 9, 56(11)\n\t" /* arg7->r9 */ \ + "ld 10, 64(11)\n\t" /* arg8->r10 */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+10]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + _argvec[2+6] = (unsigned long)arg6; \ + _argvec[2+7] = (unsigned long)arg7; \ + _argvec[2+8] = (unsigned long)arg8; \ + _argvec[2+9] = (unsigned long)arg9; \ + _argvec[2+10] = (unsigned long)arg10; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + "addi 1,1,-128\n\t" /* expand stack frame */ \ + /* arg10 */ \ + "ld 3,80(11)\n\t" \ + "std 3,120(1)\n\t" \ + /* arg9 */ \ + "ld 3,72(11)\n\t" \ + "std 3,112(1)\n\t" \ + /* args1-8 */ \ + "ld 3, 8(11)\n\t" /* arg1->r3 */ \ + "ld 4, 16(11)\n\t" /* arg2->r4 */ \ + "ld 5, 24(11)\n\t" /* arg3->r5 */ \ + "ld 6, 32(11)\n\t" /* arg4->r6 */ \ + "ld 7, 40(11)\n\t" /* arg5->r7 */ \ + "ld 8, 48(11)\n\t" /* arg6->r8 */ \ + "ld 9, 56(11)\n\t" /* arg7->r9 */ \ + "ld 10, 64(11)\n\t" /* arg8->r10 */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10,arg11) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+11]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + _argvec[2+6] = (unsigned long)arg6; \ + _argvec[2+7] = (unsigned long)arg7; \ + _argvec[2+8] = (unsigned long)arg8; \ + _argvec[2+9] = (unsigned long)arg9; \ + _argvec[2+10] = (unsigned long)arg10; \ + _argvec[2+11] = (unsigned long)arg11; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + "addi 1,1,-144\n\t" /* expand stack frame */ \ + /* arg11 */ \ + "ld 3,88(11)\n\t" \ + "std 3,128(1)\n\t" \ + /* arg10 */ \ + "ld 3,80(11)\n\t" \ + "std 3,120(1)\n\t" \ + /* arg9 */ \ + "ld 3,72(11)\n\t" \ + "std 3,112(1)\n\t" \ + /* args1-8 */ \ + "ld 3, 8(11)\n\t" /* arg1->r3 */ \ + "ld 4, 16(11)\n\t" /* arg2->r4 */ \ + "ld 5, 24(11)\n\t" /* arg3->r5 */ \ + "ld 6, 32(11)\n\t" /* arg4->r6 */ \ + "ld 7, 40(11)\n\t" /* arg5->r7 */ \ + "ld 8, 48(11)\n\t" /* arg6->r8 */ \ + "ld 9, 56(11)\n\t" /* arg7->r9 */ \ + "ld 10, 64(11)\n\t" /* arg8->r10 */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10,arg11,arg12) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+12]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + _argvec[2+6] = (unsigned long)arg6; \ + _argvec[2+7] = (unsigned long)arg7; \ + _argvec[2+8] = (unsigned long)arg8; \ + _argvec[2+9] = (unsigned long)arg9; \ + _argvec[2+10] = (unsigned long)arg10; \ + _argvec[2+11] = (unsigned long)arg11; \ + _argvec[2+12] = (unsigned long)arg12; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + "addi 1,1,-144\n\t" /* expand stack frame */ \ + /* arg12 */ \ + "ld 3,96(11)\n\t" \ + "std 3,136(1)\n\t" \ + /* arg11 */ \ + "ld 3,88(11)\n\t" \ + "std 3,128(1)\n\t" \ + /* arg10 */ \ + "ld 3,80(11)\n\t" \ + "std 3,120(1)\n\t" \ + /* arg9 */ \ + "ld 3,72(11)\n\t" \ + "std 3,112(1)\n\t" \ + /* args1-8 */ \ + "ld 3, 8(11)\n\t" /* arg1->r3 */ \ + "ld 4, 16(11)\n\t" /* arg2->r4 */ \ + "ld 5, 24(11)\n\t" /* arg3->r5 */ \ + "ld 6, 32(11)\n\t" /* arg4->r6 */ \ + "ld 7, 40(11)\n\t" /* arg5->r7 */ \ + "ld 8, 48(11)\n\t" /* arg6->r8 */ \ + "ld 9, 56(11)\n\t" /* arg7->r9 */ \ + "ld 10, 64(11)\n\t" /* arg8->r10 */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#endif /* PLAT_ppc64be_linux */ + +/* ------------------------- ppc64le-linux ----------------------- */ +#if defined(PLAT_ppc64le_linux) + +/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */ + +/* These regs are trashed by the hidden call. */ +#define __CALLER_SAVED_REGS \ + "lr", "ctr", "xer", \ + "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \ + "r0", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \ + "r11", "r12", "r13" + +/* Macros to save and align the stack before making a function + call and restore it afterwards as gcc may not keep the stack + pointer aligned if it doesn't realise calls are being made + to other functions. */ + +#define VALGRIND_ALIGN_STACK \ + "mr 28,1\n\t" \ + "rldicr 1,1,0,59\n\t" +#define VALGRIND_RESTORE_STACK \ + "mr 1,28\n\t" + +/* These CALL_FN_ macros assume that on ppc64-linux, sizeof(unsigned + long) == 8. */ + +#define CALL_FN_W_v(lval, orig) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+0]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 12,%1\n\t" \ + "std 2,-16(12)\n\t" /* save tocptr */ \ + "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ + "ld 12, 0(12)\n\t" /* target->r12 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ + "mr 12,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(12)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_W(lval, orig, arg1) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+1]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 12,%1\n\t" \ + "std 2,-16(12)\n\t" /* save tocptr */ \ + "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ + "ld 3, 8(12)\n\t" /* arg1->r3 */ \ + "ld 12, 0(12)\n\t" /* target->r12 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ + "mr 12,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(12)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+2]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 12,%1\n\t" \ + "std 2,-16(12)\n\t" /* save tocptr */ \ + "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ + "ld 3, 8(12)\n\t" /* arg1->r3 */ \ + "ld 4, 16(12)\n\t" /* arg2->r4 */ \ + "ld 12, 0(12)\n\t" /* target->r12 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ + "mr 12,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(12)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+3]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 12,%1\n\t" \ + "std 2,-16(12)\n\t" /* save tocptr */ \ + "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ + "ld 3, 8(12)\n\t" /* arg1->r3 */ \ + "ld 4, 16(12)\n\t" /* arg2->r4 */ \ + "ld 5, 24(12)\n\t" /* arg3->r5 */ \ + "ld 12, 0(12)\n\t" /* target->r12 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ + "mr 12,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(12)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+4]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 12,%1\n\t" \ + "std 2,-16(12)\n\t" /* save tocptr */ \ + "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ + "ld 3, 8(12)\n\t" /* arg1->r3 */ \ + "ld 4, 16(12)\n\t" /* arg2->r4 */ \ + "ld 5, 24(12)\n\t" /* arg3->r5 */ \ + "ld 6, 32(12)\n\t" /* arg4->r6 */ \ + "ld 12, 0(12)\n\t" /* target->r12 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ + "mr 12,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(12)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+5]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 12,%1\n\t" \ + "std 2,-16(12)\n\t" /* save tocptr */ \ + "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ + "ld 3, 8(12)\n\t" /* arg1->r3 */ \ + "ld 4, 16(12)\n\t" /* arg2->r4 */ \ + "ld 5, 24(12)\n\t" /* arg3->r5 */ \ + "ld 6, 32(12)\n\t" /* arg4->r6 */ \ + "ld 7, 40(12)\n\t" /* arg5->r7 */ \ + "ld 12, 0(12)\n\t" /* target->r12 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ + "mr 12,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(12)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+6]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + _argvec[2+6] = (unsigned long)arg6; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 12,%1\n\t" \ + "std 2,-16(12)\n\t" /* save tocptr */ \ + "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ + "ld 3, 8(12)\n\t" /* arg1->r3 */ \ + "ld 4, 16(12)\n\t" /* arg2->r4 */ \ + "ld 5, 24(12)\n\t" /* arg3->r5 */ \ + "ld 6, 32(12)\n\t" /* arg4->r6 */ \ + "ld 7, 40(12)\n\t" /* arg5->r7 */ \ + "ld 8, 48(12)\n\t" /* arg6->r8 */ \ + "ld 12, 0(12)\n\t" /* target->r12 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ + "mr 12,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(12)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+7]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + _argvec[2+6] = (unsigned long)arg6; \ + _argvec[2+7] = (unsigned long)arg7; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 12,%1\n\t" \ + "std 2,-16(12)\n\t" /* save tocptr */ \ + "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ + "ld 3, 8(12)\n\t" /* arg1->r3 */ \ + "ld 4, 16(12)\n\t" /* arg2->r4 */ \ + "ld 5, 24(12)\n\t" /* arg3->r5 */ \ + "ld 6, 32(12)\n\t" /* arg4->r6 */ \ + "ld 7, 40(12)\n\t" /* arg5->r7 */ \ + "ld 8, 48(12)\n\t" /* arg6->r8 */ \ + "ld 9, 56(12)\n\t" /* arg7->r9 */ \ + "ld 12, 0(12)\n\t" /* target->r12 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ + "mr 12,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(12)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+8]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + _argvec[2+6] = (unsigned long)arg6; \ + _argvec[2+7] = (unsigned long)arg7; \ + _argvec[2+8] = (unsigned long)arg8; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 12,%1\n\t" \ + "std 2,-16(12)\n\t" /* save tocptr */ \ + "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ + "ld 3, 8(12)\n\t" /* arg1->r3 */ \ + "ld 4, 16(12)\n\t" /* arg2->r4 */ \ + "ld 5, 24(12)\n\t" /* arg3->r5 */ \ + "ld 6, 32(12)\n\t" /* arg4->r6 */ \ + "ld 7, 40(12)\n\t" /* arg5->r7 */ \ + "ld 8, 48(12)\n\t" /* arg6->r8 */ \ + "ld 9, 56(12)\n\t" /* arg7->r9 */ \ + "ld 10, 64(12)\n\t" /* arg8->r10 */ \ + "ld 12, 0(12)\n\t" /* target->r12 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ + "mr 12,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(12)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+9]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + _argvec[2+6] = (unsigned long)arg6; \ + _argvec[2+7] = (unsigned long)arg7; \ + _argvec[2+8] = (unsigned long)arg8; \ + _argvec[2+9] = (unsigned long)arg9; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 12,%1\n\t" \ + "std 2,-16(12)\n\t" /* save tocptr */ \ + "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ + "addi 1,1,-128\n\t" /* expand stack frame */ \ + /* arg9 */ \ + "ld 3,72(12)\n\t" \ + "std 3,96(1)\n\t" \ + /* args1-8 */ \ + "ld 3, 8(12)\n\t" /* arg1->r3 */ \ + "ld 4, 16(12)\n\t" /* arg2->r4 */ \ + "ld 5, 24(12)\n\t" /* arg3->r5 */ \ + "ld 6, 32(12)\n\t" /* arg4->r6 */ \ + "ld 7, 40(12)\n\t" /* arg5->r7 */ \ + "ld 8, 48(12)\n\t" /* arg6->r8 */ \ + "ld 9, 56(12)\n\t" /* arg7->r9 */ \ + "ld 10, 64(12)\n\t" /* arg8->r10 */ \ + "ld 12, 0(12)\n\t" /* target->r12 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ + "mr 12,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(12)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+10]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + _argvec[2+6] = (unsigned long)arg6; \ + _argvec[2+7] = (unsigned long)arg7; \ + _argvec[2+8] = (unsigned long)arg8; \ + _argvec[2+9] = (unsigned long)arg9; \ + _argvec[2+10] = (unsigned long)arg10; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 12,%1\n\t" \ + "std 2,-16(12)\n\t" /* save tocptr */ \ + "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ + "addi 1,1,-128\n\t" /* expand stack frame */ \ + /* arg10 */ \ + "ld 3,80(12)\n\t" \ + "std 3,104(1)\n\t" \ + /* arg9 */ \ + "ld 3,72(12)\n\t" \ + "std 3,96(1)\n\t" \ + /* args1-8 */ \ + "ld 3, 8(12)\n\t" /* arg1->r3 */ \ + "ld 4, 16(12)\n\t" /* arg2->r4 */ \ + "ld 5, 24(12)\n\t" /* arg3->r5 */ \ + "ld 6, 32(12)\n\t" /* arg4->r6 */ \ + "ld 7, 40(12)\n\t" /* arg5->r7 */ \ + "ld 8, 48(12)\n\t" /* arg6->r8 */ \ + "ld 9, 56(12)\n\t" /* arg7->r9 */ \ + "ld 10, 64(12)\n\t" /* arg8->r10 */ \ + "ld 12, 0(12)\n\t" /* target->r12 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ + "mr 12,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(12)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10,arg11) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+11]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + _argvec[2+6] = (unsigned long)arg6; \ + _argvec[2+7] = (unsigned long)arg7; \ + _argvec[2+8] = (unsigned long)arg8; \ + _argvec[2+9] = (unsigned long)arg9; \ + _argvec[2+10] = (unsigned long)arg10; \ + _argvec[2+11] = (unsigned long)arg11; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 12,%1\n\t" \ + "std 2,-16(12)\n\t" /* save tocptr */ \ + "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ + "addi 1,1,-144\n\t" /* expand stack frame */ \ + /* arg11 */ \ + "ld 3,88(12)\n\t" \ + "std 3,112(1)\n\t" \ + /* arg10 */ \ + "ld 3,80(12)\n\t" \ + "std 3,104(1)\n\t" \ + /* arg9 */ \ + "ld 3,72(12)\n\t" \ + "std 3,96(1)\n\t" \ + /* args1-8 */ \ + "ld 3, 8(12)\n\t" /* arg1->r3 */ \ + "ld 4, 16(12)\n\t" /* arg2->r4 */ \ + "ld 5, 24(12)\n\t" /* arg3->r5 */ \ + "ld 6, 32(12)\n\t" /* arg4->r6 */ \ + "ld 7, 40(12)\n\t" /* arg5->r7 */ \ + "ld 8, 48(12)\n\t" /* arg6->r8 */ \ + "ld 9, 56(12)\n\t" /* arg7->r9 */ \ + "ld 10, 64(12)\n\t" /* arg8->r10 */ \ + "ld 12, 0(12)\n\t" /* target->r12 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ + "mr 12,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(12)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10,arg11,arg12) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+12]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + _argvec[2+6] = (unsigned long)arg6; \ + _argvec[2+7] = (unsigned long)arg7; \ + _argvec[2+8] = (unsigned long)arg8; \ + _argvec[2+9] = (unsigned long)arg9; \ + _argvec[2+10] = (unsigned long)arg10; \ + _argvec[2+11] = (unsigned long)arg11; \ + _argvec[2+12] = (unsigned long)arg12; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 12,%1\n\t" \ + "std 2,-16(12)\n\t" /* save tocptr */ \ + "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ + "addi 1,1,-144\n\t" /* expand stack frame */ \ + /* arg12 */ \ + "ld 3,96(12)\n\t" \ + "std 3,120(1)\n\t" \ + /* arg11 */ \ + "ld 3,88(12)\n\t" \ + "std 3,112(1)\n\t" \ + /* arg10 */ \ + "ld 3,80(12)\n\t" \ + "std 3,104(1)\n\t" \ + /* arg9 */ \ + "ld 3,72(12)\n\t" \ + "std 3,96(1)\n\t" \ + /* args1-8 */ \ + "ld 3, 8(12)\n\t" /* arg1->r3 */ \ + "ld 4, 16(12)\n\t" /* arg2->r4 */ \ + "ld 5, 24(12)\n\t" /* arg3->r5 */ \ + "ld 6, 32(12)\n\t" /* arg4->r6 */ \ + "ld 7, 40(12)\n\t" /* arg5->r7 */ \ + "ld 8, 48(12)\n\t" /* arg6->r8 */ \ + "ld 9, 56(12)\n\t" /* arg7->r9 */ \ + "ld 10, 64(12)\n\t" /* arg8->r10 */ \ + "ld 12, 0(12)\n\t" /* target->r12 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ + "mr 12,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(12)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#endif /* PLAT_ppc64le_linux */ + +/* ------------------------- arm-linux ------------------------- */ + +#if defined(PLAT_arm_linux) + +/* These regs are trashed by the hidden call. */ +#define __CALLER_SAVED_REGS "r0", "r1", "r2", "r3","r4", "r12", "r14" + +/* Macros to save and align the stack before making a function + call and restore it afterwards as gcc may not keep the stack + pointer aligned if it doesn't realise calls are being made + to other functions. */ + +/* This is a bit tricky. We store the original stack pointer in r10 + as it is callee-saves. gcc doesn't allow the use of r11 for some + reason. Also, we can't directly "bic" the stack pointer in thumb + mode since r13 isn't an allowed register number in that context. + So use r4 as a temporary, since that is about to get trashed + anyway, just after each use of this macro. Side effect is we need + to be very careful about any future changes, since + VALGRIND_ALIGN_STACK simply assumes r4 is usable. */ +#define VALGRIND_ALIGN_STACK \ + "mov r10, sp\n\t" \ + "mov r4, sp\n\t" \ + "bic r4, r4, #7\n\t" \ + "mov sp, r4\n\t" +#define VALGRIND_RESTORE_STACK \ + "mov sp, r10\n\t" + +/* These CALL_FN_ macros assume that on arm-linux, sizeof(unsigned + long) == 4. */ + +#define CALL_FN_W_v(lval, orig) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[1]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "ldr r4, [%1] \n\t" /* target->r4 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ + VALGRIND_RESTORE_STACK \ + "mov %0, r0\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_W(lval, orig, arg1) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[2]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "ldr r0, [%1, #4] \n\t" \ + "ldr r4, [%1] \n\t" /* target->r4 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ + VALGRIND_RESTORE_STACK \ + "mov %0, r0\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "ldr r0, [%1, #4] \n\t" \ + "ldr r1, [%1, #8] \n\t" \ + "ldr r4, [%1] \n\t" /* target->r4 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ + VALGRIND_RESTORE_STACK \ + "mov %0, r0\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[4]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "ldr r0, [%1, #4] \n\t" \ + "ldr r1, [%1, #8] \n\t" \ + "ldr r2, [%1, #12] \n\t" \ + "ldr r4, [%1] \n\t" /* target->r4 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ + VALGRIND_RESTORE_STACK \ + "mov %0, r0\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[5]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "ldr r0, [%1, #4] \n\t" \ + "ldr r1, [%1, #8] \n\t" \ + "ldr r2, [%1, #12] \n\t" \ + "ldr r3, [%1, #16] \n\t" \ + "ldr r4, [%1] \n\t" /* target->r4 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ + VALGRIND_RESTORE_STACK \ + "mov %0, r0" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[6]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "sub sp, sp, #4 \n\t" \ + "ldr r0, [%1, #20] \n\t" \ + "push {r0} \n\t" \ + "ldr r0, [%1, #4] \n\t" \ + "ldr r1, [%1, #8] \n\t" \ + "ldr r2, [%1, #12] \n\t" \ + "ldr r3, [%1, #16] \n\t" \ + "ldr r4, [%1] \n\t" /* target->r4 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ + VALGRIND_RESTORE_STACK \ + "mov %0, r0" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[7]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "ldr r0, [%1, #20] \n\t" \ + "ldr r1, [%1, #24] \n\t" \ + "push {r0, r1} \n\t" \ + "ldr r0, [%1, #4] \n\t" \ + "ldr r1, [%1, #8] \n\t" \ + "ldr r2, [%1, #12] \n\t" \ + "ldr r3, [%1, #16] \n\t" \ + "ldr r4, [%1] \n\t" /* target->r4 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ + VALGRIND_RESTORE_STACK \ + "mov %0, r0" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[8]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "sub sp, sp, #4 \n\t" \ + "ldr r0, [%1, #20] \n\t" \ + "ldr r1, [%1, #24] \n\t" \ + "ldr r2, [%1, #28] \n\t" \ + "push {r0, r1, r2} \n\t" \ + "ldr r0, [%1, #4] \n\t" \ + "ldr r1, [%1, #8] \n\t" \ + "ldr r2, [%1, #12] \n\t" \ + "ldr r3, [%1, #16] \n\t" \ + "ldr r4, [%1] \n\t" /* target->r4 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ + VALGRIND_RESTORE_STACK \ + "mov %0, r0" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[9]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "ldr r0, [%1, #20] \n\t" \ + "ldr r1, [%1, #24] \n\t" \ + "ldr r2, [%1, #28] \n\t" \ + "ldr r3, [%1, #32] \n\t" \ + "push {r0, r1, r2, r3} \n\t" \ + "ldr r0, [%1, #4] \n\t" \ + "ldr r1, [%1, #8] \n\t" \ + "ldr r2, [%1, #12] \n\t" \ + "ldr r3, [%1, #16] \n\t" \ + "ldr r4, [%1] \n\t" /* target->r4 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ + VALGRIND_RESTORE_STACK \ + "mov %0, r0" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[10]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "sub sp, sp, #4 \n\t" \ + "ldr r0, [%1, #20] \n\t" \ + "ldr r1, [%1, #24] \n\t" \ + "ldr r2, [%1, #28] \n\t" \ + "ldr r3, [%1, #32] \n\t" \ + "ldr r4, [%1, #36] \n\t" \ + "push {r0, r1, r2, r3, r4} \n\t" \ + "ldr r0, [%1, #4] \n\t" \ + "ldr r1, [%1, #8] \n\t" \ + "ldr r2, [%1, #12] \n\t" \ + "ldr r3, [%1, #16] \n\t" \ + "ldr r4, [%1] \n\t" /* target->r4 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ + VALGRIND_RESTORE_STACK \ + "mov %0, r0" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[11]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + _argvec[10] = (unsigned long)(arg10); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "ldr r0, [%1, #40] \n\t" \ + "push {r0} \n\t" \ + "ldr r0, [%1, #20] \n\t" \ + "ldr r1, [%1, #24] \n\t" \ + "ldr r2, [%1, #28] \n\t" \ + "ldr r3, [%1, #32] \n\t" \ + "ldr r4, [%1, #36] \n\t" \ + "push {r0, r1, r2, r3, r4} \n\t" \ + "ldr r0, [%1, #4] \n\t" \ + "ldr r1, [%1, #8] \n\t" \ + "ldr r2, [%1, #12] \n\t" \ + "ldr r3, [%1, #16] \n\t" \ + "ldr r4, [%1] \n\t" /* target->r4 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ + VALGRIND_RESTORE_STACK \ + "mov %0, r0" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ + arg6,arg7,arg8,arg9,arg10, \ + arg11) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[12]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + _argvec[10] = (unsigned long)(arg10); \ + _argvec[11] = (unsigned long)(arg11); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "sub sp, sp, #4 \n\t" \ + "ldr r0, [%1, #40] \n\t" \ + "ldr r1, [%1, #44] \n\t" \ + "push {r0, r1} \n\t" \ + "ldr r0, [%1, #20] \n\t" \ + "ldr r1, [%1, #24] \n\t" \ + "ldr r2, [%1, #28] \n\t" \ + "ldr r3, [%1, #32] \n\t" \ + "ldr r4, [%1, #36] \n\t" \ + "push {r0, r1, r2, r3, r4} \n\t" \ + "ldr r0, [%1, #4] \n\t" \ + "ldr r1, [%1, #8] \n\t" \ + "ldr r2, [%1, #12] \n\t" \ + "ldr r3, [%1, #16] \n\t" \ + "ldr r4, [%1] \n\t" /* target->r4 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ + VALGRIND_RESTORE_STACK \ + "mov %0, r0" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ + arg6,arg7,arg8,arg9,arg10, \ + arg11,arg12) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[13]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + _argvec[10] = (unsigned long)(arg10); \ + _argvec[11] = (unsigned long)(arg11); \ + _argvec[12] = (unsigned long)(arg12); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "ldr r0, [%1, #40] \n\t" \ + "ldr r1, [%1, #44] \n\t" \ + "ldr r2, [%1, #48] \n\t" \ + "push {r0, r1, r2} \n\t" \ + "ldr r0, [%1, #20] \n\t" \ + "ldr r1, [%1, #24] \n\t" \ + "ldr r2, [%1, #28] \n\t" \ + "ldr r3, [%1, #32] \n\t" \ + "ldr r4, [%1, #36] \n\t" \ + "push {r0, r1, r2, r3, r4} \n\t" \ + "ldr r0, [%1, #4] \n\t" \ + "ldr r1, [%1, #8] \n\t" \ + "ldr r2, [%1, #12] \n\t" \ + "ldr r3, [%1, #16] \n\t" \ + "ldr r4, [%1] \n\t" /* target->r4 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ + VALGRIND_RESTORE_STACK \ + "mov %0, r0" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#endif /* PLAT_arm_linux */ + +/* ------------------------ arm64-linux ------------------------ */ + +#if defined(PLAT_arm64_linux) + +/* These regs are trashed by the hidden call. */ +#define __CALLER_SAVED_REGS \ + "x0", "x1", "x2", "x3","x4", "x5", "x6", "x7", "x8", "x9", \ + "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", \ + "x18", "x19", "x20", "x30", \ + "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", \ + "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", \ + "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", \ + "v26", "v27", "v28", "v29", "v30", "v31" + +/* x21 is callee-saved, so we can use it to save and restore SP around + the hidden call. */ +#define VALGRIND_ALIGN_STACK \ + "mov x21, sp\n\t" \ + "bic sp, x21, #15\n\t" +#define VALGRIND_RESTORE_STACK \ + "mov sp, x21\n\t" + +/* These CALL_FN_ macros assume that on arm64-linux, + sizeof(unsigned long) == 8. */ + +#define CALL_FN_W_v(lval, orig) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[1]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "ldr x8, [%1] \n\t" /* target->x8 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ + VALGRIND_RESTORE_STACK \ + "mov %0, x0\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_W(lval, orig, arg1) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[2]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "ldr x0, [%1, #8] \n\t" \ + "ldr x8, [%1] \n\t" /* target->x8 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ + VALGRIND_RESTORE_STACK \ + "mov %0, x0\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "ldr x0, [%1, #8] \n\t" \ + "ldr x1, [%1, #16] \n\t" \ + "ldr x8, [%1] \n\t" /* target->x8 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ + VALGRIND_RESTORE_STACK \ + "mov %0, x0\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[4]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "ldr x0, [%1, #8] \n\t" \ + "ldr x1, [%1, #16] \n\t" \ + "ldr x2, [%1, #24] \n\t" \ + "ldr x8, [%1] \n\t" /* target->x8 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ + VALGRIND_RESTORE_STACK \ + "mov %0, x0\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[5]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "ldr x0, [%1, #8] \n\t" \ + "ldr x1, [%1, #16] \n\t" \ + "ldr x2, [%1, #24] \n\t" \ + "ldr x3, [%1, #32] \n\t" \ + "ldr x8, [%1] \n\t" /* target->x8 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ + VALGRIND_RESTORE_STACK \ + "mov %0, x0" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[6]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "ldr x0, [%1, #8] \n\t" \ + "ldr x1, [%1, #16] \n\t" \ + "ldr x2, [%1, #24] \n\t" \ + "ldr x3, [%1, #32] \n\t" \ + "ldr x4, [%1, #40] \n\t" \ + "ldr x8, [%1] \n\t" /* target->x8 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ + VALGRIND_RESTORE_STACK \ + "mov %0, x0" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[7]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "ldr x0, [%1, #8] \n\t" \ + "ldr x1, [%1, #16] \n\t" \ + "ldr x2, [%1, #24] \n\t" \ + "ldr x3, [%1, #32] \n\t" \ + "ldr x4, [%1, #40] \n\t" \ + "ldr x5, [%1, #48] \n\t" \ + "ldr x8, [%1] \n\t" /* target->x8 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ + VALGRIND_RESTORE_STACK \ + "mov %0, x0" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[8]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "ldr x0, [%1, #8] \n\t" \ + "ldr x1, [%1, #16] \n\t" \ + "ldr x2, [%1, #24] \n\t" \ + "ldr x3, [%1, #32] \n\t" \ + "ldr x4, [%1, #40] \n\t" \ + "ldr x5, [%1, #48] \n\t" \ + "ldr x6, [%1, #56] \n\t" \ + "ldr x8, [%1] \n\t" /* target->x8 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ + VALGRIND_RESTORE_STACK \ + "mov %0, x0" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[9]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "ldr x0, [%1, #8] \n\t" \ + "ldr x1, [%1, #16] \n\t" \ + "ldr x2, [%1, #24] \n\t" \ + "ldr x3, [%1, #32] \n\t" \ + "ldr x4, [%1, #40] \n\t" \ + "ldr x5, [%1, #48] \n\t" \ + "ldr x6, [%1, #56] \n\t" \ + "ldr x7, [%1, #64] \n\t" \ + "ldr x8, [%1] \n\t" /* target->x8 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ + VALGRIND_RESTORE_STACK \ + "mov %0, x0" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[10]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "sub sp, sp, #0x20 \n\t" \ + "ldr x0, [%1, #8] \n\t" \ + "ldr x1, [%1, #16] \n\t" \ + "ldr x2, [%1, #24] \n\t" \ + "ldr x3, [%1, #32] \n\t" \ + "ldr x4, [%1, #40] \n\t" \ + "ldr x5, [%1, #48] \n\t" \ + "ldr x6, [%1, #56] \n\t" \ + "ldr x7, [%1, #64] \n\t" \ + "ldr x8, [%1, #72] \n\t" \ + "str x8, [sp, #0] \n\t" \ + "ldr x8, [%1] \n\t" /* target->x8 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ + VALGRIND_RESTORE_STACK \ + "mov %0, x0" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[11]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + _argvec[10] = (unsigned long)(arg10); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "sub sp, sp, #0x20 \n\t" \ + "ldr x0, [%1, #8] \n\t" \ + "ldr x1, [%1, #16] \n\t" \ + "ldr x2, [%1, #24] \n\t" \ + "ldr x3, [%1, #32] \n\t" \ + "ldr x4, [%1, #40] \n\t" \ + "ldr x5, [%1, #48] \n\t" \ + "ldr x6, [%1, #56] \n\t" \ + "ldr x7, [%1, #64] \n\t" \ + "ldr x8, [%1, #72] \n\t" \ + "str x8, [sp, #0] \n\t" \ + "ldr x8, [%1, #80] \n\t" \ + "str x8, [sp, #8] \n\t" \ + "ldr x8, [%1] \n\t" /* target->x8 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ + VALGRIND_RESTORE_STACK \ + "mov %0, x0" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10,arg11) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[12]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + _argvec[10] = (unsigned long)(arg10); \ + _argvec[11] = (unsigned long)(arg11); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "sub sp, sp, #0x30 \n\t" \ + "ldr x0, [%1, #8] \n\t" \ + "ldr x1, [%1, #16] \n\t" \ + "ldr x2, [%1, #24] \n\t" \ + "ldr x3, [%1, #32] \n\t" \ + "ldr x4, [%1, #40] \n\t" \ + "ldr x5, [%1, #48] \n\t" \ + "ldr x6, [%1, #56] \n\t" \ + "ldr x7, [%1, #64] \n\t" \ + "ldr x8, [%1, #72] \n\t" \ + "str x8, [sp, #0] \n\t" \ + "ldr x8, [%1, #80] \n\t" \ + "str x8, [sp, #8] \n\t" \ + "ldr x8, [%1, #88] \n\t" \ + "str x8, [sp, #16] \n\t" \ + "ldr x8, [%1] \n\t" /* target->x8 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ + VALGRIND_RESTORE_STACK \ + "mov %0, x0" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10,arg11, \ + arg12) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[13]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + _argvec[10] = (unsigned long)(arg10); \ + _argvec[11] = (unsigned long)(arg11); \ + _argvec[12] = (unsigned long)(arg12); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "sub sp, sp, #0x30 \n\t" \ + "ldr x0, [%1, #8] \n\t" \ + "ldr x1, [%1, #16] \n\t" \ + "ldr x2, [%1, #24] \n\t" \ + "ldr x3, [%1, #32] \n\t" \ + "ldr x4, [%1, #40] \n\t" \ + "ldr x5, [%1, #48] \n\t" \ + "ldr x6, [%1, #56] \n\t" \ + "ldr x7, [%1, #64] \n\t" \ + "ldr x8, [%1, #72] \n\t" \ + "str x8, [sp, #0] \n\t" \ + "ldr x8, [%1, #80] \n\t" \ + "str x8, [sp, #8] \n\t" \ + "ldr x8, [%1, #88] \n\t" \ + "str x8, [sp, #16] \n\t" \ + "ldr x8, [%1, #96] \n\t" \ + "str x8, [sp, #24] \n\t" \ + "ldr x8, [%1] \n\t" /* target->x8 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ + VALGRIND_RESTORE_STACK \ + "mov %0, x0" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#endif /* PLAT_arm64_linux */ + +/* ------------------------- s390x-linux ------------------------- */ + +#if defined(PLAT_s390x_linux) + +/* Similar workaround as amd64 (see above), but we use r11 as frame + pointer and save the old r11 in r7. r11 might be used for + argvec, therefore we copy argvec in r1 since r1 is clobbered + after the call anyway. */ +#if defined(__GNUC__) && defined(__GCC_HAVE_DWARF2_CFI_ASM) +# define __FRAME_POINTER \ + ,"d"(__builtin_dwarf_cfa()) +# define VALGRIND_CFI_PROLOGUE \ + ".cfi_remember_state\n\t" \ + "lgr 1,%1\n\t" /* copy the argvec pointer in r1 */ \ + "lgr 7,11\n\t" \ + "lgr 11,%2\n\t" \ + ".cfi_def_cfa r11, 0\n\t" +# define VALGRIND_CFI_EPILOGUE \ + "lgr 11, 7\n\t" \ + ".cfi_restore_state\n\t" +#else +# define __FRAME_POINTER +# define VALGRIND_CFI_PROLOGUE \ + "lgr 1,%1\n\t" +# define VALGRIND_CFI_EPILOGUE +#endif + +/* Nb: On s390 the stack pointer is properly aligned *at all times* + according to the s390 GCC maintainer. (The ABI specification is not + precise in this regard.) Therefore, VALGRIND_ALIGN_STACK and + VALGRIND_RESTORE_STACK are not defined here. */ + +/* These regs are trashed by the hidden call. Note that we overwrite + r14 in s390_irgen_noredir (VEX/priv/guest_s390_irgen.c) to give the + function a proper return address. All others are ABI defined call + clobbers. */ +#if defined(__VX__) || defined(__S390_VX__) +#define __CALLER_SAVED_REGS "0", "1", "2", "3", "4", "5", "14", \ + "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", \ + "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", \ + "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", \ + "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31" +#else +#define __CALLER_SAVED_REGS "0", "1", "2", "3", "4", "5", "14", \ + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7" +#endif + +/* Nb: Although r11 is modified in the asm snippets below (inside + VALGRIND_CFI_PROLOGUE) it is not listed in the clobber section, for + two reasons: + (1) r11 is restored in VALGRIND_CFI_EPILOGUE, so effectively it is not + modified + (2) GCC will complain that r11 cannot appear inside a clobber section, + when compiled with -O -fno-omit-frame-pointer + */ + +#define CALL_FN_W_v(lval, orig) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[1]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + "aghi 15,-160\n\t" \ + "lg 1, 0(1)\n\t" /* target->r1 */ \ + VALGRIND_CALL_NOREDIR_R1 \ + "aghi 15,160\n\t" \ + VALGRIND_CFI_EPILOGUE \ + "lgr %0, 2\n\t" \ + : /*out*/ "=d" (_res) \ + : /*in*/ "d" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +/* The call abi has the arguments in r2-r6 and stack */ +#define CALL_FN_W_W(lval, orig, arg1) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[2]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + "aghi 15,-160\n\t" \ + "lg 2, 8(1)\n\t" \ + "lg 1, 0(1)\n\t" \ + VALGRIND_CALL_NOREDIR_R1 \ + "aghi 15,160\n\t" \ + VALGRIND_CFI_EPILOGUE \ + "lgr %0, 2\n\t" \ + : /*out*/ "=d" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WW(lval, orig, arg1, arg2) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + "aghi 15,-160\n\t" \ + "lg 2, 8(1)\n\t" \ + "lg 3,16(1)\n\t" \ + "lg 1, 0(1)\n\t" \ + VALGRIND_CALL_NOREDIR_R1 \ + "aghi 15,160\n\t" \ + VALGRIND_CFI_EPILOGUE \ + "lgr %0, 2\n\t" \ + : /*out*/ "=d" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWW(lval, orig, arg1, arg2, arg3) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[4]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + "aghi 15,-160\n\t" \ + "lg 2, 8(1)\n\t" \ + "lg 3,16(1)\n\t" \ + "lg 4,24(1)\n\t" \ + "lg 1, 0(1)\n\t" \ + VALGRIND_CALL_NOREDIR_R1 \ + "aghi 15,160\n\t" \ + VALGRIND_CFI_EPILOGUE \ + "lgr %0, 2\n\t" \ + : /*out*/ "=d" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWWW(lval, orig, arg1, arg2, arg3, arg4) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[5]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + _argvec[4] = (unsigned long)arg4; \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + "aghi 15,-160\n\t" \ + "lg 2, 8(1)\n\t" \ + "lg 3,16(1)\n\t" \ + "lg 4,24(1)\n\t" \ + "lg 5,32(1)\n\t" \ + "lg 1, 0(1)\n\t" \ + VALGRIND_CALL_NOREDIR_R1 \ + "aghi 15,160\n\t" \ + VALGRIND_CFI_EPILOGUE \ + "lgr %0, 2\n\t" \ + : /*out*/ "=d" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_5W(lval, orig, arg1, arg2, arg3, arg4, arg5) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[6]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + _argvec[4] = (unsigned long)arg4; \ + _argvec[5] = (unsigned long)arg5; \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + "aghi 15,-160\n\t" \ + "lg 2, 8(1)\n\t" \ + "lg 3,16(1)\n\t" \ + "lg 4,24(1)\n\t" \ + "lg 5,32(1)\n\t" \ + "lg 6,40(1)\n\t" \ + "lg 1, 0(1)\n\t" \ + VALGRIND_CALL_NOREDIR_R1 \ + "aghi 15,160\n\t" \ + VALGRIND_CFI_EPILOGUE \ + "lgr %0, 2\n\t" \ + : /*out*/ "=d" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_6W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ + arg6) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[7]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + _argvec[4] = (unsigned long)arg4; \ + _argvec[5] = (unsigned long)arg5; \ + _argvec[6] = (unsigned long)arg6; \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + "aghi 15,-168\n\t" \ + "lg 2, 8(1)\n\t" \ + "lg 3,16(1)\n\t" \ + "lg 4,24(1)\n\t" \ + "lg 5,32(1)\n\t" \ + "lg 6,40(1)\n\t" \ + "mvc 160(8,15), 48(1)\n\t" \ + "lg 1, 0(1)\n\t" \ + VALGRIND_CALL_NOREDIR_R1 \ + "aghi 15,168\n\t" \ + VALGRIND_CFI_EPILOGUE \ + "lgr %0, 2\n\t" \ + : /*out*/ "=d" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_7W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ + arg6, arg7) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[8]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + _argvec[4] = (unsigned long)arg4; \ + _argvec[5] = (unsigned long)arg5; \ + _argvec[6] = (unsigned long)arg6; \ + _argvec[7] = (unsigned long)arg7; \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + "aghi 15,-176\n\t" \ + "lg 2, 8(1)\n\t" \ + "lg 3,16(1)\n\t" \ + "lg 4,24(1)\n\t" \ + "lg 5,32(1)\n\t" \ + "lg 6,40(1)\n\t" \ + "mvc 160(8,15), 48(1)\n\t" \ + "mvc 168(8,15), 56(1)\n\t" \ + "lg 1, 0(1)\n\t" \ + VALGRIND_CALL_NOREDIR_R1 \ + "aghi 15,176\n\t" \ + VALGRIND_CFI_EPILOGUE \ + "lgr %0, 2\n\t" \ + : /*out*/ "=d" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_8W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ + arg6, arg7 ,arg8) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[9]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + _argvec[4] = (unsigned long)arg4; \ + _argvec[5] = (unsigned long)arg5; \ + _argvec[6] = (unsigned long)arg6; \ + _argvec[7] = (unsigned long)arg7; \ + _argvec[8] = (unsigned long)arg8; \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + "aghi 15,-184\n\t" \ + "lg 2, 8(1)\n\t" \ + "lg 3,16(1)\n\t" \ + "lg 4,24(1)\n\t" \ + "lg 5,32(1)\n\t" \ + "lg 6,40(1)\n\t" \ + "mvc 160(8,15), 48(1)\n\t" \ + "mvc 168(8,15), 56(1)\n\t" \ + "mvc 176(8,15), 64(1)\n\t" \ + "lg 1, 0(1)\n\t" \ + VALGRIND_CALL_NOREDIR_R1 \ + "aghi 15,184\n\t" \ + VALGRIND_CFI_EPILOGUE \ + "lgr %0, 2\n\t" \ + : /*out*/ "=d" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_9W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ + arg6, arg7 ,arg8, arg9) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[10]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + _argvec[4] = (unsigned long)arg4; \ + _argvec[5] = (unsigned long)arg5; \ + _argvec[6] = (unsigned long)arg6; \ + _argvec[7] = (unsigned long)arg7; \ + _argvec[8] = (unsigned long)arg8; \ + _argvec[9] = (unsigned long)arg9; \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + "aghi 15,-192\n\t" \ + "lg 2, 8(1)\n\t" \ + "lg 3,16(1)\n\t" \ + "lg 4,24(1)\n\t" \ + "lg 5,32(1)\n\t" \ + "lg 6,40(1)\n\t" \ + "mvc 160(8,15), 48(1)\n\t" \ + "mvc 168(8,15), 56(1)\n\t" \ + "mvc 176(8,15), 64(1)\n\t" \ + "mvc 184(8,15), 72(1)\n\t" \ + "lg 1, 0(1)\n\t" \ + VALGRIND_CALL_NOREDIR_R1 \ + "aghi 15,192\n\t" \ + VALGRIND_CFI_EPILOGUE \ + "lgr %0, 2\n\t" \ + : /*out*/ "=d" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_10W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ + arg6, arg7 ,arg8, arg9, arg10) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[11]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + _argvec[4] = (unsigned long)arg4; \ + _argvec[5] = (unsigned long)arg5; \ + _argvec[6] = (unsigned long)arg6; \ + _argvec[7] = (unsigned long)arg7; \ + _argvec[8] = (unsigned long)arg8; \ + _argvec[9] = (unsigned long)arg9; \ + _argvec[10] = (unsigned long)arg10; \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + "aghi 15,-200\n\t" \ + "lg 2, 8(1)\n\t" \ + "lg 3,16(1)\n\t" \ + "lg 4,24(1)\n\t" \ + "lg 5,32(1)\n\t" \ + "lg 6,40(1)\n\t" \ + "mvc 160(8,15), 48(1)\n\t" \ + "mvc 168(8,15), 56(1)\n\t" \ + "mvc 176(8,15), 64(1)\n\t" \ + "mvc 184(8,15), 72(1)\n\t" \ + "mvc 192(8,15), 80(1)\n\t" \ + "lg 1, 0(1)\n\t" \ + VALGRIND_CALL_NOREDIR_R1 \ + "aghi 15,200\n\t" \ + VALGRIND_CFI_EPILOGUE \ + "lgr %0, 2\n\t" \ + : /*out*/ "=d" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_11W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ + arg6, arg7 ,arg8, arg9, arg10, arg11) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[12]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + _argvec[4] = (unsigned long)arg4; \ + _argvec[5] = (unsigned long)arg5; \ + _argvec[6] = (unsigned long)arg6; \ + _argvec[7] = (unsigned long)arg7; \ + _argvec[8] = (unsigned long)arg8; \ + _argvec[9] = (unsigned long)arg9; \ + _argvec[10] = (unsigned long)arg10; \ + _argvec[11] = (unsigned long)arg11; \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + "aghi 15,-208\n\t" \ + "lg 2, 8(1)\n\t" \ + "lg 3,16(1)\n\t" \ + "lg 4,24(1)\n\t" \ + "lg 5,32(1)\n\t" \ + "lg 6,40(1)\n\t" \ + "mvc 160(8,15), 48(1)\n\t" \ + "mvc 168(8,15), 56(1)\n\t" \ + "mvc 176(8,15), 64(1)\n\t" \ + "mvc 184(8,15), 72(1)\n\t" \ + "mvc 192(8,15), 80(1)\n\t" \ + "mvc 200(8,15), 88(1)\n\t" \ + "lg 1, 0(1)\n\t" \ + VALGRIND_CALL_NOREDIR_R1 \ + "aghi 15,208\n\t" \ + VALGRIND_CFI_EPILOGUE \ + "lgr %0, 2\n\t" \ + : /*out*/ "=d" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_12W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ + arg6, arg7 ,arg8, arg9, arg10, arg11, arg12)\ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[13]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + _argvec[4] = (unsigned long)arg4; \ + _argvec[5] = (unsigned long)arg5; \ + _argvec[6] = (unsigned long)arg6; \ + _argvec[7] = (unsigned long)arg7; \ + _argvec[8] = (unsigned long)arg8; \ + _argvec[9] = (unsigned long)arg9; \ + _argvec[10] = (unsigned long)arg10; \ + _argvec[11] = (unsigned long)arg11; \ + _argvec[12] = (unsigned long)arg12; \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + "aghi 15,-216\n\t" \ + "lg 2, 8(1)\n\t" \ + "lg 3,16(1)\n\t" \ + "lg 4,24(1)\n\t" \ + "lg 5,32(1)\n\t" \ + "lg 6,40(1)\n\t" \ + "mvc 160(8,15), 48(1)\n\t" \ + "mvc 168(8,15), 56(1)\n\t" \ + "mvc 176(8,15), 64(1)\n\t" \ + "mvc 184(8,15), 72(1)\n\t" \ + "mvc 192(8,15), 80(1)\n\t" \ + "mvc 200(8,15), 88(1)\n\t" \ + "mvc 208(8,15), 96(1)\n\t" \ + "lg 1, 0(1)\n\t" \ + VALGRIND_CALL_NOREDIR_R1 \ + "aghi 15,216\n\t" \ + VALGRIND_CFI_EPILOGUE \ + "lgr %0, 2\n\t" \ + : /*out*/ "=d" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + + +#endif /* PLAT_s390x_linux */ + +/* ------------------------- mips32-linux ----------------------- */ + +#if defined(PLAT_mips32_linux) + +/* These regs are trashed by the hidden call. */ +#define __CALLER_SAVED_REGS "$2", "$3", "$4", "$5", "$6", \ +"$7", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24", \ +"$25", "$31" + +/* These CALL_FN_ macros assume that on mips-linux, sizeof(unsigned + long) == 4. */ + +#define CALL_FN_W_v(lval, orig) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[1]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + __asm__ volatile( \ + "subu $29, $29, 8 \n\t" \ + "sw $28, 0($29) \n\t" \ + "sw $31, 4($29) \n\t" \ + "subu $29, $29, 16 \n\t" \ + "lw $25, 0(%1) \n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "addu $29, $29, 16\n\t" \ + "lw $28, 0($29) \n\t" \ + "lw $31, 4($29) \n\t" \ + "addu $29, $29, 8 \n\t" \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_W(lval, orig, arg1) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[2]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + __asm__ volatile( \ + "subu $29, $29, 8 \n\t" \ + "sw $28, 0($29) \n\t" \ + "sw $31, 4($29) \n\t" \ + "subu $29, $29, 16 \n\t" \ + "lw $4, 4(%1) \n\t" /* arg1*/ \ + "lw $25, 0(%1) \n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "addu $29, $29, 16 \n\t" \ + "lw $28, 0($29) \n\t" \ + "lw $31, 4($29) \n\t" \ + "addu $29, $29, 8 \n\t" \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + __asm__ volatile( \ + "subu $29, $29, 8 \n\t" \ + "sw $28, 0($29) \n\t" \ + "sw $31, 4($29) \n\t" \ + "subu $29, $29, 16 \n\t" \ + "lw $4, 4(%1) \n\t" \ + "lw $5, 8(%1) \n\t" \ + "lw $25, 0(%1) \n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "addu $29, $29, 16 \n\t" \ + "lw $28, 0($29) \n\t" \ + "lw $31, 4($29) \n\t" \ + "addu $29, $29, 8 \n\t" \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[4]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + __asm__ volatile( \ + "subu $29, $29, 8 \n\t" \ + "sw $28, 0($29) \n\t" \ + "sw $31, 4($29) \n\t" \ + "subu $29, $29, 16 \n\t" \ + "lw $4, 4(%1) \n\t" \ + "lw $5, 8(%1) \n\t" \ + "lw $6, 12(%1) \n\t" \ + "lw $25, 0(%1) \n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "addu $29, $29, 16 \n\t" \ + "lw $28, 0($29) \n\t" \ + "lw $31, 4($29) \n\t" \ + "addu $29, $29, 8 \n\t" \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[5]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + __asm__ volatile( \ + "subu $29, $29, 8 \n\t" \ + "sw $28, 0($29) \n\t" \ + "sw $31, 4($29) \n\t" \ + "subu $29, $29, 16 \n\t" \ + "lw $4, 4(%1) \n\t" \ + "lw $5, 8(%1) \n\t" \ + "lw $6, 12(%1) \n\t" \ + "lw $7, 16(%1) \n\t" \ + "lw $25, 0(%1) \n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "addu $29, $29, 16 \n\t" \ + "lw $28, 0($29) \n\t" \ + "lw $31, 4($29) \n\t" \ + "addu $29, $29, 8 \n\t" \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[6]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + __asm__ volatile( \ + "subu $29, $29, 8 \n\t" \ + "sw $28, 0($29) \n\t" \ + "sw $31, 4($29) \n\t" \ + "lw $4, 20(%1) \n\t" \ + "subu $29, $29, 24\n\t" \ + "sw $4, 16($29) \n\t" \ + "lw $4, 4(%1) \n\t" \ + "lw $5, 8(%1) \n\t" \ + "lw $6, 12(%1) \n\t" \ + "lw $7, 16(%1) \n\t" \ + "lw $25, 0(%1) \n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "addu $29, $29, 24 \n\t" \ + "lw $28, 0($29) \n\t" \ + "lw $31, 4($29) \n\t" \ + "addu $29, $29, 8 \n\t" \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) +#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[7]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + __asm__ volatile( \ + "subu $29, $29, 8 \n\t" \ + "sw $28, 0($29) \n\t" \ + "sw $31, 4($29) \n\t" \ + "lw $4, 20(%1) \n\t" \ + "subu $29, $29, 32\n\t" \ + "sw $4, 16($29) \n\t" \ + "lw $4, 24(%1) \n\t" \ + "nop\n\t" \ + "sw $4, 20($29) \n\t" \ + "lw $4, 4(%1) \n\t" \ + "lw $5, 8(%1) \n\t" \ + "lw $6, 12(%1) \n\t" \ + "lw $7, 16(%1) \n\t" \ + "lw $25, 0(%1) \n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "addu $29, $29, 32 \n\t" \ + "lw $28, 0($29) \n\t" \ + "lw $31, 4($29) \n\t" \ + "addu $29, $29, 8 \n\t" \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[8]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + __asm__ volatile( \ + "subu $29, $29, 8 \n\t" \ + "sw $28, 0($29) \n\t" \ + "sw $31, 4($29) \n\t" \ + "lw $4, 20(%1) \n\t" \ + "subu $29, $29, 32\n\t" \ + "sw $4, 16($29) \n\t" \ + "lw $4, 24(%1) \n\t" \ + "sw $4, 20($29) \n\t" \ + "lw $4, 28(%1) \n\t" \ + "sw $4, 24($29) \n\t" \ + "lw $4, 4(%1) \n\t" \ + "lw $5, 8(%1) \n\t" \ + "lw $6, 12(%1) \n\t" \ + "lw $7, 16(%1) \n\t" \ + "lw $25, 0(%1) \n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "addu $29, $29, 32 \n\t" \ + "lw $28, 0($29) \n\t" \ + "lw $31, 4($29) \n\t" \ + "addu $29, $29, 8 \n\t" \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[9]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + __asm__ volatile( \ + "subu $29, $29, 8 \n\t" \ + "sw $28, 0($29) \n\t" \ + "sw $31, 4($29) \n\t" \ + "lw $4, 20(%1) \n\t" \ + "subu $29, $29, 40\n\t" \ + "sw $4, 16($29) \n\t" \ + "lw $4, 24(%1) \n\t" \ + "sw $4, 20($29) \n\t" \ + "lw $4, 28(%1) \n\t" \ + "sw $4, 24($29) \n\t" \ + "lw $4, 32(%1) \n\t" \ + "sw $4, 28($29) \n\t" \ + "lw $4, 4(%1) \n\t" \ + "lw $5, 8(%1) \n\t" \ + "lw $6, 12(%1) \n\t" \ + "lw $7, 16(%1) \n\t" \ + "lw $25, 0(%1) \n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "addu $29, $29, 40 \n\t" \ + "lw $28, 0($29) \n\t" \ + "lw $31, 4($29) \n\t" \ + "addu $29, $29, 8 \n\t" \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[10]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + __asm__ volatile( \ + "subu $29, $29, 8 \n\t" \ + "sw $28, 0($29) \n\t" \ + "sw $31, 4($29) \n\t" \ + "lw $4, 20(%1) \n\t" \ + "subu $29, $29, 40\n\t" \ + "sw $4, 16($29) \n\t" \ + "lw $4, 24(%1) \n\t" \ + "sw $4, 20($29) \n\t" \ + "lw $4, 28(%1) \n\t" \ + "sw $4, 24($29) \n\t" \ + "lw $4, 32(%1) \n\t" \ + "sw $4, 28($29) \n\t" \ + "lw $4, 36(%1) \n\t" \ + "sw $4, 32($29) \n\t" \ + "lw $4, 4(%1) \n\t" \ + "lw $5, 8(%1) \n\t" \ + "lw $6, 12(%1) \n\t" \ + "lw $7, 16(%1) \n\t" \ + "lw $25, 0(%1) \n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "addu $29, $29, 40 \n\t" \ + "lw $28, 0($29) \n\t" \ + "lw $31, 4($29) \n\t" \ + "addu $29, $29, 8 \n\t" \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[11]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + _argvec[10] = (unsigned long)(arg10); \ + __asm__ volatile( \ + "subu $29, $29, 8 \n\t" \ + "sw $28, 0($29) \n\t" \ + "sw $31, 4($29) \n\t" \ + "lw $4, 20(%1) \n\t" \ + "subu $29, $29, 48\n\t" \ + "sw $4, 16($29) \n\t" \ + "lw $4, 24(%1) \n\t" \ + "sw $4, 20($29) \n\t" \ + "lw $4, 28(%1) \n\t" \ + "sw $4, 24($29) \n\t" \ + "lw $4, 32(%1) \n\t" \ + "sw $4, 28($29) \n\t" \ + "lw $4, 36(%1) \n\t" \ + "sw $4, 32($29) \n\t" \ + "lw $4, 40(%1) \n\t" \ + "sw $4, 36($29) \n\t" \ + "lw $4, 4(%1) \n\t" \ + "lw $5, 8(%1) \n\t" \ + "lw $6, 12(%1) \n\t" \ + "lw $7, 16(%1) \n\t" \ + "lw $25, 0(%1) \n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "addu $29, $29, 48 \n\t" \ + "lw $28, 0($29) \n\t" \ + "lw $31, 4($29) \n\t" \ + "addu $29, $29, 8 \n\t" \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ + arg6,arg7,arg8,arg9,arg10, \ + arg11) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[12]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + _argvec[10] = (unsigned long)(arg10); \ + _argvec[11] = (unsigned long)(arg11); \ + __asm__ volatile( \ + "subu $29, $29, 8 \n\t" \ + "sw $28, 0($29) \n\t" \ + "sw $31, 4($29) \n\t" \ + "lw $4, 20(%1) \n\t" \ + "subu $29, $29, 48\n\t" \ + "sw $4, 16($29) \n\t" \ + "lw $4, 24(%1) \n\t" \ + "sw $4, 20($29) \n\t" \ + "lw $4, 28(%1) \n\t" \ + "sw $4, 24($29) \n\t" \ + "lw $4, 32(%1) \n\t" \ + "sw $4, 28($29) \n\t" \ + "lw $4, 36(%1) \n\t" \ + "sw $4, 32($29) \n\t" \ + "lw $4, 40(%1) \n\t" \ + "sw $4, 36($29) \n\t" \ + "lw $4, 44(%1) \n\t" \ + "sw $4, 40($29) \n\t" \ + "lw $4, 4(%1) \n\t" \ + "lw $5, 8(%1) \n\t" \ + "lw $6, 12(%1) \n\t" \ + "lw $7, 16(%1) \n\t" \ + "lw $25, 0(%1) \n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "addu $29, $29, 48 \n\t" \ + "lw $28, 0($29) \n\t" \ + "lw $31, 4($29) \n\t" \ + "addu $29, $29, 8 \n\t" \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ + arg6,arg7,arg8,arg9,arg10, \ + arg11,arg12) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[13]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + _argvec[10] = (unsigned long)(arg10); \ + _argvec[11] = (unsigned long)(arg11); \ + _argvec[12] = (unsigned long)(arg12); \ + __asm__ volatile( \ + "subu $29, $29, 8 \n\t" \ + "sw $28, 0($29) \n\t" \ + "sw $31, 4($29) \n\t" \ + "lw $4, 20(%1) \n\t" \ + "subu $29, $29, 56\n\t" \ + "sw $4, 16($29) \n\t" \ + "lw $4, 24(%1) \n\t" \ + "sw $4, 20($29) \n\t" \ + "lw $4, 28(%1) \n\t" \ + "sw $4, 24($29) \n\t" \ + "lw $4, 32(%1) \n\t" \ + "sw $4, 28($29) \n\t" \ + "lw $4, 36(%1) \n\t" \ + "sw $4, 32($29) \n\t" \ + "lw $4, 40(%1) \n\t" \ + "sw $4, 36($29) \n\t" \ + "lw $4, 44(%1) \n\t" \ + "sw $4, 40($29) \n\t" \ + "lw $4, 48(%1) \n\t" \ + "sw $4, 44($29) \n\t" \ + "lw $4, 4(%1) \n\t" \ + "lw $5, 8(%1) \n\t" \ + "lw $6, 12(%1) \n\t" \ + "lw $7, 16(%1) \n\t" \ + "lw $25, 0(%1) \n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "addu $29, $29, 56 \n\t" \ + "lw $28, 0($29) \n\t" \ + "lw $31, 4($29) \n\t" \ + "addu $29, $29, 8 \n\t" \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#endif /* PLAT_mips32_linux */ + +/* ------------------------- nanomips-linux -------------------- */ + +#if defined(PLAT_nanomips_linux) + +/* These regs are trashed by the hidden call. */ +#define __CALLER_SAVED_REGS "$t4", "$t5", "$a0", "$a1", "$a2", \ +"$a3", "$a4", "$a5", "$a6", "$a7", "$t0", "$t1", "$t2", "$t3", \ +"$t8","$t9", "$at" + +/* These CALL_FN_ macros assume that on mips-linux, sizeof(unsigned + long) == 4. */ + +#define CALL_FN_W_v(lval, orig) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[1]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + __asm__ volatile( \ + "lw $t9, 0(%1)\n\t" \ + VALGRIND_CALL_NOREDIR_T9 \ + "move %0, $a0\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_W(lval, orig, arg1) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[2]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + __asm__ volatile( \ + "lw $t9, 0(%1)\n\t" \ + "lw $a0, 4(%1)\n\t" \ + VALGRIND_CALL_NOREDIR_T9 \ + "move %0, $a0\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + __asm__ volatile( \ + "lw $t9, 0(%1)\n\t" \ + "lw $a0, 4(%1)\n\t" \ + "lw $a1, 8(%1)\n\t" \ + VALGRIND_CALL_NOREDIR_T9 \ + "move %0, $a0\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[4]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + __asm__ volatile( \ + "lw $t9, 0(%1)\n\t" \ + "lw $a0, 4(%1)\n\t" \ + "lw $a1, 8(%1)\n\t" \ + "lw $a2,12(%1)\n\t" \ + VALGRIND_CALL_NOREDIR_T9 \ + "move %0, $a0\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[5]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + __asm__ volatile( \ + "lw $t9, 0(%1)\n\t" \ + "lw $a0, 4(%1)\n\t" \ + "lw $a1, 8(%1)\n\t" \ + "lw $a2,12(%1)\n\t" \ + "lw $a3,16(%1)\n\t" \ + VALGRIND_CALL_NOREDIR_T9 \ + "move %0, $a0\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[6]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + __asm__ volatile( \ + "lw $t9, 0(%1)\n\t" \ + "lw $a0, 4(%1)\n\t" \ + "lw $a1, 8(%1)\n\t" \ + "lw $a2,12(%1)\n\t" \ + "lw $a3,16(%1)\n\t" \ + "lw $a4,20(%1)\n\t" \ + VALGRIND_CALL_NOREDIR_T9 \ + "move %0, $a0\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) +#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[7]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + __asm__ volatile( \ + "lw $t9, 0(%1)\n\t" \ + "lw $a0, 4(%1)\n\t" \ + "lw $a1, 8(%1)\n\t" \ + "lw $a2,12(%1)\n\t" \ + "lw $a3,16(%1)\n\t" \ + "lw $a4,20(%1)\n\t" \ + "lw $a5,24(%1)\n\t" \ + VALGRIND_CALL_NOREDIR_T9 \ + "move %0, $a0\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[8]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + __asm__ volatile( \ + "lw $t9, 0(%1)\n\t" \ + "lw $a0, 4(%1)\n\t" \ + "lw $a1, 8(%1)\n\t" \ + "lw $a2,12(%1)\n\t" \ + "lw $a3,16(%1)\n\t" \ + "lw $a4,20(%1)\n\t" \ + "lw $a5,24(%1)\n\t" \ + "lw $a6,28(%1)\n\t" \ + VALGRIND_CALL_NOREDIR_T9 \ + "move %0, $a0\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[9]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + __asm__ volatile( \ + "lw $t9, 0(%1)\n\t" \ + "lw $a0, 4(%1)\n\t" \ + "lw $a1, 8(%1)\n\t" \ + "lw $a2,12(%1)\n\t" \ + "lw $a3,16(%1)\n\t" \ + "lw $a4,20(%1)\n\t" \ + "lw $a5,24(%1)\n\t" \ + "lw $a6,28(%1)\n\t" \ + "lw $a7,32(%1)\n\t" \ + VALGRIND_CALL_NOREDIR_T9 \ + "move %0, $a0\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[10]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + __asm__ volatile( \ + "addiu $sp, $sp, -16 \n\t" \ + "lw $t9,36(%1) \n\t" \ + "sw $t9, 0($sp) \n\t" \ + "lw $t9, 0(%1) \n\t" \ + "lw $a0, 4(%1) \n\t" \ + "lw $a1, 8(%1) \n\t" \ + "lw $a2,12(%1) \n\t" \ + "lw $a3,16(%1) \n\t" \ + "lw $a4,20(%1) \n\t" \ + "lw $a5,24(%1) \n\t" \ + "lw $a6,28(%1) \n\t" \ + "lw $a7,32(%1) \n\t" \ + VALGRIND_CALL_NOREDIR_T9 \ + "move %0, $a0 \n\t" \ + "addiu $sp, $sp, 16 \n\t" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[11]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + _argvec[10] = (unsigned long)(arg10); \ + __asm__ volatile( \ + "addiu $sp, $sp, -16 \n\t" \ + "lw $t9,36(%1) \n\t" \ + "sw $t9, 0($sp) \n\t" \ + "lw $t9,40(%1) \n\t" \ + "sw $t9, 4($sp) \n\t" \ + "lw $t9, 0(%1) \n\t" \ + "lw $a0, 4(%1) \n\t" \ + "lw $a1, 8(%1) \n\t" \ + "lw $a2,12(%1) \n\t" \ + "lw $a3,16(%1) \n\t" \ + "lw $a4,20(%1) \n\t" \ + "lw $a5,24(%1) \n\t" \ + "lw $a6,28(%1) \n\t" \ + "lw $a7,32(%1) \n\t" \ + VALGRIND_CALL_NOREDIR_T9 \ + "move %0, $a0 \n\t" \ + "addiu $sp, $sp, 16 \n\t" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ + arg6,arg7,arg8,arg9,arg10, \ + arg11) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[12]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + _argvec[10] = (unsigned long)(arg10); \ + _argvec[11] = (unsigned long)(arg11); \ + __asm__ volatile( \ + "addiu $sp, $sp, -16 \n\t" \ + "lw $t9,36(%1) \n\t" \ + "sw $t9, 0($sp) \n\t" \ + "lw $t9,40(%1) \n\t" \ + "sw $t9, 4($sp) \n\t" \ + "lw $t9,44(%1) \n\t" \ + "sw $t9, 8($sp) \n\t" \ + "lw $t9, 0(%1) \n\t" \ + "lw $a0, 4(%1) \n\t" \ + "lw $a1, 8(%1) \n\t" \ + "lw $a2,12(%1) \n\t" \ + "lw $a3,16(%1) \n\t" \ + "lw $a4,20(%1) \n\t" \ + "lw $a5,24(%1) \n\t" \ + "lw $a6,28(%1) \n\t" \ + "lw $a7,32(%1) \n\t" \ + VALGRIND_CALL_NOREDIR_T9 \ + "move %0, $a0 \n\t" \ + "addiu $sp, $sp, 16 \n\t" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ + arg6,arg7,arg8,arg9,arg10, \ + arg11,arg12) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[13]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + _argvec[10] = (unsigned long)(arg10); \ + _argvec[11] = (unsigned long)(arg11); \ + _argvec[12] = (unsigned long)(arg12); \ + __asm__ volatile( \ + "addiu $sp, $sp, -16 \n\t" \ + "lw $t9,36(%1) \n\t" \ + "sw $t9, 0($sp) \n\t" \ + "lw $t9,40(%1) \n\t" \ + "sw $t9, 4($sp) \n\t" \ + "lw $t9,44(%1) \n\t" \ + "sw $t9, 8($sp) \n\t" \ + "lw $t9,48(%1) \n\t" \ + "sw $t9,12($sp) \n\t" \ + "lw $t9, 0(%1) \n\t" \ + "lw $a0, 4(%1) \n\t" \ + "lw $a1, 8(%1) \n\t" \ + "lw $a2,12(%1) \n\t" \ + "lw $a3,16(%1) \n\t" \ + "lw $a4,20(%1) \n\t" \ + "lw $a5,24(%1) \n\t" \ + "lw $a6,28(%1) \n\t" \ + "lw $a7,32(%1) \n\t" \ + VALGRIND_CALL_NOREDIR_T9 \ + "move %0, $a0 \n\t" \ + "addiu $sp, $sp, 16 \n\t" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#endif /* PLAT_nanomips_linux */ + +/* ------------------------- mips64-linux ------------------------- */ + +#if defined(PLAT_mips64_linux) + +/* These regs are trashed by the hidden call. */ +#define __CALLER_SAVED_REGS "$2", "$3", "$4", "$5", "$6", \ +"$7", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24", \ +"$25", "$31" + +/* These CALL_FN_ macros assume that on mips64-linux, + sizeof(long long) == 8. */ + +#define MIPS64_LONG2REG_CAST(x) ((long long)(long)x) + +#define CALL_FN_W_v(lval, orig) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long long _argvec[1]; \ + volatile unsigned long long _res; \ + _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ + __asm__ volatile( \ + "ld $25, 0(%1)\n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) (long)_res; \ + } while (0) + +#define CALL_FN_W_W(lval, orig, arg1) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long long _argvec[2]; \ + volatile unsigned long long _res; \ + _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ + _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ + __asm__ volatile( \ + "ld $4, 8(%1)\n\t" /* arg1*/ \ + "ld $25, 0(%1)\n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) (long)_res; \ + } while (0) + +#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long long _argvec[3]; \ + volatile unsigned long long _res; \ + _argvec[0] = _orig.nraddr; \ + _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ + _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ + __asm__ volatile( \ + "ld $4, 8(%1)\n\t" \ + "ld $5, 16(%1)\n\t" \ + "ld $25, 0(%1)\n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) (long)_res; \ + } while (0) + + +#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long long _argvec[4]; \ + volatile unsigned long long _res; \ + _argvec[0] = _orig.nraddr; \ + _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ + _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ + _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ + __asm__ volatile( \ + "ld $4, 8(%1)\n\t" \ + "ld $5, 16(%1)\n\t" \ + "ld $6, 24(%1)\n\t" \ + "ld $25, 0(%1)\n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) (long)_res; \ + } while (0) + +#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long long _argvec[5]; \ + volatile unsigned long long _res; \ + _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ + _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ + _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ + _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ + _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \ + __asm__ volatile( \ + "ld $4, 8(%1)\n\t" \ + "ld $5, 16(%1)\n\t" \ + "ld $6, 24(%1)\n\t" \ + "ld $7, 32(%1)\n\t" \ + "ld $25, 0(%1)\n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) (long)_res; \ + } while (0) + +#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long long _argvec[6]; \ + volatile unsigned long long _res; \ + _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ + _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ + _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ + _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ + _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \ + _argvec[5] = MIPS64_LONG2REG_CAST(arg5); \ + __asm__ volatile( \ + "ld $4, 8(%1)\n\t" \ + "ld $5, 16(%1)\n\t" \ + "ld $6, 24(%1)\n\t" \ + "ld $7, 32(%1)\n\t" \ + "ld $8, 40(%1)\n\t" \ + "ld $25, 0(%1)\n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) (long)_res; \ + } while (0) + +#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long long _argvec[7]; \ + volatile unsigned long long _res; \ + _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ + _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ + _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ + _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ + _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \ + _argvec[5] = MIPS64_LONG2REG_CAST(arg5); \ + _argvec[6] = MIPS64_LONG2REG_CAST(arg6); \ + __asm__ volatile( \ + "ld $4, 8(%1)\n\t" \ + "ld $5, 16(%1)\n\t" \ + "ld $6, 24(%1)\n\t" \ + "ld $7, 32(%1)\n\t" \ + "ld $8, 40(%1)\n\t" \ + "ld $9, 48(%1)\n\t" \ + "ld $25, 0(%1)\n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) (long)_res; \ + } while (0) + +#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long long _argvec[8]; \ + volatile unsigned long long _res; \ + _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ + _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ + _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ + _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ + _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \ + _argvec[5] = MIPS64_LONG2REG_CAST(arg5); \ + _argvec[6] = MIPS64_LONG2REG_CAST(arg6); \ + _argvec[7] = MIPS64_LONG2REG_CAST(arg7); \ + __asm__ volatile( \ + "ld $4, 8(%1)\n\t" \ + "ld $5, 16(%1)\n\t" \ + "ld $6, 24(%1)\n\t" \ + "ld $7, 32(%1)\n\t" \ + "ld $8, 40(%1)\n\t" \ + "ld $9, 48(%1)\n\t" \ + "ld $10, 56(%1)\n\t" \ + "ld $25, 0(%1) \n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) (long)_res; \ + } while (0) + +#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long long _argvec[9]; \ + volatile unsigned long long _res; \ + _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ + _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ + _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ + _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ + _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \ + _argvec[5] = MIPS64_LONG2REG_CAST(arg5); \ + _argvec[6] = MIPS64_LONG2REG_CAST(arg6); \ + _argvec[7] = MIPS64_LONG2REG_CAST(arg7); \ + _argvec[8] = MIPS64_LONG2REG_CAST(arg8); \ + __asm__ volatile( \ + "ld $4, 8(%1)\n\t" \ + "ld $5, 16(%1)\n\t" \ + "ld $6, 24(%1)\n\t" \ + "ld $7, 32(%1)\n\t" \ + "ld $8, 40(%1)\n\t" \ + "ld $9, 48(%1)\n\t" \ + "ld $10, 56(%1)\n\t" \ + "ld $11, 64(%1)\n\t" \ + "ld $25, 0(%1) \n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) (long)_res; \ + } while (0) + +#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long long _argvec[10]; \ + volatile unsigned long long _res; \ + _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ + _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ + _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ + _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ + _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \ + _argvec[5] = MIPS64_LONG2REG_CAST(arg5); \ + _argvec[6] = MIPS64_LONG2REG_CAST(arg6); \ + _argvec[7] = MIPS64_LONG2REG_CAST(arg7); \ + _argvec[8] = MIPS64_LONG2REG_CAST(arg8); \ + _argvec[9] = MIPS64_LONG2REG_CAST(arg9); \ + __asm__ volatile( \ + "dsubu $29, $29, 8\n\t" \ + "ld $4, 72(%1)\n\t" \ + "sd $4, 0($29)\n\t" \ + "ld $4, 8(%1)\n\t" \ + "ld $5, 16(%1)\n\t" \ + "ld $6, 24(%1)\n\t" \ + "ld $7, 32(%1)\n\t" \ + "ld $8, 40(%1)\n\t" \ + "ld $9, 48(%1)\n\t" \ + "ld $10, 56(%1)\n\t" \ + "ld $11, 64(%1)\n\t" \ + "ld $25, 0(%1)\n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "daddu $29, $29, 8\n\t" \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) (long)_res; \ + } while (0) + +#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long long _argvec[11]; \ + volatile unsigned long long _res; \ + _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ + _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ + _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ + _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ + _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \ + _argvec[5] = MIPS64_LONG2REG_CAST(arg5); \ + _argvec[6] = MIPS64_LONG2REG_CAST(arg6); \ + _argvec[7] = MIPS64_LONG2REG_CAST(arg7); \ + _argvec[8] = MIPS64_LONG2REG_CAST(arg8); \ + _argvec[9] = MIPS64_LONG2REG_CAST(arg9); \ + _argvec[10] = MIPS64_LONG2REG_CAST(arg10); \ + __asm__ volatile( \ + "dsubu $29, $29, 16\n\t" \ + "ld $4, 72(%1)\n\t" \ + "sd $4, 0($29)\n\t" \ + "ld $4, 80(%1)\n\t" \ + "sd $4, 8($29)\n\t" \ + "ld $4, 8(%1)\n\t" \ + "ld $5, 16(%1)\n\t" \ + "ld $6, 24(%1)\n\t" \ + "ld $7, 32(%1)\n\t" \ + "ld $8, 40(%1)\n\t" \ + "ld $9, 48(%1)\n\t" \ + "ld $10, 56(%1)\n\t" \ + "ld $11, 64(%1)\n\t" \ + "ld $25, 0(%1)\n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "daddu $29, $29, 16\n\t" \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) (long)_res; \ + } while (0) + +#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ + arg6,arg7,arg8,arg9,arg10, \ + arg11) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long long _argvec[12]; \ + volatile unsigned long long _res; \ + _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ + _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ + _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ + _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ + _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \ + _argvec[5] = MIPS64_LONG2REG_CAST(arg5); \ + _argvec[6] = MIPS64_LONG2REG_CAST(arg6); \ + _argvec[7] = MIPS64_LONG2REG_CAST(arg7); \ + _argvec[8] = MIPS64_LONG2REG_CAST(arg8); \ + _argvec[9] = MIPS64_LONG2REG_CAST(arg9); \ + _argvec[10] = MIPS64_LONG2REG_CAST(arg10); \ + _argvec[11] = MIPS64_LONG2REG_CAST(arg11); \ + __asm__ volatile( \ + "dsubu $29, $29, 24\n\t" \ + "ld $4, 72(%1)\n\t" \ + "sd $4, 0($29)\n\t" \ + "ld $4, 80(%1)\n\t" \ + "sd $4, 8($29)\n\t" \ + "ld $4, 88(%1)\n\t" \ + "sd $4, 16($29)\n\t" \ + "ld $4, 8(%1)\n\t" \ + "ld $5, 16(%1)\n\t" \ + "ld $6, 24(%1)\n\t" \ + "ld $7, 32(%1)\n\t" \ + "ld $8, 40(%1)\n\t" \ + "ld $9, 48(%1)\n\t" \ + "ld $10, 56(%1)\n\t" \ + "ld $11, 64(%1)\n\t" \ + "ld $25, 0(%1)\n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "daddu $29, $29, 24\n\t" \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) (long)_res; \ + } while (0) + +#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ + arg6,arg7,arg8,arg9,arg10, \ + arg11,arg12) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long long _argvec[13]; \ + volatile unsigned long long _res; \ + _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ + _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ + _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ + _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ + _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \ + _argvec[5] = MIPS64_LONG2REG_CAST(arg5); \ + _argvec[6] = MIPS64_LONG2REG_CAST(arg6); \ + _argvec[7] = MIPS64_LONG2REG_CAST(arg7); \ + _argvec[8] = MIPS64_LONG2REG_CAST(arg8); \ + _argvec[9] = MIPS64_LONG2REG_CAST(arg9); \ + _argvec[10] = MIPS64_LONG2REG_CAST(arg10); \ + _argvec[11] = MIPS64_LONG2REG_CAST(arg11); \ + _argvec[12] = MIPS64_LONG2REG_CAST(arg12); \ + __asm__ volatile( \ + "dsubu $29, $29, 32\n\t" \ + "ld $4, 72(%1)\n\t" \ + "sd $4, 0($29)\n\t" \ + "ld $4, 80(%1)\n\t" \ + "sd $4, 8($29)\n\t" \ + "ld $4, 88(%1)\n\t" \ + "sd $4, 16($29)\n\t" \ + "ld $4, 96(%1)\n\t" \ + "sd $4, 24($29)\n\t" \ + "ld $4, 8(%1)\n\t" \ + "ld $5, 16(%1)\n\t" \ + "ld $6, 24(%1)\n\t" \ + "ld $7, 32(%1)\n\t" \ + "ld $8, 40(%1)\n\t" \ + "ld $9, 48(%1)\n\t" \ + "ld $10, 56(%1)\n\t" \ + "ld $11, 64(%1)\n\t" \ + "ld $25, 0(%1)\n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "daddu $29, $29, 32\n\t" \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) (long)_res; \ + } while (0) + +#endif /* PLAT_mips64_linux */ + +/* ------------------------------------------------------------------ */ +/* ARCHITECTURE INDEPENDENT MACROS for CLIENT REQUESTS. */ +/* */ +/* ------------------------------------------------------------------ */ + +/* Some request codes. There are many more of these, but most are not + exposed to end-user view. These are the public ones, all of the + form 0x1000 + small_number. + + Core ones are in the range 0x00000000--0x0000ffff. The non-public + ones start at 0x2000. +*/ + +/* These macros are used by tools -- they must be public, but don't + embed them into other programs. */ +#define VG_USERREQ_TOOL_BASE(a,b) \ + ((unsigned int)(((a)&0xff) << 24 | ((b)&0xff) << 16)) +#define VG_IS_TOOL_USERREQ(a, b, v) \ + (VG_USERREQ_TOOL_BASE(a,b) == ((v) & 0xffff0000)) + +/* !! ABIWARNING !! ABIWARNING !! ABIWARNING !! ABIWARNING !! + This enum comprises an ABI exported by Valgrind to programs + which use client requests. DO NOT CHANGE THE NUMERIC VALUES OF THESE + ENTRIES, NOR DELETE ANY -- add new ones at the end of the most + relevant group. */ +typedef + enum { VG_USERREQ__RUNNING_ON_VALGRIND = 0x1001, + VG_USERREQ__DISCARD_TRANSLATIONS = 0x1002, + + /* These allow any function to be called from the simulated + CPU but run on the real CPU. Nb: the first arg passed to + the function is always the ThreadId of the running + thread! So CLIENT_CALL0 actually requires a 1 arg + function, etc. */ + VG_USERREQ__CLIENT_CALL0 = 0x1101, + VG_USERREQ__CLIENT_CALL1 = 0x1102, + VG_USERREQ__CLIENT_CALL2 = 0x1103, + VG_USERREQ__CLIENT_CALL3 = 0x1104, + + /* Can be useful in regression testing suites -- eg. can + send Valgrind's output to /dev/null and still count + errors. */ + VG_USERREQ__COUNT_ERRORS = 0x1201, + + /* Allows the client program and/or gdbserver to execute a monitor + command. */ + VG_USERREQ__GDB_MONITOR_COMMAND = 0x1202, + + /* Allows the client program to change a dynamic command line + option. */ + VG_USERREQ__CLO_CHANGE = 0x1203, + + /* These are useful and can be interpreted by any tool that + tracks malloc() et al, by using vg_replace_malloc.c. */ + VG_USERREQ__MALLOCLIKE_BLOCK = 0x1301, + VG_USERREQ__RESIZEINPLACE_BLOCK = 0x130b, + VG_USERREQ__FREELIKE_BLOCK = 0x1302, + /* Memory pool support. */ + VG_USERREQ__CREATE_MEMPOOL = 0x1303, + VG_USERREQ__DESTROY_MEMPOOL = 0x1304, + VG_USERREQ__MEMPOOL_ALLOC = 0x1305, + VG_USERREQ__MEMPOOL_FREE = 0x1306, + VG_USERREQ__MEMPOOL_TRIM = 0x1307, + VG_USERREQ__MOVE_MEMPOOL = 0x1308, + VG_USERREQ__MEMPOOL_CHANGE = 0x1309, + VG_USERREQ__MEMPOOL_EXISTS = 0x130a, + + /* Allow printfs to valgrind log. */ + /* The first two pass the va_list argument by value, which + assumes it is the same size as or smaller than a UWord, + which generally isn't the case. Hence are deprecated. + The second two pass the vargs by reference and so are + immune to this problem. */ + /* both :: char* fmt, va_list vargs (DEPRECATED) */ + VG_USERREQ__PRINTF = 0x1401, + VG_USERREQ__PRINTF_BACKTRACE = 0x1402, + /* both :: char* fmt, va_list* vargs */ + VG_USERREQ__PRINTF_VALIST_BY_REF = 0x1403, + VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF = 0x1404, + + /* Stack support. */ + VG_USERREQ__STACK_REGISTER = 0x1501, + VG_USERREQ__STACK_DEREGISTER = 0x1502, + VG_USERREQ__STACK_CHANGE = 0x1503, + + /* Wine support */ + VG_USERREQ__LOAD_PDB_DEBUGINFO = 0x1601, + + /* Querying of debug info. */ + VG_USERREQ__MAP_IP_TO_SRCLOC = 0x1701, + + /* Disable/enable error reporting level. Takes a single + Word arg which is the delta to this thread's error + disablement indicator. Hence 1 disables or further + disables errors, and -1 moves back towards enablement. + Other values are not allowed. */ + VG_USERREQ__CHANGE_ERR_DISABLEMENT = 0x1801, + + /* Some requests used for Valgrind internal, such as + self-test or self-hosting. */ + /* Initialise IR injection */ + VG_USERREQ__VEX_INIT_FOR_IRI = 0x1901, + /* Used by Inner Valgrind to inform Outer Valgrind where to + find the list of inner guest threads */ + VG_USERREQ__INNER_THREADS = 0x1902 + } Vg_ClientRequest; + +#if !defined(__GNUC__) +# define __extension__ /* */ +#endif + + +/* Returns the number of Valgrinds this code is running under. That + is, 0 if running natively, 1 if running under Valgrind, 2 if + running under Valgrind which is running under another Valgrind, + etc. */ +#define RUNNING_ON_VALGRIND \ + (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* if not */, \ + VG_USERREQ__RUNNING_ON_VALGRIND, \ + 0, 0, 0, 0, 0) \ + + +/* Discard translation of code in the range [_qzz_addr .. _qzz_addr + + _qzz_len - 1]. Useful if you are debugging a JITter or some such, + since it provides a way to make sure valgrind will retranslate the + invalidated area. Returns no value. */ +#define VALGRIND_DISCARD_TRANSLATIONS(_qzz_addr,_qzz_len) \ + VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DISCARD_TRANSLATIONS, \ + _qzz_addr, _qzz_len, 0, 0, 0) + +#define VALGRIND_INNER_THREADS(_qzz_addr) \ + VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__INNER_THREADS, \ + _qzz_addr, 0, 0, 0, 0) + + +/* These requests are for getting Valgrind itself to print something. + Possibly with a backtrace. This is a really ugly hack. The return value + is the number of characters printed, excluding the "**<pid>** " part at the + start and the backtrace (if present). */ + +#if defined(__GNUC__) || defined(__INTEL_COMPILER) && !defined(_MSC_VER) +/* Modern GCC will optimize the static routine out if unused, + and unused attribute will shut down warnings about it. */ +static int VALGRIND_PRINTF(const char *format, ...) + __attribute__((format(__printf__, 1, 2), __unused__)); +#endif +static int +#if defined(_MSC_VER) +__inline +#endif +VALGRIND_PRINTF(const char *format, ...) +{ +#if defined(NVALGRIND) + (void)format; + return 0; +#else /* NVALGRIND */ +#if defined(_MSC_VER) || defined(__MINGW64__) + uintptr_t _qzz_res; +#else + unsigned long _qzz_res; +#endif + va_list vargs; + va_start(vargs, format); +#if defined(_MSC_VER) || defined(__MINGW64__) + _qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0, + VG_USERREQ__PRINTF_VALIST_BY_REF, + (uintptr_t)format, + (uintptr_t)&vargs, + 0, 0, 0); +#else + _qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0, + VG_USERREQ__PRINTF_VALIST_BY_REF, + (unsigned long)format, + (unsigned long)&vargs, + 0, 0, 0); +#endif + va_end(vargs); + return (int)_qzz_res; +#endif /* NVALGRIND */ +} + +#if defined(__GNUC__) || defined(__INTEL_COMPILER) && !defined(_MSC_VER) +static int VALGRIND_PRINTF_BACKTRACE(const char *format, ...) + __attribute__((format(__printf__, 1, 2), __unused__)); +#endif +static int +#if defined(_MSC_VER) +__inline +#endif +VALGRIND_PRINTF_BACKTRACE(const char *format, ...) +{ +#if defined(NVALGRIND) + (void)format; + return 0; +#else /* NVALGRIND */ +#if defined(_MSC_VER) || defined(__MINGW64__) + uintptr_t _qzz_res; +#else + unsigned long _qzz_res; +#endif + va_list vargs; + va_start(vargs, format); +#if defined(_MSC_VER) || defined(__MINGW64__) + _qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0, + VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF, + (uintptr_t)format, + (uintptr_t)&vargs, + 0, 0, 0); +#else + _qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0, + VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF, + (unsigned long)format, + (unsigned long)&vargs, + 0, 0, 0); +#endif + va_end(vargs); + return (int)_qzz_res; +#endif /* NVALGRIND */ +} + + +/* These requests allow control to move from the simulated CPU to the + real CPU, calling an arbitrary function. + + Note that the current ThreadId is inserted as the first argument. + So this call: + + VALGRIND_NON_SIMD_CALL2(f, arg1, arg2) + + requires f to have this signature: + + Word f(Word tid, Word arg1, Word arg2) + + where "Word" is a word-sized type. + + Note that these client requests are not entirely reliable. For example, + if you call a function with them that subsequently calls printf(), + there's a high chance Valgrind will crash. Generally, your prospects of + these working are made higher if the called function does not refer to + any global variables, and does not refer to any libc or other functions + (printf et al). Any kind of entanglement with libc or dynamic linking is + likely to have a bad outcome, for tricky reasons which we've grappled + with a lot in the past. +*/ +#define VALGRIND_NON_SIMD_CALL0(_qyy_fn) \ + VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ + VG_USERREQ__CLIENT_CALL0, \ + _qyy_fn, \ + 0, 0, 0, 0) + +#define VALGRIND_NON_SIMD_CALL1(_qyy_fn, _qyy_arg1) \ + VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ + VG_USERREQ__CLIENT_CALL1, \ + _qyy_fn, \ + _qyy_arg1, 0, 0, 0) + +#define VALGRIND_NON_SIMD_CALL2(_qyy_fn, _qyy_arg1, _qyy_arg2) \ + VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ + VG_USERREQ__CLIENT_CALL2, \ + _qyy_fn, \ + _qyy_arg1, _qyy_arg2, 0, 0) + +#define VALGRIND_NON_SIMD_CALL3(_qyy_fn, _qyy_arg1, _qyy_arg2, _qyy_arg3) \ + VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ + VG_USERREQ__CLIENT_CALL3, \ + _qyy_fn, \ + _qyy_arg1, _qyy_arg2, \ + _qyy_arg3, 0) + + +/* Counts the number of errors that have been recorded by a tool. Nb: + the tool must record the errors with VG_(maybe_record_error)() or + VG_(unique_error)() for them to be counted. */ +#define VALGRIND_COUNT_ERRORS \ + (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR( \ + 0 /* default return */, \ + VG_USERREQ__COUNT_ERRORS, \ + 0, 0, 0, 0, 0) + +/* Several Valgrind tools (Memcheck, Massif, Helgrind, DRD) rely on knowing + when heap blocks are allocated in order to give accurate results. This + happens automatically for the standard allocator functions such as + malloc(), calloc(), realloc(), memalign(), new, new[], free(), delete, + delete[], etc. + + But if your program uses a custom allocator, this doesn't automatically + happen, and Valgrind will not do as well. For example, if you allocate + superblocks with mmap() and then allocates chunks of the superblocks, all + Valgrind's observations will be at the mmap() level and it won't know that + the chunks should be considered separate entities. In Memcheck's case, + that means you probably won't get heap block overrun detection (because + there won't be redzones marked as unaddressable) and you definitely won't + get any leak detection. + + The following client requests allow a custom allocator to be annotated so + that it can be handled accurately by Valgrind. + + VALGRIND_MALLOCLIKE_BLOCK marks a region of memory as having been allocated + by a malloc()-like function. For Memcheck (an illustrative case), this + does two things: + + - It records that the block has been allocated. This means any addresses + within the block mentioned in error messages will be + identified as belonging to the block. It also means that if the block + isn't freed it will be detected by the leak checker. + + - It marks the block as being addressable and undefined (if 'is_zeroed' is + not set), or addressable and defined (if 'is_zeroed' is set). This + controls how accesses to the block by the program are handled. + + 'addr' is the start of the usable block (ie. after any + redzone), 'sizeB' is its size. 'rzB' is the redzone size if the allocator + can apply redzones -- these are blocks of padding at the start and end of + each block. Adding redzones is recommended as it makes it much more likely + Valgrind will spot block overruns. `is_zeroed' indicates if the memory is + zeroed (or filled with another predictable value), as is the case for + calloc(). + + VALGRIND_MALLOCLIKE_BLOCK should be put immediately after the point where a + heap block -- that will be used by the client program -- is allocated. + It's best to put it at the outermost level of the allocator if possible; + for example, if you have a function my_alloc() which calls + internal_alloc(), and the client request is put inside internal_alloc(), + stack traces relating to the heap block will contain entries for both + my_alloc() and internal_alloc(), which is probably not what you want. + + For Memcheck users: if you use VALGRIND_MALLOCLIKE_BLOCK to carve out + custom blocks from within a heap block, B, that has been allocated with + malloc/calloc/new/etc, then block B will be *ignored* during leak-checking + -- the custom blocks will take precedence. + + VALGRIND_FREELIKE_BLOCK is the partner to VALGRIND_MALLOCLIKE_BLOCK. For + Memcheck, it does two things: + + - It records that the block has been deallocated. This assumes that the + block was annotated as having been allocated via + VALGRIND_MALLOCLIKE_BLOCK. Otherwise, an error will be issued. + + - It marks the block as being unaddressable. + + VALGRIND_FREELIKE_BLOCK should be put immediately after the point where a + heap block is deallocated. + + VALGRIND_RESIZEINPLACE_BLOCK informs a tool about reallocation. For + Memcheck, it does four things: + + - It records that the size of a block has been changed. This assumes that + the block was annotated as having been allocated via + VALGRIND_MALLOCLIKE_BLOCK. Otherwise, an error will be issued. + + - If the block shrunk, it marks the freed memory as being unaddressable. + + - If the block grew, it marks the new area as undefined and defines a red + zone past the end of the new block. + + - The V-bits of the overlap between the old and the new block are preserved. + + VALGRIND_RESIZEINPLACE_BLOCK should be put after allocation of the new block + and before deallocation of the old block. + + In many cases, these three client requests will not be enough to get your + allocator working well with Memcheck. More specifically, if your allocator + writes to freed blocks in any way then a VALGRIND_MAKE_MEM_UNDEFINED call + will be necessary to mark the memory as addressable just before the zeroing + occurs, otherwise you'll get a lot of invalid write errors. For example, + you'll need to do this if your allocator recycles freed blocks, but it + zeroes them before handing them back out (via VALGRIND_MALLOCLIKE_BLOCK). + Alternatively, if your allocator reuses freed blocks for allocator-internal + data structures, VALGRIND_MAKE_MEM_UNDEFINED calls will also be necessary. + + Really, what's happening is a blurring of the lines between the client + program and the allocator... after VALGRIND_FREELIKE_BLOCK is called, the + memory should be considered unaddressable to the client program, but the + allocator knows more than the rest of the client program and so may be able + to safely access it. Extra client requests are necessary for Valgrind to + understand the distinction between the allocator and the rest of the + program. + + Ignored if addr == 0. +*/ +#define VALGRIND_MALLOCLIKE_BLOCK(addr, sizeB, rzB, is_zeroed) \ + VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MALLOCLIKE_BLOCK, \ + addr, sizeB, rzB, is_zeroed, 0) + +/* See the comment for VALGRIND_MALLOCLIKE_BLOCK for details. + Ignored if addr == 0. +*/ +#define VALGRIND_RESIZEINPLACE_BLOCK(addr, oldSizeB, newSizeB, rzB) \ + VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__RESIZEINPLACE_BLOCK, \ + addr, oldSizeB, newSizeB, rzB, 0) + +/* See the comment for VALGRIND_MALLOCLIKE_BLOCK for details. + Ignored if addr == 0. +*/ +#define VALGRIND_FREELIKE_BLOCK(addr, rzB) \ + VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__FREELIKE_BLOCK, \ + addr, rzB, 0, 0, 0) + +/* Create a memory pool. */ +#define VALGRIND_CREATE_MEMPOOL(pool, rzB, is_zeroed) \ + VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__CREATE_MEMPOOL, \ + pool, rzB, is_zeroed, 0, 0) + +/* Create a memory pool with some flags specifying extended behaviour. + When flags is zero, the behaviour is identical to VALGRIND_CREATE_MEMPOOL. + + The flag VALGRIND_MEMPOOL_METAPOOL specifies that the pieces of memory + associated with the pool using VALGRIND_MEMPOOL_ALLOC will be used + by the application as superblocks to dole out MALLOC_LIKE blocks using + VALGRIND_MALLOCLIKE_BLOCK. In other words, a meta pool is a "2 levels" + pool : first level is the blocks described by VALGRIND_MEMPOOL_ALLOC. + The second level blocks are described using VALGRIND_MALLOCLIKE_BLOCK. + Note that the association between the pool and the second level blocks + is implicit : second level blocks will be located inside first level + blocks. It is necessary to use the VALGRIND_MEMPOOL_METAPOOL flag + for such 2 levels pools, as otherwise valgrind will detect overlapping + memory blocks, and will abort execution (e.g. during leak search). + + Such a meta pool can also be marked as an 'auto free' pool using the flag + VALGRIND_MEMPOOL_AUTO_FREE, which must be OR-ed together with the + VALGRIND_MEMPOOL_METAPOOL. For an 'auto free' pool, VALGRIND_MEMPOOL_FREE + will automatically free the second level blocks that are contained + inside the first level block freed with VALGRIND_MEMPOOL_FREE. + In other words, calling VALGRIND_MEMPOOL_FREE will cause implicit calls + to VALGRIND_FREELIKE_BLOCK for all the second level blocks included + in the first level block. + Note: it is an error to use the VALGRIND_MEMPOOL_AUTO_FREE flag + without the VALGRIND_MEMPOOL_METAPOOL flag. +*/ +#define VALGRIND_MEMPOOL_AUTO_FREE 1 +#define VALGRIND_MEMPOOL_METAPOOL 2 +#define VALGRIND_CREATE_MEMPOOL_EXT(pool, rzB, is_zeroed, flags) \ + VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__CREATE_MEMPOOL, \ + pool, rzB, is_zeroed, flags, 0) + +/* Destroy a memory pool. */ +#define VALGRIND_DESTROY_MEMPOOL(pool) \ + VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DESTROY_MEMPOOL, \ + pool, 0, 0, 0, 0) + +/* Associate a piece of memory with a memory pool. */ +#define VALGRIND_MEMPOOL_ALLOC(pool, addr, size) \ + VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MEMPOOL_ALLOC, \ + pool, addr, size, 0, 0) + +/* Disassociate a piece of memory from a memory pool. */ +#define VALGRIND_MEMPOOL_FREE(pool, addr) \ + VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MEMPOOL_FREE, \ + pool, addr, 0, 0, 0) + +/* Disassociate any pieces outside a particular range. */ +#define VALGRIND_MEMPOOL_TRIM(pool, addr, size) \ + VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MEMPOOL_TRIM, \ + pool, addr, size, 0, 0) + +/* Resize and/or move a piece associated with a memory pool. */ +#define VALGRIND_MOVE_MEMPOOL(poolA, poolB) \ + VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MOVE_MEMPOOL, \ + poolA, poolB, 0, 0, 0) + +/* Resize and/or move a piece associated with a memory pool. */ +#define VALGRIND_MEMPOOL_CHANGE(pool, addrA, addrB, size) \ + VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MEMPOOL_CHANGE, \ + pool, addrA, addrB, size, 0) + +/* Return 1 if a mempool exists, else 0. */ +#define VALGRIND_MEMPOOL_EXISTS(pool) \ + (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ + VG_USERREQ__MEMPOOL_EXISTS, \ + pool, 0, 0, 0, 0) + +/* Mark a piece of memory as being a stack. Returns a stack id. + start is the lowest addressable stack byte, end is the highest + addressable stack byte. */ +#define VALGRIND_STACK_REGISTER(start, end) \ + (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ + VG_USERREQ__STACK_REGISTER, \ + start, end, 0, 0, 0) + +/* Unmark the piece of memory associated with a stack id as being a + stack. */ +#define VALGRIND_STACK_DEREGISTER(id) \ + VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__STACK_DEREGISTER, \ + id, 0, 0, 0, 0) + +/* Change the start and end address of the stack id. + start is the new lowest addressable stack byte, end is the new highest + addressable stack byte. */ +#define VALGRIND_STACK_CHANGE(id, start, end) \ + VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__STACK_CHANGE, \ + id, start, end, 0, 0) + +/* Load PDB debug info for Wine PE image_map. */ +#define VALGRIND_LOAD_PDB_DEBUGINFO(fd, ptr, total_size, delta) \ + VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__LOAD_PDB_DEBUGINFO, \ + fd, ptr, total_size, delta, 0) + +/* Map a code address to a source file name and line number. buf64 + must point to a 64-byte buffer in the caller's address space. The + result will be dumped in there and is guaranteed to be zero + terminated. If no info is found, the first byte is set to zero. */ +#define VALGRIND_MAP_IP_TO_SRCLOC(addr, buf64) \ + (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ + VG_USERREQ__MAP_IP_TO_SRCLOC, \ + addr, buf64, 0, 0, 0) + +/* Disable error reporting for this thread. Behaves in a stack like + way, so you can safely call this multiple times provided that + VALGRIND_ENABLE_ERROR_REPORTING is called the same number of times + to re-enable reporting. The first call of this macro disables + reporting. Subsequent calls have no effect except to increase the + number of VALGRIND_ENABLE_ERROR_REPORTING calls needed to re-enable + reporting. Child threads do not inherit this setting from their + parents -- they are always created with reporting enabled. */ +#define VALGRIND_DISABLE_ERROR_REPORTING \ + VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__CHANGE_ERR_DISABLEMENT, \ + 1, 0, 0, 0, 0) + +/* Re-enable error reporting, as per comments on + VALGRIND_DISABLE_ERROR_REPORTING. */ +#define VALGRIND_ENABLE_ERROR_REPORTING \ + VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__CHANGE_ERR_DISABLEMENT, \ + -1, 0, 0, 0, 0) + +/* Execute a monitor command from the client program. + If a connection is opened with GDB, the output will be sent + according to the output mode set for vgdb. + If no connection is opened, output will go to the log output. + Returns 1 if command not recognised, 0 otherwise. */ +#define VALGRIND_MONITOR_COMMAND(command) \ + VALGRIND_DO_CLIENT_REQUEST_EXPR(0, VG_USERREQ__GDB_MONITOR_COMMAND, \ + command, 0, 0, 0, 0) + + +/* Change the value of a dynamic command line option. + Note that unknown or not dynamically changeable options + will cause a warning message to be output. */ +#define VALGRIND_CLO_CHANGE(option) \ + VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__CLO_CHANGE, \ + option, 0, 0, 0, 0) + + +#undef PLAT_x86_darwin +#undef PLAT_amd64_darwin +#undef PLAT_x86_win32 +#undef PLAT_amd64_win64 +#undef PLAT_x86_linux +#undef PLAT_amd64_linux +#undef PLAT_ppc32_linux +#undef PLAT_ppc64be_linux +#undef PLAT_ppc64le_linux +#undef PLAT_arm_linux +#undef PLAT_s390x_linux +#undef PLAT_mips32_linux +#undef PLAT_mips64_linux +#undef PLAT_nanomips_linux +#undef PLAT_x86_solaris +#undef PLAT_amd64_solaris + +#endif /* __VALGRIND_H */ |