From 54fa07f5c7be025ee1a241deabe4a5dbcca61599 Mon Sep 17 00:00:00 2001 From: Joseph Date: Mon, 23 Jan 2023 07:57:34 -0500 Subject: tests for refunds_by_coin and ready_deposit --- src/exchangedb/Makefile.am | 10 +- src/exchangedb/exchange_do_get_ready_deposit.sql | 64 +++ src/exchangedb/exchange_do_refund_by_coin.sql | 94 ++++ src/exchangedb/pg_get_ready_deposit.c | 193 ++++++- src/exchangedb/pg_select_refunds_by_coin.c | 196 ++++++- src/exchangedb/procedures.sql.in | 2 + .../test_exchangedb_populate_link_data.c | 29 +- .../test_exchangedb_populate_ready_deposit.c | 39 +- ...st_exchangedb_populate_select_refunds_by_coin.c | 602 +++++++++++++++++++++ src/exchangedb/test_exchangedb_populate_table.c | 559 ------------------- 10 files changed, 1139 insertions(+), 649 deletions(-) create mode 100644 src/exchangedb/exchange_do_get_ready_deposit.sql create mode 100644 src/exchangedb/exchange_do_refund_by_coin.sql create mode 100644 src/exchangedb/test_exchangedb_populate_select_refunds_by_coin.c delete mode 100644 src/exchangedb/test_exchangedb_populate_table.c (limited to 'src') diff --git a/src/exchangedb/Makefile.am b/src/exchangedb/Makefile.am index feeb09cd..2ae5fe42 100644 --- a/src/exchangedb/Makefile.am +++ b/src/exchangedb/Makefile.am @@ -296,7 +296,7 @@ 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-select-refunds-by-coin-postgres\ test-exchangedb-populate-link-data-postgres\ test-exchangedb-populate-ready-deposit-postgres @@ -306,7 +306,7 @@ 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-select-refunds-by-coin-postgres\ test-exchangedb-populate-link-data-postgres\ test-exchangedb-populate-ready-deposit-postgres test_exchangedb_postgres_SOURCES = \ @@ -369,9 +369,9 @@ test_exchangedb_batch_reserves_in_insert_postgres_LDADD = \ -lgnunetutil \ $(XLIB) -test_exchangedb_populate_table_postgres_SOURCES = \ - test_exchangedb_populate_table.c -test_exchangedb_populate_table_postgres_LDADD = \ +test_exchangedb_populate_select_refunds_by_coin_postgres_SOURCES = \ + test_exchangedb_populate_select_refunds_by_coin.c +test_exchangedb_populate_select_refunds_by_coin_postgres_LDADD = \ libtalerexchangedb.la \ $(top_builddir)/src/json/libtalerjson.la \ $(top_builddir)/src/util/libtalerutil.la \ diff --git a/src/exchangedb/exchange_do_get_ready_deposit.sql b/src/exchangedb/exchange_do_get_ready_deposit.sql new file mode 100644 index 00000000..b887571e --- /dev/null +++ b/src/exchangedb/exchange_do_get_ready_deposit.sql @@ -0,0 +1,64 @@ +-- +-- 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 +-- +CREATE OR REPLACE FUNCTION exchange_do_get_ready_deposit( + IN in_now INT8, + IN in_start_shard_now INT8, + IN in_end_shard_now INT8, + OUT out_payto_uri VARCHAR, + OUT out_merchant_pub BYTEA +) +LANGUAGE plpgsql +AS $$ +DECLARE + var_wire_target_h_payto BYTEA; +DECLARE + var_coin_pub BYTEA; +DECLARE + var_deposit_serial_id INT8; +BEGIN + +SELECT + coin_pub + ,deposit_serial_id + INTO + var_coin_pub + ,var_deposit_serial_id + FROM deposits_by_ready + WHERE wire_deadline <= in_now + AND shard >= in_start_shard_now + AND shard <=in_end_shard_now + ORDER BY + wire_deadline ASC + ,shard ASC; + +SELECT + merchant_pub + ,wire_target_h_payto + INTO + out_merchant_pub + ,var_wire_target_h_payto + FROM deposits + WHERE coin_pub=var_coin_pub + AND deposit_serial_id=var_deposit_serial_id; + +SELECT + payto_uri + INTO out_payto_uri + FROM wire_targets + WHERE wire_target_h_payto=var_wire_target_h_payto; + +RETURN; +END $$; diff --git a/src/exchangedb/exchange_do_refund_by_coin.sql b/src/exchangedb/exchange_do_refund_by_coin.sql new file mode 100644 index 00000000..ee00e2b5 --- /dev/null +++ b/src/exchangedb/exchange_do_refund_by_coin.sql @@ -0,0 +1,94 @@ +-- +-- 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 +-- +/*DROP FUNCTION exchange_do_refund_by_coin( + IN in_coin_pub BYTEA, + IN in_merchant_pub BYTEA, + IN in_h_contract BYTEA +);*/ +CREATE OR REPLACE FUNCTION exchange_do_refund_by_coin( + IN in_coin_pub BYTEA, + IN in_merchant_pub BYTEA, + IN in_h_contract BYTEA +) +RETURNS SETOF record +LANGUAGE plpgsql +AS $$ +DECLARE + curs CURSOR + FOR + SELECT + amount_with_fee_val + ,amount_with_fee_frac + ,deposit_serial_id + FROM refunds + WHERE coin_pub=in_coin_pub; +DECLARE + i RECORD; +BEGIN +OPEN curs; +LOOP + FETCH NEXT FROM curs INTO i; + EXIT WHEN NOT FOUND; + RETURN QUERY + SELECT + i.amount_with_fee_val + ,i.amount_with_fee_frac + FROM deposits + WHERE + coin_pub=in_coin_pub + AND merchant_pub=in_merchant_pub + AND h_contract_terms=in_h_contract + AND i.deposit_serial_id = deposit_serial_id; +END LOOP; +CLOSE curs; +END $$; + +/*RETURNS TABLE(amount_with_fee_val INT8, amount_with_fee_frac INT4) +LANGUAGE plpgsql +AS $$ +DECLARE + curs CURSOR + FOR + SELECT + r.amount_with_fee_val + ,r.amount_with_fee_frac + ,r.deposit_serial_id + FROM refunds r + WHERE r.coin_pub=in_coin_pub; +DECLARE + i RECORD; +BEGIN +OPEN curs; +LOOP + FETCH NEXT FROM curs INTO i; + IF FOUND + THEN + RETURN QUERY + SELECT + i.amount_with_fee_val + ,i.amount_with_fee_frac + FROM deposits + WHERE + merchant_pub=in_merchant_pub + AND h_contract_terms=in_h_contract + AND i.deposit_serial_id = deposit_serial_id; + END IF; + EXIT WHEN NOT FOUND; +END LOOP; +CLOSE curs; + +END $$; +*/ diff --git a/src/exchangedb/pg_get_ready_deposit.c b/src/exchangedb/pg_get_ready_deposit.c index af123529..73ac9e47 100644 --- a/src/exchangedb/pg_get_ready_deposit.c +++ b/src/exchangedb/pg_get_ready_deposit.c @@ -41,6 +41,7 @@ TEH_PG_get_ready_deposit (void *cls, GNUNET_PQ_query_param_uint64 (&end_shard_row), GNUNET_PQ_query_param_end }; + struct GNUNET_PQ_ResultSpec rs[] = { GNUNET_PQ_result_spec_auto_from_type ("merchant_pub", merchant_pub), @@ -57,26 +58,180 @@ TEH_PG_get_ready_deposit (void *cls, "Finding ready deposits by deadline %s (%llu)\n", GNUNET_TIME_absolute2s (now), (unsigned long long) now.abs_value_us); - PREPARE (pg, - "deposits_get_ready", - "SELECT" - " payto_uri" - ",merchant_pub" - " FROM deposits_by_ready dbr" - " JOIN deposits dep" - " ON (dbr.coin_pub = dep.coin_pub AND" - " dbr.deposit_serial_id = dep.deposit_serial_id)" - " JOIN wire_targets wt" - " USING (wire_target_h_payto)" - " WHERE dbr.wire_deadline<=$1" - " AND dbr.shard >= $2" - " AND dbr.shard <= $3" - " ORDER BY " - " dbr.wire_deadline ASC" - " ,dbr.shard ASC" - " LIMIT 1;"); + int choose_mode =-2; + const char *query; + + if (-2 == choose_mode) + { + const char *mode = getenv ("NEW_LOGIC"); + char dummy; + if ( (NULL==mode) || + (1 != sscanf (mode, + "%d%c", + &choose_mode, + &dummy)) ) + { + if (NULL != mode) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Bad mode `%s' specified\n", + mode); + } + if (NULL==mode) + choose_mode=0; + + + } + switch (choose_mode) + { + case 0: + query="deposits_get_ready"; + PREPARE (pg, + query, + "SELECT" + " payto_uri" + ",merchant_pub" + " FROM deposits_by_ready dbr" + " JOIN deposits dep" + " ON (dbr.coin_pub = dep.coin_pub AND" + " dbr.deposit_serial_id = dep.deposit_serial_id)" + " JOIN wire_targets wt" + " USING (wire_target_h_payto)" + " WHERE dbr.wire_deadline<=$1" + " AND dbr.shard >= $2" + " AND dbr.shard <= $3" + " ORDER BY " + " dbr.wire_deadline ASC" + " ,dbr.shard ASC" + " LIMIT 1;"); + break; + case 1: + query="deposits_get_ready_v1"; + PREPARE (pg, + query, + "WITH rc AS MATERIALIZED (" + " SELECT" + " coin_pub" + ",deposit_serial_id" + " FROM deposits_by_ready" + " WHERE" + " wire_deadline<=$1" + " AND shard >= $2" + " AND shard <= $3" + " ORDER BY " + " wire_deadline ASC" + " ,shard ASC" + " LIMIT 1" + ")" + "SELECT" + " wt.payto_uri" + ",dep.merchant_pub" + " FROM (" + " SELECT" + " wire_target_h_payto" + ",merchant_pub" + " FROM deposits" + " WHERE coin_pub=(SELECT coin_pub FROM rc)" + " AND deposit_serial_id=(SELECT deposit_serial_id FROM rc)" + ") dep" + " JOIN wire_targets wt" + " ON (dep.wire_target_h_payto = wt.wire_target_h_payto)" + ); + + break; + case 2: + query = "stored_procedure_get_ready_deposit"; + PREPARE (pg, + query, + "SELECT" + " out_payto_uri AS payto_uri" + ",out_merchant_pub AS merchant_pub" + " FROM" + " exchange_do_get_ready_deposit" + " ($1, $2, $3) "); + break; + case 3: + query="deposits_get_ready_v3"; + PREPARE (pg, + query, + "WITH rc AS MATERIALIZED (" + " SELECT" + " coin_pub" + ",deposit_serial_id" + " FROM deposits_by_ready" + " WHERE" + " wire_deadline<=$1" + " AND shard >= $2" + " AND shard <= $3" + " ORDER BY " + " wire_deadline ASC" + " ,shard ASC" + " LIMIT 1" + ")" + "SELECT" + " wt.payto_uri" + ",dep.merchant_pub" + " FROM (" + " SELECT" + " wire_target_h_payto" + ",merchant_pub" + ",coin_pub" + " FROM deposits" + " WHERE coin_pub=(SELECT coin_pub FROM rc)" + " AND deposit_serial_id=(SELECT deposit_serial_id FROM rc)" + ") dep" + " JOIN wire_targets wt" + " ON (dep.wire_target_h_payto = wt.wire_target_h_payto)" + " JOIN rc" + " ON (dep.coin_pub=rc.coin_pub)" + ); + + break; + case 4: + query="deposits_get_ready_v4"; + PREPARE (pg, + query, + "WITH rc AS MATERIALIZED (" + " SELECT" + " coin_pub" + ",deposit_serial_id" + " FROM deposits_by_ready" + " WHERE" + " wire_deadline<=$1" + " AND shard >= $2" + " AND shard <= $3" + " ORDER BY " + " wire_deadline ASC" + " ,shard ASC" + " LIMIT 1" + ")," + "WITH rv AS MATERIALIZED (" + " SELECT" + " payto_uri" + ",wire_target_h_payto" + " FROM wire_targets" + ")" + "SELECT" + " rv.payto_uri" + ",dep.merchant_pub" + " FROM (" + " SELECT" + " wire_target_h_payto" + ",merchant_pub" + " FROM deposits" + " WHERE coin_pub=(SELECT coin_pub FROM rc)" + " AND deposit_serial_id=(SELECT deposit_serial_id FROM rc)" + ") dep" + " JOIN rv" + " ON (rv.wire_target_h_payto=dep.wire_target_h_payto)" + ); + break; + default: + GNUNET_break (0); + return GNUNET_DB_STATUS_HARD_ERROR; + } + return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "deposits_get_ready", + query, params, rs); } diff --git a/src/exchangedb/pg_select_refunds_by_coin.c b/src/exchangedb/pg_select_refunds_by_coin.c index b9db2b70..255cac34 100644 --- a/src/exchangedb/pg_select_refunds_by_coin.c +++ b/src/exchangedb/pg_select_refunds_by_coin.c @@ -112,17 +112,47 @@ TEH_PG_select_refunds_by_coin ( GNUNET_PQ_query_param_auto_from_type (h_contract), GNUNET_PQ_query_param_end }; + struct GNUNET_PQ_QueryParam params5[] = { + GNUNET_PQ_query_param_auto_from_type (coin_pub), + GNUNET_PQ_query_param_end + }; + struct SelectRefundContext srctx = { .cb = cb, .cb_cls = cb_cls, .pg = pg, .status = GNUNET_OK }; + static int percent_refund = -2; + const char *query; + struct GNUNET_PQ_QueryParam *xparams = params; - if (NULL == getenv ("NEW_LOGIC")) + if (-2 == percent_refund) { + const char *mode = getenv ("NEW_LOGIC"); + char dummy; + + if ( (NULL==mode) || + (1 != sscanf (mode, + "%d%c", + &percent_refund, + &dummy)) ) + { + if (NULL != mode) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Bad mode `%s' specified\n", + mode); + } + if (NULL==mode) + percent_refund=0; + } + + switch (percent_refund) + { + case 0: + query = "get_refunds_by_coin_and_contract-v0"; PREPARE (pg, - "get_refunds_by_coin_and_contract", + query, "SELECT" " ref.amount_with_fee_val" ",ref.amount_with_fee_frac" @@ -132,12 +162,26 @@ TEH_PG_select_refunds_by_coin ( " WHERE ref.coin_pub=$1" " AND dep.merchant_pub=$2" " AND dep.h_contract_terms=$3;"); - } - else - { - // FIXME-Joseph + break; + case 1: + query = "get_refunds_by_coin_and_contract-v1"; + PREPARE (pg, + query, + "SELECT" + " ref.amount_with_fee_val" + ",ref.amount_with_fee_frac" + " FROM refunds ref" + " LEFT JOIN deposits dep" + " ON dep.coin_pub = ref.coin_pub" + " AND ref.deposit_serial_id = dep.deposit_serial_id" + " WHERE ref.coin_pub=$1" + " AND dep.merchant_pub=$2" + " AND dep.h_contract_terms=$3;"); + break; + case 2: + query = "get_refunds_by_coin_and_contract-v2"; PREPARE (pg, - "get_refunds_by_coin_and_contract", + query, "WITH rc AS MATERIALIZED(" "SELECT" " amount_with_fee_val" @@ -149,21 +193,139 @@ TEH_PG_select_refunds_by_coin ( "SELECT" " 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" + " JOIN rc" + " ON rc.deposit_serial_id = dep.deposit_serial_id" " WHERE" - " dep.coin_pub = $1" // optional... + " dep.coin_pub = $1" " AND dep.merchant_pub = $2" - " AND dep.h_contract_terms = $3) dep" - " JOIN rc" - " USING (coin_pub,deposit_serial_id)"); + " AND dep.h_contract_terms = $3"); + break; + case 3: + query = "get_refunds_by_coin_and_contract-v3"; + PREPARE (pg, + query, + "WITH rc AS MATERIALIZED(" + "SELECT" + " amount_with_fee_val" + ",amount_with_fee_frac" + ",deposit_serial_id" + " FROM refunds" + " WHERE coin_pub=$1)" + "SELECT" + " rc.amount_with_fee_val" + " ,rc.amount_with_fee_frac" + " FROM (" + "SELECT" + " amount_with_fee_val" + ",amount_with_fee_frac" + " FROM deposits depos" + " WHERE" + " depos.coin_pub = $1" + " AND depos.merchant_pub = $2" + " AND depos.h_contract_terms = $3) dep, rc;"); + break; + case 4: + query = "get_refunds_by_coin_and_contract-v4"; + PREPARE (pg, + query, + "WITH rc AS MATERIALIZED(" + "SELECT" + " amount_with_fee_val" + ",amount_with_fee_frac" + ",coin_pub" + ",deposit_serial_id" + " FROM refunds ref" + " WHERE ref.coin_pub=$1)" + "SELECT" + " rc.amount_with_fee_val" + " ,rc.amount_with_fee_frac" + " ,deposit_serial_id" + " FROM (" + "SELECT" + " amount_with_fee_val" + ",amount_with_fee_frac" + " FROM deposits depos" + " WHERE" + " depos.merchant_pub = $2" + " AND depos.h_contract_terms = $3) dep JOIN rc " + "USING(deposit_serial_id, coin_pub);"); + break; + case 5: + query = "get_refunds_by_coin_and_contract-v-broken"; + xparams = params5; + PREPARE (pg, + query, + "SELECT" + " amount_with_fee_val" + ",amount_with_fee_frac" + ",coin_pub" + ",deposit_serial_id" + " FROM refunds" + " WHERE coin_pub=$1;"); + break; + case 8: + query = "get_refunds_by_coin_and_contract-v8"; + PREPARE (pg, + query, + "WITH" + " rc AS MATERIALIZED(" + " SELECT" + " amount_with_fee_val" + " ,amount_with_fee_frac" + " ,coin_pub" + " ,deposit_serial_id" + " FROM refunds" + " WHERE coin_pub=$1)," + " dep AS MATERIALIZED(" + " SELECT" + " deposit_serial_id" + " FROM deposits" + " WHERE coin_pub = $1" + " AND merchant_pub = $2" + " AND h_contract_terms = $3" + ")" + "SELECT" + " rc.amount_with_fee_val" + " ,rc.amount_with_fee_frac" + " FROM " + " rc JOIN dep USING (deposit_serial_id);"); + break; + case 9: + query = "get_refunds_by_coin_and_contract-v9-broken"; + PREPARE (pg, + query, + "SELECT" + " ref.amount_with_fee_val" + " ,ref.amount_with_fee_frac" + " FROM deposits dep" + " JOIN refunds ref USING(deposit_serial_id)" + " WHERE dep.coin_pub IN (" + " SELECT coin_pub" + " FROM refunds" + " WHERE coin_pub=$1)" + " AND merchant_pub = $2" + " AND h_contract_terms = $3;"); + break; + case 10: + query = "get_refunds_by_coin_and_contract-v10-broken"; + PREPARE (pg, + query, + "SELECT" + " *" + " FROM" + " exchange_do_refund_by_coin" + " ($1, $2, $3) " + " AS (amount_with_fee_val INT8, amount_with_fee_frac INT4);"); + break; + default: + GNUNET_break (0); + return GNUNET_DB_STATUS_HARD_ERROR; } + qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn, - "get_refunds_by_coin_and_contract", - params, + query, + xparams, &get_refunds_cb, &srctx); if (GNUNET_SYSERR == srctx.status) diff --git a/src/exchangedb/procedures.sql.in b/src/exchangedb/procedures.sql.in index 73b75af2..ef6341a1 100644 --- a/src/exchangedb/procedures.sql.in +++ b/src/exchangedb/procedures.sql.in @@ -44,5 +44,7 @@ SET search_path TO exchange; #include "exchange_do_batch2_reserves_in_insert.sql" #include "exchange_do_batch4_reserves_in_insert.sql" #include "exchange_do_batch8_reserves_in_insert.sql" +#include "exchange_do_refund_by_coin.sql" +#include "exchange_do_get_ready_deposit.sql" COMMIT; diff --git a/src/exchangedb/test_exchangedb_populate_link_data.c b/src/exchangedb/test_exchangedb_populate_link_data.c index ff294874..1323f3b3 100644 --- a/src/exchangedb/test_exchangedb_populate_link_data.c +++ b/src/exchangedb/test_exchangedb_populate_link_data.c @@ -24,14 +24,6 @@ #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". */ @@ -55,22 +47,10 @@ static int result; #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 NUM_ROWS 1000 #define MELT_NEW_COINS 5 #define MELT_NOREVEAL_INDEX 1 /** @@ -82,7 +62,10 @@ static struct TALER_DenomFeeSet fees; * Denomination keys used for fresh coins in melt test. */ static struct DenomKeyPair **new_dkp; - +static int result; +static struct TALER_EXCHANGEDB_RefreshRevealedCoin *revealed_coins; +static struct TALER_TransferPrivateKeyP tprivs[TALER_CNC_KAPPA]; +static struct TALER_TransferPublicKeyP tpub; struct DenomKeyPair { struct TALER_DenominationPrivateKey priv; @@ -222,8 +205,6 @@ handle_link_data_cb (void *cls, } } - - /** * Main function that will be run by the scheduler. * diff --git a/src/exchangedb/test_exchangedb_populate_ready_deposit.c b/src/exchangedb/test_exchangedb_populate_ready_deposit.c index 49b1bf5d..97273fc9 100644 --- a/src/exchangedb/test_exchangedb_populate_ready_deposit.c +++ b/src/exchangedb/test_exchangedb_populate_ready_deposit.c @@ -24,9 +24,6 @@ #include "taler_exchangedb_plugin.h" #include "math.h" - -#define NUM_ROWS 1000 - /** * Global result from the testcase. */ @@ -55,20 +52,13 @@ static int result; #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 NUM_ROWS 1000000 +#define ROUNDS 10000 #define MELT_NEW_COINS 5 #define MELT_NOREVEAL_INDEX 1 /** @@ -81,7 +71,7 @@ static struct TALER_MerchantWireHashP h_wire_wt; * Denomination keys used for fresh coins in melt test. */ static struct DenomKeyPair **new_dkp; - +static struct TALER_EXCHANGEDB_RefreshRevealedCoin *revealed_coins; struct DenomKeyPair { struct TALER_DenominationPrivateKey priv; @@ -389,7 +379,6 @@ run (void *cls) &nonce_ok, &ruuid)); } - { /* ENSURE_COIN_KNOWN */ uint64_t known_coin_id; @@ -408,23 +397,23 @@ run (void *cls) 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); + { + 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 ****/ + /**** CALL GET READY DEPOSIT ****/ for (unsigned int r=0; r< ROUNDS; r++) { struct GNUNET_TIME_Absolute time; diff --git a/src/exchangedb/test_exchangedb_populate_select_refunds_by_coin.c b/src/exchangedb/test_exchangedb_populate_select_refunds_by_coin.c new file mode 100644 index 00000000..c094b204 --- /dev/null +++ b/src/exchangedb/test_exchangedb_populate_select_refunds_by_coin.c @@ -0,0 +1,602 @@ +/* + 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_table.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" + +/** + * 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" +#define RSA_KEY_SIZE 1024 +#define ROUNDS 10000 +#define NUM_ROWS 1000000 +#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; +static struct DenomKeyPair **new_dkp; +static struct TALER_EXCHANGEDB_RefreshRevealedCoin *revealed_coins; +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; +} +/** + * Callback invoked with information about refunds applicable + * to a particular coin. + * + * @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 +check_refund_cb (void *cls, + const struct TALER_Amount *amount_with_fee) +{ + 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; +} + + +/** + * Main function that will be run by the scheduler. + * + * @param cls closure with config + */ + +static void +run (void *cls) +{ + struct GNUNET_CONFIGURATION_Handle *cfg = cls; + const uint32_t num_partitions = 10; + struct GNUNET_TIME_Timestamp ts; + 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_ExchangeWithdrawValues alg_values = { + .cipher = TALER_DENOMINATION_RSA + }; + 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; + unsigned int count=0; + + ref = GNUNET_new_array (ROUNDS +1, + struct TALER_EXCHANGEDB_Refund); + depos = GNUNET_new_array (ROUNDS +1, + struct TALER_EXCHANGEDB_Deposit); + ZR_BLK (&cbc); + + 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)); + GNUNET_assert (NUM_ROWS >= ROUNDS); + + ts = GNUNET_TIME_timestamp_get (); + deadline = GNUNET_TIME_timestamp_get (); + //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)); + 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++) + { + 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 + + 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])); + } + { + bool not_found; + bool refund_ok; + bool gone; + bool conflict; + unsigned int refund_percent=0; + switch (refund_percent){ + case 2 ://100% refund + 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)); + break; + case 1 ://10% refund + if (count < (NUM_ROWS/10)) + { + 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; + } + else + { + ref[i].coin = depos[i].coin; + RND_BLK(&ref[i].details.merchant_pub); + RND_BLK(&ref[i].details.merchant_sig); + RND_BLK(&ref[i].details.h_contract_terms); + RND_BLK(&ref[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)); + count++; + break; + case 0://no refund + ref[i].coin=depos[i].coin; + RND_BLK(&ref[i].details.merchant_pub); + RND_BLK(&ref[i].details.merchant_sig); + RND_BLK(&ref[i].details.h_contract_terms); + RND_BLK(&ref[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)); + break; + }/* END OF SWITCH CASE */ + } + 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 (0 > + 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 == + 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 +1 ; 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 deleted file mode 100644 index face454f..00000000 --- a/src/exchangedb/test_exchangedb_populate_table.c +++ /dev/null @@ -1,559 +0,0 @@ -/* - 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_table.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 10000 - -/** - * 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 -#define ROUNDS 1000 -#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; - -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. - * - * @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; -} -/** - * Callback invoked with information about refunds applicable - * to a particular coin. - * - * @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 -check_refund_cb (void *cls, - const struct TALER_Amount *amount_with_fee) -{ - 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; -} - - -/** - * Main function that will be run by the scheduler. - * - * @param cls closure with config - */ - -static void -run (void *cls) -{ - struct GNUNET_CONFIGURATION_Handle *cfg = cls; - const uint32_t num_partitions = 10; - struct DenomKeyPair *dkp = NULL; - struct GNUNET_TIME_Timestamp ts; - 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_ExchangeWithdrawValues alg_values = { - .cipher = TALER_DENOMINATION_RSA - }; - 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); - - 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)); - GNUNET_assert (NUM_ROWS >= ROUNDS); - - ts = GNUNET_TIME_timestamp_get (); - deadline = GNUNET_TIME_timestamp_get (); - //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)); - 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++) - { - 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 - - 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 == - 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 +1 ; i++) - { - TALER_denom_sig_free (&depos[i].coin.denom_sig); - } - GNUNET_free(depos); - GNUNET_free(ref); - 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 */ -- cgit v1.2.3