diff options
Diffstat (limited to 'src/benchmark')
-rw-r--r-- | src/benchmark/.gitignore | 3 | ||||
-rw-r--r-- | src/benchmark/Makefile.am | 48 | ||||
-rw-r--r-- | src/benchmark/bank-benchmark-cs.conf | 5 | ||||
-rw-r--r-- | src/benchmark/bank-benchmark-rsa.conf | 5 | ||||
-rw-r--r-- | src/benchmark/benchmark-common.conf | 106 | ||||
-rw-r--r-- | src/benchmark/benchmark-cs.conf | 16 | ||||
-rw-r--r-- | src/benchmark/benchmark-rsa.conf | 16 | ||||
-rw-r--r-- | src/benchmark/benchmark.conf | 151 | ||||
-rw-r--r-- | src/benchmark/coins-cs.conf | 58 | ||||
-rw-r--r-- | src/benchmark/coins-rsa.conf | 63 | ||||
-rw-r--r-- | src/benchmark/exchange_benchmark_home/.local/share/taler/exchange/offline-keys/master.priv | 1 | ||||
-rw-r--r-- | src/benchmark/taler-aggregator-benchmark.c | 658 | ||||
-rw-r--r-- | src/benchmark/taler-bank-benchmark.c | 576 | ||||
-rw-r--r-- | src/benchmark/taler-exchange-benchmark.c | 984 |
14 files changed, 1771 insertions, 919 deletions
diff --git a/src/benchmark/.gitignore b/src/benchmark/.gitignore new file mode 100644 index 000000000..a1b4711e7 --- /dev/null +++ b/src/benchmark/.gitignore @@ -0,0 +1,3 @@ +taler-bank-benchmark +taler-aggregator-benchmark +*.edited diff --git a/src/benchmark/Makefile.am b/src/benchmark/Makefile.am index af1f5b94c..c82584626 100644 --- a/src/benchmark/Makefile.am +++ b/src/benchmark/Makefile.am @@ -11,18 +11,53 @@ if USE_COVERAGE endif bin_PROGRAMS = \ + taler-aggregator-benchmark \ + taler-bank-benchmark \ taler-exchange-benchmark + +taler_aggregator_benchmark_SOURCES = \ + taler-aggregator-benchmark.c +taler_aggregator_benchmark_LDADD = \ + $(LIBGCRYPT_LIBS) \ + $(top_builddir)/src/exchangedb/libtalerexchangedb.la \ + $(top_builddir)/src/json/libtalerjson.la \ + $(top_builddir)/src/util/libtalerutil.la \ + -lgnunetjson \ + -ljansson \ + -lgnunetutil \ + $(XLIB) + +taler_bank_benchmark_SOURCES = \ + taler-bank-benchmark.c +taler_bank_benchmark_LDADD = \ + $(LIBGCRYPT_LIBS) \ + $(top_builddir)/src/testing/libtalertesting.la \ + $(top_builddir)/src/lib/libtalerexchange.la \ + $(top_builddir)/src/bank-lib/libtalerfakebank.la \ + $(top_builddir)/src/bank-lib/libtalerbank.la \ + $(top_builddir)/src/exchangedb/libtalerexchangedb.la \ + $(top_builddir)/src/json/libtalerjson.la \ + $(top_builddir)/src/util/libtalerutil.la \ + $(top_builddir)/src/extensions/libtalerextensions.la \ + -lgnunetjson \ + -lgnunetcurl \ + -lgnunetutil \ + -ljansson \ + $(XLIB) + taler_exchange_benchmark_SOURCES = \ taler-exchange-benchmark.c taler_exchange_benchmark_LDADD = \ $(LIBGCRYPT_LIBS) \ - $(top_builddir)/src/json/libtalerjson.la \ - $(top_builddir)/src/util/libtalerutil.la \ $(top_builddir)/src/lib/libtalerexchange.la \ + $(top_builddir)/src/exchangedb/libtalerexchangedb.la \ $(top_builddir)/src/testing/libtalertesting.la \ $(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 \ -lgnunetjson \ -lgnunetcurl \ -lgnunetutil \ @@ -30,5 +65,10 @@ taler_exchange_benchmark_LDADD = \ $(XLIB) EXTRA_DIST = \ - benchmark.conf \ - exchange_benchmark_home/.local/share/taler/exchange/offline-keys/master.priv + benchmark-common.conf \ + benchmark-cs.conf \ + benchmark-rsa.conf \ + bank-benchmark-cs.conf \ + bank-benchmark-rsa.conf \ + coins-cs.conf \ + coins-rsa.conf diff --git a/src/benchmark/bank-benchmark-cs.conf b/src/benchmark/bank-benchmark-cs.conf new file mode 100644 index 000000000..39c82a3fe --- /dev/null +++ b/src/benchmark/bank-benchmark-cs.conf @@ -0,0 +1,5 @@ +# This file is in the public domain. +@INLINE@ benchmark-common.conf +@INLINE@ coins-cs.conf + + diff --git a/src/benchmark/bank-benchmark-rsa.conf b/src/benchmark/bank-benchmark-rsa.conf new file mode 100644 index 000000000..ca5d6b0da --- /dev/null +++ b/src/benchmark/bank-benchmark-rsa.conf @@ -0,0 +1,5 @@ +# This file is in the public domain. +@INLINE@ benchmark-common.conf +@INLINE@ coins-rsa.conf + + diff --git a/src/benchmark/benchmark-common.conf b/src/benchmark/benchmark-common.conf new file mode 100644 index 000000000..e47115a2b --- /dev/null +++ b/src/benchmark/benchmark-common.conf @@ -0,0 +1,106 @@ +# This file is in the public domain. +[paths] +TALER_TEST_HOME=exchange_benchmark_home/ + +[taler] +CURRENCY=EUR +CURRENCY_ROUND_UNIT=EUR:0.01 + +[exchange] +AML_THRESHOLD=EUR:99999999 +SIGNKEY_LEGAL_DURATION=2 years +PORT=8081 +MASTER_PUBLIC_KEY=98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG +DB=postgres +BASE_URL="http://localhost:8081/" +# Only set this option if you are actually running +# multiple aggregators! +# AGGREGATOR_SHARD_SIZE=67108864 +WIREWATCH_IDLE_SLEEP_INTERVAL=5 ms + +[exchangedb-postgres] +CONFIG="postgres:///talercheck" + +[exchange-offline] +MASTER_PRIV_FILE=${TALER_TEST_HOME}/.local/share/taler/exchange/offline-keys/master.priv + +[taler-exchange-secmod-rsa] +LOOKAHEAD_SIGN="1 d" + +[taler-exchange-secmod-cs] +LOOKAHEAD_SIGN="1 d" + +[taler-exchange-secmod-eddsa] +DURATION="2 d" +LOOKAHEAD_SIGN="1 d" + +# account-2 is suitable for fakebank +[exchange-account-1] +PAYTO_URI = "payto://x-taler-bank/localhost/exchange?receiver-name=exchange" +ENABLE_DEBIT = YES +ENABLE_CREDIT = YES + +[exchange-accountcredentials-1] +WIRE_GATEWAY_AUTH_METHOD = none +WIRE_GATEWAY_URL = "http://localhost:8080/accounts/exchange/taler-wire-gateway/" + +[admin-accountcredentials-1] +WIRE_GATEWAY_AUTH_METHOD = none +WIRE_GATEWAY_URL = "http://localhost:8080/accounts/exchange/taler-wire-gateway/" + +# account-2 is suitable for libeufin +[exchange-account-2] +ENABLE_DEBIT = YES +ENABLE_CREDIT = YES +PAYTO_URI = payto://iban/SANDBOXX/DE033310?receiver-name=Exchange+Company + +[exchange-accountcredentials-2] +WIRE_GATEWAY_AUTH_METHOD = basic +USERNAME = exchange +PASSWORD = x +WIRE_GATEWAY_URL = "http://localhost:8080/accounts/exchange/taler-wire-gateway/" + +[admin-accountcredentials-2] +WIRE_GATEWAY_AUTH_METHOD = basic +USERNAME = admin +PASSWORD = secret +WIRE_GATEWAY_URL = "http://localhost:8080/accounts/exchange/taler-wire-gateway/" + + +# Trust local exchange for "EUR" currency +[merchant-exchange-benchmark] +EXCHANGE_BASE_URL = http://localhost:8081/ +MASTER_KEY=98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG +# If currency does not match [TALER] section, the exchange +# will be ignored! +CURRENCY = EUR + + +[merchantdb-postgres] +CONFIG="postgres:///talercheck" + +[auditordb-postgres] +CONFIG="postgres:///talercheck" + +[syncdb-postgres] +CONFIG="postgres:///talercheck" + +[exchange] +WIREWATCH_IDLE_SLEEP_INTERVAL = 5000 ms + +[bank] +HTTP_PORT=8080 +SERVE=http +RAM_LIMIT=10000000 + +[libeufin-bank] +CURRENCY = EUR + +[libeufin-nexus] +DB_CONNECTION="postgresql:///talercheck" + +[libeufin-sandbox] +DB_CONNECTION="postgresql:///talercheck" + +[auditor] +BASE_URL="http://localhost:8083/" diff --git a/src/benchmark/benchmark-cs.conf b/src/benchmark/benchmark-cs.conf new file mode 100644 index 000000000..7f660ad31 --- /dev/null +++ b/src/benchmark/benchmark-cs.conf @@ -0,0 +1,16 @@ +# This file is in the public domain. +@INLINE@ benchmark-common.conf +@INLINE@ coins-cs.conf + +[exchange-account-test] +# What is the bank account (with the "Taler Bank" demo system)? Must end with "/". +PAYTO_URI = "payto://x-taler-bank/localhost/Exchange" +# Authentication information for basic authentication +ENABLE_DEBIT = YES +ENABLE_CREDIT = YES + +[exchange-accountcredentials-test] +WIRE_GATEWAY_URL = http://localhost:8082/accounts/Exchange/taler-wire-gateway/ +WIRE_GATEWAY_AUTH_METHOD = "basic" +USERNAME = Exchange +PASSWORD = x diff --git a/src/benchmark/benchmark-rsa.conf b/src/benchmark/benchmark-rsa.conf new file mode 100644 index 000000000..a6c1512ee --- /dev/null +++ b/src/benchmark/benchmark-rsa.conf @@ -0,0 +1,16 @@ +# This file is in the public domain. +@INLINE@ benchmark-common.conf +@INLINE@ coins-rsa.conf + +[exchange-account-test] +# What is the bank account (with the "Taler Bank" demo system)? Must end with "/". +PAYTO_URI = "payto://x-taler-bank/localhost/Exchange" +# Authentication information for basic authentication +ENABLE_DEBIT = YES +ENABLE_CREDIT = YES + +[exchange-accountcredentials-test] +WIRE_GATEWAY_URL = http://localhost:8082/accounts/Exchange/taler-wire-gateway/ +WIRE_GATEWAY_AUTH_METHOD = "basic" +USERNAME = Exchange +PASSWORD = x diff --git a/src/benchmark/benchmark.conf b/src/benchmark/benchmark.conf deleted file mode 100644 index b9d1d141d..000000000 --- a/src/benchmark/benchmark.conf +++ /dev/null @@ -1,151 +0,0 @@ -# This file is in the public domain. -# -[paths] -# Persistent data storage for the testcase -# This value is a default for `taler_config_home' -taler_test_home = exchange_benchmark_home/ - -[taler] -# Currency supported by the exchange (can only be one) -currency = EUR -CURRENCY_ROUND_UNIT = EUR:0.01 - -[exchange] -# how long is one signkey valid? -signkey_duration = 4 weeks -# how long are the signatures with the signkey valid? -legal_duration = 2 years -# how long do we provide to clients denomination and signing keys -# ahead of time? -lookahead_provide = 4 weeks 1 day -# 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/" -# Keep it short so the test runs fast. -lookahead_sign = 12 h - -[auditor] -BASE_URL = "http://localhost:8083/" - -[exchangedb-postgres] -config = "postgres:///talercheck" - -[benchmark-remote-exchange] -host = localhost -# Adjust $HOME to match remote target! -dir = $HOME/repos/taler/exchange/src/benchmark - -[bank] -HTTP_PORT = 8082 -SERVE = http -MAX_DEBT = EUR:100000000000.0 -MAX_DEBT_BANK = EUR:1000000000000000.0 - -[benchmark] -USER_PAYTO_URI = payto://x-taler-bank/localhost:8082/42 - -[exchange-account-2] -# What is the payto://-URL of the exchange (to generate wire response) -PAYTO_URI = "payto://x-taler-bank/localhost:8082/Exchange" -# What is the bank account (with the "Taler Bank" demo system)? Must end with "/". -WIRE_GATEWAY_URL = http://localhost:8082/taler-wire-gateway/Exchange/ -# This is the response we give out for the /wire request. It provides -# wallets with the bank information for transfers to the exchange. -WIRE_RESPONSE = ${TALER_CONFIG_HOME}/account-exchange.json -# Authentication information for basic authentication -WIRE_GATEWAY_AUTH_METHOD = "basic" -username = Exchange -password = x - -enable_debit = YES -enable_credit = YES - - - -[fees-x-taler-bank] -# Fees for the foreseeable future... -# If you see this after 2017, update to match the next 10 years... -wire-fee-2018 = EUR:0.01 -wire-fee-2019 = EUR:0.01 -wire-fee-2020 = EUR:0.01 -wire-fee-2021 = EUR:0.01 -wire-fee-2022 = EUR:0.01 -wire-fee-2023 = EUR:0.01 -wire-fee-2024 = EUR:0.01 -wire-fee-2025 = EUR:0.01 -wire-fee-2026 = EUR:0.01 -wire-fee-2027 = EUR:0.01 - -closing-fee-2018 = EUR:0.01 -closing-fee-2019 = EUR:0.01 -closing-fee-2020 = EUR:0.01 -closing-fee-2021 = EUR:0.01 -closing-fee-2022 = EUR:0.01 -closing-fee-2023 = EUR:0.01 -closing-fee-2024 = EUR:0.01 -closing-fee-2025 = EUR:0.01 -closing-fee-2026 = EUR:0.01 -closing-fee-2027 = EUR:0.01 - -# 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 -rsa_keysize = 2048 - -[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 = 2048 - -[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 = 2048 - -[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 = 2048 - -[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 = 2048 diff --git a/src/benchmark/coins-cs.conf b/src/benchmark/coins-cs.conf new file mode 100644 index 000000000..c4b5a45c1 --- /dev/null +++ b/src/benchmark/coins-cs.conf @@ -0,0 +1,58 @@ +# 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 = 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/benchmark/coins-rsa.conf b/src/benchmark/coins-rsa.conf new file mode 100644 index 000000000..42eb8acfc --- /dev/null +++ b/src/benchmark/coins-rsa.conf @@ -0,0 +1,63 @@ +# 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 = 2048 + +[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 = 2048 + +[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 = 2048 + +[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 = 2048 + +[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 = 2048 diff --git a/src/benchmark/exchange_benchmark_home/.local/share/taler/exchange/offline-keys/master.priv b/src/benchmark/exchange_benchmark_home/.local/share/taler/exchange/offline-keys/master.priv deleted file mode 100644 index 394926938..000000000 --- a/src/benchmark/exchange_benchmark_home/.local/share/taler/exchange/offline-keys/master.priv +++ /dev/null @@ -1 +0,0 @@ -p^-33XX!\0qmU_
\ No newline at end of file diff --git a/src/benchmark/taler-aggregator-benchmark.c b/src/benchmark/taler-aggregator-benchmark.c new file mode 100644 index 000000000..228d050e4 --- /dev/null +++ b/src/benchmark/taler-aggregator-benchmark.c @@ -0,0 +1,658 @@ +/* + 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 Affero 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 benchmark/taler-aggregator-benchmark.c + * @brief Setup exchange database suitable for aggregator benchmarking + * @author Christian Grothoff + */ +#include "platform.h" +#include <jansson.h> +#include <gnunet/gnunet_util_lib.h> +#include <gnunet/gnunet_json_lib.h> +#include "taler_util.h" +#include "taler_signatures.h" +#include "taler_exchangedb_lib.h" +#include "taler_json_lib.h" +#include "taler_error_codes.h" + + +/** + * Exit code. + */ +static int global_ret; + +/** + * How many deposits we want to create per merchant. + */ +static unsigned int howmany_deposits = 1; + +/** + * How many merchants do we want to setup. + */ +static unsigned int howmany_merchants = 1; + +/** + * Probability of a refund, as in $NUMBER:100. + * Use 0 for no refunds. + */ +static unsigned int refund_rate = 0; + +/** + * Currency used. + */ +static char *currency; + +/** + * Configuration. + */ +static const struct GNUNET_CONFIGURATION_Handle *cfg; + +/** + * Database plugin. + */ +static struct TALER_EXCHANGEDB_Plugin *plugin; + +/** + * Main task doing the work(). + */ +static struct GNUNET_SCHEDULER_Task *task; + +/** + * Hash of the denomination. + */ +static struct TALER_DenominationHashP h_denom_pub; + +/** + * "signature" to use for the coin(s). + */ +static struct TALER_DenominationSignature denom_sig; + +/** + * Time range when deposits start. + */ +static struct GNUNET_TIME_Timestamp start; + +/** + * Time range when deposits end. + */ +static struct GNUNET_TIME_Timestamp end; + + +/** + * Throw a weighted coin with @a probability. + * + * @return #GNUNET_OK with @a probability, + * #GNUNET_NO with 1 - @a probability + */ +static unsigned int +eval_probability (float probability) +{ + uint64_t random; + float random_01; + + random = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, + UINT64_MAX); + random_01 = (double) random / (double) UINT64_MAX; + return (random_01 <= probability) ? GNUNET_OK : GNUNET_NO; +} + + +/** + * Randomize data at pointer @a x + * + * @param x pointer to data to randomize + */ +#define RANDOMIZE(x) \ + GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, x, sizeof (*x)) + + +/** + * Initialize @a out with an amount given by @a val and + * @a frac using the main "currency". + * + * @param val value to set + * @param frac fraction to set + * @param[out] out where to write the amount + */ +static void +make_amount (unsigned int val, + unsigned int frac, + struct TALER_Amount *out) +{ + GNUNET_assert (GNUNET_OK == + TALER_amount_set_zero (currency, + out)); + out->value = val; + out->fraction = frac; +} + + +/** + * Create random-ish timestamp. + * + * @return time stamp between start and end + */ +static struct GNUNET_TIME_Timestamp +random_time (void) +{ + uint64_t delta; + struct GNUNET_TIME_Absolute ret; + + delta = end.abs_time.abs_value_us - start.abs_time.abs_value_us; + delta = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_NONCE, + delta); + ret.abs_value_us = start.abs_time.abs_value_us + delta; + return GNUNET_TIME_absolute_to_timestamp (ret); +} + + +/** + * Function run on shutdown. + * + * @param cls unused + */ +static void +do_shutdown (void *cls) +{ + (void) cls; + if (NULL != plugin) + { + TALER_EXCHANGEDB_plugin_unload (plugin); + plugin = NULL; + } + if (NULL != task) + { + GNUNET_SCHEDULER_cancel (task); + task = NULL; + } + TALER_denom_sig_free (&denom_sig); +} + + +struct Merchant +{ + + /** + * Public key of the merchant. Enables later identification + * of the merchant in case of a need to rollback transactions. + */ + struct TALER_MerchantPublicKeyP merchant_pub; + + /** + * Hash of the (canonical) representation of @e wire, used + * to check the signature on the request. Generated by + * the exchange from the detailed wire data provided by the + * merchant. + */ + struct TALER_MerchantWireHashP h_wire; + + /** + * Salt used when computing @e h_wire. + */ + struct TALER_WireSaltP wire_salt; + + /** + * Account information for the merchant. + */ + char *payto_uri; + +}; + +struct Deposit +{ + + /** + * Information about the coin that is being deposited. + */ + struct TALER_CoinPublicInfo coin; + + /** + * Hash over the proposal data between merchant and customer + * (remains unknown to the Exchange). + */ + struct TALER_PrivateContractHashP h_contract_terms; + +}; + + +/** + * Add a refund from @a m for @a d. + * + * @param m merchant granting the refund + * @param d deposit being refunded + * @return true on success + */ +static bool +add_refund (const struct Merchant *m, + const struct Deposit *d) +{ + struct TALER_EXCHANGEDB_Refund r; + + r.coin = d->coin; + r.details.merchant_pub = m->merchant_pub; + RANDOMIZE (&r.details.merchant_sig); + r.details.h_contract_terms = d->h_contract_terms; + r.details.rtransaction_id = 42; + make_amount (0, 5000000, &r.details.refund_amount); + make_amount (0, 5, &r.details.refund_fee); + if (0 >= + plugin->insert_refund (plugin->cls, + &r)) + { + GNUNET_break (0); + global_ret = EXIT_FAILURE; + GNUNET_SCHEDULER_shutdown (); + return false; + } + return true; +} + + +/** + * Add a (random-ish) deposit for merchant @a m. + * + * @param m merchant to receive the deposit + * @return true on success + */ +static bool +add_deposit (const struct Merchant *m) +{ + struct Deposit d; + struct TALER_EXCHANGEDB_CoinDepositInformation deposit; + struct TALER_EXCHANGEDB_BatchDeposit bd = { + .cdis = &deposit, + .num_cdis = 1 + }; + uint64_t known_coin_id; + struct TALER_DenominationHashP dph; + struct TALER_AgeCommitmentHash agh; + + RANDOMIZE (&d.coin.coin_pub); + d.coin.denom_pub_hash = h_denom_pub; + d.coin.denom_sig = denom_sig; + RANDOMIZE (&d.h_contract_terms); + d.coin.no_age_commitment = true; + memset (&d.coin.h_age_commitment, + 0, + sizeof (d.coin.h_age_commitment)); + + if (0 >= + plugin->ensure_coin_known (plugin->cls, + &d.coin, + &known_coin_id, + &dph, + &agh)) + { + GNUNET_break (0); + global_ret = EXIT_FAILURE; + GNUNET_SCHEDULER_shutdown (); + return false; + } + deposit.coin = d.coin; + RANDOMIZE (&deposit.csig); + bd.merchant_pub = m->merchant_pub; + bd.h_contract_terms = d.h_contract_terms; + bd.wire_salt = m->wire_salt; + bd.receiver_wire_account = m->payto_uri; + bd.wallet_timestamp = random_time (); + do { + bd.refund_deadline = random_time (); + bd.wire_deadline = random_time (); + } while (GNUNET_TIME_timestamp_cmp (bd.wire_deadline, + <, + bd.refund_deadline)); + + make_amount (1, 0, &deposit.amount_with_fee); + + { + struct GNUNET_TIME_Timestamp now; + bool balance_ok; + uint32_t bad_idx; + bool conflict; + + now = random_time (); + if (0 >= + plugin->do_deposit (plugin->cls, + &bd, + &now, + &balance_ok, + &bad_idx, + &conflict)) + { + GNUNET_break (0); + global_ret = EXIT_FAILURE; + GNUNET_SCHEDULER_shutdown (); + return false; + } + } + if (GNUNET_YES == + eval_probability (((float) refund_rate) / 100.0)) + return add_refund (m, + &d); + return true; +} + + +/** + * Function to do the work. + * + * @param cls unused + */ +static void +work (void *cls) +{ + struct Merchant m; + uint64_t rnd1; + uint64_t rnd2; + + (void) cls; + task = NULL; + rnd1 = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_NONCE, + UINT64_MAX); + rnd2 = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_NONCE, + UINT64_MAX); + GNUNET_asprintf (&m.payto_uri, + "payto://x-taler-bank/localhost:8082/account-%llX-%llX", + (unsigned long long) rnd1, + (unsigned long long) rnd2); + RANDOMIZE (&m.merchant_pub); + RANDOMIZE (&m.wire_salt); + TALER_merchant_wire_signature_hash (m.payto_uri, + &m.wire_salt, + &m.h_wire); + if (GNUNET_OK != + plugin->start (plugin->cls, + "aggregator-benchmark-fill")) + { + GNUNET_break (0); + global_ret = EXIT_FAILURE; + GNUNET_free (m.payto_uri); + GNUNET_SCHEDULER_shutdown (); + return; + } + for (unsigned int i = 0; i<howmany_deposits; i++) + { + if (! add_deposit (&m)) + { + global_ret = EXIT_FAILURE; + GNUNET_SCHEDULER_shutdown (); + GNUNET_free (m.payto_uri); + return; + } + } + if (0 <= + plugin->commit (plugin->cls)) + { + if (0 == --howmany_merchants) + { + GNUNET_SCHEDULER_shutdown (); + GNUNET_free (m.payto_uri); + return; + } + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to commit, will try again\n"); + } + GNUNET_free (m.payto_uri); + task = GNUNET_SCHEDULER_add_now (&work, + NULL); +} + + +/** + * Actual execution. + * + * @param cls unused + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param c configuration + */ +static void +run (void *cls, + char *const *args, + const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + struct TALER_EXCHANGEDB_DenominationKeyInformation issue; + + (void) cls; + (void) args; + (void) cfgfile; + /* make sure everything 'ends' before the current time, + so that the aggregator will process everything without + need for time-travel */ + end = GNUNET_TIME_timestamp_get (); + start = GNUNET_TIME_absolute_to_timestamp ( + GNUNET_TIME_absolute_subtract (end.abs_time, + GNUNET_TIME_UNIT_MONTHS)); + cfg = c; + if (GNUNET_OK != + TALER_config_get_currency (cfg, + ¤cy)) + { + global_ret = EXIT_NOTCONFIGURED; + return; + } + plugin = TALER_EXCHANGEDB_plugin_load (cfg); + if (NULL == plugin) + { + global_ret = EXIT_NOTCONFIGURED; + return; + } + if (GNUNET_SYSERR == + plugin->preflight (plugin->cls)) + { + global_ret = EXIT_FAILURE; + TALER_EXCHANGEDB_plugin_unload (plugin); + return; + } + GNUNET_SCHEDULER_add_shutdown (&do_shutdown, + NULL); + memset (&issue, + 0, + sizeof (issue)); + RANDOMIZE (&issue.signature); + issue.start + = start; + issue.expire_withdraw + = GNUNET_TIME_absolute_to_timestamp ( + GNUNET_TIME_absolute_add (start.abs_time, + GNUNET_TIME_UNIT_DAYS)); + issue.expire_deposit + = end; + issue.expire_legal + = GNUNET_TIME_absolute_to_timestamp ( + GNUNET_TIME_absolute_add (end.abs_time, + GNUNET_TIME_UNIT_YEARS)); + { + struct TALER_DenominationPrivateKey pk; + struct TALER_DenominationPublicKey denom_pub; + struct TALER_CoinPubHashP c_hash; + struct TALER_PlanchetDetail pd; + struct TALER_BlindedDenominationSignature bds; + struct TALER_PlanchetMasterSecretP ps; + struct TALER_CoinSpendPublicKeyP coin_pub; + struct TALER_AgeCommitmentHash hac; + union GNUNET_CRYPTO_BlindingSecretP bks; + const struct TALER_ExchangeWithdrawValues *alg_values; + + RANDOMIZE (&coin_pub); + GNUNET_assert (GNUNET_OK == + TALER_denom_priv_create (&pk, + &denom_pub, + GNUNET_CRYPTO_BSA_RSA, + 1024)); + alg_values = TALER_denom_ewv_rsa_singleton (); + denom_pub.age_mask = issue.age_mask; + TALER_denom_pub_hash (&denom_pub, + &h_denom_pub); + make_amount (2, 0, &issue.value); + make_amount (0, 5, &issue.fees.withdraw); + make_amount (0, 5, &issue.fees.deposit); + make_amount (0, 5, &issue.fees.refresh); + make_amount (0, 5, &issue.fees.refund); + issue.denom_hash = h_denom_pub; + if (0 >= + plugin->insert_denomination_info (plugin->cls, + &denom_pub, + &issue)) + { + GNUNET_break (0); + GNUNET_SCHEDULER_shutdown (); + global_ret = EXIT_FAILURE; + return; + } + + TALER_planchet_blinding_secret_create (&ps, + TALER_denom_ewv_rsa_singleton (), + &bks); + + { + struct GNUNET_HashCode seed; + struct TALER_AgeMask mask = { + .bits = 1 | (1 << 8) | (1 << 12) | (1 << 16) | (1 << 18) + }; + struct TALER_AgeCommitmentProof acp = {0}; + + GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, + &seed, + sizeof(seed)); + TALER_age_restriction_commit (&mask, + 13, + &seed, + &acp); + TALER_age_commitment_hash (&acp.commitment, + &hac); + } + + GNUNET_assert (GNUNET_OK == + TALER_denom_blind (&denom_pub, + &bks, + NULL, + &hac, + &coin_pub, + alg_values, + &c_hash, + &pd.blinded_planchet)); + GNUNET_assert (GNUNET_OK == + TALER_denom_sign_blinded (&bds, + &pk, + false, + &pd.blinded_planchet)); + TALER_blinded_planchet_free (&pd.blinded_planchet); + GNUNET_assert (GNUNET_OK == + TALER_denom_sig_unblind (&denom_sig, + &bds, + &bks, + &c_hash, + alg_values, + &denom_pub)); + TALER_blinded_denom_sig_free (&bds); + TALER_denom_pub_free (&denom_pub); + TALER_denom_priv_free (&pk); + } + + { + struct TALER_WireFeeSet fees; + struct TALER_MasterSignatureP master_sig; + unsigned int year; + struct GNUNET_TIME_Timestamp ws; + struct GNUNET_TIME_Timestamp we; + + year = GNUNET_TIME_get_current_year (); + for (unsigned int y = year - 1; y<year + 2; y++) + { + ws = GNUNET_TIME_absolute_to_timestamp (GNUNET_TIME_year_to_time (y - 1)); + we = GNUNET_TIME_absolute_to_timestamp (GNUNET_TIME_year_to_time (y)); + make_amount (0, 5, &fees.wire); + make_amount (0, 5, &fees.closing); + memset (&master_sig, + 0, + sizeof (master_sig)); + if (0 > + plugin->insert_wire_fee (plugin->cls, + "x-taler-bank", + ws, + we, + &fees, + &master_sig)) + { + GNUNET_break (0); + GNUNET_SCHEDULER_shutdown (); + global_ret = EXIT_FAILURE; + return; + } + } + } + + task = GNUNET_SCHEDULER_add_now (&work, + NULL); +} + + +/** + * The main function of the taler-aggregator-benchmark tool. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, non-zero on failure + */ +int +main (int argc, + char *const *argv) +{ + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_option_uint ('d', + "deposits", + "DN", + "How many deposits we should instantiate per merchant", + &howmany_deposits), + GNUNET_GETOPT_option_uint ('m', + "merchants", + "DM", + "How many merchants should we create", + &howmany_merchants), + GNUNET_GETOPT_option_uint ('r', + "refunds", + "RATE", + "Probability of refund per deposit (0-100)", + &refund_rate), + GNUNET_GETOPT_OPTION_END + }; + enum GNUNET_GenericReturnValue result; + + unsetenv ("XDG_DATA_HOME"); + unsetenv ("XDG_CONFIG_HOME"); + if (0 >= + (result = GNUNET_PROGRAM_run (argc, + argv, + "taler-aggregator-benchmark", + "generate database to benchmark the aggregator", + options, + &run, + NULL))) + { + if (GNUNET_NO == result) + return EXIT_SUCCESS; + return EXIT_INVALIDARGUMENT; + } + return global_ret; +} diff --git a/src/benchmark/taler-bank-benchmark.c b/src/benchmark/taler-bank-benchmark.c new file mode 100644 index 000000000..528798424 --- /dev/null +++ b/src/benchmark/taler-bank-benchmark.c @@ -0,0 +1,576 @@ +/* + This file is part of TALER + (C) 2014-2023 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it + under the terms of the GNU Affero 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 benchmark/taler-bank-benchmark.c + * @brief code to benchmark only the 'bank' and the 'taler-exchange-wirewatch' tool + * @author Marcello Stanisci + * @author Christian Grothoff + */ +// TODO: +// - use more than one 'client' bank account +// - also add taler-exchange-transfer to simulate outgoing payments +#include "platform.h" +#include <gnunet/gnunet_util_lib.h> +#include <microhttpd.h> +#include <sys/resource.h> +#include "taler_util.h" +#include "taler_signatures.h" +#include "taler_json_lib.h" +#include "taler_bank_service.h" +#include "taler_exchangedb_lib.h" +#include "taler_fakebank_lib.h" +#include "taler_testing_lib.h" +#include "taler_error_codes.h" + +#define SHARD_SIZE "1024" + +/** + * Credentials to use for the benchmark. + */ +static struct TALER_TESTING_Credentials cred; + +/** + * Array of all the commands the benchmark is running. + */ +static struct TALER_TESTING_Command *all_commands; + +/** + * Name of our configuration file. + */ +static char *cfg_filename; + +/** + * Use the fakebank instead of LibEuFin. + */ +static int use_fakebank; + +/** + * Verbosity level. + */ +static unsigned int verbose; + +/** + * How many reserves we want to create per client. + */ +static unsigned int howmany_reserves = 1; + +/** + * How many clients we want to create. + */ +static unsigned int howmany_clients = 1; + +/** + * How many wirewatch processes do we want to create. + */ +static unsigned int start_wirewatch; + +/** + * Log level used during the run. + */ +static char *loglev; + +/** + * Log file. + */ +static char *logfile; + +/** + * Configuration. + */ +static struct GNUNET_CONFIGURATION_Handle *cfg; + +/** + * Section with the configuration data for the exchange + * bank account. + */ +static char *exchange_bank_section; + +/** + * Currency used. + */ +static char *currency; + +/** + * Array of command labels. + */ +static char **labels; + +/** + * Length of #labels. + */ +static unsigned int label_len; + +/** + * Offset in #labels. + */ +static unsigned int label_off; + +/** + * Performance counters. + */ +static struct TALER_TESTING_Timer timings[] = { + { .prefix = "createreserve" }, + { .prefix = NULL } +}; + + +/** + * Add label to the #labels table and return it. + * + * @param label string to add to the table + * @return same string, now stored in the table + */ +const char * +add_label (char *label) +{ + if (label_off == label_len) + GNUNET_array_grow (labels, + label_len, + label_len * 2 + 4); + labels[label_off++] = label; + return label; +} + + +/** + * Print performance statistics for this process. + */ +static void +print_stats (void) +{ + for (unsigned int i = 0; NULL != timings[i].prefix; i++) + { + char *total; + char *latency; + + total = GNUNET_strdup ( + GNUNET_STRINGS_relative_time_to_string (timings[i].total_duration, + true)); + latency = GNUNET_strdup ( + GNUNET_STRINGS_relative_time_to_string (timings[i].success_latency, + true)); + fprintf (stderr, + "%s-%d took %s in total with %s for latency for %u executions (%u repeats)\n", + timings[i].prefix, + (int) getpid (), + total, + latency, + timings[i].num_commands, + timings[i].num_retries); + GNUNET_free (total); + GNUNET_free (latency); + } +} + + +/** + * Actual commands construction and execution. + * + * @param cls unused + * @param is interpreter to run commands with + */ +static void +run (void *cls, + struct TALER_TESTING_Interpreter *is) +{ + char *total_reserve_amount; + size_t len; + + (void) cls; + len = howmany_reserves + 2; + all_commands = GNUNET_malloc_large ((1 + len) + * sizeof (struct TALER_TESTING_Command)); + GNUNET_assert (NULL != all_commands); + all_commands[0] + = TALER_TESTING_cmd_get_exchange ("get-exchange", + cred.cfg, + NULL, + true, + true); + + GNUNET_asprintf (&total_reserve_amount, + "%s:5", + currency); + for (unsigned int j = 0; j < howmany_reserves; j++) + { + char *create_reserve_label; + + GNUNET_asprintf (&create_reserve_label, + "createreserve-%u", + j); + // TODO: vary user accounts more... + all_commands[1 + j] + = TALER_TESTING_cmd_admin_add_incoming_retry ( + TALER_TESTING_cmd_admin_add_incoming (add_label ( + create_reserve_label), + total_reserve_amount, + &cred.ba_admin, + cred.user42_payto)); + } + GNUNET_free (total_reserve_amount); + all_commands[1 + howmany_reserves] + = TALER_TESTING_cmd_stat (timings); + all_commands[1 + howmany_reserves + 1] + = TALER_TESTING_cmd_end (); + TALER_TESTING_run2 (is, + all_commands, + GNUNET_TIME_UNIT_FOREVER_REL); /* no timeout */ +} + + +/** + * Starts #howmany_clients workers to run the client logic from #run(). + */ +static enum GNUNET_GenericReturnValue +launch_clients (void) +{ + enum GNUNET_GenericReturnValue result = GNUNET_OK; + pid_t cpids[howmany_clients]; + + if (1 == howmany_clients) + { + /* do everything in this process */ + result = TALER_TESTING_loop (&run, + NULL); + if (verbose) + print_stats (); + return result; + } + /* start work processes */ + for (unsigned int i = 0; i<howmany_clients; i++) + { + if (0 == (cpids[i] = fork ())) + { + /* I am the child, do the work! */ + GNUNET_log_setup ("benchmark-worker", + NULL == loglev ? "INFO" : loglev, + logfile); + result = TALER_TESTING_loop (&run, + NULL); + if (verbose) + print_stats (); + if (GNUNET_OK != result) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failure in child process test suite!\n"); + if (GNUNET_OK == result) + exit (0); + else + exit (1); + } + if (-1 == cpids[i]) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, + "fork"); + howmany_clients = i; + result = GNUNET_SYSERR; + break; + } + /* fork() success, continue starting more processes! */ + } + /* collect all children */ + for (unsigned int i = 0; i<howmany_clients; i++) + { + int wstatus; + +again: + if (cpids[i] != + waitpid (cpids[i], + &wstatus, + 0)) + { + if (EINTR == errno) + goto again; + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, + "waitpid"); + return GNUNET_SYSERR; + } + if ( (! WIFEXITED (wstatus)) || + (0 != WEXITSTATUS (wstatus)) ) + { + GNUNET_break (0); + result = GNUNET_SYSERR; + } + } + return result; +} + + +/** + * Run the benchmark in parallel in many (client) processes + * and summarize result. + * + * @return #GNUNET_OK on success + */ +static enum GNUNET_GenericReturnValue +parallel_benchmark (void) +{ + enum GNUNET_GenericReturnValue result = GNUNET_OK; + struct GNUNET_OS_Process *wirewatch[GNUNET_NZL (start_wirewatch)]; + + memset (wirewatch, + 0, + sizeof (wirewatch)); + /* start exchange wirewatch */ + for (unsigned int w = 0; w<start_wirewatch; w++) + { + wirewatch[w] = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL, + NULL, NULL, NULL, + "taler-exchange-wirewatch", + "taler-exchange-wirewatch", + "-c", cfg_filename, + "-a", exchange_bank_section, + "-S", SHARD_SIZE, + (NULL != loglev) ? "-L" : NULL, + loglev, + NULL); + if (NULL == wirewatch[w]) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to launch wirewatch, aborting benchmark\n"); + for (unsigned int x = 0; x<w; x++) + { + GNUNET_break (0 == + GNUNET_OS_process_kill (wirewatch[x], + SIGTERM)); + GNUNET_break (GNUNET_OK == + GNUNET_OS_process_wait (wirewatch[x])); + GNUNET_OS_process_destroy (wirewatch[x]); + wirewatch[x] = NULL; + } + return GNUNET_SYSERR; + } + } + result = launch_clients (); + /* Ensure wirewatch runs to completion! */ + if (0 != start_wirewatch) + { + /* replace ONE of the wirewatchers with one that is in test-mode */ + GNUNET_break (0 == + GNUNET_OS_process_kill (wirewatch[0], + SIGTERM)); + GNUNET_break (GNUNET_OK == + GNUNET_OS_process_wait (wirewatch[0])); + GNUNET_OS_process_destroy (wirewatch[0]); + wirewatch[0] = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL, + NULL, NULL, NULL, + "taler-exchange-wirewatch", + "taler-exchange-wirewatch", + "-c", cfg_filename, + "-a", exchange_bank_section, + "-S", SHARD_SIZE, + "-t", + (NULL != loglev) ? "-L" : NULL, + loglev, + NULL); + /* wait for it to finish! */ + GNUNET_break (GNUNET_OK == + GNUNET_OS_process_wait (wirewatch[0])); + GNUNET_OS_process_destroy (wirewatch[0]); + wirewatch[0] = NULL; + /* Then stop the rest, which should basically also be finished */ + for (unsigned int w = 1; w<start_wirewatch; w++) + { + GNUNET_break (0 == + GNUNET_OS_process_kill (wirewatch[w], + SIGTERM)); + GNUNET_break (GNUNET_OK == + GNUNET_OS_process_wait (wirewatch[w])); + GNUNET_OS_process_destroy (wirewatch[w]); + } + + /* But be extra sure we did finish all shards by doing one more */ + GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, + "Shard check phase\n"); + wirewatch[0] = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL, + NULL, NULL, NULL, + "taler-exchange-wirewatch", + "taler-exchange-wirewatch", + "-c", cfg_filename, + "-a", exchange_bank_section, + "-S", SHARD_SIZE, + "-t", + (NULL != loglev) ? "-L" : NULL, + loglev, + NULL); + /* wait for it to finish! */ + GNUNET_break (GNUNET_OK == + GNUNET_OS_process_wait (wirewatch[0])); + GNUNET_OS_process_destroy (wirewatch[0]); + wirewatch[0] = NULL; + } + + return result; +} + + +/** + * The main function of the serve tool + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, or `enum PaymentGeneratorError` on error + */ +int +main (int argc, + char *const *argv) +{ + enum GNUNET_GenericReturnValue result; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_option_mandatory ( + GNUNET_GETOPT_option_cfgfile (&cfg_filename)), + GNUNET_GETOPT_option_flag ('f', + "fakebank", + "we are using fakebank", + &use_fakebank), + GNUNET_GETOPT_option_help ("taler-bank benchmark"), + GNUNET_GETOPT_option_string ('l', + "logfile", + "LF", + "will log to file LF", + &logfile), + GNUNET_GETOPT_option_loglevel (&loglev), + GNUNET_GETOPT_option_uint ('p', + "worker-parallelism", + "NPROCS", + "How many client processes we should run", + &howmany_clients), + GNUNET_GETOPT_option_uint ('r', + "reserves", + "NRESERVES", + "How many reserves per client we should create", + &howmany_reserves), + GNUNET_GETOPT_option_mandatory ( + GNUNET_GETOPT_option_string ( + 'u', + "exchange-account-section", + "SECTION", + "use exchange bank account configuration from the given SECTION", + &exchange_bank_section)), + GNUNET_GETOPT_option_version (PACKAGE_VERSION " " VCS_VERSION), + GNUNET_GETOPT_option_verbose (&verbose), + GNUNET_GETOPT_option_uint ('w', + "wirewatch", + "NPROC", + "run NPROC taler-exchange-wirewatch processes", + &start_wirewatch), + GNUNET_GETOPT_OPTION_END + }; + struct GNUNET_TIME_Relative duration; + + unsetenv ("XDG_DATA_HOME"); + unsetenv ("XDG_CONFIG_HOME"); + if (0 >= + (result = GNUNET_GETOPT_run ("taler-bank-benchmark", + options, + argc, + argv))) + { + GNUNET_free (cfg_filename); + if (GNUNET_NO == result) + return 0; + return EXIT_INVALIDARGUMENT; + } + if (NULL == exchange_bank_section) + exchange_bank_section = "exchange-account-1"; + if (NULL == loglev) + loglev = "INFO"; + GNUNET_log_setup ("taler-bank-benchmark", + loglev, + logfile); + cfg = GNUNET_CONFIGURATION_create (); + if (GNUNET_OK != + GNUNET_CONFIGURATION_load (cfg, + cfg_filename)) + { + TALER_LOG_ERROR ("Could not parse configuration\n"); + GNUNET_free (cfg_filename); + return EXIT_NOTCONFIGURED; + } + if (GNUNET_OK != + TALER_config_get_currency (cfg, + ¤cy)) + { + GNUNET_CONFIGURATION_destroy (cfg); + GNUNET_free (cfg_filename); + return EXIT_NOTCONFIGURED; + } + + if (GNUNET_OK != + TALER_TESTING_get_credentials ( + cfg_filename, + exchange_bank_section, + use_fakebank + ? TALER_TESTING_BS_FAKEBANK + : TALER_TESTING_BS_IBAN, + &cred)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Required bank credentials not given in configuration\n"); + GNUNET_free (cfg_filename); + return EXIT_NOTCONFIGURED; + } + + { + struct GNUNET_TIME_Absolute start_time; + + start_time = GNUNET_TIME_absolute_get (); + result = parallel_benchmark (); + duration = GNUNET_TIME_absolute_get_duration (start_time); + } + + if (GNUNET_OK == result) + { + struct rusage usage; + unsigned long long tps; + + GNUNET_assert (0 == getrusage (RUSAGE_CHILDREN, + &usage)); + fprintf (stdout, + "Executed Reserve=%u * Parallel=%u, operations in %s\n", + howmany_reserves, + howmany_clients, + GNUNET_STRINGS_relative_time_to_string (duration, + GNUNET_YES)); + if (! GNUNET_TIME_relative_is_zero (duration)) + { + tps = ((unsigned long long) howmany_reserves) * howmany_clients * 1000LLU + / (duration.rel_value_us / 1000LL); + fprintf (stdout, + "RAW: %04u %04u %16llu (%llu TPS)\n", + howmany_reserves, + howmany_clients, + (unsigned long long) duration.rel_value_us, + tps); + } + fprintf (stdout, + "CPU time: sys %llu user %llu\n", + (unsigned long long) (usage.ru_stime.tv_sec * 1000 * 1000 + + usage.ru_stime.tv_usec), + (unsigned long long) (usage.ru_utime.tv_sec * 1000 * 1000 + + usage.ru_utime.tv_usec)); + } + for (unsigned int i = 0; i<label_off; i++) + GNUNET_free (labels[i]); + GNUNET_array_grow (labels, + label_len, + 0); + GNUNET_CONFIGURATION_destroy (cfg); + GNUNET_free (cfg_filename); + return (GNUNET_OK == result) ? 0 : result; +} diff --git a/src/benchmark/taler-exchange-benchmark.c b/src/benchmark/taler-exchange-benchmark.c index 57fde4306..75424a358 100644 --- a/src/benchmark/taler-exchange-benchmark.c +++ b/src/benchmark/taler-exchange-benchmark.c @@ -1,6 +1,6 @@ /* This file is part of TALER - (C) 2014-2020 Taler Systems SA + (C) 2014-2023 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as @@ -28,24 +28,7 @@ #include <microhttpd.h> #include <sys/resource.h> #include "taler_util.h" -#include "taler_signatures.h" -#include "taler_exchange_service.h" -#include "taler_json_lib.h" -#include "taler_bank_service.h" -#include "taler_fakebank_lib.h" #include "taler_testing_lib.h" -#include "taler_error_codes.h" - -/* Error codes. */ -enum BenchmarkError -{ - MISSING_BANK_URL, - FAILED_TO_LAUNCH_BANK, - BAD_CLI_ARG, - BAD_CONFIG_FILE, - NO_CONFIG_FILE_GIVEN -}; - /** * The whole benchmark is a repetition of a "unit". Each @@ -54,56 +37,11 @@ enum BenchmarkError */ #define UNITY_SIZE 6 -#define FIRST_INSTRUCTION -1 - - -/** - * What mode should the benchmark run in? - */ -enum BenchmarkMode -{ - /** - * Run as client (with fakebank), also starts a remote exchange. - */ - MODE_CLIENT = 1, - - /** - * Run the the exchange. - */ - MODE_EXCHANGE = 2, - - /** - * Run both, for a local benchmark. - */ - MODE_BOTH = 3, -}; - /** - * Hold information regarding which bank has the exchange account. + * Credentials to use for the benchmark. */ -static struct TALER_BANK_AuthenticationData exchange_bank_account; - -/** - * Configuration of our exchange. - */ -static struct TALER_TESTING_ExchangeConfiguration ec; - -/** - * Hold information about a user at the bank. - */ -static char *user_payto_uri; - -/** - * Time snapshot taken right before executing the CMDs. - */ -static struct GNUNET_TIME_Absolute start_time; - -/** - * Benchmark duration time taken right after the CMD interpreter - * returns. - */ -static struct GNUNET_TIME_Relative duration; +static struct TALER_TESTING_Credentials cred; /** * Array of all the commands the benchmark is running. @@ -116,16 +54,6 @@ static struct TALER_TESTING_Command *all_commands; static char *cfg_filename; /** - * Exit code. - */ -static int result; - -/** - * Use the fakebank instead of the Python bank. - */ -static int use_fakebank; - -/** * How many coins we want to create per client and reserve. */ static unsigned int howmany_coins = 1; @@ -146,11 +74,6 @@ static unsigned int refresh_rate = 10; static unsigned int howmany_clients = 1; /** - * Bank configuration to use. - */ -static struct TALER_TESTING_BankConfiguration bc; - -/** * Log level used during the run. */ static char *loglev; @@ -161,16 +84,6 @@ static char *loglev; static char *logfile; /** - * Benchmarking mode (run as client, exchange, both) as string. - */ -static char *mode_str; - -/** - * Benchmarking mode (run as client, exchange, both). - */ -static enum BenchmarkMode mode; - -/** * Configuration. */ static struct GNUNET_CONFIGURATION_Handle *cfg; @@ -181,19 +94,20 @@ static struct GNUNET_CONFIGURATION_Handle *cfg; static int reserves_first; /** - * Currency used. + * Are we running against 'fakebank'? */ -static char *currency; +static int use_fakebank; /** - * Remote host that runs the exchange. + * Section with the configuration data for the exchange + * bank account. */ -static char *remote_host; +static char *exchange_bank_section; /** - * Remote benchmarking directory. + * Currency used. */ -static char *remote_dir; +static char *currency; /** * Array of command labels. @@ -211,12 +125,6 @@ static unsigned int label_len; static unsigned int label_off; /** - * Don't kill exchange/fakebank/wirewatch until - * requested by the user explicitly. - */ -static int linger; - -/** * Performance counters. */ static struct TALER_TESTING_Timer timings[] = { @@ -252,40 +160,18 @@ static struct TALER_TESTING_Command cmd_transfer_to_exchange (const char *label, const char *amount) { - return TALER_TESTING_cmd_admin_add_incoming_retry - (TALER_TESTING_cmd_admin_add_incoming (label, - amount, - &exchange_bank_account, - user_payto_uri)); -} - - -/** - * Decide which exchange account is going to be - * used to address a wire transfer to. Used at - * withdrawal time. - * - * @param cls closure - * @param section section name. - */ -static void -pick_exchange_account_cb (void *cls, - const char *section) -{ - if (0 == strncasecmp ("exchange-account-", - section, - strlen ("exchange-account-"))) - { - const char **s = cls; - - *s = section; - } + return TALER_TESTING_cmd_admin_add_incoming_retry ( + TALER_TESTING_cmd_admin_add_incoming (label, + amount, + &cred.ba_admin, + cred.user42_payto)); } /** * Throw a weighted coin with @a probability. * + * @param probability weight of the coin flip * @return #GNUNET_OK with @a probability, * #GNUNET_NO with 1 - @a probability */ @@ -297,7 +183,7 @@ eval_probability (float probability) random = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX); - random_01 = (double) random / UINT64_MAX; + random_01 = (double) random / (double) UINT64_MAX; return (random_01 <= probability) ? GNUNET_OK : GNUNET_NO; } @@ -320,16 +206,26 @@ run (void *cls, char *amount_1; (void) cls; - all_commands = GNUNET_new_array (howmany_reserves * (1 /* Withdraw block */ - + howmany_coins) /* All units */ - + 1 /* stat CMD */ - + 1 /* End CMD */, - struct TALER_TESTING_Command); + all_commands = GNUNET_malloc_large ( + (1 /* exchange CMD */ + + howmany_reserves + * (1 /* Withdraw block */ + + howmany_coins) /* All units */ + + 1 /* stat CMD */ + + 1 /* End CMD */) * sizeof (struct TALER_TESTING_Command)); + GNUNET_assert (NULL != all_commands); + all_commands[0] + = TALER_TESTING_cmd_get_exchange ("get-exchange", + cred.cfg, + NULL, + true, + true); GNUNET_asprintf (&amount_5, "%s:5", currency); GNUNET_asprintf (&amount_4, "%s:4", currency); GNUNET_asprintf (&amount_1, "%s:1", currency); - GNUNET_assert (GNUNET_OK == TALER_amount_get_zero (currency, - &total_reserve_amount)); + GNUNET_assert (GNUNET_OK == + TALER_amount_set_zero (currency, + &total_reserve_amount)); total_reserve_amount.value = 5 * howmany_coins; GNUNET_asprintf (&withdraw_fee_str, "%s:0.1", @@ -360,9 +256,9 @@ run (void *cls, GNUNET_asprintf (&batch_label, "batch-start-%u", j); - all_commands[reserves_first - ? j - : j * (howmany_coins + 1)] + all_commands[1 + (reserves_first + ? j + : j * (howmany_coins + 1))] = TALER_TESTING_cmd_batch (add_label (batch_label), make_reserve); } @@ -381,23 +277,25 @@ run (void *cls, wl = add_label (withdraw_label); GNUNET_asprintf (&order_enc, "{\"nonce\": %llu}", - i + (howmany_coins * j)); + ((unsigned long long) i) + + (howmany_coins * (unsigned long long) j)); unit[0] = - TALER_TESTING_cmd_withdraw_with_retry - (TALER_TESTING_cmd_withdraw_amount (wl, - create_reserve_label, - amount_5, - MHD_HTTP_OK)); + TALER_TESTING_cmd_withdraw_with_retry ( + TALER_TESTING_cmd_withdraw_amount (wl, + create_reserve_label, + amount_5, + 0, /* age restriction off */ + MHD_HTTP_OK)); unit[1] = - TALER_TESTING_cmd_deposit_with_retry - (TALER_TESTING_cmd_deposit ("deposit", - wl, - 0, /* Index of the one withdrawn coin in the traits. */ - user_payto_uri, - add_label (order_enc), - GNUNET_TIME_UNIT_ZERO, - amount_1, - MHD_HTTP_OK)); + TALER_TESTING_cmd_deposit_with_retry ( + TALER_TESTING_cmd_deposit ("deposit", + wl, + 0, /* Index of the one withdrawn coin in the traits. */ + cred.user43_payto, + add_label (order_enc), + GNUNET_TIME_UNIT_ZERO, + amount_1, + MHD_HTTP_OK)); if (eval_probability (refresh_rate / 100.0)) { char *melt_label; @@ -416,21 +314,21 @@ run (void *cls, j); rl = add_label (reveal_label); unit[2] = - TALER_TESTING_cmd_melt_with_retry - (TALER_TESTING_cmd_melt (ml, - wl, - MHD_HTTP_OK, - NULL)); + TALER_TESTING_cmd_melt_with_retry ( + TALER_TESTING_cmd_melt (ml, + wl, + MHD_HTTP_OK, + NULL)); unit[3] = - TALER_TESTING_cmd_refresh_reveal_with_retry - (TALER_TESTING_cmd_refresh_reveal (rl, - ml, - MHD_HTTP_OK)); + TALER_TESTING_cmd_refresh_reveal_with_retry ( + TALER_TESTING_cmd_refresh_reveal (rl, + ml, + MHD_HTTP_OK)); unit[4] = - TALER_TESTING_cmd_refresh_link_with_retry - (TALER_TESTING_cmd_refresh_link ("link", - rl, - MHD_HTTP_OK)); + TALER_TESTING_cmd_refresh_link_with_retry ( + TALER_TESTING_cmd_refresh_link ("link", + rl, + MHD_HTTP_OK)); unit[5] = TALER_TESTING_cmd_end (); } else @@ -440,16 +338,16 @@ run (void *cls, "unit-%u-%u", i, j); - all_commands[reserves_first - ? howmany_reserves + j * howmany_coins + i - : j * (howmany_coins + 1) + (1 + i)] + all_commands[1 + (reserves_first + ? howmany_reserves + j * howmany_coins + i + : j * (howmany_coins + 1) + (1 + i))] = TALER_TESTING_cmd_batch (add_label (unit_label), unit); } } - all_commands[howmany_reserves * (1 + howmany_coins)] + all_commands[1 + howmany_reserves * (1 + howmany_coins)] = TALER_TESTING_cmd_stat (timings); - all_commands[howmany_reserves * (1 + howmany_coins) + 1] + all_commands[1 + howmany_reserves * (1 + howmany_coins) + 1] = TALER_TESTING_cmd_end (); TALER_TESTING_run2 (is, all_commands, @@ -458,7 +356,6 @@ run (void *cls, GNUNET_free (amount_4); GNUNET_free (amount_5); GNUNET_free (withdraw_fee_str); - result = 1; } @@ -475,10 +372,10 @@ print_stats (void) total = GNUNET_strdup ( GNUNET_STRINGS_relative_time_to_string (timings[i].total_duration, - GNUNET_YES)); + true)); latency = GNUNET_strdup ( GNUNET_STRINGS_relative_time_to_string (timings[i].success_latency, - GNUNET_YES)); + true)); fprintf (stderr, "%s-%d took %s in total with %s for latency for %u executions (%u repeats)\n", timings[i].prefix, @@ -494,44 +391,6 @@ print_stats (void) /** - * Stop the fakebank. - * - * @param cls fakebank handle - */ -static void -stop_fakebank (void *cls) -{ - struct TALER_FAKEBANK_Handle *fakebank = cls; - - TALER_FAKEBANK_stop (fakebank); -} - - -/** - * Start the fakebank. - * - * @param cls NULL - */ -static void -launch_fakebank (void *cls) -{ - struct TALER_FAKEBANK_Handle *fakebank; - - (void) cls; - fakebank - = TALER_TESTING_run_fakebank (exchange_bank_account.wire_gateway_url, - currency); - if (NULL == fakebank) - { - GNUNET_break (0); - return; - } - GNUNET_SCHEDULER_add_shutdown (&stop_fakebank, - fakebank); -} - - -/** * Run the benchmark in parallel in many (client) processes * and summarize result. * @@ -540,369 +399,58 @@ launch_fakebank (void *cls) * @param config_file configuration file to use * @return #GNUNET_OK on success */ -static int +static enum GNUNET_GenericReturnValue parallel_benchmark (TALER_TESTING_Main main_cb, void *main_cb_cls, const char *config_file) { - int result = GNUNET_OK; + enum GNUNET_GenericReturnValue result = GNUNET_OK; pid_t cpids[howmany_clients]; - pid_t fakebank = -1; - int wstatus; - struct GNUNET_OS_Process *bankd = NULL; - struct GNUNET_OS_Process *auditord = NULL; - struct GNUNET_OS_Process *exchanged = NULL; - struct GNUNET_OS_Process *wirewatch = NULL; - struct GNUNET_OS_Process *exchange_slave = NULL; - struct GNUNET_DISK_PipeHandle *exchange_slave_pipe; - if ( (MODE_CLIENT == mode) || (MODE_BOTH == mode) ) + if (1 == howmany_clients) { - if (use_fakebank) + result = TALER_TESTING_loop (main_cb, + main_cb_cls); + print_stats (); + } + else + { + for (unsigned int i = 0; i<howmany_clients; i++) { - /* start fakebank */ - fakebank = fork (); - if (0 == fakebank) + if (0 == (cpids[i] = fork ())) { - GNUNET_log_setup ("benchmark-fakebank", - NULL == loglev ? "INFO" : loglev, + /* I am the child, do the work! */ + GNUNET_log_setup ("benchmark-worker", + loglev, logfile); - GNUNET_SCHEDULER_run (&launch_fakebank, - NULL); - exit (0); + result = TALER_TESTING_loop (main_cb, + main_cb_cls); + print_stats (); + if (GNUNET_OK != result) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failure in child process %u test suite!\n", + i); + if (GNUNET_OK == result) + exit (0); + else + exit (1); } - if (-1 == fakebank) + if (-1 == cpids[i]) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "fork"); - return GNUNET_SYSERR; - } - } - else - { - /* start bank */ - if (GNUNET_OK != - TALER_TESTING_prepare_bank (cfg_filename, - GNUNET_NO, - "exchange-account-2", - &bc)) - { - return 1; - } - bankd = TALER_TESTING_run_bank (cfg_filename, - "http://localhost:8082/"); - if (NULL == bankd) - return 77; - } - } - - if ( (MODE_EXCHANGE == mode) || (MODE_BOTH == mode) ) - { - /* start exchange */ - exchanged = GNUNET_OS_start_process (GNUNET_NO, - GNUNET_OS_INHERIT_STD_ALL, - NULL, NULL, NULL, - "taler-exchange-httpd", - "taler-exchange-httpd", - "-c", config_file, - "-C", - NULL); - if ( (NULL == exchanged) && (MODE_BOTH == mode) ) - { - if (-1 != fakebank) - { - kill (fakebank, - SIGTERM); - waitpid (fakebank, - &wstatus, - 0); - } - if (NULL != bankd) - { - GNUNET_OS_process_kill (bankd, - SIGTERM); - GNUNET_OS_process_destroy (bankd); - } - return 77; - } - /* start auditor */ - auditord = GNUNET_OS_start_process (GNUNET_NO, - GNUNET_OS_INHERIT_STD_ALL, - NULL, NULL, NULL, - "taler-auditor-httpd", - "taler-auditor-httpd", - "-c", config_file, - NULL); - if (NULL == auditord) - { - GNUNET_OS_process_kill (exchanged, - SIGTERM); - if (MODE_BOTH == mode) - { - if (-1 != fakebank) - { - kill (fakebank, - SIGTERM); - waitpid (fakebank, - &wstatus, - 0); - } - if (NULL != bankd) - { - GNUNET_OS_process_kill (bankd, - SIGTERM); - GNUNET_OS_process_destroy (bankd); - } - } - GNUNET_OS_process_destroy (exchanged); - return 77; - } - /* start exchange wirewatch */ - wirewatch = GNUNET_OS_start_process (GNUNET_NO, - GNUNET_OS_INHERIT_STD_ALL, - NULL, NULL, NULL, - "taler-exchange-wirewatch", - "taler-exchange-wirewatch", - "-c", config_file, - NULL); - if (NULL == wirewatch) - { - GNUNET_OS_process_kill (auditord, - SIGTERM); - GNUNET_OS_process_kill (exchanged, - SIGTERM); - if (MODE_BOTH == mode) - { - if (-1 != fakebank) - { - kill (fakebank, - SIGTERM); - waitpid (fakebank, - &wstatus, - 0); - } - if (NULL != bankd) - { - GNUNET_OS_process_kill (bankd, - SIGTERM); - GNUNET_OS_process_destroy (bankd); - } - } - GNUNET_OS_process_destroy (exchanged); - return 77; - } - } - - if (MODE_CLIENT == mode) - { - char *remote_cmd; - - GNUNET_asprintf (&remote_cmd, - ("cd '%s'; " - "taler-exchange-benchmark --mode=exchange -c '%s'"), - remote_dir, - config_file); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "remote command: %s\n", - remote_cmd); - - GNUNET_assert (NULL != (exchange_slave_pipe = - GNUNET_DISK_pipe (GNUNET_YES, - GNUNET_YES, - 0, 0))); - - exchange_slave = GNUNET_OS_start_process (GNUNET_NO, - GNUNET_OS_INHERIT_STD_OUT_AND_ERR, - exchange_slave_pipe, NULL, NULL, - "ssh", - "ssh", - /* Don't ask for pw/passphrase, rather fail */ - "-oBatchMode=yes", - remote_host, - remote_cmd, - NULL); - GNUNET_free (remote_cmd); - } - - /* We always wait for the exchange, no matter if it's running locally or - remotely */ - if (0 != TALER_TESTING_wait_exchange_ready (ec.exchange_url)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to detect running exchange at `%s'\n", - ec.exchange_url); - GNUNET_OS_process_kill (exchanged, - SIGTERM); - if ( (MODE_BOTH == mode) || (MODE_CLIENT == mode)) - { - if (-1 != fakebank) - { - kill (fakebank, - SIGTERM); - waitpid (fakebank, - &wstatus, - 0); - } - if (NULL != bankd) - { - GNUNET_OS_process_kill (bankd, - SIGTERM); - GNUNET_OS_process_destroy (bankd); + howmany_clients = i; + result = GNUNET_SYSERR; + break; } + /* fork() success, continue starting more processes! */ } - GNUNET_OS_process_wait (exchanged); - GNUNET_OS_process_destroy (exchanged); - if (NULL != wirewatch) - { - GNUNET_OS_process_kill (wirewatch, - SIGTERM); - GNUNET_OS_process_wait (wirewatch); - GNUNET_OS_process_destroy (wirewatch); - } - if (NULL != auditord) - { - GNUNET_OS_process_kill (auditord, - SIGTERM); - GNUNET_OS_process_wait (auditord); - GNUNET_OS_process_destroy (auditord); - } - return 77; - } - if ( (MODE_CLIENT == mode) || (MODE_BOTH == mode) ) - { - if (-1 != fakebank) - sleep (1); /* make sure fakebank process is ready before continuing */ - - start_time = GNUNET_TIME_absolute_get (); - result = GNUNET_OK; - - if (1 == howmany_clients) - { - result = TALER_TESTING_setup (main_cb, - main_cb_cls, - cfg, - exchanged, - GNUNET_YES); - print_stats (); - } - else + /* collect all children */ + for (unsigned int i = 0; i<howmany_clients; i++) { - for (unsigned int i = 0; i<howmany_clients; i++) - { - if (0 == (cpids[i] = fork ())) - { - /* I am the child, do the work! */ - GNUNET_log_setup ("benchmark-worker", - NULL == loglev ? "INFO" : loglev, - logfile); - - result = TALER_TESTING_setup (main_cb, - main_cb_cls, - cfg, - exchanged, - GNUNET_YES); - print_stats (); - if (GNUNET_OK != result) - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failure in child process test suite!\n"); - if (GNUNET_OK == result) - exit (0); - else - exit (1); - } - if (-1 == cpids[i]) - { - GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, - "fork"); - howmany_clients = i; - result = GNUNET_SYSERR; - break; - } - /* fork() success, continue starting more processes! */ - } - /* collect all children */ - for (unsigned int i = 0; i<howmany_clients; i++) - { - waitpid (cpids[i], - &wstatus, - 0); - if ( (! WIFEXITED (wstatus)) || - (0 != WEXITSTATUS (wstatus)) ) - { - GNUNET_break (0); - result = GNUNET_SYSERR; - } - } - } - } - - /* Wait for our master to die or to tell us to die */ - if (MODE_EXCHANGE == mode) - (void) getchar (); - - if ( (GNUNET_YES == linger) && - ( ((mode == MODE_BOTH) || - (mode == MODE_CLIENT) ) ) ) - { - printf ("press ENTER to stop\n"); - (void) getchar (); - } - - if (MODE_CLIENT == mode) - { - char c = 'q'; - - GNUNET_assert (NULL != exchange_slave); + int wstatus; - /* Write a character to the pipe to end the exchange slave. - * We can't send a signal here, as it would just kill SSH and - * not necessarily the process on the other machine. */ - GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle - (exchange_slave_pipe, GNUNET_DISK_PIPE_END_WRITE), - &c, sizeof (c)); - - GNUNET_break (GNUNET_OK == - GNUNET_OS_process_wait (exchange_slave)); - GNUNET_OS_process_destroy (exchange_slave); - } - - if ( (MODE_EXCHANGE == mode) || (MODE_BOTH == mode) ) - { - GNUNET_assert (NULL != wirewatch); - GNUNET_assert (NULL != exchanged); - GNUNET_assert (NULL != auditord); - /* stop wirewatch */ - GNUNET_break (0 == - GNUNET_OS_process_kill (wirewatch, - SIGTERM)); - GNUNET_break (GNUNET_OK == - GNUNET_OS_process_wait (wirewatch)); - GNUNET_OS_process_destroy (wirewatch); - /* stop auditor */ - GNUNET_break (0 == - GNUNET_OS_process_kill (auditord, - SIGTERM)); - GNUNET_break (GNUNET_OK == - GNUNET_OS_process_wait (auditord)); - GNUNET_OS_process_destroy (auditord); - /* stop exchange */ - GNUNET_break (0 == - GNUNET_OS_process_kill (exchanged, - SIGTERM)); - GNUNET_break (GNUNET_OK == - GNUNET_OS_process_wait (exchanged)); - GNUNET_OS_process_destroy (exchanged); - } - - if ( (MODE_CLIENT == mode) || (MODE_BOTH == mode) ) - { - /* stop fakebank */ - if (-1 != fakebank) - { - kill (fakebank, - SIGTERM); - waitpid (fakebank, + waitpid (cpids[i], &wstatus, 0); if ( (! WIFEXITED (wstatus)) || @@ -912,12 +460,6 @@ parallel_benchmark (TALER_TESTING_Main main_cb, result = GNUNET_SYSERR; } } - if (NULL != bankd) - { - GNUNET_OS_process_kill (bankd, - SIGTERM); - GNUNET_OS_process_destroy (bankd); - } } return result; } @@ -935,55 +477,65 @@ main (int argc, char *const *argv) { struct GNUNET_GETOPT_CommandLineOption options[] = { - GNUNET_GETOPT_option_mandatory - (GNUNET_GETOPT_option_cfgfile (&cfg_filename)), - GNUNET_GETOPT_option_version (PACKAGE_VERSION " " VCS_VERSION), - GNUNET_GETOPT_option_help ("Exchange benchmark"), - GNUNET_GETOPT_option_loglevel (&loglev), - GNUNET_GETOPT_option_uint ('n', - "coins-number", - "CN", - "How many coins we should instantiate per reserve", - &howmany_coins), - GNUNET_GETOPT_option_uint ('p', - "parallelism", - "NPROCS", - "How many client processes we should run", - &howmany_clients), - GNUNET_GETOPT_option_uint ('r', - "reserves", - "NRESERVES", - "How many reserves per client we should create", - &howmany_reserves), - GNUNET_GETOPT_option_uint ('R', - "refresh-rate", - "RATE", - "Probability of refresh per coin (0-100)", - &refresh_rate), - GNUNET_GETOPT_option_string ('m', - "mode", - "MODE", - "run as exchange, clients or both", - &mode_str), - GNUNET_GETOPT_option_string ('l', - "logfile", - "LF", - "will log to file LF", - &logfile), - GNUNET_GETOPT_option_flag ('f', - "fakebank", - "start a fakebank instead of the Python bank", - &use_fakebank), - GNUNET_GETOPT_option_flag ('F', - "reserves-first", - "should all reserves be created first, before starting normal operations", - &reserves_first), - GNUNET_GETOPT_option_flag ('K', - "linger", - "linger around until key press", - &linger), + GNUNET_GETOPT_option_mandatory ( + GNUNET_GETOPT_option_cfgfile ( + &cfg_filename)), + GNUNET_GETOPT_option_version ( + PACKAGE_VERSION " " VCS_VERSION), + GNUNET_GETOPT_option_flag ( + 'f', + "fakebank", + "use fakebank for the banking system", + &use_fakebank), + GNUNET_GETOPT_option_flag ( + 'F', + "reserves-first", + "should all reserves be created first, before starting normal operations", + &reserves_first), + GNUNET_GETOPT_option_help ( + "Exchange benchmark"), + GNUNET_GETOPT_option_string ( + 'l', + "logfile", + "LF", + "will log to file LF", + &logfile), + GNUNET_GETOPT_option_loglevel ( + &loglev), + GNUNET_GETOPT_option_uint ( + 'n', + "coins-number", + "CN", + "How many coins we should instantiate per reserve", + &howmany_coins), + GNUNET_GETOPT_option_uint ( + 'p', + "parallelism", + "NPROCS", + "How many client processes we should run", + &howmany_clients), + GNUNET_GETOPT_option_uint ( + 'r', + "reserves", + "NRESERVES", + "How many reserves per client we should create", + &howmany_reserves), + GNUNET_GETOPT_option_uint ( + 'R', + "refresh-rate", + "RATE", + "Probability of refresh per coin (0-100)", + &refresh_rate), + GNUNET_GETOPT_option_string ( + 'u', + "exchange-account-section", + "SECTION", + "use exchange bank account configuration from the given SECTION", + &exchange_bank_section), GNUNET_GETOPT_OPTION_END }; + enum GNUNET_GenericReturnValue result; + struct GNUNET_TIME_Relative duration; unsetenv ("XDG_DATA_HOME"); unsetenv ("XDG_CONFIG_HOME"); @@ -993,29 +545,26 @@ main (int argc, argc, argv))) { - GNUNET_free_non_null (cfg_filename); - return BAD_CLI_ARG; + GNUNET_free (cfg_filename); + if (GNUNET_NO == result) + return 0; + return EXIT_INVALIDARGUMENT; } + if (NULL == exchange_bank_section) + exchange_bank_section = "exchange-account-1"; + if (NULL == loglev) + loglev = "INFO"; GNUNET_log_setup ("taler-exchange-benchmark", - NULL == loglev ? "INFO" : loglev, + loglev, logfile); - if (NULL == mode_str) - mode = MODE_BOTH; - else if (0 == strcmp (mode_str, "exchange")) - mode = MODE_EXCHANGE; - else if (0 == strcmp (mode_str, "client")) - mode = MODE_CLIENT; - else if (0 == strcmp (mode_str, "both")) - mode = MODE_BOTH; - else + if (NULL == cfg_filename) + cfg_filename = GNUNET_CONFIGURATION_default_filename (); + if (NULL == cfg_filename) { - TALER_LOG_ERROR ("Unknown mode given: '%s'\n", mode_str); - GNUNET_free_non_null (cfg_filename); - return BAD_CONFIG_FILE; + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Can't find default configuration file.\n"); + return EXIT_NOTCONFIGURED; } - if (NULL == cfg_filename) - cfg_filename = GNUNET_strdup ( - GNUNET_OS_project_data_get ()->user_config_file); cfg = GNUNET_CONFIGURATION_create (); if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, @@ -1023,7 +572,7 @@ main (int argc, { TALER_LOG_ERROR ("Could not parse configuration\n"); GNUNET_free (cfg_filename); - return BAD_CONFIG_FILE; + return EXIT_NOTCONFIGURED; } if (GNUNET_OK != TALER_config_get_currency (cfg, @@ -1031,182 +580,91 @@ main (int argc, { GNUNET_CONFIGURATION_destroy (cfg); GNUNET_free (cfg_filename); - return BAD_CONFIG_FILE; + return EXIT_NOTCONFIGURED; } if (howmany_clients > 10240) { TALER_LOG_ERROR ("-p option value given is too large\n"); - return BAD_CLI_ARG; + return EXIT_INVALIDARGUMENT; } if (0 == howmany_clients) { TALER_LOG_ERROR ("-p option value must not be zero\n"); GNUNET_free (cfg_filename); - return BAD_CLI_ARG; + return EXIT_INVALIDARGUMENT; } + if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - "benchmark", - "USER_PAYTO_URI", - &user_payto_uri)) + TALER_TESTING_get_credentials ( + cfg_filename, + exchange_bank_section, + use_fakebank + ? TALER_TESTING_BS_FAKEBANK + : TALER_TESTING_BS_IBAN, + &cred)) { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "benchmark", - "USER_PAYTO_URI"); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Required bank credentials not given in configuration\n"); GNUNET_free (cfg_filename); - return BAD_CONFIG_FILE; + return EXIT_NOTCONFIGURED; } { - const char *bank_details_section; + struct GNUNET_TIME_Absolute start_time; - GNUNET_CONFIGURATION_iterate_sections (cfg, - &pick_exchange_account_cb, - &bank_details_section); - if (NULL == bank_details_section) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Missing specification of bank account in configuration\n"); - GNUNET_free (cfg_filename); - return BAD_CONFIG_FILE; - } - if (GNUNET_OK != - TALER_BANK_auth_parse_cfg (cfg, - bank_details_section, - &exchange_bank_account)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Configuration fails to provide exchange bank details in section `%s'\n", - bank_details_section); - GNUNET_free (cfg_filename); - return BAD_CONFIG_FILE; - } - } - if ( (MODE_EXCHANGE == mode) || (MODE_BOTH == mode) ) - { - struct GNUNET_OS_Process *compute_wire_response; - - compute_wire_response - = GNUNET_OS_start_process (GNUNET_NO, - GNUNET_OS_INHERIT_STD_ALL, - NULL, NULL, NULL, - "taler-exchange-wire", - "taler-exchange-wire", - "-c", cfg_filename, - NULL); - if (NULL == compute_wire_response) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to run `taler-exchange-wire`, is your PATH correct?\n"); - GNUNET_free (cfg_filename); - return BAD_CONFIG_FILE; - } - GNUNET_OS_process_wait (compute_wire_response); - GNUNET_OS_process_destroy (compute_wire_response); - /* If we use the fakebank, we MUST reset the database as the fakebank - will have forgotten everything... */ - GNUNET_assert (GNUNET_OK == - TALER_TESTING_prepare_exchange (cfg_filename, - (GNUNET_YES == use_fakebank) - ? GNUNET_YES - : GNUNET_NO, - &ec)); - } - else - { - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - "exchange", - "BASE_URL", - &ec.exchange_url)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "exchange", - "base_url"); - GNUNET_CONFIGURATION_destroy (cfg); - GNUNET_free (cfg_filename); - return BAD_CONFIG_FILE; - } - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - "benchmark-remote-exchange", - "host", - &remote_host)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "benchmark-remote-exchange", - "host"); - GNUNET_CONFIGURATION_destroy (cfg); - GNUNET_free (cfg_filename); - return BAD_CONFIG_FILE; - } - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - "benchmark-remote-exchange", - "dir", - &remote_dir)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "benchmark-remote-exchange", - "dir"); - GNUNET_CONFIGURATION_destroy (cfg); - GNUNET_free (cfg_filename); - return BAD_CONFIG_FILE; - } + start_time = GNUNET_TIME_absolute_get (); + result = parallel_benchmark (&run, + NULL, + cfg_filename); + duration = GNUNET_TIME_absolute_get_duration (start_time); } - result = parallel_benchmark (&run, - NULL, - cfg_filename); - GNUNET_CONFIGURATION_destroy (cfg); - GNUNET_free (cfg_filename); - - /* If we're the exchange worker, we're done now. No need to print results */ - if (MODE_EXCHANGE == mode) - { - return (GNUNET_OK == result) ? 0 : result; - } - duration = GNUNET_TIME_absolute_get_duration (start_time); if (GNUNET_OK == result) { struct rusage usage; - GNUNET_assert (0 == getrusage (RUSAGE_CHILDREN, &usage)); + + GNUNET_assert (0 == getrusage (RUSAGE_CHILDREN, + &usage)); fprintf (stdout, - "Executed (Withdraw=%u, Deposit=%u, Refresh~=%5.2f) * Reserve=%u * Parallel=%u, operations in %s\n", + "Executed (Withdraw=%u, Deposit=%u, Refresh~=%5.2f)" + " * Reserve=%u * Parallel=%u, operations in %s\n", howmany_coins, howmany_coins, (float) howmany_coins * (refresh_rate / 100.0), howmany_reserves, howmany_clients, - GNUNET_STRINGS_relative_time_to_string - (duration, - GNUNET_NO)); + GNUNET_STRINGS_relative_time_to_string ( + duration, + false)); fprintf (stdout, "(approximately %s/coin)\n", - GNUNET_STRINGS_relative_time_to_string - (GNUNET_TIME_relative_divide (duration, - (unsigned long long) howmany_coins - * howmany_reserves - * howmany_clients), - GNUNET_YES)); + GNUNET_STRINGS_relative_time_to_string ( + GNUNET_TIME_relative_divide ( + duration, + (unsigned long long) howmany_coins + * howmany_reserves + * howmany_clients), + true)); fprintf (stdout, "RAW: %04u %04u %04u %16llu\n", howmany_coins, howmany_reserves, howmany_clients, (unsigned long long) duration.rel_value_us); - fprintf (stdout, "cpu time: sys %llu user %llu\n", \ + fprintf (stdout, + "cpu time: sys %llu user %llu\n", (unsigned long long) (usage.ru_stime.tv_sec * 1000 * 1000 + usage.ru_stime.tv_usec), (unsigned long long) (usage.ru_utime.tv_sec * 1000 * 1000 + usage.ru_utime.tv_usec)); } + for (unsigned int i = 0; i<label_off; i++) GNUNET_free (labels[i]); GNUNET_array_grow (labels, label_len, 0); + GNUNET_CONFIGURATION_destroy (cfg); + GNUNET_free (cfg_filename); return (GNUNET_OK == result) ? 0 : result; } |