From 5de648b0f6f8efba2665dd05cf3b4f45a1ac164b Mon Sep 17 00:00:00 2001 From: Joseph Date: Wed, 11 Jan 2023 05:54:49 -0500 Subject: [PATCH] new functions for inserting into link_data ready_deposit refunds --- contrib/gana | 2 +- src/exchangedb/Makefile.am | 55 +- src/exchangedb/pg_get_link_data.c | 11 +- src/exchangedb/pg_select_refunds_by_coin.c | 27 +- .../test_exchangedb_populate_link_data.c | 548 ++++++++++++++++++ .../test_exchangedb_populate_ready_deposit.c | 546 +++++++++++++++++ .../test_exchangedb_populate_table.c | 546 ++++++++--------- 7 files changed, 1419 insertions(+), 316 deletions(-) create mode 100644 src/exchangedb/test_exchangedb_populate_link_data.c create mode 100644 src/exchangedb/test_exchangedb_populate_ready_deposit.c diff --git a/contrib/gana b/contrib/gana index df1d19891..3e659ed54 160000 --- a/contrib/gana +++ b/contrib/gana @@ -1 +1 @@ -Subproject commit df1d198918cbdd03c18723d818979c8d09f8f231 +Subproject commit 3e659ed54023230dd45dbec5664f176e1763d260 diff --git a/src/exchangedb/Makefile.am b/src/exchangedb/Makefile.am index ddb899a0a..40607af68 100644 --- a/src/exchangedb/Makefile.am +++ b/src/exchangedb/Makefile.am @@ -296,7 +296,9 @@ check_PROGRAMS = \ perf-exchangedb-reserves-in-insert-postgres\ test-exchangedb-by-j-postgres\ test-exchangedb-batch-reserves-in-insert-postgres\ - test-exchangedb-populate-table-postgres + test-exchangedb-populate-table-postgres\ + test-exchangedb-populate-link-data-postgres\ + test-exchangedb-populate-ready-deposit-postgres AM_TESTS_ENVIRONMENT=export TALER_PREFIX=$${TALER_PREFIX:-@libdir@};export PATH=$${TALER_PREFIX:-@prefix@}/bin:$$PATH; TESTS = \ @@ -304,7 +306,9 @@ TESTS = \ test-exchangedb-by-j-postgres\ perf-exchangedb-reserves-in-insert-postgres\ test-exchangedb-batch-reserves-in-insert-postgres\ - test-exchangedb-populate-table-postgres + test-exchangedb-populate-table-postgres\ + test-exchangedb-populate-link-data-postgres\ + test-exchangedb-populate-ready-deposit-postgres test_exchangedb_postgres_SOURCES = \ test_exchangedb.c test_exchangedb_postgres_LDADD = \ @@ -375,6 +379,53 @@ test_exchangedb_populate_table_postgres_LDADD = \ -ljansson \ -lgnunetjson \ -lgnunetutil \ + -lm \ + $(XLIB) + +bench_db_postgres_SOURCES = \ + bench_db.c +bench_db_postgres_LDADD = \ + libtalerexchangedb.la \ + $(top_builddir)/src/util/libtalerutil.la \ + $(top_builddir)/src/pq/libtalerpq.la \ + -lgnunetpq \ + -lgnunetutil \ + $(XLIB) + +test_exchangedb_populate_link_data_postgres_SOURCES = \ + test_exchangedb_populate_link_data.c +test_exchangedb_populate_link_data_postgres_LDADD = \ + libtalerexchangedb.la \ + $(top_builddir)/src/json/libtalerjson.la \ + $(top_builddir)/src/util/libtalerutil.la \ + $(top_builddir)/src/pq/libtalerpq.la \ + -ljansson \ + -lgnunetjson \ + -lgnunetutil \ + -lm \ + $(XLIB) + +bench_db_postgres_SOURCES = \ + bench_db.c +bench_db_postgres_LDADD = \ + libtalerexchangedb.la \ + $(top_builddir)/src/util/libtalerutil.la \ + $(top_builddir)/src/pq/libtalerpq.la \ + -lgnunetpq \ + -lgnunetutil \ + $(XLIB) + +test_exchangedb_populate_ready_deposit_postgres_SOURCES = \ + test_exchangedb_populate_ready_deposit.c +test_exchangedb_populate_ready_deposit_postgres_LDADD = \ + libtalerexchangedb.la \ + $(top_builddir)/src/json/libtalerjson.la \ + $(top_builddir)/src/util/libtalerutil.la \ + $(top_builddir)/src/pq/libtalerpq.la \ + -ljansson \ + -lgnunetjson \ + -lgnunetutil \ + -lm \ $(XLIB) EXTRA_test_exchangedb_postgres_DEPENDENCIES = \ diff --git a/src/exchangedb/pg_get_link_data.c b/src/exchangedb/pg_get_link_data.c index f15bf35a2..9bc4c9b04 100644 --- a/src/exchangedb/pg_get_link_data.c +++ b/src/exchangedb/pg_get_link_data.c @@ -208,7 +208,7 @@ TEH_PG_get_link_data (void *cls, "WITH rc AS MATERIALIZED (" "SELECT" "* FROM refresh_commitments" - "WHERE old_coin_pub=$1" + " WHERE old_coin_pub=$1" ")" "SELECT " " tp.transfer_pub" @@ -219,11 +219,10 @@ TEH_PG_get_link_data (void *cls, ",rrc.freshcoin_index" ",rrc.coin_ev" " FROM refresh_revealed_coins rrc" - " USING (melt_serial_id)" - " JOIN refresh_transfer_keys tp" - " USING (melt_serial_id)" - " JOIN denominations denoms" - " USING (denominations_serial)" + " JOIN refresh_transfer_keys tp" + " USING (melt_serial_id)" + " JOIN denominations denoms" + " USING (denominations_serial)" " ORDER BY tp.transfer_pub, rrc.freshcoin_index ASC"); } diff --git a/src/exchangedb/pg_select_refunds_by_coin.c b/src/exchangedb/pg_select_refunds_by_coin.c index 84b63a719..b9db2b709 100644 --- a/src/exchangedb/pg_select_refunds_by_coin.c +++ b/src/exchangedb/pg_select_refunds_by_coin.c @@ -140,16 +140,25 @@ TEH_PG_select_refunds_by_coin ( "get_refunds_by_coin_and_contract", "WITH rc AS MATERIALIZED(" "SELECT" - " * FROM refunds ref" - "WHERE ref.coin_pub=$1" - "AND dep.merchant_pub=$2" - "AND dep.h_contract_terms=$3" - ")" + " amount_with_fee_val" + ",amount_with_fee_frac" + ",coin_pub" + ",deposit_serial_id" + " FROM refunds ref" + " WHERE ref.coin_pub=$1)" "SELECT" - " ref.amount_with_fee_val" - " ,ref.amount_with_fee_frac" - "FROM deposits dep" - "JOIN rc" + " rc.amount_with_fee_val" + " ,rc.amount_with_fee_frac" + " FROM " + "(SELECT" + " rc.amount_with_fee_val" + " ,rc.amount_with_fee_frac" + " FROM deposits dep" + " WHERE" + " dep.coin_pub = $1" // optional... + " AND dep.merchant_pub = $2" + " AND dep.h_contract_terms = $3) dep" + " JOIN rc" " USING (coin_pub,deposit_serial_id)"); } qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn, diff --git a/src/exchangedb/test_exchangedb_populate_link_data.c b/src/exchangedb/test_exchangedb_populate_link_data.c new file mode 100644 index 000000000..ff294874a --- /dev/null +++ b/src/exchangedb/test_exchangedb_populate_link_data.c @@ -0,0 +1,548 @@ +/* + 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 +*/ +/** + * @file exchangedb/test_exchangedb_populate_link_data.c + * @brief test cases for DB interaction functions + * @author Joseph Xu + */ +#include "platform.h" +#include "taler_exchangedb_lib.h" +#include "taler_json_lib.h" +#include "taler_exchangedb_plugin.h" +#include "math.h" + + +#define NUM_ROWS 1000 + +/** + * Global result from the testcase. + */ +static int result; + +/** + * Report line of error if @a cond is true, and jump to label "drop". + */ +#define FAILIF(cond) \ + do { \ + if (! (cond)) {break;} \ + GNUNET_break (0); \ + goto drop; \ + } while (0) + + +/** + * Initializes @a ptr with random data. + */ +#define RND_BLK(ptr) \ + GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, ptr, sizeof (*ptr)) + +/** + * Initializes @a ptr with zeros. + */ +#define ZR_BLK(ptr) \ + memset (ptr, 0, sizeof (*ptr)) + + +/** + * Currency we use. Must match test-exchange-db-*.conf. + */ +#define CURRENCY "EUR" + +/** + * How big do we make the RSA keys? + */ +#define RSA_KEY_SIZE 1024 +static struct TALER_EXCHANGEDB_RefreshRevealedCoin *revealed_coins; + +static struct TALER_TransferPrivateKeyP tprivs[TALER_CNC_KAPPA]; + +static struct TALER_TransferPublicKeyP tpub; +#define ROUNDS 10 +#define MELT_NEW_COINS 5 +#define MELT_NOREVEAL_INDEX 1 +/** + * Database plugin under test. + */ +static struct TALER_EXCHANGEDB_Plugin *plugin; +static struct TALER_DenomFeeSet fees; +/** + * Denomination keys used for fresh coins in melt test. + */ +static struct DenomKeyPair **new_dkp; + +struct DenomKeyPair +{ + struct TALER_DenominationPrivateKey priv; + struct TALER_DenominationPublicKey pub; +}; + + +/** + * Destroy a denomination key pair. The key is not necessarily removed from the DB. + * + * @param dkp the key pair to destroy + */ +static void +destroy_denom_key_pair (struct DenomKeyPair *dkp) +{ + TALER_denom_pub_free (&dkp->pub); + TALER_denom_priv_free (&dkp->priv); + GNUNET_free (dkp); +} + + +/** + * Create a denomination key pair by registering the denomination in the DB. + * + * @param size the size of the denomination key + * @param now time to use for key generation, legal expiration will be 3h later. + * @param fees fees to use + * @return the denominaiton key pair; NULL upon error + */ +static struct DenomKeyPair * +create_denom_key_pair (unsigned int size, + struct GNUNET_TIME_Timestamp now, + const struct TALER_Amount *value, + const struct TALER_DenomFeeSet *fees) +{ + struct DenomKeyPair *dkp; + struct TALER_EXCHANGEDB_DenominationKey dki; + struct TALER_EXCHANGEDB_DenominationKeyInformation issue2; + + dkp = GNUNET_new (struct DenomKeyPair); + GNUNET_assert (GNUNET_OK == + TALER_denom_priv_create (&dkp->priv, + &dkp->pub, + TALER_DENOMINATION_RSA, + size)); + memset (&dki, + 0, + sizeof (struct TALER_EXCHANGEDB_DenominationKey)); + dki.denom_pub = dkp->pub; + dki.issue.start = now; + dki.issue.expire_withdraw + = GNUNET_TIME_absolute_to_timestamp ( + GNUNET_TIME_absolute_add ( + now.abs_time, + GNUNET_TIME_UNIT_HOURS)); + dki.issue.expire_deposit + = GNUNET_TIME_absolute_to_timestamp ( + GNUNET_TIME_absolute_add ( + now.abs_time, + GNUNET_TIME_relative_multiply ( + GNUNET_TIME_UNIT_HOURS, 2))); + dki.issue.expire_legal + = GNUNET_TIME_absolute_to_timestamp ( + GNUNET_TIME_absolute_add ( + now.abs_time, + GNUNET_TIME_relative_multiply ( + GNUNET_TIME_UNIT_HOURS, 3))); + dki.issue.value = *value; + dki.issue.fees = *fees; + TALER_denom_pub_hash (&dkp->pub, + &dki.issue.denom_hash); + if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != + plugin->insert_denomination_info (plugin->cls, + &dki.denom_pub, + &dki.issue)) + { + GNUNET_break (0); + destroy_denom_key_pair (dkp); + return NULL; + } + memset (&issue2, 0, sizeof (issue2)); + if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != + plugin->get_denomination_info (plugin->cls, + &dki.issue.denom_hash, + &issue2)) + { + GNUNET_break (0); + destroy_denom_key_pair (dkp); + return NULL; + } + if (0 != GNUNET_memcmp (&dki.issue, + &issue2)) + { + GNUNET_break (0); + destroy_denom_key_pair (dkp); + return NULL; + } + return dkp; +} + +/** + * Function called with the session hashes and transfer secret + * information for a given coin. + * + * @param cls closure + * @param transfer_pub public transfer key for the session + * @param ldl link data for @a transfer_pub + */ +static void +handle_link_data_cb (void *cls, + const struct TALER_TransferPublicKeyP *transfer_pub, + const struct TALER_EXCHANGEDB_LinkList *ldl) +{ + (void) cls; + (void) transfer_pub; + for (const struct TALER_EXCHANGEDB_LinkList *ldlp = ldl; + NULL != ldlp; + ldlp = ldlp->next) + { + bool found; + + found = false; + for (unsigned int cnt = 0; cnt < MELT_NEW_COINS; cnt++) + { + if ( (0 == + TALER_denom_pub_cmp (&ldlp->denom_pub, + &new_dkp[cnt]->pub)) && + (0 == + TALER_blinded_denom_sig_cmp (&ldlp->ev_sig, + &revealed_coins[cnt].coin_sig)) ) + { + found = true; + break; + } + } + GNUNET_assert (GNUNET_NO != found); + } +} + + + +/** + * Main function that will be run by the scheduler. + * + * @param cls closure with config + */ + +static void +run (void *cls) +{ + struct TALER_EXCHANGEDB_Refresh *refresh; + uint64_t melt_serial_id; + struct GNUNET_CONFIGURATION_Handle *cfg = cls; + const uint32_t num_partitions = 10; + struct DenomKeyPair *dkp = NULL; + struct TALER_EXCHANGEDB_Deposit *depos=NULL; + struct TALER_Amount value; + struct TALER_DenominationPublicKey *new_denom_pubs = NULL; + struct GNUNET_TIME_Relative times = GNUNET_TIME_UNIT_ZERO; + unsigned long long sqrs=0; + struct TALER_EXCHANGEDB_Refund *ref=NULL; + unsigned int *perm; + unsigned long long duration_sq; + struct TALER_EXCHANGEDB_RefreshRevealedCoin *ccoin; + struct TALER_ExchangeWithdrawValues alg_values = { + .cipher = TALER_DENOMINATION_RSA + }; + + ref = GNUNET_new_array (ROUNDS +1, + struct TALER_EXCHANGEDB_Refund); + depos = GNUNET_new_array (ROUNDS +1, + struct TALER_EXCHANGEDB_Deposit); + refresh = GNUNET_new_array (ROUNDS +1, + struct TALER_EXCHANGEDB_Refresh); + + if (NULL == + (plugin = TALER_EXCHANGEDB_plugin_load (cfg))) + { + GNUNET_break (0); + result = 77; + return; + } + (void) plugin->drop_tables (plugin->cls); + if (GNUNET_OK != + plugin->create_tables (plugin->cls, + true, + num_partitions)) + { + GNUNET_break (0); + result = 77; + goto cleanup; + } + if (GNUNET_OK != + plugin->preflight (plugin->cls)) + { + GNUNET_break (0); + goto cleanup; + } + + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY ":1.000010", + &value)); + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY ":0.000010", + &fees.withdraw)); + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY ":0.000010", + &fees.deposit)); + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY ":0.000010", + &fees.refresh)); + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY ":0.000010", + &fees.refund)); + //DENOMINATION + { + //PAIR KEY LIST + new_dkp = GNUNET_new_array (MELT_NEW_COINS, + struct DenomKeyPair *); + //PUBLIC KEY LIST + new_denom_pubs = GNUNET_new_array (MELT_NEW_COINS, + struct TALER_DenominationPublicKey); + //REFRESH REVEAL COIN LIST + revealed_coins + = GNUNET_new_array (MELT_NEW_COINS, + struct TALER_EXCHANGEDB_RefreshRevealedCoin); + for (unsigned int cnt = 0; cnt < MELT_NEW_COINS; cnt++) + { + struct GNUNET_TIME_Timestamp now; + struct TALER_BlindedRsaPlanchet *rp; + struct TALER_BlindedPlanchet *bp; + + now = GNUNET_TIME_timestamp_get (); + //5 KEY PAIR + new_dkp[cnt] = create_denom_key_pair (RSA_KEY_SIZE, + now, + &value, + &fees); + GNUNET_assert (NULL != new_dkp[cnt]); + new_denom_pubs[cnt] = new_dkp[cnt]->pub; + ccoin = &revealed_coins[cnt]; + bp = &ccoin->blinded_planchet; + bp->cipher = TALER_DENOMINATION_RSA; + rp = &bp->details.rsa_blinded_planchet; + rp->blinded_msg_size = 1 + (size_t) GNUNET_CRYPTO_random_u64 ( + GNUNET_CRYPTO_QUALITY_WEAK, + (RSA_KEY_SIZE / 8) - 1); + rp->blinded_msg = GNUNET_malloc (rp->blinded_msg_size); + GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, + rp->blinded_msg, + rp->blinded_msg_size); + TALER_denom_pub_hash (&new_dkp[cnt]->pub, + &ccoin->h_denom_pub); + ccoin->exchange_vals = alg_values; + TALER_coin_ev_hash (bp, + &ccoin->h_denom_pub, + &ccoin->coin_envelope_hash); + GNUNET_assert (GNUNET_OK == + TALER_denom_sign_blinded (&ccoin->coin_sig, + &new_dkp[cnt]->priv, + true, + bp)); + } + } + perm = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_NONCE, + NUM_ROWS); + //BEGIN + FAILIF (GNUNET_OK != + plugin->start (plugin->cls, + "Transaction")); + for (unsigned int j = 0; j < NUM_ROWS; j++) + { + union TALER_DenominationBlindingKeyP bks; + struct TALER_CoinSpendPublicKeyP coin_pub; + struct TALER_CoinPubHashP c_hash; + unsigned int k = (unsigned int)rand()%5; + unsigned int i = perm[j]; + if (i >= ROUNDS) + i = ROUNDS; /* throw-away slot, do not keep around */ + RND_BLK (&coin_pub); + RND_BLK (&c_hash); + + RND_BLK (&depos[i].coin.coin_pub); + TALER_denom_pub_hash (&new_dkp[k]->pub, + &depos[i].coin.denom_pub_hash); + GNUNET_assert (GNUNET_OK == + TALER_denom_sig_unblind (&depos[i].coin.denom_sig, + &ccoin->coin_sig, + &bks, + &c_hash, + &alg_values, + &new_dkp[k]->pub)); + { + /* ENSURE_COIN_KNOWN */ + uint64_t known_coin_id; + struct TALER_DenominationHashP dph; + struct TALER_AgeCommitmentHash agh; + bool zombie_required = false; + bool balance_ok; + FAILIF (TALER_EXCHANGEDB_CKS_ADDED != + plugin->ensure_coin_known (plugin->cls, + &depos[i].coin, + &known_coin_id, + &dph, + &agh)); + /**** INSERT REFRESH COMMITMENTS ****/ + refresh[i].coin = depos[i].coin; + RND_BLK (&refresh[i].coin_sig); + RND_BLK (&refresh[i].rc); + refresh[i].amount_with_fee = value; + refresh[i].noreveal_index = MELT_NOREVEAL_INDEX; + FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != + plugin->do_melt (plugin->cls, + NULL, + &refresh[i], + known_coin_id, + &zombie_required, + &balance_ok)); + FAILIF (! balance_ok); + FAILIF (zombie_required); + } + /**** INSERT REFRESH_REVEAL + TRANSFER_KEYS *****/ + RND_BLK (&tprivs); + RND_BLK (&tpub); + RND_BLK(&melt_serial_id); + FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != + plugin->insert_refresh_reveal (plugin->cls, + melt_serial_id, + MELT_NEW_COINS, + revealed_coins, + TALER_CNC_KAPPA - 1, + tprivs, + &tpub)); + if (ROUNDS == i) + TALER_denom_sig_free (&depos[i].coin.denom_sig); + } + /* End of benchmark setup */ + GNUNET_free(perm); + // commit + FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != + plugin->commit (plugin->cls)); + /**** CALL GET LINK DATA ****/ + for (unsigned int r=0; r< ROUNDS; r++) + { + struct GNUNET_TIME_Absolute time; + struct GNUNET_TIME_Relative duration; + enum GNUNET_DB_QueryStatus qs; + time = GNUNET_TIME_absolute_get(); + qs = plugin->get_link_data (plugin->cls, + &refresh[r].coin.coin_pub, + &handle_link_data_cb, + NULL); + FAILIF (qs < 0); + + duration = GNUNET_TIME_absolute_get_duration (time); + times = GNUNET_TIME_relative_add (times, + duration); + duration_sq = duration.rel_value_us * duration.rel_value_us; + GNUNET_assert (duration_sq / duration.rel_value_us == duration.rel_value_us); + GNUNET_assert (sqrs + duration_sq >= sqrs); + sqrs += duration_sq; + } + + /* evaluation of performance */ + { + struct GNUNET_TIME_Relative avg; + double avg_dbl; + double variance; + + avg = GNUNET_TIME_relative_divide (times, + ROUNDS); + avg_dbl = avg.rel_value_us; + variance = sqrs - (avg_dbl * avg_dbl * ROUNDS); + fprintf(stdout, + "%8llu ± %6.0f\n", + (unsigned long long) avg.rel_value_us, + sqrt (variance / (ROUNDS-1))); + } + result = 0; +drop: + GNUNET_break (GNUNET_OK == + plugin->drop_tables (plugin->cls)); +cleanup: + if (NULL != dkp) + destroy_denom_key_pair (dkp); + if (NULL != revealed_coins) + { + for (unsigned int cnt = 0; cnt < MELT_NEW_COINS; cnt++) + { + TALER_blinded_denom_sig_free (&revealed_coins[cnt].coin_sig); + TALER_blinded_planchet_free (&revealed_coins[cnt].blinded_planchet); + } + GNUNET_free (revealed_coins); + revealed_coins = NULL; + } + GNUNET_free (new_denom_pubs); + for (unsigned int cnt = 0; + (NULL != new_dkp) && (cnt < MELT_NEW_COINS) && (NULL != new_dkp[cnt]); + cnt++) + destroy_denom_key_pair (new_dkp[cnt]); + GNUNET_free (new_dkp); + for (unsigned int i=0; i< ROUNDS; i++) + { + TALER_denom_sig_free (&depos[i].coin.denom_sig); + } + GNUNET_free(depos); + GNUNET_free(ref); + GNUNET_free(refresh); + dkp = NULL; + TALER_EXCHANGEDB_plugin_unload (plugin); + plugin = NULL; +} + + +int +main (int argc, + char *const argv[]) +{ + const char *plugin_name; + char *config_filename; + char *testname; + struct GNUNET_CONFIGURATION_Handle *cfg; + + (void) argc; + result = -1; + if (NULL == (plugin_name = strrchr (argv[0], (int) '-'))) + { + GNUNET_break (0); + return -1; + } + GNUNET_log_setup (argv[0], + "WARNING", + NULL); + plugin_name++; + (void) GNUNET_asprintf (&testname, + "test-exchange-db-%s", + plugin_name); + (void) GNUNET_asprintf (&config_filename, + "%s.conf", + testname); + fprintf (stdout, + "Using config: %s\n", + config_filename); + cfg = GNUNET_CONFIGURATION_create (); + if (GNUNET_OK != + GNUNET_CONFIGURATION_parse (cfg, + config_filename)) + { + GNUNET_break (0); + GNUNET_free (config_filename); + GNUNET_free (testname); + return 2; + } + GNUNET_SCHEDULER_run (&run, + cfg); + GNUNET_CONFIGURATION_destroy (cfg); + GNUNET_free (config_filename); + GNUNET_free (testname); + return result; +} + + +/* end of test_exchangedb_by_j.c */ diff --git a/src/exchangedb/test_exchangedb_populate_ready_deposit.c b/src/exchangedb/test_exchangedb_populate_ready_deposit.c new file mode 100644 index 000000000..49b1bf5d2 --- /dev/null +++ b/src/exchangedb/test_exchangedb_populate_ready_deposit.c @@ -0,0 +1,546 @@ +/* + 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 +*/ +/** + * @file exchangedb/test_exchangedb_populate_ready_deposit.c + * @brief test cases for DB interaction functions + * @author Joseph Xu + */ +#include "platform.h" +#include "taler_exchangedb_lib.h" +#include "taler_json_lib.h" +#include "taler_exchangedb_plugin.h" +#include "math.h" + + +#define NUM_ROWS 1000 + +/** + * Global result from the testcase. + */ +static int result; + +/** + * Report line of error if @a cond is true, and jump to label "drop". + */ +#define FAILIF(cond) \ + do { \ + if (! (cond)) {break;} \ + GNUNET_break (0); \ + goto drop; \ + } while (0) + + +/** + * Initializes @a ptr with random data. + */ +#define RND_BLK(ptr) \ + GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, ptr, sizeof (*ptr)) + +/** + * Initializes @a ptr with zeros. + */ +#define ZR_BLK(ptr) \ + memset (ptr, 0, sizeof (*ptr)) + + +/** + * Currency we use. Must match test-exchange-db-*.conf. + */ +#define CURRENCY "EUR" + +/** + * How big do we make the RSA keys? + */ +#define RSA_KEY_SIZE 1024 +static struct TALER_EXCHANGEDB_RefreshRevealedCoin *revealed_coins; + + +#define ROUNDS 100 +#define MELT_NEW_COINS 5 +#define MELT_NOREVEAL_INDEX 1 +/** + * Database plugin under test. + */ +static struct TALER_EXCHANGEDB_Plugin *plugin; +static struct TALER_DenomFeeSet fees; +static struct TALER_MerchantWireHashP h_wire_wt; +/** + * Denomination keys used for fresh coins in melt test. + */ +static struct DenomKeyPair **new_dkp; + +struct DenomKeyPair +{ + struct TALER_DenominationPrivateKey priv; + struct TALER_DenominationPublicKey pub; +}; + + +/** + * Destroy a denomination key pair. The key is not necessarily removed from the DB. + * + * @param dkp the key pair to destroy + */ +static void +destroy_denom_key_pair (struct DenomKeyPair *dkp) +{ + TALER_denom_pub_free (&dkp->pub); + TALER_denom_priv_free (&dkp->priv); + GNUNET_free (dkp); +} + + +/** + * Create a denomination key pair by registering the denomination in the DB. + * + * @param size the size of the denomination key + * @param now time to use for key generation, legal expiration will be 3h later. + * @param fees fees to use + * @return the denominaiton key pair; NULL upon error + */ +static struct DenomKeyPair * +create_denom_key_pair (unsigned int size, + struct GNUNET_TIME_Timestamp now, + const struct TALER_Amount *value, + const struct TALER_DenomFeeSet *fees) +{ + struct DenomKeyPair *dkp; + struct TALER_EXCHANGEDB_DenominationKey dki; + struct TALER_EXCHANGEDB_DenominationKeyInformation issue2; + + dkp = GNUNET_new (struct DenomKeyPair); + GNUNET_assert (GNUNET_OK == + TALER_denom_priv_create (&dkp->priv, + &dkp->pub, + TALER_DENOMINATION_RSA, + size)); + memset (&dki, + 0, + sizeof (struct TALER_EXCHANGEDB_DenominationKey)); + dki.denom_pub = dkp->pub; + dki.issue.start = now; + dki.issue.expire_withdraw + = GNUNET_TIME_absolute_to_timestamp ( + GNUNET_TIME_absolute_add ( + now.abs_time, + GNUNET_TIME_UNIT_HOURS)); + dki.issue.expire_deposit + = GNUNET_TIME_absolute_to_timestamp ( + GNUNET_TIME_absolute_add ( + now.abs_time, + GNUNET_TIME_relative_multiply ( + GNUNET_TIME_UNIT_HOURS, 2))); + dki.issue.expire_legal + = GNUNET_TIME_absolute_to_timestamp ( + GNUNET_TIME_absolute_add ( + now.abs_time, + GNUNET_TIME_relative_multiply ( + GNUNET_TIME_UNIT_HOURS, 3))); + dki.issue.value = *value; + dki.issue.fees = *fees; + TALER_denom_pub_hash (&dkp->pub, + &dki.issue.denom_hash); + if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != + plugin->insert_denomination_info (plugin->cls, + &dki.denom_pub, + &dki.issue)) + { + GNUNET_break (0); + destroy_denom_key_pair (dkp); + return NULL; + } + memset (&issue2, 0, sizeof (issue2)); + if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != + plugin->get_denomination_info (plugin->cls, + &dki.issue.denom_hash, + &issue2)) + { + GNUNET_break (0); + destroy_denom_key_pair (dkp); + return NULL; + } + if (0 != GNUNET_memcmp (&dki.issue, + &issue2)) + { + GNUNET_break (0); + destroy_denom_key_pair (dkp); + return NULL; + } + return dkp; +} + + + + +/** + * Main function that will be run by the scheduler. + * + * @param cls closure with config + */ + +static void +run (void *cls) +{ + struct TALER_EXCHANGEDB_Refresh refresh; + struct GNUNET_CONFIGURATION_Handle *cfg = cls; + const uint32_t num_partitions = 10; + struct TALER_Amount value; + struct TALER_EXCHANGEDB_CollectableBlindcoin cbc; + struct TALER_DenominationPublicKey *new_denom_pubs = NULL; + struct GNUNET_TIME_Relative times = GNUNET_TIME_UNIT_ZERO; + unsigned long long sqrs=0; + struct TALER_EXCHANGEDB_Deposit *depos=NULL; + struct TALER_EXCHANGEDB_Refund *ref=NULL; + unsigned int *perm; + unsigned long long duration_sq; + struct TALER_EXCHANGEDB_RefreshRevealedCoin *ccoin; + struct TALER_ExchangeWithdrawValues alg_values = { + .cipher = TALER_DENOMINATION_RSA + }; + + ref = GNUNET_new_array (ROUNDS +1, + struct TALER_EXCHANGEDB_Refund); + depos = GNUNET_new_array (ROUNDS +1, + struct TALER_EXCHANGEDB_Deposit); + + if (NULL == + (plugin = TALER_EXCHANGEDB_plugin_load (cfg))) + { + GNUNET_break (0); + result = 77; + return; + } + (void) plugin->drop_tables (plugin->cls); + if (GNUNET_OK != + plugin->create_tables (plugin->cls, + true, + num_partitions)) + { + GNUNET_break (0); + result = 77; + goto cleanup; + } + if (GNUNET_OK != + plugin->preflight (plugin->cls)) + { + GNUNET_break (0); + goto cleanup; + } + + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY ":1.000010", + &value)); + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY ":0.000010", + &fees.withdraw)); + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY ":0.000010", + &fees.deposit)); + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY ":0.000010", + &fees.refresh)); + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY ":0.000010", + &fees.refund)); + //DENOMINATION + { + ZR_BLK (&cbc); + //PAIR KEY LIST + new_dkp = GNUNET_new_array (MELT_NEW_COINS, + struct DenomKeyPair *); + //PUBLIC KEY LIST + new_denom_pubs = GNUNET_new_array (MELT_NEW_COINS, + struct TALER_DenominationPublicKey); + //REFRESH REVEAL COIN LIST + revealed_coins + = GNUNET_new_array (MELT_NEW_COINS, + struct TALER_EXCHANGEDB_RefreshRevealedCoin); + for (unsigned int cnt = 0; cnt < MELT_NEW_COINS; cnt++) + { + struct GNUNET_TIME_Timestamp now; + struct TALER_BlindedRsaPlanchet *rp; + struct TALER_BlindedPlanchet *bp; + + now = GNUNET_TIME_timestamp_get (); + //5 KEY PAIR + new_dkp[cnt] = create_denom_key_pair (RSA_KEY_SIZE, + now, + &value, + &fees); + GNUNET_assert (NULL != new_dkp[cnt]); + new_denom_pubs[cnt] = new_dkp[cnt]->pub; + ccoin = &revealed_coins[cnt]; + bp = &ccoin->blinded_planchet; + bp->cipher = TALER_DENOMINATION_RSA; + rp = &bp->details.rsa_blinded_planchet; + rp->blinded_msg_size = 1 + (size_t) GNUNET_CRYPTO_random_u64 ( + GNUNET_CRYPTO_QUALITY_WEAK, + (RSA_KEY_SIZE / 8) - 1); + rp->blinded_msg = GNUNET_malloc (rp->blinded_msg_size); + GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, + rp->blinded_msg, + rp->blinded_msg_size); + TALER_denom_pub_hash (&new_dkp[cnt]->pub, + &ccoin->h_denom_pub); + ccoin->exchange_vals = alg_values; + TALER_coin_ev_hash (bp, + &ccoin->h_denom_pub, + &ccoin->coin_envelope_hash); + GNUNET_assert (GNUNET_OK == + TALER_denom_sign_blinded (&ccoin->coin_sig, + &new_dkp[cnt]->priv, + true, + bp)); + GNUNET_assert (GNUNET_OK == + TALER_coin_ev_hash (bp, + &cbc.denom_pub_hash, + &cbc.h_coin_envelope)); + GNUNET_assert ( + GNUNET_OK == + TALER_denom_sign_blinded ( + &cbc.sig, + &new_dkp[cnt]->priv, + false, + bp)); + } + } + perm = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_NONCE, + NUM_ROWS); + //BEGIN + FAILIF (GNUNET_OK != + plugin->start (plugin->cls, + "Transaction")); + for (unsigned int j = 0; j < NUM_ROWS; j++) + { + /*** NEED TO INSERT REFRESH COMMITMENTS + ENSURECOIN ***/ + union TALER_DenominationBlindingKeyP bks; + struct GNUNET_TIME_Timestamp deadline; + struct TALER_CoinSpendPublicKeyP coin_pub; + struct TALER_ReservePublicKeyP reserve_pub; + struct TALER_CoinPubHashP c_hash; + unsigned int k = (unsigned int)rand()%5; + unsigned int i = perm[j]; + if (i >= ROUNDS) + i = ROUNDS; /* throw-away slot, do not keep around */ + depos[i].deposit_fee = fees.deposit; + RND_BLK (&coin_pub); + RND_BLK (&c_hash); + RND_BLK (&reserve_pub); + RND_BLK (&cbc.reserve_sig); + TALER_denom_pub_hash (&new_dkp[k]->pub, + &cbc.denom_pub_hash); + deadline = GNUNET_TIME_timestamp_get (); + RND_BLK (&depos[i].coin.coin_pub); + TALER_denom_pub_hash (&new_dkp[k]->pub, + &depos[i].coin.denom_pub_hash); + GNUNET_assert (GNUNET_OK == + TALER_denom_sig_unblind (&depos[i].coin.denom_sig, + &ccoin->coin_sig, + &bks, + &c_hash, + &alg_values, + &new_dkp[k]->pub)); + RND_BLK (&depos[i].merchant_pub); + RND_BLK (&depos[i].csig); + RND_BLK (&depos[i].h_contract_terms); + RND_BLK (&depos[i].wire_salt); + depos[i].amount_with_fee = value; + depos[i].refund_deadline = deadline; + depos[i].wire_deadline = deadline; + depos[i].receiver_wire_account = + "payto://iban/DE67830654080004822650?receiver-name=Test"; + TALER_merchant_wire_signature_hash ( + "payto://iban/DE67830654080004822650?receiver-name=Test", + &depos[i].wire_salt, + &h_wire_wt); + cbc.reserve_pub = reserve_pub; + cbc.amount_with_fee = value; + GNUNET_assert (GNUNET_OK == + TALER_amount_set_zero (CURRENCY, + &cbc.withdraw_fee)); + { + /* INSERT WIRE TARGETS */ + bool found; + bool nonce_ok; + bool balance_ok; + uint64_t ruuid; + struct GNUNET_TIME_Timestamp now; + now = GNUNET_TIME_timestamp_get (); + FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != + plugin->do_withdraw (plugin->cls, + NULL, + &cbc, + now, + &found, + &balance_ok, + &nonce_ok, + &ruuid)); + } + + { + /* ENSURE_COIN_KNOWN */ + uint64_t known_coin_id; + struct TALER_DenominationHashP dph; + struct TALER_AgeCommitmentHash agh; + FAILIF (TALER_EXCHANGEDB_CKS_ADDED != + plugin->ensure_coin_known (plugin->cls, + &depos[i].coin, + &known_coin_id, + &dph, + &agh)); + refresh.coin = depos[i].coin; + RND_BLK (&refresh.coin_sig); + RND_BLK (&refresh.rc); + refresh.amount_with_fee = value; + refresh.noreveal_index = MELT_NOREVEAL_INDEX; + } + /*STORE INTO DEPOSIT*/ + { + struct GNUNET_TIME_Timestamp now; + now = GNUNET_TIME_timestamp_get (); + FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != + plugin->insert_deposit (plugin->cls, + now, + &depos[i])); + } + if (ROUNDS == i) + TALER_denom_sig_free (&depos[i].coin.denom_sig); + } + /* End of benchmark setup */ + GNUNET_free(perm); + // commit + FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != + plugin->commit (plugin->cls)); + /**** CALL GET LINK DATA ****/ + for (unsigned int r=0; r< ROUNDS; r++) + { + struct GNUNET_TIME_Absolute time; + struct GNUNET_TIME_Relative duration; + struct TALER_MerchantPublicKeyP merchant_pub; + char *payto_uri; + time = GNUNET_TIME_absolute_get(); + FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != + plugin->get_ready_deposit (plugin->cls, + 0, + INT32_MAX, + &merchant_pub, + &payto_uri)); + + duration = GNUNET_TIME_absolute_get_duration (time); + times = GNUNET_TIME_relative_add (times, + duration); + duration_sq = duration.rel_value_us * duration.rel_value_us; + GNUNET_assert (duration_sq / duration.rel_value_us == duration.rel_value_us); + GNUNET_assert (sqrs + duration_sq >= sqrs); + sqrs += duration_sq; + } + + /* evaluation of performance */ + { + struct GNUNET_TIME_Relative avg; + double avg_dbl; + double variance; + + avg = GNUNET_TIME_relative_divide (times, + ROUNDS); + avg_dbl = avg.rel_value_us; + variance = sqrs - (avg_dbl * avg_dbl * ROUNDS); + fprintf(stdout, + "%8llu ± %6.0f\n", + (unsigned long long) avg.rel_value_us, + sqrt (variance / (ROUNDS-1))); + } + result = 0; +drop: + GNUNET_break (GNUNET_OK == + plugin->drop_tables (plugin->cls)); +cleanup: + if (NULL != revealed_coins) + { + for (unsigned int cnt = 0; cnt < MELT_NEW_COINS; cnt++) + { + TALER_blinded_denom_sig_free (&revealed_coins[cnt].coin_sig); + TALER_blinded_planchet_free (&revealed_coins[cnt].blinded_planchet); + } + GNUNET_free (revealed_coins); + revealed_coins = NULL; + } + GNUNET_free (new_denom_pubs); + for (unsigned int cnt = 0; + (NULL != new_dkp) && (cnt < MELT_NEW_COINS) && (NULL != new_dkp[cnt]); + cnt++) + destroy_denom_key_pair (new_dkp[cnt]); + GNUNET_free (new_dkp); + for (unsigned int i=0; i< ROUNDS ; i++) + { + TALER_denom_sig_free (&depos[i].coin.denom_sig); + } + GNUNET_free(depos); + GNUNET_free(ref); + TALER_EXCHANGEDB_plugin_unload (plugin); + plugin = NULL; +} + + +int +main (int argc, + char *const argv[]) +{ + const char *plugin_name; + char *config_filename; + char *testname; + struct GNUNET_CONFIGURATION_Handle *cfg; + + (void) argc; + result = -1; + if (NULL == (plugin_name = strrchr (argv[0], (int) '-'))) + { + GNUNET_break (0); + return -1; + } + GNUNET_log_setup (argv[0], + "WARNING", + NULL); + plugin_name++; + (void) GNUNET_asprintf (&testname, + "test-exchange-db-%s", + plugin_name); + (void) GNUNET_asprintf (&config_filename, + "%s.conf", + testname); + fprintf (stdout, + "Using config: %s\n", + config_filename); + cfg = GNUNET_CONFIGURATION_create (); + if (GNUNET_OK != + GNUNET_CONFIGURATION_parse (cfg, + config_filename)) + { + GNUNET_break (0); + GNUNET_free (config_filename); + GNUNET_free (testname); + return 2; + } + GNUNET_SCHEDULER_run (&run, + cfg); + GNUNET_CONFIGURATION_destroy (cfg); + GNUNET_free (config_filename); + GNUNET_free (testname); + return result; +} + + +/* end of test_exchangedb_by_j.c */ diff --git a/src/exchangedb/test_exchangedb_populate_table.c b/src/exchangedb/test_exchangedb_populate_table.c index d67d1307a..face454fd 100644 --- a/src/exchangedb/test_exchangedb_populate_table.c +++ b/src/exchangedb/test_exchangedb_populate_table.c @@ -22,8 +22,11 @@ #include "taler_exchangedb_lib.h" #include "taler_json_lib.h" #include "taler_exchangedb_plugin.h" +#include "math.h" -/**o +#define NUM_ROWS 10000 + +/** * Global result from the testcase. */ static int result; @@ -56,20 +59,13 @@ static int result; * Currency we use. Must match test-exchange-db-*.conf. */ #define CURRENCY "EUR" - - -/** - * Number of newly minted coins to use in the test. - */ -#define MELT_NEW_COINS 5 -#define i 0 -#define NUMBER_DEPOSIT 10 /** * How big do we make the RSA keys? */ #define RSA_KEY_SIZE 1024 - - +#define ROUNDS 1000 +#define MELT_NEW_COINS 5 +#define MELT_NOREVEAL_INDEX 1 /** * Database plugin under test. */ @@ -82,8 +78,8 @@ struct DenomKeyPair struct TALER_DenominationPrivateKey priv; struct TALER_DenominationPublicKey pub; }; - - +static struct DenomKeyPair **new_dkp; +static struct TALER_EXCHANGEDB_RefreshRevealedCoin *revealed_coins; /** * Destroy a denomination key pair. The key is not necessarily removed from the DB. * @@ -176,90 +172,28 @@ create_denom_key_pair (unsigned int size, } return dkp; } - /** - * Here we store the hash of the payto URI. - */ -static struct TALER_PaytoHashP wire_target_h_payto; -/** - * Counter used in auditor-related db functions. Used to count - * expected rows. - */ -static unsigned int auditor_row_cnt; -/** - * Callback for #select_deposits_above_serial_id () + * Callback invoked with information about refunds applicable + * to a particular coin. * - * @param cls closure - * @param rowid unique serial ID for the deposit in our DB - * @param exchange_timestamp when did the deposit happen - * @param deposit deposit details - * @param denom_pub denomination of the @a coin_pub - * @param done flag set if the deposit was already executed (or not) + * @param cls closure with the `struct TALER_EXCHANGEDB_Refund *` we expect to get + * @param amount_with_fee amount being refunded * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop */ static enum GNUNET_GenericReturnValue -audit_deposit_cb (void *cls, - uint64_t rowid, - struct GNUNET_TIME_Timestamp exchange_timestamp, - const struct TALER_EXCHANGEDB_Deposit *deposit, - const struct TALER_DenominationPublicKey *denom_pub, - bool done) +check_refund_cb (void *cls, + const struct TALER_Amount *amount_with_fee) { - (void) cls; - (void) rowid; - (void) exchange_timestamp; - (void) deposit; - (void) denom_pub; - (void) done; - auditor_row_cnt++; + const struct TALER_EXCHANGEDB_Refund *refund = cls; + + if (0 != TALER_amount_cmp (amount_with_fee, + &refund->details.refund_amount)) + { + GNUNET_break (0); + result = 66; + } return GNUNET_OK; } -/** - * Function called on deposits that are past their due date - * and have not yet seen a wire transfer. - * - * @param cls closure a `struct TALER_EXCHANGEDB_Deposit *` - * @param rowid deposit table row of the coin's deposit - * @param coin_pub public key of the coin - * @param amount value of the deposit, including fee - * @param payto_uri where should the funds be wired - * @param deadline what was the requested wire transfer deadline - * @param done did the exchange claim that it made a transfer? - */ -static void -wire_missing_cb (void *cls, - uint64_t rowid, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - const struct TALER_Amount *amount, - const char *payto_uri, - struct GNUNET_TIME_Timestamp deadline, - bool done) -{ - const struct TALER_EXCHANGEDB_Deposit *deposit = cls; - - (void) payto_uri; - (void) deadline; - (void) rowid; - if (done) - { - GNUNET_break (0); - result = 66; - } - if (0 != TALER_amount_cmp (amount, - &deposit->amount_with_fee)) - { - GNUNET_break (0); - result = 66; - } - if (0 != GNUNET_memcmp (coin_pub, - &deposit->coin.coin_pub)) - { - GNUNET_break (0); - result = 66; - } -} - - /** @@ -275,27 +209,28 @@ run (void *cls) const uint32_t num_partitions = 10; struct DenomKeyPair *dkp = NULL; struct GNUNET_TIME_Timestamp ts; - struct TALER_EXCHANGEDB_Deposit depos[NUMBER_DEPOSIT]; + struct TALER_EXCHANGEDB_Deposit *depos=NULL; struct GNUNET_TIME_Timestamp deadline; struct TALER_Amount value; union TALER_DenominationBlindingKeyP bks; struct TALER_CoinPubHashP c_hash; struct TALER_EXCHANGEDB_CollectableBlindcoin cbc; - struct TALER_EXCHANGEDB_CollectableBlindcoin cbc2; struct TALER_ExchangeWithdrawValues alg_values = { .cipher = TALER_DENOMINATION_RSA }; - struct TALER_PlanchetMasterSecretP ps; - struct TALER_ReservePublicKeyP reserve_pub; - struct TALER_EXCHANGEDB_Refund ref; - + struct GNUNET_TIME_Relative times = GNUNET_TIME_UNIT_ZERO; + unsigned long long sqrs = 0; + struct TALER_EXCHANGEDB_Refund *ref=NULL; + unsigned int *perm; + unsigned long long duration_sq; + struct TALER_CoinSpendPublicKeyP coin_pub; + struct TALER_EXCHANGEDB_RefreshRevealedCoin *ccoin; + struct TALER_DenominationPublicKey *new_denom_pubs = NULL; + ref = GNUNET_new_array (ROUNDS +1, + struct TALER_EXCHANGEDB_Refund); + depos = GNUNET_new_array (ROUNDS +1, + struct TALER_EXCHANGEDB_Deposit); ZR_BLK (&cbc); - ZR_BLK (&cbc2); - RND_BLK (&reserve_pub); - - memset (&ref, - 0, - sizeof (ref)); if (NULL == (plugin = TALER_EXCHANGEDB_plugin_load (cfg))) @@ -337,209 +272,207 @@ run (void *cls) GNUNET_assert (GNUNET_OK == TALER_string_to_amount (CURRENCY ":0.000010", &fees.refund)); + GNUNET_assert (NUM_ROWS >= ROUNDS); + ts = GNUNET_TIME_timestamp_get (); deadline = GNUNET_TIME_timestamp_get (); - dkp = create_denom_key_pair (RSA_KEY_SIZE, - ts, - &value, - &fees); - - GNUNET_assert (NULL != dkp); - TALER_denom_pub_hash (&dkp->pub, - &cbc.denom_pub_hash); - RND_BLK (&cbc.reserve_sig); - RND_BLK (&ps); - TALER_planchet_blinding_secret_create (&ps, - &alg_values, - &bks); - - - cbc.reserve_pub = reserve_pub; - cbc.amount_with_fee = value; - GNUNET_assert (GNUNET_OK == - TALER_amount_set_zero (CURRENCY, - &cbc.withdraw_fee)); - /* for (unsigned int i=0; i< NUMBER_DEPOSIT; i++) - {*/ - fprintf(stdout, "%d\n", i); - struct TALER_CoinSpendPublicKeyP coin_pub; - RND_BLK (&coin_pub); - { - struct TALER_PlanchetDetail pd; - - struct TALER_AgeCommitmentHash age_hash; - struct TALER_AgeCommitmentHash *p_ah[2] = { - NULL, - &age_hash - }; - - RND_BLK (&age_hash); - - for (size_t k = 0; k < sizeof(p_ah) / sizeof(p_ah[0]); k++) - { - fprintf(stdout, "OPEN\n"); - - GNUNET_assert (GNUNET_OK == - TALER_denom_blind (&dkp->pub, - &bks, - p_ah[k], - &coin_pub, - &alg_values, - &c_hash, - &pd.blinded_planchet)); - GNUNET_assert (GNUNET_OK == - TALER_coin_ev_hash (&pd.blinded_planchet, - &cbc.denom_pub_hash, - &cbc.h_coin_envelope)); - if (k != 0) - TALER_blinded_denom_sig_free (&cbc.sig); - GNUNET_assert ( - GNUNET_OK == - TALER_denom_sign_blinded ( - &cbc.sig, - &dkp->priv, - false, - &pd.blinded_planchet)); - TALER_blinded_planchet_free (&pd.blinded_planchet); - } - } - - - depos[i].deposit_fee = fees.deposit; - - RND_BLK (&depos[i].coin.coin_pub); - - TALER_denom_pub_hash (&dkp->pub, - &depos[i].coin.denom_pub_hash); - // TALER_denom_pub_hash (&dkp->pub, - // &ref.coin.denom_pub_hash); - GNUNET_assert (GNUNET_OK == - TALER_denom_sig_unblind (&depos[i].coin.denom_sig, - &cbc.sig, - &bks, - &c_hash, - &alg_values, - &dkp->pub)); - - RND_BLK (&depos[i].merchant_pub); - RND_BLK (&depos[i].csig); - RND_BLK (&depos[i].h_contract_terms); - RND_BLK (&depos[i].wire_salt); - depos[i].amount_with_fee = value; - depos[i].refund_deadline = deadline; - depos[i].wire_deadline = deadline; - depos[i].receiver_wire_account = - "payto://iban/DE67830654080004822650?receiver-name=Test"; - TALER_merchant_wire_signature_hash ( - "payto://iban/DE67830654080004822650?receiver-name=Test", - &depos[i].wire_salt, - &h_wire_wt); - depos[i].timestamp = ts; - result = 8; - { - uint64_t known_coin_id; - struct TALER_DenominationHashP dph; - struct TALER_AgeCommitmentHash agh; - FAILIF (TALER_EXCHANGEDB_CKS_ADDED != - plugin->ensure_coin_known (plugin->cls, - &depos[i].coin, - &known_coin_id, - &dph, - &agh)); - } - - /*wire + deposit for get_ready_deposit*/ - - /*STORE INTO DEPOSIT*/ + //DENOMINATION + { + //PAIR KEY LIST + new_dkp = GNUNET_new_array (MELT_NEW_COINS, + struct DenomKeyPair *); + //PUBLIC KEY LIST + new_denom_pubs = GNUNET_new_array (MELT_NEW_COINS, + struct TALER_DenominationPublicKey); + //REFRESH REVEAL COIN LIST + revealed_coins + = GNUNET_new_array (MELT_NEW_COINS, + struct TALER_EXCHANGEDB_RefreshRevealedCoin); + for (unsigned int cnt = 0; cnt < MELT_NEW_COINS; cnt++) { struct GNUNET_TIME_Timestamp now; - struct GNUNET_TIME_Timestamp r; - struct TALER_Amount deposit_fee; - struct TALER_MerchantWireHashP h_wire; + struct TALER_BlindedRsaPlanchet *rp; + struct TALER_BlindedPlanchet *bp; now = GNUNET_TIME_timestamp_get (); - FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != - plugin->insert_deposit (plugin->cls, - now, - &depos[i])); - TALER_merchant_wire_signature_hash (depos[i].receiver_wire_account, - &depos[i].wire_salt, - &h_wire); - FAILIF (1 != - plugin->have_deposit2 (plugin->cls, - &depos[i].h_contract_terms, - &h_wire, - &depos[i].coin.coin_pub, - &depos[i].merchant_pub, - depos[i].refund_deadline, - &deposit_fee, - &r)); - FAILIF (GNUNET_TIME_timestamp_cmp (now, - !=, - r)); + //5 KEY PAIR + new_dkp[cnt] = create_denom_key_pair (RSA_KEY_SIZE, + now, + &value, + &fees); + GNUNET_assert (NULL != new_dkp[cnt]); + new_denom_pubs[cnt] = new_dkp[cnt]->pub; + ccoin = &revealed_coins[cnt]; + bp = &ccoin->blinded_planchet; + bp->cipher = TALER_DENOMINATION_RSA; + rp = &bp->details.rsa_blinded_planchet; + rp->blinded_msg_size = 1 + (size_t) GNUNET_CRYPTO_random_u64 ( + GNUNET_CRYPTO_QUALITY_WEAK, + (RSA_KEY_SIZE / 8) - 1); + rp->blinded_msg = GNUNET_malloc (rp->blinded_msg_size); + GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, + rp->blinded_msg, + rp->blinded_msg_size); + TALER_denom_pub_hash (&new_dkp[cnt]->pub, + &ccoin->h_denom_pub); + ccoin->exchange_vals = alg_values; + TALER_coin_ev_hash (bp, + &ccoin->h_denom_pub, + &ccoin->coin_envelope_hash); + GNUNET_assert (GNUNET_OK == + TALER_denom_sign_blinded (&ccoin->coin_sig, + &new_dkp[cnt]->priv, + true, + bp)); + GNUNET_assert (GNUNET_OK == + TALER_coin_ev_hash (bp, + &cbc.denom_pub_hash, + &cbc.h_coin_envelope)); + GNUNET_assert ( + GNUNET_OK == + TALER_denom_sign_blinded ( + &cbc.sig, + &new_dkp[cnt]->priv, + false, + bp)); } - { - struct GNUNET_TIME_Timestamp start_range; - struct GNUNET_TIME_Timestamp end_range; + } - start_range = GNUNET_TIME_absolute_to_timestamp ( - GNUNET_TIME_absolute_subtract (deadline.abs_time, - GNUNET_TIME_UNIT_SECONDS)); - end_range = GNUNET_TIME_absolute_to_timestamp ( - GNUNET_TIME_absolute_add (deadline.abs_time, - GNUNET_TIME_UNIT_SECONDS)); - /*Aborted*/ - FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != - plugin->select_deposits_missing_wire (plugin->cls, - start_range, - end_range, - &wire_missing_cb, - &depos[i])); + perm = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_NONCE, + NUM_ROWS); + // begin + FAILIF (GNUNET_OK != + plugin->start (plugin->cls, + "Transaction")); + for (unsigned int j=0; j< NUM_ROWS; j++) + { + unsigned int i = perm[j]; + unsigned int k = (unsigned int)rand()%5; + if (i >= ROUNDS) + i = ROUNDS; /* throw-away slot, do not keep around */ + RND_BLK (&coin_pub); + RND_BLK (&c_hash); + depos[i].deposit_fee = fees.deposit; + RND_BLK (&depos[i].coin.coin_pub); + TALER_denom_pub_hash (&new_dkp[k]->pub, + &depos[i].coin.denom_pub_hash); + // TALER_denom_pub_hash (&dkp->pub, + // &ref.coin.denom_pub_hash); + GNUNET_assert (GNUNET_OK == + TALER_denom_sig_unblind (&depos[i].coin.denom_sig, + &cbc.sig, + &bks, + &c_hash, + &alg_values, + &new_dkp[k]->pub)); + RND_BLK (&depos[i].merchant_pub); + RND_BLK (&depos[i].csig); + RND_BLK (&depos[i].h_contract_terms); + RND_BLK (&depos[i].wire_salt); + depos[i].amount_with_fee = value; + depos[i].refund_deadline = deadline; + depos[i].wire_deadline = deadline; + depos[i].receiver_wire_account = + "payto://iban/DE67830654080004822650?receiver-name=Test"; + TALER_merchant_wire_signature_hash ( + "payto://iban/DE67830654080004822650?receiver-name=Test", + &depos[i].wire_salt, + &h_wire_wt); + depos[i].timestamp = ts; + uint64_t known_coin_id; + {//ENSURE_COIN_KNOWN - FAILIF (8 != result); - } - auditor_row_cnt = 0; - FAILIF (0 >= - plugin->select_deposits_above_serial_id (plugin->cls, - 0, - &audit_deposit_cb, - NULL)); - FAILIF (0 == auditor_row_cnt); - result = 8; - sleep (2); - /*CREATE DEPOSIT*/ - { - struct TALER_MerchantPublicKeyP merchant_pub2; - char *payto_uri2; - - FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != - plugin->get_ready_deposit (plugin->cls, - 0, - INT32_MAX, - &merchant_pub2, - &payto_uri2)); - FAILIF (0 != GNUNET_memcmp (&merchant_pub2, - &depos[i].merchant_pub)); - FAILIF (0 != strcmp (payto_uri2, - depos[i].receiver_wire_account)); - TALER_payto_hash (payto_uri2, - &wire_target_h_payto); - GNUNET_free (payto_uri2); - // } - /* { - RND_BLK (&ref.details.merchant_pub); - RND_BLK(&ref.details.merchant_sig); - ref.details.h_contract_terms = depos.h_contract_terms; - ref.coin.coin_pub = depos.coin.coin_pub; - ref.details.rtransaction_id = 1; - ref.details.refund_amount = value; - ref.details.refund_fee = fees.refund; - FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != - plugin->insert_refund (plugin->cls, - &ref)); - }*/ + struct TALER_DenominationHashP dph; + struct TALER_AgeCommitmentHash agh; + FAILIF (TALER_EXCHANGEDB_CKS_ADDED != + plugin->ensure_coin_known (plugin->cls, + &depos[i].coin, + &known_coin_id, + &dph, + &agh)); + } + /*STORE INTO DEPOSIT*/ + { + struct GNUNET_TIME_Timestamp now; + now = GNUNET_TIME_timestamp_get (); + FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != + plugin->insert_deposit (plugin->cls, + now, + &depos[i])); } + /* 100% Refund */ + { + bool not_found; + bool refund_ok; + bool gone; + bool conflict; + ref[i].coin = depos[i].coin; + ref[i].details.merchant_pub = depos[i].merchant_pub; + RND_BLK(&ref[i].details.merchant_sig); + ref[i].details.h_contract_terms = depos[i].h_contract_terms; + ref[i].coin.coin_pub = depos[i].coin.coin_pub; + ref[i].details.rtransaction_id = i; + ref[i].details.refund_amount = value; + ref[i].details.refund_fee = fees.refund; + FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != + plugin->do_refund (plugin->cls, + &ref[i], + &fees.deposit, + known_coin_id, + ¬_found, + &refund_ok, + &gone, + &conflict)); + + /* FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != + plugin->insert_refund (plugin->cls, + &ref[i]));*/ + } + if (ROUNDS == i) + TALER_denom_sig_free (&depos[i].coin.denom_sig); + } + /* End of benchmark setup */ + GNUNET_free (perm); + // commit + FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != + plugin->commit (plugin->cls)); + for (unsigned int r = 0; r < ROUNDS; r++) + { + struct GNUNET_TIME_Absolute time; + struct GNUNET_TIME_Relative duration; + + time = GNUNET_TIME_absolute_get (); + FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != + plugin->select_refunds_by_coin (plugin->cls, + &ref[r].coin.coin_pub, + &ref[r].details.merchant_pub, + &ref[r].details.h_contract_terms, + &check_refund_cb, + &ref[r])); + duration = GNUNET_TIME_absolute_get_duration (time); + times = GNUNET_TIME_relative_add (times, + duration); + duration_sq = duration.rel_value_us * duration.rel_value_us; + GNUNET_assert (duration_sq / duration.rel_value_us == duration.rel_value_us); + GNUNET_assert (sqrs + duration_sq >= sqrs); + sqrs += duration_sq; + } + /* evaluation of performance */ + { + struct GNUNET_TIME_Relative avg; + double avg_dbl; + double variance; + + avg = GNUNET_TIME_relative_divide (times, + ROUNDS); + avg_dbl = avg.rel_value_us; + variance = sqrs - (avg_dbl * avg_dbl * ROUNDS); + fprintf(stdout, + "%8llu ± %6.0f\n", + (unsigned long long) avg.rel_value_us, + sqrt (variance / (ROUNDS-1))); + } result = 0; drop: GNUNET_break (GNUNET_OK == @@ -547,11 +480,28 @@ drop: cleanup: if (NULL != dkp) destroy_denom_key_pair (dkp); - // for (unsigned int i=0; i