From ab03ba16e9bc63eb5384e7b6b590fc029bf61152 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sun, 5 Feb 2023 19:11:47 +0100 Subject: exchangedb: use partial index instead of materialized tables deposits_by_ready and deposits_by_matching; remove now broken code; rename benchmarks to use perf_-prefix and correspond to function they benchmark --- src/exchange/taler-exchange-wirewatch.c | 422 +-------- src/exchangedb/.gitignore | 16 +- src/exchangedb/0002-deposits.sql | 46 +- src/exchangedb/Makefile.am | 71 +- src/exchangedb/perf_deposits_get_ready.c | 533 +++++++++++ .../perf_exchangedb_reserves_in_insert.c | 193 ---- src/exchangedb/perf_get_link_data.c | 536 +++++++++++ src/exchangedb/perf_reserves_in_insert.c | 231 +++++ src/exchangedb/perf_select_refunds_by_coin.c | 602 ++++++++++++ src/exchangedb/pg_aggregate.c | 22 +- src/exchangedb/pg_batch2_reserves_in_insert.c | 914 ------------------ src/exchangedb/pg_batch2_reserves_in_insert.h | 34 - src/exchangedb/pg_batch4_reserves_in_insert.c | 595 ------------ src/exchangedb/pg_batch_reserves_in_insert.c | 252 ----- src/exchangedb/pg_batch_reserves_in_insert.h | 35 - src/exchangedb/pg_get_link_data.c | 26 +- src/exchangedb/pg_get_ready_deposit.c | 180 +--- src/exchangedb/pg_reserves_in_insert.c | 1000 ++++++++++++++++---- src/exchangedb/pg_reserves_in_insert.h | 30 +- src/exchangedb/pg_select_refunds_by_coin.c | 17 +- src/exchangedb/plugin_exchangedb_postgres.c | 6 - .../test_exchangedb_batch_reserves_in_insert.c | 196 ---- .../test_exchangedb_populate_link_data.c | 534 ----------- .../test_exchangedb_populate_ready_deposit.c | 535 ----------- ...st_exchangedb_populate_select_refunds_by_coin.c | 602 ------------ src/include/taler_exchangedb_plugin.h | 49 +- 26 files changed, 2842 insertions(+), 4835 deletions(-) create mode 100644 src/exchangedb/perf_deposits_get_ready.c delete mode 100644 src/exchangedb/perf_exchangedb_reserves_in_insert.c create mode 100644 src/exchangedb/perf_get_link_data.c create mode 100644 src/exchangedb/perf_reserves_in_insert.c create mode 100644 src/exchangedb/perf_select_refunds_by_coin.c delete mode 100644 src/exchangedb/pg_batch2_reserves_in_insert.c delete mode 100644 src/exchangedb/pg_batch2_reserves_in_insert.h delete mode 100644 src/exchangedb/pg_batch4_reserves_in_insert.c delete mode 100644 src/exchangedb/pg_batch_reserves_in_insert.c delete mode 100644 src/exchangedb/pg_batch_reserves_in_insert.h delete mode 100644 src/exchangedb/test_exchangedb_batch_reserves_in_insert.c delete mode 100644 src/exchangedb/test_exchangedb_populate_link_data.c delete mode 100644 src/exchangedb/test_exchangedb_populate_ready_deposit.c delete mode 100644 src/exchangedb/test_exchangedb_populate_select_refunds_by_coin.c diff --git a/src/exchange/taler-exchange-wirewatch.c b/src/exchange/taler-exchange-wirewatch.c index a1a3a4ff2..a7a6b004f 100644 --- a/src/exchange/taler-exchange-wirewatch.c +++ b/src/exchange/taler-exchange-wirewatch.c @@ -491,389 +491,6 @@ transaction_completed (void) } -/** - * We got incoming transaction details from the bank. Add them - * to the database. - * - * @param details array of transaction details - * @param details_length length of the @a details array - */ -static void -process_reply (const struct TALER_BANK_CreditDetails *details, - unsigned int details_length) -{ - enum GNUNET_DB_QueryStatus qs; - bool shard_done; - uint64_t lroff = latest_row_off; - - if (0 == details_length) - { - /* Server should have used 204, not 200! */ - GNUNET_break_op (0); - transaction_completed (); - return; - } - hh_returned_data = true; - /* check serial IDs for range constraints */ - for (unsigned int i = 0; iserial_id < lroff) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Serial ID %llu not monotonic (got %llu before). Failing!\n", - (unsigned long long) cd->serial_id, - (unsigned long long) lroff); - db_plugin->rollback (db_plugin->cls); - GNUNET_SCHEDULER_shutdown (); - return; - } - if (cd->serial_id > shard_end) - { - /* we are *past* the current shard (likely because the serial_id of the - shard_end happens to not exist in the DB). So commit and stop this - iteration! */ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Serial ID %llu past shard end at %llu, ending iteration early!\n", - (unsigned long long) cd->serial_id, - (unsigned long long) shard_end); - details_length = i; - progress = true; - lroff = cd->serial_id - 1; - break; - } - lroff = cd->serial_id; - } - if (GNUNET_OK != - db_plugin->start_read_committed (db_plugin->cls, - "wirewatch check for incoming wire transfers")) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to start database transaction!\n"); - global_ret = EXIT_FAILURE; - GNUNET_SCHEDULER_shutdown (); - return; - } - started_transaction = true; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Importing %u transactions\n", - details_length); - for (unsigned int i = 0; ireserves_in_insert (db_plugin->cls, - &cd->reserve_pub, - &cd->amount, - cd->execution_date, - cd->debit_account_uri, - ai->section_name, - cd->serial_id); - switch (qs) - { - case GNUNET_DB_STATUS_HARD_ERROR: - GNUNET_break (0); - GNUNET_SCHEDULER_shutdown (); - return; - case GNUNET_DB_STATUS_SOFT_ERROR: - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Got DB soft error for reserves_in_insert. Rolling back.\n"); - handle_soft_error (); - return; - case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - /* Either wirewatch was freshly started after the system was - shutdown and we're going over an incomplete shard again - after being restarted, or the shard lock period was too - short (number of workers set incorrectly?) and a 2nd - wirewatcher has been stealing our work while we are still - at it. */ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Attempted to import transaction %llu (%s) twice. " - "This should happen rarely (if not, ask for support).\n", - (unsigned long long) cd->serial_id, - job_name); - break; - case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Imported transaction %llu.", - (unsigned long long) cd->serial_id); - /* normal case */ - progress = true; - break; - } - } - latest_row_off = lroff; - shard_done = (shard_end <= latest_row_off); - if (shard_done) - { - /* shard is complete, mark this as well */ - qs = db_plugin->complete_shard (db_plugin->cls, - job_name, - shard_start, - shard_end); - switch (qs) - { - case GNUNET_DB_STATUS_HARD_ERROR: - GNUNET_break (0); - GNUNET_SCHEDULER_shutdown (); - return; - case GNUNET_DB_STATUS_SOFT_ERROR: - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Got DB soft error for complete_shard. Rolling back.\n"); - handle_soft_error (); - return; - case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - GNUNET_break (0); - /* Not expected, but let's just continue */ - break; - case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: - /* normal case */ - progress = true; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Completed shard %s (%llu,%llu] after %s\n", - job_name, - (unsigned long long) shard_start, - (unsigned long long) shard_end, - GNUNET_STRINGS_relative_time_to_string ( - GNUNET_TIME_absolute_get_duration (shard_start_time), - true)); - break; - } - } - if (! progress) - { - db_plugin->rollback (db_plugin->cls); - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Committing %s progress (%llu,%llu] at %llu\n (%s)", - job_name, - (unsigned long long) shard_start, - (unsigned long long) shard_end, - (unsigned long long) latest_row_off, - shard_done - ? "shard done" - : "shard incomplete"); - qs = db_plugin->commit (db_plugin->cls); - switch (qs) - { - case GNUNET_DB_STATUS_HARD_ERROR: - GNUNET_break (0); - GNUNET_SCHEDULER_shutdown (); - return; - case GNUNET_DB_STATUS_SOFT_ERROR: - /* reduce transaction size to reduce rollback probability */ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Got DB soft error on commit. Reducing transaction size.\n"); - handle_soft_error (); - return; - case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: - started_transaction = false; - /* normal case */ - break; - } - } - if (shard_done) - { - shard_delay = GNUNET_TIME_absolute_get_duration (shard_start_time); - shard_open = false; - transaction_completed (); - return; - } - GNUNET_assert (NULL == task); - task = GNUNET_SCHEDULER_add_now (&continue_with_shard, - NULL); -} - - -/** - * We got incoming transaction details from the bank. Add them - * to the database. - * - * @param details array of transaction details - * @param details_length length of the @a details array - */ -static void -process_reply_batched (const struct TALER_BANK_CreditDetails *details, - unsigned int details_length) -{ - enum GNUNET_DB_QueryStatus qs; - bool shard_done; - uint64_t lroff = latest_row_off; - - if (0 == details_length) - { - /* Server should have used 204, not 200! */ - GNUNET_break_op (0); - transaction_completed (); - return; - } - /* check serial IDs for range constraints */ - for (unsigned int i = 0; iserial_id < lroff) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Serial ID %llu not monotonic (got %llu before). Failing!\n", - (unsigned long long) cd->serial_id, - (unsigned long long) lroff); - db_plugin->rollback (db_plugin->cls); - GNUNET_SCHEDULER_shutdown (); - return; - } - if (cd->serial_id > shard_end) - { - /* we are *past* the current shard (likely because the serial_id of the - shard_end happens to not exist in the DB). So commit and stop this - iteration! */ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Serial ID %llu past shard end at %llu, ending iteration early!\n", - (unsigned long long) cd->serial_id, - (unsigned long long) shard_end); - details_length = i; - progress = true; - lroff = cd->serial_id - 1; - break; - } - lroff = cd->serial_id; - } - if (0 != details_length) - { - enum GNUNET_DB_QueryStatus qss[details_length]; - struct TALER_EXCHANGEDB_ReserveInInfo reserves[details_length]; - - hh_returned_data = true; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Importing %u transactions\n", - details_length); - for (unsigned int i = 0; ireserve_pub = &cd->reserve_pub; - res->balance = &cd->amount; - res->execution_time = cd->execution_date; - res->sender_account_details = cd->debit_account_uri; - res->exchange_account_name = ai->section_name; - res->wire_reference = cd->serial_id; - } - qs = db_plugin->batch_reserves_in_insert (db_plugin->cls, - reserves, - details_length, - qss); - switch (qs) - { - case GNUNET_DB_STATUS_HARD_ERROR: - GNUNET_break (0); - GNUNET_SCHEDULER_shutdown (); - return; - case GNUNET_DB_STATUS_SOFT_ERROR: - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Got DB soft error for batch_reserves_in_insert. Rolling back.\n"); - handle_soft_error (); - return; - default: - break; - } - for (unsigned int i = 0; iserial_id, - job_name); - break; - case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Imported transaction %llu.", - (unsigned long long) cd->serial_id); - /* normal case */ - progress = true; - break; - } - } - } - - latest_row_off = lroff; - shard_done = (shard_end <= latest_row_off); - if (shard_done) - { - /* shard is complete, mark this as well */ - qs = db_plugin->complete_shard (db_plugin->cls, - job_name, - shard_start, - shard_end); - switch (qs) - { - case GNUNET_DB_STATUS_HARD_ERROR: - GNUNET_break (0); - GNUNET_SCHEDULER_shutdown (); - return; - case GNUNET_DB_STATUS_SOFT_ERROR: - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Got DB soft error for complete_shard. Rolling back.\n"); - handle_soft_error (); - return; - case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - GNUNET_break (0); - /* Not expected, but let's just continue */ - break; - case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: - /* normal case */ - progress = true; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Completed shard %s (%llu,%llu] after %s\n", - job_name, - (unsigned long long) shard_start, - (unsigned long long) shard_end, - GNUNET_STRINGS_relative_time_to_string ( - GNUNET_TIME_absolute_get_duration (shard_start_time), - true)); - break; - } - shard_delay = GNUNET_TIME_absolute_get_duration (shard_start_time); - shard_open = false; - transaction_completed (); - return; - } - GNUNET_assert (NULL == task); - task = GNUNET_SCHEDULER_add_now (&continue_with_shard, - NULL); -} - - /** * We got incoming transaction details from the bank. Add them * to the database. @@ -883,9 +500,9 @@ process_reply_batched (const struct TALER_BANK_CreditDetails *details, * @param details_length length of the @a details array */ static void -process_reply_batched2 (unsigned int batch_size, - const struct TALER_BANK_CreditDetails *details, - unsigned int details_length) +process_reply (unsigned int batch_size, + const struct TALER_BANK_CreditDetails *details, + unsigned int details_length) { enum GNUNET_DB_QueryStatus qs; bool shard_done; @@ -950,11 +567,11 @@ process_reply_batched2 (unsigned int batch_size, res->exchange_account_name = ai->section_name; res->wire_reference = cd->serial_id; } - qs = db_plugin->batch2_reserves_in_insert (db_plugin->cls, - reserves, - details_length, - batch_size, - qss); + qs = db_plugin->reserves_in_insert (db_plugin->cls, + reserves, + details_length, + batch_size, + qss); switch (qs) { case GNUNET_DB_STATUS_HARD_ERROR: @@ -1074,7 +691,7 @@ history_cb (void *cls, (void) cls; if (-2 == batch_mode) { - const char *mode = getenv ("TALER_USE_BATCH"); + const char *mode = getenv ("TALER_WIREWATCH_BATCH_SIZE"); char dummy; if ( (NULL == mode) || @@ -1087,7 +704,7 @@ history_cb (void *cls, GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Bad batch mode `%s' specified\n", mode); - batch_mode = -1; + batch_mode = 8; /* maximum supported is currently 8 */ } } GNUNET_assert (NULL == task); @@ -1098,22 +715,9 @@ history_cb (void *cls, switch (reply->http_status) { case MHD_HTTP_OK: - switch (batch_mode) - { - case -1: - process_reply (reply->details.success.details, - reply->details.success.details_length); - break; - case 0: - process_reply_batched (reply->details.success.details, - reply->details.success.details_length); - break; - default: - process_reply_batched2 ((unsigned int) batch_mode, - reply->details.success.details, - reply->details.success.details_length); - break; - } + process_reply (batch_mode, + reply->details.success.details, + reply->details.success.details_length); return; case MHD_HTTP_NO_CONTENT: transaction_completed (); diff --git a/src/exchangedb/.gitignore b/src/exchangedb/.gitignore index dd3c5ed1b..264217a3d 100644 --- a/src/exchangedb/.gitignore +++ b/src/exchangedb/.gitignore @@ -1,17 +1,9 @@ -test-exchangedb-auditors -test-exchangedb-denomkeys -test-exchangedb-fees test-exchangedb-postgres -test-exchangedb-signkeys -test-perf-taler-exchangedb bench-db-postgres -shard-drop0001.sqltest-exchangedb-by-j-postgres -test-exchangedb-by-j-postgres -perf-exchangedb-reserves-in-insert-postgres +perf_deposits_get_ready-postgres +perf_get_link_data-postgres +perf_reserves_in_insert-postgres +perf_select_refunds_by_coin-postgres exchange-0002.sql procedures.sql exchange-0003.sql -test-exchangedb-batch-reserves-in-insert-postgres -test-exchangedb-populate-table-postgres -test-exchangedb-populate-link-data-postgres -test-exchangedb-populate-ready-deposit-postgres diff --git a/src/exchangedb/0002-deposits.sql b/src/exchangedb/0002-deposits.sql index 92210afa3..d8afdac84 100644 --- a/src/exchangedb/0002-deposits.sql +++ b/src/exchangedb/0002-deposits.sql @@ -1,6 +1,6 @@ -- -- This file is part of TALER --- Copyright (C) 2014--2022 Taler Systems SA +-- Copyright (C) 2014--2023 Taler Systems SA -- -- TALER is free software; you can redistribute it and/or modify it under the -- terms of the GNU General Public License as published by the Free Software @@ -116,6 +116,22 @@ BEGIN ',ADD CONSTRAINT ' || table_name || '_coin_pub_merchant_pub_h_contract_terms_key' ' UNIQUE (coin_pub, merchant_pub, h_contract_terms)' ); + EXECUTE FORMAT ( + 'CREATE INDEX ' || table_name || '_by_ready ' + 'ON ' || table_name || ' ' + '(wire_deadline ASC' + ',shard ASC' + ',coin_pub' + ') WHERE NOT (done OR policy_blocked);' + ); + EXECUTE FORMAT ( + 'CREATE INDEX ' || table_name || '_for_matching ' + 'ON ' || table_name || ' ' + '(refund_deadline ASC' + ',merchant_pub' + ',coin_pub' + ') WHERE NOT (done OR policy_blocked);' + ); END $$; @@ -399,29 +415,5 @@ INSERT INTO exchange_tables ,'exchange-0002' ,'foreign' ,TRUE - ,FALSE), - ('deposits_by_ready' - ,'exchange-0002' - ,'create' - ,TRUE - ,TRUE), - ('deposits_by_ready' - ,'exchange-0002' - ,'constrain' - ,TRUE - ,TRUE), - ('deposits_for_matching' - ,'exchange-0002' - ,'create' - ,TRUE - ,TRUE), - ('deposits_for_matching' - ,'exchange-0002' - ,'constrain' - ,TRUE - ,TRUE), - ('deposits' - ,'exchange-0002' - ,'master' - ,TRUE - ,FALSE); + ,FALSE) + ; diff --git a/src/exchangedb/Makefile.am b/src/exchangedb/Makefile.am index e8ef104e1..49bc649b5 100644 --- a/src/exchangedb/Makefile.am +++ b/src/exchangedb/Makefile.am @@ -255,8 +255,6 @@ libtaler_plugin_exchangedb_postgres_la_SOURCES = \ pg_select_purse_deposits_above_serial_id.h pg_select_purse_deposits_above_serial_id.c \ pg_select_account_merges_above_serial_id.h pg_select_account_merges_above_serial_id.c \ pg_select_all_purse_decisions_above_serial_id.h pg_select_all_purse_decisions_above_serial_id.c \ - pg_batch_reserves_in_insert.h pg_batch_reserves_in_insert.c \ - pg_batch2_reserves_in_insert.h pg_batch2_reserves_in_insert.c \ pg_select_reserve_open_above_serial_id.c pg_select_reserve_open_above_serial_id.h libtaler_plugin_exchangedb_postgres_la_LIBADD = \ $(LTLIBINTL) @@ -295,22 +293,14 @@ check_PROGRAMS = \ noinst_PROGRAMS = \ bench-db-postgres\ - perf-exchangedb-reserves-in-insert-postgres\ - test-exchangedb-by-j-postgres\ - test-exchangedb-batch-reserves-in-insert-postgres\ - test-exchangedb-populate-select-refunds-by-coin-postgres\ - test-exchangedb-populate-link-data-postgres\ - test-exchangedb-populate-ready-deposit-postgres + perf_get_link_data-postgres\ + perf_select_refunds_by_coin-postgres\ + perf_reserves_in_insert-postgres \ + perf_deposits_get_ready-postgres AM_TESTS_ENVIRONMENT=export TALER_PREFIX=$${TALER_PREFIX:-@libdir@};export PATH=$${TALER_PREFIX:-@prefix@}/bin:$$PATH; TESTS = \ - test-exchangedb-postgres\ - test-exchangedb-by-j-postgres\ - perf-exchangedb-reserves-in-insert-postgres\ - test-exchangedb-batch-reserves-in-insert-postgres\ - test-exchangedb-populate-select-refunds-by-coin-postgres\ - test-exchangedb-populate-link-data-postgres\ - test-exchangedb-populate-ready-deposit-postgres + (check_PROGRAMS) test_exchangedb_postgres_SOURCES = \ test_exchangedb.c test_exchangedb_postgres_LDADD = \ @@ -323,32 +313,6 @@ test_exchangedb_postgres_LDADD = \ -lgnunetutil \ $(XLIB) -test_exchangedb_by_j_postgres_SOURCES = \ - test_exchangedb_by_j.c -test_exchangedb_by_j_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) - - -perf_exchangedb_reserves_in_insert_postgres_SOURCES = \ - perf_exchangedb_reserves_in_insert.c -perf_exchangedb_reserves_in_insert_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 \ - $(XLIB) - bench_db_postgres_SOURCES = \ bench_db.c bench_db_postgres_LDADD = \ @@ -359,9 +323,9 @@ bench_db_postgres_LDADD = \ -lgnunetutil \ $(XLIB) -test_exchangedb_batch_reserves_in_insert_postgres_SOURCES = \ - test_exchangedb_batch_reserves_in_insert.c -test_exchangedb_batch_reserves_in_insert_postgres_LDADD = \ +perf_reserves_in_insert_postgres_SOURCES = \ + perf_reserves_in_insert.c +perf_reserves_in_insert_postgres_LDADD = \ libtalerexchangedb.la \ $(top_builddir)/src/json/libtalerjson.la \ $(top_builddir)/src/util/libtalerutil.la \ @@ -369,11 +333,12 @@ test_exchangedb_batch_reserves_in_insert_postgres_LDADD = \ -ljansson \ -lgnunetjson \ -lgnunetutil \ + -lm \ $(XLIB) -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 = \ +perf_select_refunds_by_coin_postgres_SOURCES = \ + perf_select_refunds_by_coin.c +perf_select_refunds_by_coin_postgres_LDADD = \ libtalerexchangedb.la \ $(top_builddir)/src/json/libtalerjson.la \ $(top_builddir)/src/util/libtalerutil.la \ @@ -384,9 +349,9 @@ test_exchangedb_populate_select_refunds_by_coin_postgres_LDADD = \ -lm \ $(XLIB) -test_exchangedb_populate_link_data_postgres_SOURCES = \ - test_exchangedb_populate_link_data.c -test_exchangedb_populate_link_data_postgres_LDADD = \ +perf_get_link_data_postgres_SOURCES = \ + perf_get_link_data.c +perf_get_link_data_postgres_LDADD = \ libtalerexchangedb.la \ $(top_builddir)/src/json/libtalerjson.la \ $(top_builddir)/src/util/libtalerutil.la \ @@ -397,9 +362,9 @@ test_exchangedb_populate_link_data_postgres_LDADD = \ -lm \ $(XLIB) -test_exchangedb_populate_ready_deposit_postgres_SOURCES = \ - test_exchangedb_populate_ready_deposit.c -test_exchangedb_populate_ready_deposit_postgres_LDADD = \ +perf_deposits_get_ready_postgres_SOURCES = \ + perf_deposits_get_ready.c +perf_deposits_get_ready_postgres_LDADD = \ libtalerexchangedb.la \ $(top_builddir)/src/json/libtalerjson.la \ $(top_builddir)/src/util/libtalerutil.la \ diff --git a/src/exchangedb/perf_deposits_get_ready.c b/src/exchangedb/perf_deposits_get_ready.c new file mode 100644 index 000000000..4ad08223c --- /dev/null +++ b/src/exchangedb/perf_deposits_get_ready.c @@ -0,0 +1,533 @@ +/* + This file is part of TALER + Copyright (C) 2014-2023 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as 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/perf_deposits_get_ready.c + * @brief benchmark for deposits_get_ready + * @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 NUM_ROWS 1000 +#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; + +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; +} + + +/** + * 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)); + { + ZR_BLK (&cbc); + new_dkp = GNUNET_new_array (MELT_NEW_COINS, + struct DenomKeyPair *); + new_denom_pubs = GNUNET_new_array (MELT_NEW_COINS, + struct TALER_DenominationPublicKey); + 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 (); + 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); + 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)); + { + 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; + } + { + 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); + } + FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != + plugin->commit (plugin->cls)); + GNUNET_free (perm); + /* End of benchmark setup */ + + /**** CALL GET READY DEPOSIT ****/ + 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; + enum GNUNET_DB_QueryStatus qs; + + time = GNUNET_TIME_absolute_get (); + qs = plugin->get_ready_deposit (plugin->cls, + 0, + INT32_MAX, + &merchant_pub, + &payto_uri); + FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs); + 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; + 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++; + { + char *testname; + + GNUNET_asprintf (&testname, + "test-exchange-db-%s", + plugin_name); + GNUNET_asprintf (&config_filename, + "%s.conf", + testname); + GNUNET_free (testname); + } + cfg = GNUNET_CONFIGURATION_create (); + if (GNUNET_OK != + GNUNET_CONFIGURATION_parse (cfg, + config_filename)) + { + GNUNET_break (0); + GNUNET_free (config_filename); + return 2; + } + GNUNET_SCHEDULER_run (&run, + cfg); + GNUNET_CONFIGURATION_destroy (cfg); + GNUNET_free (config_filename); + return result; +} + + +/* end of perf_deposits_get_ready.c */ diff --git a/src/exchangedb/perf_exchangedb_reserves_in_insert.c b/src/exchangedb/perf_exchangedb_reserves_in_insert.c deleted file mode 100644 index fc2a00089..000000000 --- a/src/exchangedb/perf_exchangedb_reserves_in_insert.c +++ /dev/null @@ -1,193 +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_by_j.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" - -/** - * 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" - -/** - * Database plugin under test. - */ -static struct TALER_EXCHANGEDB_Plugin *plugin; - - -/** - * 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; - - 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; - } - for (unsigned int i = 0; i< 8; i++) - { - static unsigned int batches[] = {1, 1, 0, 2, 4, 16, 64, 256}; - const char *sndr = "payto://x-taler-bank/localhost:8080/1"; - struct TALER_Amount value; - unsigned int batch_size = batches[i]; - struct GNUNET_TIME_Absolute now; - struct GNUNET_TIME_Timestamp ts; - struct GNUNET_TIME_Relative duration; - struct TALER_ReservePublicKeyP reserve_pub; - - GNUNET_assert (GNUNET_OK == - TALER_string_to_amount (CURRENCY ":1.000010", - &value)); - now = GNUNET_TIME_absolute_get (); - ts = GNUNET_TIME_timestamp_get (); - for (unsigned int r = 0; r<10; r++) - { - plugin->start (plugin->cls, - "test_by_exchange_j"); - for (unsigned int k = 0; kreserves_in_insert (plugin->cls, - &reserve_pub, - &value, - ts, - sndr, - "section", - 4)); - } - plugin->commit (plugin->cls); - } - duration = GNUNET_TIME_absolute_get_duration (now); - fprintf (stdout, - "for a batchsize equal to %d it took %s\n", - batch_size, - GNUNET_STRINGS_relative_time_to_string (duration, - GNUNET_NO) ); - } - result = 0; -drop: - GNUNET_break (GNUNET_OK == - plugin->drop_tables (plugin->cls)); -cleanup: - 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/perf_get_link_data.c b/src/exchangedb/perf_get_link_data.c new file mode 100644 index 000000000..eb1f5f6e2 --- /dev/null +++ b/src/exchangedb/perf_get_link_data.c @@ -0,0 +1,536 @@ +/* + This file is part of TALER + Copyright (C) 2014-2023 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as 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/perf_get_link_data.c + * @brief benchmark for get_link_data + * @author Joseph Xu + */ +#include "platform.h" +#include "taler_exchangedb_lib.h" +#include "taler_json_lib.h" +#include "taler_exchangedb_plugin.h" +#include "math.h" + +/** + * 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)) + +#define CURRENCY "EUR" +#define RSA_KEY_SIZE 1024 +#define ROUNDS 100 +#define NUM_ROWS 1000 +#define MELT_NEW_COINS 5 +#define DENOMINATIONS 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; +static int result; + +static struct TALER_TransferPrivateKeyP tprivs[TALER_CNC_KAPPA]; +static struct TALER_TransferPublicKeyP tpub; +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; + (void) ldl; +} + + +/** + * 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 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_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)); + { + new_dkp = GNUNET_new_array (MELT_NEW_COINS, + struct DenomKeyPair *); + + for (unsigned int cnt = 0; cnt < MELT_NEW_COINS; cnt++) + { + struct GNUNET_TIME_Timestamp now = GNUNET_TIME_timestamp_get (); + + new_dkp[cnt] = create_denom_key_pair (RSA_KEY_SIZE, + now, + &value, + &fees); + GNUNET_assert (NULL != new_dkp[cnt]); + } + } + perm = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_NONCE, + NUM_ROWS); + FAILIF (GNUNET_OK != + plugin->start (plugin->cls, + "Transaction")); + for (unsigned int j = 0; j < NUM_ROWS; j++) + { + union TALER_DenominationBlindingKeyP bks; + struct TALER_CoinPubHashP c_hash; + unsigned int i = perm[j]; + uint64_t known_coin_id; + struct TALER_EXCHANGEDB_CollectableBlindcoin cbc; + if (i >= ROUNDS) + i = ROUNDS; /* throw-away slot, do not keep around */ + RND_BLK (&depos[i].coin.coin_pub); + ZR_BLK (&cbc); + TALER_denom_pub_hash (&new_dkp[(unsigned int) rand () + % MELT_NEW_COINS]->pub, + &depos[i].coin.denom_pub_hash); + + + { + struct TALER_EXCHANGEDB_RefreshRevealedCoin + revealed_coins[MELT_NEW_COINS]; + + for (unsigned int p = 0; pblinded_planchet; + struct TALER_BlindedRsaPlanchet *rp = &bp->details.rsa_blinded_planchet; + + /* h_coin_ev must be unique, but we only have MELT_NEW_COINS created + above for NUM_ROWS iterations; instead of making "all new" coins, + we simply randomize the hash here as nobody is checking for consistency + anyway ;-) */ + bp->cipher = TALER_DENOMINATION_RSA; + 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[(unsigned int) rand () + % MELT_NEW_COINS]->pub, + &revealed_coin->h_denom_pub); + revealed_coin->exchange_vals = alg_values; + TALER_coin_ev_hash (bp, + &revealed_coin->h_denom_pub, + &revealed_coin->coin_envelope_hash); + GNUNET_assert (GNUNET_OK == + TALER_denom_sign_blinded (&revealed_coin->coin_sig, + &new_dkp[(unsigned + int) rand () + % MELT_NEW_COINS]-> + priv, + true, + bp)); + GNUNET_assert ( + GNUNET_OK == + TALER_denom_sign_blinded ( + &cbc.sig, + &new_dkp[(unsigned int) rand () % MELT_NEW_COINS]->priv, + false, + bp)); + } + GNUNET_assert (GNUNET_OK == + TALER_denom_sig_unblind (&depos[i].coin.denom_sig, + &cbc.sig, + &bks, + &c_hash, + &alg_values, + &new_dkp[(unsigned int) rand () + % MELT_NEW_COINS]->pub)); + { + /* ENSURE_COIN_KNOWN */ + 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)); + } + /****GET melt_serial_id generated by default****/ + { + struct TALER_EXCHANGEDB_Melt ret_refresh_session; + + FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != + plugin->get_melt (plugin->cls, + &refresh[i].rc, + &ret_refresh_session, + &melt_serial_id)); + } + /**** INSERT REFRESH_REVEAL + TRANSFER_KEYS *****/ + { + static unsigned int cnt; + + RND_BLK (&tprivs); + RND_BLK (&tpub); + 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)); + cnt++; + // fprintf (stderr, "CNT: %u - %llu\n", cnt, (unsigned long long) melt_serial_id); + } + 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); + } + + /* { + struct TALER_CoinSpendPublicKeyP ocp; + uint64_t rrc_serial; + + FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != + plugin->get_old_coin_by_h_blind (plugin->cls, + &revealed_coins->coin_envelope_hash, + &ocp, + &rrc_serial)); + }*/ + } + if (ROUNDS == i) + TALER_denom_sig_free (&depos[i].coin.denom_sig); + } + /* End of benchmark setup */ + GNUNET_free (perm); + 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; + 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); + 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); + 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/perf_reserves_in_insert.c b/src/exchangedb/perf_reserves_in_insert.c new file mode 100644 index 000000000..9f3ed4604 --- /dev/null +++ b/src/exchangedb/perf_reserves_in_insert.c @@ -0,0 +1,231 @@ +/* + This file is part of TALER + Copyright (C) 2014-2023 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as 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/perf_reserves_in_insert.c + * @brief benchmark for 'reserves_in_insert' + * @author Joseph Xu + */ +#include "platform.h" +#include "taler_exchangedb_lib.h" +#include "taler_json_lib.h" +#include "taler_exchangedb_plugin.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)) + +/** + * How many rounds do we average over? + */ +#define ROUNDS 5 + +/** + * Currency we use. Must match test-exchange-db-*.conf. + */ +#define CURRENCY "EUR" + +/** + * Database plugin under test. + */ +static struct TALER_EXCHANGEDB_Plugin *plugin; + + +/** + * 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; + static unsigned int batches[] = {1, 1, 2, 3, 4, 16, 32 }; + const unsigned int lcm = 3 * 32; + struct GNUNET_TIME_Relative times[sizeof (batches) / sizeof(*batches)]; + unsigned long long sqrs[sizeof (batches) / sizeof(*batches)]; + + 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; + } + + memset (times, 0, sizeof (times)); + memset (sqrs, 0, sizeof (sqrs)); + for (unsigned int r = 0; r < ROUNDS; r++) + { + for (unsigned int i = 0; + i< sizeof(batches) / sizeof(*batches); + i++) + { + unsigned int batch_size = batches[i]; + struct TALER_Amount value; + struct GNUNET_TIME_Absolute now; + struct GNUNET_TIME_Timestamp ts; + unsigned long long duration_sq; + struct GNUNET_TIME_Relative duration; + + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY ":1.000010", + &value)); + now = GNUNET_TIME_absolute_get (); + ts = GNUNET_TIME_timestamp_get (); + { + const char *sndr = "payto://x-taler-bank/localhost:8080/1"; + struct TALER_ReservePublicKeyP reserve_pubs[lcm]; + struct TALER_EXCHANGEDB_ReserveInInfo reserves[lcm]; + enum GNUNET_DB_QueryStatus results[lcm]; + + for (unsigned int k = 0; kreserves_in_insert (plugin->cls, + reserves, + lcm, + batch_size, + results)); + } + duration = GNUNET_TIME_absolute_get_duration (now); + times[i] = GNUNET_TIME_relative_add (times[i], + 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[i] + duration_sq >= sqrs[i]); + sqrs[i] += duration_sq; + } /* for 'i' batch size */ + } /* for 'r' ROUNDS */ + + for (unsigned int i = 0; + i< sizeof(batches) / sizeof(*batches); + i++) + { + struct GNUNET_TIME_Relative avg; + double avg_dbl; + double variance; + + avg = GNUNET_TIME_relative_divide (times[i], + ROUNDS); + avg_dbl = avg.rel_value_us; + variance = sqrs[i] - (avg_dbl * avg_dbl * ROUNDS); + fprintf (stdout, + "Batch[%2u]: %8llu ± %6.0f\n", + batches[i], + (unsigned long long) avg.rel_value_us, + sqrt (variance / (ROUNDS - 1))); + } + result = 0; +drop: + GNUNET_break (GNUNET_OK == + plugin->drop_tables (plugin->cls)); +cleanup: + 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); + 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 perf_reserves_in_insert.c */ diff --git a/src/exchangedb/perf_select_refunds_by_coin.c b/src/exchangedb/perf_select_refunds_by_coin.c new file mode 100644 index 000000000..85c92f4b9 --- /dev/null +++ b/src/exchangedb/perf_select_refunds_by_coin.c @@ -0,0 +1,602 @@ +/* + This file is part of TALER + Copyright (C) 2014-2023 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as 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/perf_select_refunds_by_coin.c + * @brief benchmark for select_refunds_by_coin + * @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 100 +#define NUM_ROWS 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; + +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 (); + { + new_dkp = GNUNET_new_array (MELT_NEW_COINS, + struct DenomKeyPair *); + new_denom_pubs = GNUNET_new_array (MELT_NEW_COINS, + struct TALER_DenominationPublicKey); + 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 (); + 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); + 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); + 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; + { + 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)); + } + { + 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); + 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; + 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++; + { + char *testname; + + GNUNET_asprintf (&testname, + "test-exchange-db-%s", + plugin_name); + GNUNET_asprintf (&config_filename, + "%s.conf", + testname); + GNUNET_free (testname); + } + cfg = GNUNET_CONFIGURATION_create (); + if (GNUNET_OK != + GNUNET_CONFIGURATION_parse (cfg, + config_filename)) + { + GNUNET_break (0); + GNUNET_free (config_filename); + return 2; + } + GNUNET_SCHEDULER_run (&run, + cfg); + GNUNET_CONFIGURATION_destroy (cfg); + GNUNET_free (config_filename); + return result; +} + + +/* end of perf_select_refunds_by_coin.c */ diff --git a/src/exchangedb/pg_aggregate.c b/src/exchangedb/pg_aggregate.c index f1c4d6776..6e94cbebb 100644 --- a/src/exchangedb/pg_aggregate.c +++ b/src/exchangedb/pg_aggregate.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2022 Taler Systems SA + Copyright (C) 2022, 2023 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -72,26 +72,16 @@ TEH_PG_aggregate ( now = GNUNET_TIME_absolute_round_down (GNUNET_TIME_absolute_get (), pg->aggregator_shift); - /* Used in #postgres_aggregate() */ + /* Used in #postgres_aggregate() */ PREPARE (pg, "aggregate", - "WITH rdy AS (" /* find deposits ready by merchant */ - " SELECT" - " coin_pub" - " FROM deposits_for_matching" - " WHERE refund_deadline<$1" /* filter by shard, only actually executable deposits */ - " AND merchant_pub=$2" /* filter by target merchant */ - " ORDER BY refund_deadline ASC" /* ordering is not critical */ - " LIMIT " - TALER_QUOTE (TALER_EXCHANGEDB_MATCHING_DEPOSITS_LIMIT) /* limits transaction size */ - " )" - " ,dep AS (" /* restrict to our merchant and account and mark as done */ + "WITH dep AS (" /* restrict to our merchant and account and mark as done */ " UPDATE deposits" " SET done=TRUE" - " WHERE coin_pub IN (SELECT coin_pub FROM rdy)" - " AND merchant_pub=$2" /* theoretically, same coin could be spent at another merchant */ + " WHERE NOT (done OR policy_blocked)" /* only actually executable deposits */ + " AND refund_deadline<$1" /* filter by shard */ + " AND merchant_pub=$2" /* filter by target merchant */ " AND wire_target_h_payto=$3" /* merchant could have a 2nd bank account */ - " AND done=FALSE" /* theoretically, same coin could be spend at the same merchant a 2nd time */ " RETURNING" " deposit_serial_id" " ,coin_pub" diff --git a/src/exchangedb/pg_batch2_reserves_in_insert.c b/src/exchangedb/pg_batch2_reserves_in_insert.c deleted file mode 100644 index 1ef9045da..000000000 --- a/src/exchangedb/pg_batch2_reserves_in_insert.c +++ /dev/null @@ -1,914 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 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/pg_batch2_reserves_in_insert.c - * @brief Implementation of the reserves_in_insert function for Postgres - * @author Joseph Xu - */ -#include "platform.h" -#include "taler_error_codes.h" -#include "taler_dbevents.h" -#include "taler_pq_lib.h" -#include "pg_batch2_reserves_in_insert.h" -#include "pg_helper.h" -#include "pg_start.h" -#include "pg_rollback.h" -#include "pg_start_read_committed.h" -#include "pg_commit.h" -#include "pg_reserves_get.h" -#include "pg_reserves_update.h" -#include "pg_setup_wire_target.h" -#include "pg_event_notify.h" -#include "pg_preflight.h" - -/** - * Generate event notification for the reserve change. - * - * @param reserve_pub reserve to notfiy on - */ -static char * -compute_notify_on_reserve (const struct TALER_ReservePublicKeyP *reserve_pub) -{ - struct TALER_ReserveEventP rep = { - .header.size = htons (sizeof (rep)), - .header.type = htons (TALER_DBEVENT_EXCHANGE_RESERVE_INCOMING), - .reserve_pub = *reserve_pub - }; - - return GNUNET_PG_get_event_notify_channel (&rep.header); -} - - -static enum GNUNET_DB_QueryStatus -insert1(struct PostgresClosure *pg, - const struct TALER_EXCHANGEDB_ReserveInInfo reserves[1], - struct GNUNET_TIME_Timestamp expiry, - struct GNUNET_TIME_Timestamp gc, - struct TALER_PaytoHashP h_payto, - char *const * notify_s, - struct GNUNET_TIME_Timestamp reserve_expiration, - bool *transaction_duplicate, - bool *conflict, - uint64_t *reserve_uuid, - enum GNUNET_DB_QueryStatus results[1]) -{ - enum GNUNET_DB_QueryStatus qs2; - PREPARE (pg, - "batch1_reserve_create", - "SELECT " - " out_reserve_found AS conflicted" - ",transaction_duplicate" - ",ruuid AS reserve_uuid" - " FROM exchange_do_batch_reserves_in_insert" - " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12);"); - - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (reserves[0].reserve_pub), - GNUNET_PQ_query_param_timestamp (&expiry), - GNUNET_PQ_query_param_timestamp (&gc), - GNUNET_PQ_query_param_uint64 (&reserves[0].wire_reference), - TALER_PQ_query_param_amount (reserves[0].balance), - GNUNET_PQ_query_param_string (reserves[0].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[0].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto), - GNUNET_PQ_query_param_string (reserves[0].sender_account_details), - GNUNET_PQ_query_param_timestamp (&reserve_expiration), - GNUNET_PQ_query_param_string (notify_s[0]), - GNUNET_PQ_query_param_end - }; - - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_bool ("conflicted", - &conflict[0]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate", - &transaction_duplicate[0]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid", - &reserve_uuid[0]), - GNUNET_PQ_result_spec_end - }; - - - TALER_payto_hash (reserves[0].sender_account_details, - &h_payto); - - qs2 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "batch1_reserve_create", - params, - rs); - - if (qs2 < 0) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to create reserves 1(%d)\n", - qs2); - results[0] = qs2; - return qs2; - } - GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs2); - if ((! conflict[0]) && transaction_duplicate[0]) - { - GNUNET_break (0); - TEH_PG_rollback (pg); - results[0] = GNUNET_DB_STATUS_HARD_ERROR; - return GNUNET_DB_STATUS_HARD_ERROR; - } - results[0] = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; - return qs2; -} - - - -static enum GNUNET_DB_QueryStatus -insert2 (struct PostgresClosure *pg, - const struct TALER_EXCHANGEDB_ReserveInInfo reserves[2], - struct GNUNET_TIME_Timestamp expiry, - struct GNUNET_TIME_Timestamp gc, - struct TALER_PaytoHashP h_payto, - char *const*notify_s, - struct GNUNET_TIME_Timestamp reserve_expiration, - bool *transaction_duplicate, - bool *conflict, - uint64_t *reserve_uuid, - enum GNUNET_DB_QueryStatus results[1]) -{ - enum GNUNET_DB_QueryStatus qs1; - PREPARE (pg, - "batch2_reserve_create", - "SELECT " - "out_reserve_found AS conflicted" - ",out_reserve_found2 AS conflicted2" - ",transaction_duplicate" - ",transaction_duplicate2" - ",ruuid AS reserve_uuid" - ",ruuid2 AS reserve_uuid2" - " FROM exchange_do_batch2_reserves_insert" - " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22);"); - - struct GNUNET_PQ_QueryParam params[] = { - - GNUNET_PQ_query_param_auto_from_type (reserves[0].reserve_pub), - GNUNET_PQ_query_param_timestamp (&expiry), - GNUNET_PQ_query_param_timestamp (&gc), - GNUNET_PQ_query_param_uint64 (&reserves[0].wire_reference), - TALER_PQ_query_param_amount (reserves[0].balance), - GNUNET_PQ_query_param_string (reserves[0].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[0].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto), - GNUNET_PQ_query_param_string (reserves[0].sender_account_details), - GNUNET_PQ_query_param_timestamp (&reserve_expiration), - GNUNET_PQ_query_param_string (notify_s[0]), - GNUNET_PQ_query_param_string (notify_s[1]), - - GNUNET_PQ_query_param_auto_from_type (reserves[1].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[1].wire_reference), - TALER_PQ_query_param_amount (reserves[1].balance), - GNUNET_PQ_query_param_string (reserves[1].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[1].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto), - GNUNET_PQ_query_param_string (reserves[1].sender_account_details), - GNUNET_PQ_query_param_timestamp (&reserve_expiration), - GNUNET_PQ_query_param_end - }; - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_bool ("conflicted", - &conflict[0]), - GNUNET_PQ_result_spec_bool ("conflicted2", - &conflict[1]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate", - &transaction_duplicate[0]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate2", - &transaction_duplicate[1]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid", - &reserve_uuid[0]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid2", - &reserve_uuid[1]), - GNUNET_PQ_result_spec_end - }; - - TALER_payto_hash (reserves[0].sender_account_details, - &h_payto); - TALER_payto_hash (reserves[1].sender_account_details, - &h_payto); - - - qs1 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "batch2_reserve_create", - params, - rs); - if (qs1 < 0) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to create reserves 2(%d)\n", - qs1); - results[0]=qs1; - return qs1; - } - - GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs1); - /* results[i] = (transaction_duplicate) - ? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS - : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;*/ - - if ( - ((! conflict[0]) && (transaction_duplicate[0])) - ||((! conflict[1]) && (transaction_duplicate[1])) - ) - { - GNUNET_break (0); - TEH_PG_rollback (pg); //ROLLBACK - results[0] = GNUNET_DB_STATUS_HARD_ERROR; - return GNUNET_DB_STATUS_HARD_ERROR; - } - results[0] = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; - return qs1; -} - - -static enum GNUNET_DB_QueryStatus -insert4 (struct PostgresClosure *pg, - const struct TALER_EXCHANGEDB_ReserveInInfo reserves[4], - struct GNUNET_TIME_Timestamp expiry, - struct GNUNET_TIME_Timestamp gc, - struct TALER_PaytoHashP h_payto, - char *const*notify_s, - struct GNUNET_TIME_Timestamp reserve_expiration, - bool *transaction_duplicate, - bool *conflict, - uint64_t *reserve_uuid, - enum GNUNET_DB_QueryStatus results[1]) -{ - enum GNUNET_DB_QueryStatus qs3; - PREPARE (pg, - "batch4_reserve_create", - "SELECT " - "out_reserve_found AS conflicted" - ",out_reserve_found2 AS conflicted2" - ",out_reserve_found3 AS conflicted3" - ",out_reserve_found4 AS conflicted4" - ",transaction_duplicate" - ",transaction_duplicate2" - ",transaction_duplicate3" - ",transaction_duplicate4" - ",ruuid AS reserve_uuid" - ",ruuid2 AS reserve_uuid2" - ",ruuid3 AS reserve_uuid3" - ",ruuid4 AS reserve_uuid4" - " FROM exchange_do_batch4_reserves_insert" - " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$30,$31,$32,$33,$34,$35,$36,$37,$38,$39, $40, $41,$42);"); - - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (reserves[0].reserve_pub), - GNUNET_PQ_query_param_timestamp (&expiry), - GNUNET_PQ_query_param_timestamp (&gc), - GNUNET_PQ_query_param_uint64 (&reserves[0].wire_reference), - TALER_PQ_query_param_amount (reserves[0].balance), - GNUNET_PQ_query_param_string (reserves[0].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[0].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto), - GNUNET_PQ_query_param_string (reserves[0].sender_account_details), - GNUNET_PQ_query_param_timestamp (&reserve_expiration), - GNUNET_PQ_query_param_string (notify_s[0]), - GNUNET_PQ_query_param_string (notify_s[1]), - GNUNET_PQ_query_param_string (notify_s[2]), - GNUNET_PQ_query_param_string (notify_s[3]), - - GNUNET_PQ_query_param_auto_from_type (reserves[1].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[1].wire_reference), - TALER_PQ_query_param_amount (reserves[1].balance), - GNUNET_PQ_query_param_string (reserves[1].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[1].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto), - GNUNET_PQ_query_param_string (reserves[1].sender_account_details), - GNUNET_PQ_query_param_timestamp (&reserve_expiration), - - GNUNET_PQ_query_param_auto_from_type (reserves[2].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[2].wire_reference), - TALER_PQ_query_param_amount (reserves[2].balance), - GNUNET_PQ_query_param_string (reserves[2].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[2].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto), - GNUNET_PQ_query_param_string (reserves[2].sender_account_details), - GNUNET_PQ_query_param_timestamp (&reserve_expiration), - - GNUNET_PQ_query_param_auto_from_type (reserves[3].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[3].wire_reference), - TALER_PQ_query_param_amount (reserves[3].balance), - GNUNET_PQ_query_param_string (reserves[3].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[3].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto), - GNUNET_PQ_query_param_string (reserves[3].sender_account_details), - GNUNET_PQ_query_param_timestamp (&reserve_expiration), - - GNUNET_PQ_query_param_end - }; - - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_bool ("conflicted", - &conflict[0]), - GNUNET_PQ_result_spec_bool ("conflicted2", - &conflict[1]), - GNUNET_PQ_result_spec_bool ("conflicted3", - &conflict[2]), - GNUNET_PQ_result_spec_bool ("conflicted4", - &conflict[3]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate", - &transaction_duplicate[0]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate2", - &transaction_duplicate[1]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate3", - &transaction_duplicate[2]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate4", - &transaction_duplicate[3]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid", - &reserve_uuid[0]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid2", - &reserve_uuid[1]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid3", - &reserve_uuid[2]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid4", - &reserve_uuid[3]), - GNUNET_PQ_result_spec_end - }; - - TALER_payto_hash (reserves[0].sender_account_details, - &h_payto); - TALER_payto_hash (reserves[1].sender_account_details, - &h_payto); - TALER_payto_hash (reserves[2].sender_account_details, - &h_payto); - TALER_payto_hash (reserves[3].sender_account_details, - &h_payto); - - qs3 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "batch4_reserve_create", - params, - rs); - if (qs3 < 0) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to create reserves4 (%d)\n", - qs3); - results[0] = qs3; - return qs3; - } - - GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs3); - - if ( - ((! conflict[0]) && (transaction_duplicate[0])) - ||((! conflict[1]) && (transaction_duplicate[1])) - ||((! conflict[2]) && (transaction_duplicate[2])) - ||((! conflict[3]) && (transaction_duplicate[3])) - ) - { - GNUNET_break (0); - TEH_PG_rollback (pg); - results[0] = GNUNET_DB_STATUS_HARD_ERROR; - return GNUNET_DB_STATUS_HARD_ERROR; - } - results[0] = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; - return qs3; -} - - -static enum GNUNET_DB_QueryStatus -insert8 (struct PostgresClosure *pg, - const struct TALER_EXCHANGEDB_ReserveInInfo reserves[8], - struct GNUNET_TIME_Timestamp expiry, - struct GNUNET_TIME_Timestamp gc, - struct TALER_PaytoHashP h_payto, - char *const*notify_s, - struct GNUNET_TIME_Timestamp reserve_expiration, - bool *transaction_duplicate, - bool *conflict, - uint64_t *reserve_uuid, - enum GNUNET_DB_QueryStatus results[1]) -{ - enum GNUNET_DB_QueryStatus qs3; - PREPARE (pg, - "batch8_reserve_create", - "SELECT " - "out_reserve_found AS conflicted" - ",out_reserve_found2 AS conflicted2" - ",out_reserve_found3 AS conflicted3" - ",out_reserve_found4 AS conflicted4" - ",out_reserve_found5 AS conflicted5" - ",out_reserve_found6 AS conflicted6" - ",out_reserve_found7 AS conflicted7" - ",out_reserve_found8 AS conflicted8" - ",transaction_duplicate" - ",transaction_duplicate2" - ",transaction_duplicate3" - ",transaction_duplicate4" - ",transaction_duplicate5" - ",transaction_duplicate6" - ",transaction_duplicate7" - ",transaction_duplicate8" - ",ruuid AS reserve_uuid" - ",ruuid2 AS reserve_uuid2" - ",ruuid3 AS reserve_uuid3" - ",ruuid4 AS reserve_uuid4" - ",ruuid5 AS reserve_uuid5" - ",ruuid6 AS reserve_uuid6" - ",ruuid7 AS reserve_uuid7" - ",ruuid8 AS reserve_uuid8" - " FROM exchange_do_batch8_reserves_insert" - " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$30,$31,$32,$33,$34,$35,$36,$37,$38,$39, $40, $41,$42,$43,$44,$45,$46,$47,$48,$49,$50,$51,$52,$53,$54,$55,$56,$57,$58,$59,$60,$61,$62,$63,$64,$65,$66,$67,$68,$69,$70,$71,$72,$73,$74,$75,$76,$77,$78,$79,$80,$81,$82);"); - - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (reserves[0].reserve_pub), - GNUNET_PQ_query_param_timestamp (&expiry), - GNUNET_PQ_query_param_timestamp (&gc), - GNUNET_PQ_query_param_uint64 (&reserves[0].wire_reference), - TALER_PQ_query_param_amount (reserves[0].balance), - GNUNET_PQ_query_param_string (reserves[0].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[0].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto), - GNUNET_PQ_query_param_string (reserves[0].sender_account_details), - GNUNET_PQ_query_param_timestamp (&reserve_expiration), - GNUNET_PQ_query_param_string (notify_s[0]), - GNUNET_PQ_query_param_string (notify_s[1]), - GNUNET_PQ_query_param_string (notify_s[2]), - GNUNET_PQ_query_param_string (notify_s[3]), - GNUNET_PQ_query_param_string (notify_s[4]), - GNUNET_PQ_query_param_string (notify_s[5]), - GNUNET_PQ_query_param_string (notify_s[6]), - GNUNET_PQ_query_param_string (notify_s[7]), - - GNUNET_PQ_query_param_auto_from_type (reserves[1].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[1].wire_reference), - TALER_PQ_query_param_amount (reserves[1].balance), - GNUNET_PQ_query_param_string (reserves[1].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[1].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto), - GNUNET_PQ_query_param_string (reserves[1].sender_account_details), - GNUNET_PQ_query_param_timestamp (&reserve_expiration), - - GNUNET_PQ_query_param_auto_from_type (reserves[2].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[2].wire_reference), - TALER_PQ_query_param_amount (reserves[2].balance), - GNUNET_PQ_query_param_string (reserves[2].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[2].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto), - GNUNET_PQ_query_param_string (reserves[2].sender_account_details), - GNUNET_PQ_query_param_timestamp (&reserve_expiration), - - GNUNET_PQ_query_param_auto_from_type (reserves[3].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[3].wire_reference), - TALER_PQ_query_param_amount (reserves[3].balance), - GNUNET_PQ_query_param_string (reserves[3].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[3].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto), - GNUNET_PQ_query_param_string (reserves[3].sender_account_details), - GNUNET_PQ_query_param_timestamp (&reserve_expiration), - - GNUNET_PQ_query_param_auto_from_type (reserves[4].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[4].wire_reference), - TALER_PQ_query_param_amount (reserves[4].balance), - GNUNET_PQ_query_param_string (reserves[4].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[4].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto), - GNUNET_PQ_query_param_string (reserves[4].sender_account_details), - GNUNET_PQ_query_param_timestamp (&reserve_expiration), - - GNUNET_PQ_query_param_auto_from_type (reserves[5].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[5].wire_reference), - TALER_PQ_query_param_amount (reserves[5].balance), - GNUNET_PQ_query_param_string (reserves[5].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[5].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto), - GNUNET_PQ_query_param_string (reserves[5].sender_account_details), - GNUNET_PQ_query_param_timestamp (&reserve_expiration), - - GNUNET_PQ_query_param_auto_from_type (reserves[6].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[6].wire_reference), - TALER_PQ_query_param_amount (reserves[6].balance), - GNUNET_PQ_query_param_string (reserves[6].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[6].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto), - GNUNET_PQ_query_param_string (reserves[6].sender_account_details), - GNUNET_PQ_query_param_timestamp (&reserve_expiration), - - GNUNET_PQ_query_param_auto_from_type (reserves[7].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[7].wire_reference), - TALER_PQ_query_param_amount (reserves[7].balance), - GNUNET_PQ_query_param_string (reserves[7].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[7].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto), - GNUNET_PQ_query_param_string (reserves[7].sender_account_details), - GNUNET_PQ_query_param_timestamp (&reserve_expiration), - - GNUNET_PQ_query_param_end - }; - - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_bool ("conflicted", - &conflict[0]), - GNUNET_PQ_result_spec_bool ("conflicted2", - &conflict[1]), - GNUNET_PQ_result_spec_bool ("conflicted3", - &conflict[2]), - GNUNET_PQ_result_spec_bool ("conflicted4", - &conflict[3]), - GNUNET_PQ_result_spec_bool ("conflicted5", - &conflict[4]), - GNUNET_PQ_result_spec_bool ("conflicted6", - &conflict[5]), - GNUNET_PQ_result_spec_bool ("conflicted7", - &conflict[6]), - GNUNET_PQ_result_spec_bool ("conflicted8", - &conflict[7]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate", - &transaction_duplicate[0]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate2", - &transaction_duplicate[1]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate3", - &transaction_duplicate[2]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate4", - &transaction_duplicate[3]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate5", - &transaction_duplicate[4]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate6", - &transaction_duplicate[5]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate7", - &transaction_duplicate[6]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate8", - &transaction_duplicate[7]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid", - &reserve_uuid[0]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid2", - &reserve_uuid[1]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid3", - &reserve_uuid[2]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid4", - &reserve_uuid[3]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid5", - &reserve_uuid[4]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid6", - &reserve_uuid[5]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid7", - &reserve_uuid[6]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid8", - &reserve_uuid[7]), - GNUNET_PQ_result_spec_end - }; - - TALER_payto_hash (reserves[0].sender_account_details, - &h_payto); - TALER_payto_hash (reserves[1].sender_account_details, - &h_payto); - TALER_payto_hash (reserves[2].sender_account_details, - &h_payto); - TALER_payto_hash (reserves[3].sender_account_details, - &h_payto); - TALER_payto_hash (reserves[4].sender_account_details, - &h_payto); - TALER_payto_hash (reserves[5].sender_account_details, - &h_payto); - TALER_payto_hash (reserves[6].sender_account_details, - &h_payto); - TALER_payto_hash (reserves[7].sender_account_details, - &h_payto); - - qs3 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "batch8_reserve_create", - params, - rs); - if (qs3 < 0) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to create reserves8 (%d)\n", - qs3); - results[0]=qs3; - return qs3; - } - - GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs3); - /* results[i] = (transaction_duplicate) - ? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS - : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;*/ - - if ( - ((! conflict[0]) && (transaction_duplicate[0])) - ||((! conflict[1]) && (transaction_duplicate[1])) - ||((! conflict[2]) && (transaction_duplicate[2])) - ||((! conflict[3]) && (transaction_duplicate[3])) - ||((! conflict[4]) && (transaction_duplicate[4])) - ||((! conflict[5]) && (transaction_duplicate[5])) - ||((! conflict[6]) && (transaction_duplicate[6])) - ||((! conflict[7]) && (transaction_duplicate[7])) - ) - { - GNUNET_break (0); - TEH_PG_rollback (pg); - results[0]=GNUNET_DB_STATUS_HARD_ERROR; - return GNUNET_DB_STATUS_HARD_ERROR; - } - results[0] = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; - return qs3; -} - -enum GNUNET_DB_QueryStatus -TEH_PG_batch2_reserves_in_insert (void *cls, - const struct TALER_EXCHANGEDB_ReserveInInfo *reserves, - unsigned int reserves_length, - unsigned int batch_size, - enum GNUNET_DB_QueryStatus *results) -{ - struct PostgresClosure *pg = cls; - enum GNUNET_DB_QueryStatus qs1; - enum GNUNET_DB_QueryStatus qs2; - enum GNUNET_DB_QueryStatus qs4; - enum GNUNET_DB_QueryStatus qs5; - struct GNUNET_TIME_Timestamp expiry; - struct GNUNET_TIME_Timestamp gc; - struct TALER_PaytoHashP h_payto; - uint64_t reserve_uuid[reserves_length]; - bool transaction_duplicate[reserves_length]; - bool need_update = false; - bool t_duplicate=false; - struct GNUNET_TIME_Timestamp reserve_expiration - = GNUNET_TIME_relative_to_timestamp (pg->idle_reserve_expiration_time); - bool conflicts[reserves_length]; - char *notify_s[reserves_length]; - - if (GNUNET_OK != - TEH_PG_preflight (pg)) - { - GNUNET_break (0); - return GNUNET_DB_STATUS_HARD_ERROR; - } - - expiry = GNUNET_TIME_absolute_to_timestamp ( - GNUNET_TIME_absolute_add (reserves->execution_time.abs_time, - pg->idle_reserve_expiration_time)); - gc = GNUNET_TIME_absolute_to_timestamp ( - GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), - pg->legal_reserve_expiration_time)); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Creating reserve %s with expiration in %s\n", - TALER_B2S (&(reserves->reserve_pub)), - GNUNET_STRINGS_relative_time_to_string ( - pg->idle_reserve_expiration_time, - GNUNET_NO)); - - if (GNUNET_OK != - TEH_PG_start_read_committed(pg, - "READ_COMMITED")) - { - GNUNET_break (0); - return GNUNET_DB_STATUS_HARD_ERROR; - } - - /* Optimistically assume this is a new reserve, create balance for the first - time; we do this before adding the actual transaction to "reserves_in", - as for a new reserve it can't be a duplicate 'add' operation, and as - the 'add' operation needs the reserve entry as a foreign key. */ - for (unsigned int i=0;ireserve_pub); - } - - unsigned int i=0; - - while (i < reserves_length) - { - unsigned int bs = GNUNET_MIN (batch_size, - reserves_length - i); - if (bs >= 8) - { - qs1=insert8(pg, - &reserves[i], - expiry, - gc, - h_payto, - ¬ify_s[i], - reserve_expiration, - &transaction_duplicate[i], - &conflicts[i], - &reserve_uuid[i], - &results[i]); - - if (qs1<0) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to create reserve batch_8 (%d)\n", - qs1); - return qs1; - } - need_update |= conflicts[i]; - need_update |= conflicts[i+1]; - need_update |= conflicts[i+2]; - need_update |= conflicts[i+3]; - need_update |= conflicts[i+4]; - need_update |= conflicts[i+5]; - need_update |= conflicts[i+6]; - need_update |= conflicts[i+7]; - t_duplicate |= transaction_duplicate[i]; - t_duplicate |= transaction_duplicate[i+1]; - t_duplicate |= transaction_duplicate[i+2]; - t_duplicate |= transaction_duplicate[i+3]; - t_duplicate |= transaction_duplicate[i+4]; - t_duplicate |= transaction_duplicate[i+5]; - t_duplicate |= transaction_duplicate[i+6]; - t_duplicate |= transaction_duplicate[i+7]; - i+=8; - continue; - } - switch (bs) - { - case 7: - case 6 : - case 5: - case 4 : - qs4=insert4(pg, - &reserves[i], - expiry, - gc, - h_payto, - ¬ify_s[i], - reserve_expiration, - &transaction_duplicate[i], - &conflicts[i], - &reserve_uuid[i], - &results[i]); - - if (qs4<0) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to create reserve batch_4 (%d)\n", - qs4); - return qs4; - } - need_update |= conflicts[i]; - need_update |= conflicts[i+1]; - need_update |= conflicts[i+2]; - need_update |= conflicts[i+3]; - t_duplicate |= transaction_duplicate[i]; - t_duplicate |= transaction_duplicate[i+1]; - t_duplicate |= transaction_duplicate[i+2]; - t_duplicate |= transaction_duplicate[i+3]; - // fprintf(stdout, "reserve_uuid : %ld %ld %ld %ld\n", reserve_uuid[i], reserve_uuid[i+1], reserve_uuid[i+2], reserve_uuid[i+3]); - i += 4; - break; - case 3: - case 2: - qs5=insert2(pg, - &reserves[i], - expiry, - gc, - h_payto, - ¬ify_s[i], - reserve_expiration, - &transaction_duplicate[i], - &conflicts[i], - &reserve_uuid[i], - &results[i]); - if (qs5<0) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to create reserve batch_2 (%d)\n", - qs5); - return qs5; - } - need_update |= conflicts[i]; - need_update |= conflicts[i+1]; - t_duplicate |= transaction_duplicate[i]; - t_duplicate |= transaction_duplicate[i+1]; - results[i] = (t_duplicate) - ? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS - : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; - // fprintf(stdout, "reserve_uuid : %ld %ld\n", reserve_uuid[i], reserve_uuid[i+1]); - i += 2; - break; - case 1: - qs2 = insert1(pg, - &reserves[i], - expiry, - gc, - h_payto, - ¬ify_s[i], - reserve_expiration, - &transaction_duplicate[i], - &conflicts[i], - &reserve_uuid[i], - &results[i]); - if (qs2<0) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to create reserve batch_1 (%d)\n)" - ,qs2); - return qs2; - } - need_update |= conflicts[i]; - t_duplicate |= transaction_duplicate[i]; - // fprintf(stdout, "reserve uuid : %ld c :%d t:%d\n", reserve_uuid[i], conflicts[i], transaction_duplicate[i]); - i += 1; - break; - case 0: - GNUNET_assert (0); - break; - } - } /* end while */ - // commit - { - enum GNUNET_DB_QueryStatus cs; - - cs = TEH_PG_commit (pg); - if (cs < 0) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to commit\n"); - return cs; - } - } - if (! need_update) - { - goto exit; - } - // begin serializable - { - if (GNUNET_OK != - TEH_PG_start (pg, - "reserve-insert-continued")) - { - GNUNET_break (0); - return GNUNET_DB_STATUS_HARD_ERROR; - } - } - - enum GNUNET_DB_QueryStatus qs3; - PREPARE (pg, - "reserves_update", - "SELECT" - " out_duplicate AS duplicate " - "FROM exchange_do_batch_reserves_update" - " ($1,$2,$3,$4,$5,$6,$7,$8);"); - for (unsigned int i = 0; iconn, - "reserves_update", - params, - rs); - if (qs3<0) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to update reserves (%d)\n", - qs3); - results[i] = qs3; - return qs3; - } - results[i] = duplicate - ? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS - : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; - } - } - - { - enum GNUNET_DB_QueryStatus cs; - - cs = TEH_PG_commit (pg); - if (cs < 0) - return cs; - } - -exit: - for (unsigned int i = 0; i - */ -/** - * @file exchangedb/pg_batch2_reserves_in_insert.h - * @brief implementation of the batch2_reserves_in_insert function for Postgres - * @author Joseph XU - */ -#ifndef PG_BATCH2_RESERVES_IN_INSERT_H -#define PG_BATCH2_RESERVES_IN_INSERT_H - -#include "taler_util.h" -#include "taler_json_lib.h" -#include "taler_exchangedb_plugin.h" -enum GNUNET_DB_QueryStatus -TEH_PG_batch2_reserves_in_insert (void *cls, - const struct TALER_EXCHANGEDB_ReserveInInfo *reserves, - unsigned int reserves_length, - unsigned int batch_size, - enum GNUNET_DB_QueryStatus *results); - -#endif diff --git a/src/exchangedb/pg_batch4_reserves_in_insert.c b/src/exchangedb/pg_batch4_reserves_in_insert.c deleted file mode 100644 index 6536eb56c..000000000 --- a/src/exchangedb/pg_batch4_reserves_in_insert.c +++ /dev/null @@ -1,595 +0,0 @@ - -/* - This file is part of TALER - Copyright (C) 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/pg_batch_reserves_in_insert.c - * @brief Implementation of the reserves_in_insert function for Postgres - * @author Joseph Xu - */ -#include "platform.h" -#include "taler_error_codes.h" -#include "taler_dbevents.h" -#include "taler_pq_lib.h" -#include "pg_batch_reserves_in_insert.h" -#include "pg_helper.h" -#include "pg_start.h" -#include "pg_rollback.h" -#include "pg_start_read_committed.h" -#include "pg_commit.h" -#include "pg_reserves_get.h" -#include "pg_reserves_update.h" -#include "pg_setup_wire_target.h" -#include "pg_event_notify.h" -#include "pg_preflight.h" - -/** - * Generate event notification for the reserve change. - * - * @param reserve_pub reserve to notfiy on - */ -static char * -compute_notify_on_reserve (const struct TALER_ReservePublicKeyP *reserve_pub) -{ - struct TALER_ReserveEventP rep = { - .header.size = htons (sizeof (rep)), - .header.type = htons (TALER_DBEVENT_EXCHANGE_RESERVE_INCOMING), - .reserve_pub = *reserve_pub - }; - - return GNUNET_PG_get_event_notify_channel (&rep.header); -} - - -static enum GNUNET_DB_QueryStatus -insert1(struct PostgresClosure *pg, - const struct TALER_EXCHANGEDB_ReserveInInfo *reserve, - struct GNUNET_TIME_Timestamp expiry, - struct GNUNET_TIME_Timestamp gc, - struct TALER_PaytoHashP h_payto, - const char *notify_s, - struct GNUNET_TIME_Timestamp reserve_expiration, - bool *transaction_duplicate, - bool *conflict, - uint64_t *reserve_uuid) -{ - enum GNUNET_DB_QueryStatus qs2; - PREPARE (pg, - "reserve_creates", - "SELECT " - "out_reserve_found AS conflicted" - ",transaction_duplicate" - ",ruuid AS reserve_uuid" - " FROM exchange_do_batch_reserves_in_insert" - " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12);"); - - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (&reserve->reserve_pub), - GNUNET_PQ_query_param_timestamp (&expiry), - GNUNET_PQ_query_param_timestamp (&gc), - GNUNET_PQ_query_param_uint64 (&reserve->wire_reference), - TALER_PQ_query_param_amount (&reserve->balance), - GNUNET_PQ_query_param_string (reserve->exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserve->execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto), - GNUNET_PQ_query_param_string (reserve->sender_account_details), - GNUNET_PQ_query_param_timestamp (&reserve_expiration), - GNUNET_PQ_query_param_string (notify_s), - GNUNET_PQ_query_param_end - }; - - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_bool ("conflicted", - conflict), - GNUNET_PQ_result_spec_bool ("transaction_duplicate", - transaction_duplicate), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid", - reserve_uuid), - GNUNET_PQ_result_spec_end - }; - - TALER_payto_hash (reserve->sender_account_details, - &h_payto); - - /* Note: query uses 'on conflict do nothing' */ - qs2 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "reserve_creates", - params, - rs); - - if (qs2 < 0) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to create reserves (%d)\n", - qs2); - return qs2; - } - GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs2); - - if ((*conflict) && (*transaction_duplicate)) - { - GNUNET_break (0); - TEH_PG_rollback (pg); - return GNUNET_DB_STATUS_HARD_ERROR; - } - return qs2; -} - - - -static enum GNUNET_DB_QueryStatus -insert2 (struct PostgresClosure *pg, - const struct TALER_EXCHANGEDB_ReserveInInfo *reserve0, - const struct TALER_EXCHANGEDB_ReserveInInfo *reserve1, - struct GNUNET_TIME_Timestamp expiry, - struct GNUNET_TIME_Timestamp gc, - struct TALER_PaytoHashP h_payto, - const char *notify_s, - struct GNUNET_TIME_Timestamp reserve_expiration, - bool *transaction_duplicate, - bool *transaction_duplicate2, - bool *conflict, - bool *conflict2, - uint64_t *reserve_uuid, - uint64_t *reserve_uuid2) -{ - PREPARE (pg, - "reserve_create", - "SELECT " - "out_reserve_found AS conflicted" - ",out_reserve_found2 AS conflicted2" - ",transaction_duplicate" - ",transaction_duplicate2" - ",ruuid AS reserve_uuid" - ",ruuid2 AS reserve_uuid2" - " FROM exchange_do_batch2_reserves_insert" - " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21);"); - - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (&reserve0->reserve_pub), - GNUNET_PQ_query_param_timestamp (&expiry), - GNUNET_PQ_query_param_timestamp (&gc), - GNUNET_PQ_query_param_uint64 (&reserve0->wire_reference), - TALER_PQ_query_param_amount (&reserve0->balance), - GNUNET_PQ_query_param_string (reserve0->exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserve0->execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto), - GNUNET_PQ_query_param_string (reserve0->sender_account_details), - GNUNET_PQ_query_param_timestamp (&reserve_expiration), - GNUNET_PQ_query_param_string (notify_s), - GNUNET_PQ_query_param_auto_from_type (&reserve1->reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserve1->wire_reference), - TALER_PQ_query_param_amount (&reserve1->balance), - GNUNET_PQ_query_param_string (reserve1->exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserve1->execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto), - GNUNET_PQ_query_param_string (reserve1->sender_account_details), - GNUNET_PQ_query_param_timestamp (&reserve_expiration), - - GNUNET_PQ_query_param_end - }; - - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_bool ("conflicted", - conflict), - GNUNET_PQ_result_spec_bool ("conflicted2", - conflict2), - GNUNET_PQ_result_spec_bool ("transaction_duplicate", - transaction_duplicate), - GNUNET_PQ_result_spec_bool ("transaction_duplicate2", - transaction_duplicate2), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid", - reserve_uuid), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid2", - reserve_uuid2), - GNUNET_PQ_result_spec_end - }; - - TALER_payto_hash (reserve0->sender_account_details, - &h_payto); - TALER_payto_hash (reserve1->sender_account_details, - &h_payto); - - - qs1 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "reserve_create", - params, - rs); - if (qs1 < 0) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to create reserves (%d)\n", - qs1); - return qs1; - } - /* - GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs1); - results[i] = (transaction_duplicate) - ? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS - : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;*/ - - if ((*conflict) && (*transaction_duplicate) ||((*conflict2) && (*transaction_duplicate2))) - { - GNUNET_break (0); - TEH_PG_rollback (pg); - return GNUNET_DB_STATUS_HARD_ERROR; - } - -} - - -static enum GNUNET_DB_QueryStatus -insert4 (struct PostgresClosure *pg, - const struct TALER_EXCHANGEDB_ReserveInInfo *reserve0, - const struct TALER_EXCHANGEDB_ReserveInInfo *reserve1, - const struct TALER_EXCHANGEDB_ReserveInInfo *reserve2, - const struct TALER_EXCHANGEDB_ReserveInInfo *reserve3, - struct GNUNET_TIME_Timestamp expiry, - struct GNUNET_TIME_Timestamp gc, - struct TALER_PaytoHashP h_payto, - const char *notify_s, - struct GNUNET_TIME_Timestamp reserve_expiration, - bool *transaction_duplicate, - bool *transaction_duplicate2, - bool *transaction_duplicate3, - bool *transaction_duplicate4, - bool *conflict, - bool *conflict2, - bool *conflict3, - bool *conflict4, - uint64_t *reserve_uuid, - uint64_t *reserve_uuid2, - uint64_t *reserve_uuid3, - uint64_t *reserve_uuid4) -{ - PREPARE (pg, - "reserve_create", - "SELECT " - "out_reserve_found AS conflicted" - ",out_reserve_found2 AS conflicted2" - ",out_reserve_found3 AS conflicted3" - ",out_reserve_found4 AS conflicted4" - ",transaction_duplicate" - ",transaction_duplicate2" - ",transaction_duplicate3" - ",transaction_duplicate4" - ",ruuid AS reserve_uuid" - ",ruuid2 AS reserve_uuid2" - ",ruuid3 AS reserve_uuid3" - ",ruuid4 AS reserve_uuid4" - " FROM exchange_do_batch4_reserves_insert" - " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$30,$31,$32,$33,$34,$35,$36,$37,$38,$39);"); - - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (&reserve0->reserve_pub), - GNUNET_PQ_query_param_timestamp (&expiry), - GNUNET_PQ_query_param_timestamp (&gc), - GNUNET_PQ_query_param_uint64 (&reserve0->wire_reference), - TALER_PQ_query_param_amount (&reserve0->balance), - GNUNET_PQ_query_param_string (reserve0->exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserve0->execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto), - GNUNET_PQ_query_param_string (reserve0->sender_account_details), - GNUNET_PQ_query_param_timestamp (&reserve_expiration), - GNUNET_PQ_query_param_string (notify_s), - - GNUNET_PQ_query_param_auto_from_type (&reserve1->reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserve1->wire_reference), - TALER_PQ_query_param_amount (&reserve1->balance), - GNUNET_PQ_query_param_string (reserve1->exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserve1->execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto), - GNUNET_PQ_query_param_string (reserve1->sender_account_details), - GNUNET_PQ_query_param_timestamp (&reserve_expiration), - - GNUNET_PQ_query_param_auto_from_type (&reserve2->reserve_pub), - GNUNET_PQ_query_param_timestamp (&expiry), - GNUNET_PQ_query_param_timestamp (&gc), - GNUNET_PQ_query_param_uint64 (&reserve2->wire_reference), - TALER_PQ_query_param_amount (&reserve2->balance), - GNUNET_PQ_query_param_string (reserve2->exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserve2->execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto), - GNUNET_PQ_query_param_string (reserve2->sender_account_details), - GNUNET_PQ_query_param_timestamp (&reserve_expiration), - - GNUNET_PQ_query_param_auto_from_type (&reserve3->reserve_pub), - GNUNET_PQ_query_param_timestamp (&expiry), - GNUNET_PQ_query_param_timestamp (&gc), - GNUNET_PQ_query_param_uint64 (&reserve3->wire_reference), - TALER_PQ_query_param_amount (&reserve3->balance), - GNUNET_PQ_query_param_string (reserve3->exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserve3->execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto), - GNUNET_PQ_query_param_string (reserve3->sender_account_details), - GNUNET_PQ_query_param_timestamp (&reserve_expiration) - - GNUNET_PQ_query_param_end - }; - - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_bool ("conflicted", - conflict), - GNUNET_PQ_result_spec_bool ("conflicted2", - conflict2), - GNUNET_PQ_result_spec_bool ("conflicted3", - conflict3), - GNUNET_PQ_result_spec_bool ("conflicted4", - conflict4), - GNUNET_PQ_result_spec_bool ("transaction_duplicate", - transaction_duplicate), - GNUNET_PQ_result_spec_bool ("transaction_duplicate2", - transaction_duplicate2), - GNUNET_PQ_result_spec_bool ("transaction_duplicate3", - transaction_duplicate3), - GNUNET_PQ_result_spec_bool ("transaction_duplicate4", - transaction_duplicate4), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid", - reserve_uuid), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid2", - reserve_uuid2), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid3", - reserve_uuid3), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid4", - reserve_uuid4), - GNUNET_PQ_result_spec_end - }; - - TALER_payto_hash (reserve0->sender_account_details, - &h_payto); - TALER_payto_hash (reserve1->sender_account_details, - &h_payto); - - - qs1 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "reserve_create", - params, - rs); - if (qs1 < 0) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to create reserves (%d)\n", - qs1); - return qs1; - } - /* - GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs1); - results[i] = (transaction_duplicate) - ? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS - : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;*/ - - if ((*conflict) && (*transaction_duplicate) ||((*conflict2) && (*transaction_duplicate2))) - { - GNUNET_break (0); - TEH_PG_rollback (pg); - return GNUNET_DB_STATUS_HARD_ERROR; - } - -} - - - -enum GNUNET_DB_QueryStatus -TEH_PG_batch2_reserves_in_insert (void *cls, - const struct TALER_EXCHANGEDB_ReserveInInfo *reserves, - unsigned int reserves_length, - enum GNUNET_DB_QueryStatus *results) -{ - struct PostgresClosure *pg = cls; - enum GNUNET_DB_QueryStatus qs1; - enum GNUNET_DB_QueryStatus qs2; - enum GNUNET_DB_QueryStatus qs4; - enum GNUNET_DB_QueryStatus qs5; - struct GNUNET_TIME_Timestamp expiry; - struct GNUNET_TIME_Timestamp gc; - struct TALER_PaytoHashP h_payto; - uint64_t reserve_uuid[reserves_length]; - bool conflicted; - bool conflicted2; - bool transaction_duplicate[reserves_length]; - bool need_update = false; - bool need_update2 = false; - struct GNUNET_TIME_Timestamp reserve_expiration - = GNUNET_TIME_relative_to_timestamp (pg->idle_reserve_expiration_time); - bool conflicts[reserves_length]; - char *notify_s[reserves_length]; - - if (GNUNET_OK != - TEH_PG_preflight (pg)) - { - GNUNET_break (0); - return GNUNET_DB_STATUS_HARD_ERROR; - } - - expiry = GNUNET_TIME_absolute_to_timestamp ( - GNUNET_TIME_absolute_add (reserves->execution_time.abs_time, - pg->idle_reserve_expiration_time)); - gc = GNUNET_TIME_absolute_to_timestamp ( - GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), - pg->legal_reserve_expiration_time)); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Creating reserve %s with expiration in %s\n", - TALER_B2S (&(reserves->reserve_pub)), - GNUNET_STRINGS_relative_time_to_string ( - pg->idle_reserve_expiration_time, - GNUNET_NO)); - - { - if (GNUNET_OK != - TEH_PG_start_read_committed(pg, - "READ_COMMITED")) - { - GNUNET_break (0); - return GNUNET_DB_STATUS_HARD_ERROR; - } - } - /* Optimistically assume this is a new reserve, create balance for the first - time; we do this before adding the actual transaction to "reserves_in", - as for a new reserve it can't be a duplicate 'add' operation, and as - the 'add' operation needs the reserve entry as a foreign key. */ - for (unsigned int i=0;ireserve_pub); - } - - unsigned int i=0; - - while (i < reserves_length) - { - if (reserves_length - i >= 4) - { - qs4=insert4(pg, - &reserves[i], - &reserves[i+2], - &reserves[i+3], - &reserves[i+4], - expiry, - gc, - h_payto, - ¬ify_s[i], - reserve_expiration, - &transaction_duplicate[i], - &transaction_duplicate[i+1], - &transaction_duplicate[i+2], - &transaction_duplicate[i+3], - &conflicts[i], - &conflicts[i+1], - &conflicts[i+2], - &conflicts[i+3], - &reserve_uuid[i], - &reserve_uuid[i+1], - &reserve_uuid[i+2], - &reserve_uuid[i+3]); - - need_update |= conflicts[i]; - need_update |= conflicts[i+1]; - need_update |= conflicts[i+2]; - need_update |= conflicts[i+3]; - i += 4; - continue; - } - switch (reserves_length - i) - { - case 3: - case 2: - qs5=insert2(pg, - &reserves[i], - &reserves[i+1], - expiry, - gc, - h_payto, - notify_s[i], - reserve_expiration, - &transaction_duplicate[i], - &transaction_duplicate[i+1], - &conflicts[i], - &conflicts[i+1], - &reserve_uuid[i], - &reserve_uuid[i+1]); - need_update |= conflicts[i]; - need_update |= conflicts[i+1]; - i += 2; - break; - case 1: - qs2 = insert1(pg, - &reserves[i], - expiry, - gc, - h_payto, - notify_s[i], - reserve_expiration, - &transaction_duplicate[i], - &conflicts[i], - &reserve_uuid[i]); - need_update |= conflicts[i]; - i += 1; - break; - case 0: - GNUNET_assert (0); - break; - } - } /* end while */ - // commit - { - enum GNUNET_DB_QueryStatus cs; - - cs = TEH_PG_commit (pg); - if (cs < 0) - return cs; - } - - if (!need_update ) - goto exit; - // begin serializable - { - if (GNUNET_OK != - TEH_PG_start(pg, - "reserve-insert-continued")) - { - GNUNET_break (0); - return GNUNET_DB_STATUS_HARD_ERROR; - } - } - - enum GNUNET_DB_QueryStatus qs3; - PREPARE (pg, - "reserves_in_add_transaction", - "CALL exchange_do_batch_reserves_update" - " ($1,$2,$3,$4,$5,$6,$7,$8,$9);"); - for (unsigned int i=0;ireserve_pub), - GNUNET_PQ_query_param_timestamp (&expiry), - GNUNET_PQ_query_param_uint64 (&reserve->wire_reference), - TALER_PQ_query_param_amount (&reserve->balance), - GNUNET_PQ_query_param_string (reserve->exchange_account_name), - GNUNET_PQ_query_param_bool (conflicted), - GNUNET_PQ_query_param_auto_from_type (&h_payto), - GNUNET_PQ_query_param_string (notify_s[i]), - GNUNET_PQ_query_param_end - }; - - qs3 = GNUNET_PQ_eval_prepared_non_select (pg->conn, - "reserves_in_add_transaction", - params); - if (qs3<0) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to update reserves (%d)\n", - qs3); - return qs3; - } - } - } - { - enum GNUNET_DB_QueryStatus cs; - - cs = TEH_PG_commit (pg); - if (cs < 0) - return cs; - } - - exit: - for (unsigned int i=0;i - */ -/** - * @file exchangedb/pg_batch_reserves_in_insert.c - * @brief Implementation of the reserves_in_insert function for Postgres - * @author Joseph Xu - */ -#include "platform.h" -#include "taler_error_codes.h" -#include "taler_dbevents.h" -#include "taler_pq_lib.h" -#include "pg_batch_reserves_in_insert.h" -#include "pg_helper.h" -#include "pg_start.h" -#include "pg_rollback.h" -#include "pg_start_read_committed.h" -#include "pg_commit.h" -#include "pg_reserves_get.h" -#include "pg_reserves_update.h" -#include "pg_setup_wire_target.h" -#include "pg_event_notify.h" -#include "pg_preflight.h" - - -/** - * Generate event notification for the reserve change. - * - * @param reserve_pub reserve to notfiy on - */ -static char * -compute_notify_on_reserve (const struct TALER_ReservePublicKeyP *reserve_pub) -{ - struct TALER_ReserveEventP rep = { - .header.size = htons (sizeof (rep)), - .header.type = htons (TALER_DBEVENT_EXCHANGE_RESERVE_INCOMING), - .reserve_pub = *reserve_pub - }; - - return GNUNET_PG_get_event_notify_channel (&rep.header); -} - - -enum GNUNET_DB_QueryStatus -TEH_PG_batch_reserves_in_insert ( - void *cls, - const struct TALER_EXCHANGEDB_ReserveInInfo *reserves, - unsigned int reserves_length, - enum GNUNET_DB_QueryStatus *results) -{ - struct PostgresClosure *pg = cls; - enum GNUNET_DB_QueryStatus qs1; - struct GNUNET_TIME_Timestamp expiry; - struct GNUNET_TIME_Timestamp gc; - struct TALER_PaytoHashP h_payto; - uint64_t reserve_uuid; - struct GNUNET_TIME_Timestamp reserve_expiration - = GNUNET_TIME_relative_to_timestamp (pg->idle_reserve_expiration_time); - bool conflicts[reserves_length]; - char *notify_s[reserves_length]; - - if (GNUNET_OK != - TEH_PG_preflight (pg)) - { - GNUNET_break (0); - return GNUNET_DB_STATUS_HARD_ERROR; - } - PREPARE (pg, - "reserve_create", - "SELECT " - "out_reserve_found AS conflicted" - ",transaction_duplicate" - ",ruuid AS reserve_uuid" - " FROM exchange_do_batch_reserves_in_insert" - " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12);"); - expiry = GNUNET_TIME_absolute_to_timestamp ( - GNUNET_TIME_absolute_add (reserves->execution_time.abs_time, - pg->idle_reserve_expiration_time)); - gc = GNUNET_TIME_absolute_to_timestamp ( - GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), - pg->legal_reserve_expiration_time)); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Creating reserve %s with expiration in %s\n", - TALER_B2S (reserves->reserve_pub), - GNUNET_STRINGS_relative_time_to_string ( - pg->idle_reserve_expiration_time, - GNUNET_NO)); - if (GNUNET_OK != - TEH_PG_start_read_committed (pg, - "READ_COMMITED")) - { - GNUNET_break (0); - return GNUNET_DB_STATUS_HARD_ERROR; - } - /* Optimistically assume this is a new reserve, create balance for the first - time; we do this before adding the actual transaction to "reserves_in", - as for a new reserve it can't be a duplicate 'add' operation, and as - the 'add' operation needs the reserve entry as a foreign key. */ - for (unsigned int i = 0; ireserve_pub); - } - bool need_update = false; - for (unsigned int i = 0; iconn, - "reserve_create", - params, - rs); - if (qs1 < 0) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to create reserves (%d)\n", - qs1); - results[i] = qs1; - return qs1; - } - GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs1); - conflicts[i] = conflicted; - // fprintf(stdout, "%d", conflicts[i]); - if (conflicts[i] && transaction_duplicate) - { - GNUNET_break (0); - results[i] = GNUNET_DB_STATUS_HARD_ERROR; - TEH_PG_rollback (pg); - return GNUNET_DB_STATUS_HARD_ERROR; - } - results[i] = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; - need_update |= conflicted; - } - // commit - { - enum GNUNET_DB_QueryStatus cs; - - cs = TEH_PG_commit (pg); - if (cs < 0) - return cs; - } - if (! need_update) - goto exit; - // begin serializable - { - if (GNUNET_OK != - TEH_PG_start (pg, - "reserve-insert-continued")) - { - GNUNET_break (0); - return GNUNET_DB_STATUS_HARD_ERROR; - } - } - - enum GNUNET_DB_QueryStatus qs2; - PREPARE (pg, - "reserves_in_add_transaction", - "SELECT" - " out_duplicate AS duplicate" - " FROM exchange_do_batch_reserves_update" - " ($1,$2,$3,$4,$5,$6,$7,$8);"); - for (unsigned int i = 0; iconn, - "reserves_in_add_transaction", - params, - rs); - if (qs2 < 0) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to update reserves (%d)\n", - qs2); - results[i] = qs2; - return qs2; - } - results[i] = duplicate - ? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS - : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; - } - } - { - enum GNUNET_DB_QueryStatus cs; - - cs = TEH_PG_commit (pg); - if (cs < 0) - return cs; - } -exit: - for (unsigned int i = 0; i - */ -/** - * @file exchangedb/pg_batch_reserves_in_insert.h - * @brief implementation of the batch_reserves_in_insert function for Postgres - * @author Christian Grothoff - */ -#ifndef PG_BATCH_RESERVES_IN_INSERT_H -#define PG_BATCH_RESERVES_IN_INSERT_H - -#include "taler_util.h" -#include "taler_json_lib.h" -#include "taler_exchangedb_plugin.h" - - -enum GNUNET_DB_QueryStatus -TEH_PG_batch_reserves_in_insert (void *cls, - const struct TALER_EXCHANGEDB_ReserveInInfo *reserves, - unsigned int reserves_length, - enum GNUNET_DB_QueryStatus *results); - -#endif diff --git a/src/exchangedb/pg_get_link_data.c b/src/exchangedb/pg_get_link_data.c index 26225a13d..a07954335 100644 --- a/src/exchangedb/pg_get_link_data.c +++ b/src/exchangedb/pg_get_link_data.c @@ -55,7 +55,7 @@ struct LinkDataContext /** * Status, set to #GNUNET_SYSERR on errors, */ - int status; + enum GNUNET_GenericReturnValue status; }; @@ -190,20 +190,18 @@ TEH_PG_get_link_data (void *cls, "%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; + { + if (NULL != mode) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Bad mode `%s' specified\n", + mode); + percent_refund = 0; + } } - switch (percent_refund) { case 0: - query="get_link"; + query = "get_link"; PREPARE (pg, query, "SELECT " @@ -225,7 +223,7 @@ TEH_PG_get_link_data (void *cls, " ORDER BY tp.transfer_pub, rrc.freshcoin_index ASC"); break; case 1: - query="get_link_v1"; + query = "get_link_v1"; PREPARE (pg, query, "WITH rc AS MATERIALIZED (" @@ -252,7 +250,7 @@ TEH_PG_get_link_data (void *cls, " ORDER BY tp.transfer_pub, rrc.freshcoin_index ASC"); break; case 2: - query="get_link_v2"; + query = "get_link_v2"; PREPARE (pg, query, "SELECT" @@ -300,5 +298,3 @@ TEH_PG_get_link_data (void *cls, return GNUNET_DB_STATUS_HARD_ERROR; return qs; } - - diff --git a/src/exchangedb/pg_get_ready_deposit.c b/src/exchangedb/pg_get_ready_deposit.c index 73ac9e47b..91151c617 100644 --- a/src/exchangedb/pg_get_ready_deposit.c +++ b/src/exchangedb/pg_get_ready_deposit.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2022 Taler Systems SA + Copyright (C) 2022, 2023 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -33,15 +33,16 @@ TEH_PG_get_ready_deposit (void *cls, struct TALER_MerchantPublicKeyP *merchant_pub, char **payto_uri) { + static int choose_mode = -2; struct PostgresClosure *pg = cls; - struct GNUNET_TIME_Absolute now = {0}; + struct GNUNET_TIME_Absolute now + = GNUNET_TIME_absolute_get (); struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_absolute_time (&now), GNUNET_PQ_query_param_uint64 (&start_shard_row), 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), @@ -49,181 +50,70 @@ TEH_PG_get_ready_deposit (void *cls, payto_uri), GNUNET_PQ_result_spec_end }; - - now = GNUNET_TIME_absolute_round_down (GNUNET_TIME_absolute_get (), - pg->aggregator_shift); - GNUNET_assert (start_shard_row < end_shard_row); - GNUNET_assert (end_shard_row <= INT32_MAX); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Finding ready deposits by deadline %s (%llu)\n", - GNUNET_TIME_absolute2s (now), - (unsigned long long) now.abs_value_us); - int choose_mode =-2; const char *query; if (-2 == choose_mode) { - const char *mode = getenv ("NEW_LOGIC"); + const char *mode = getenv ("TALER_POSTGRES_GET_READY_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; - - + { + if (NULL != mode) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Bad mode `%s' specified\n", + mode); + choose_mode = 0; + } } switch (choose_mode) { case 0: - query="deposits_get_ready"; + query = "deposits_get_ready-v5"; 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" + " FROM deposits dep" + " JOIN wire_targets wt" + " USING (wire_target_h_payto)" + " WHERE NOT (done OR policy_blocked)" + " AND dep.wire_deadline<=$1" + " AND dep.shard >= $2" + " AND dep.shard <= $3" " ORDER BY " - " dbr.wire_deadline ASC" - " ,dbr.shard ASC" + " dep.wire_deadline ASC" + " ,dep.shard ASC" " LIMIT 1;"); break; case 1: - query="deposits_get_ready_v1"; + query = "deposits_get_ready-v6"; 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" + " merchant_pub" + ",wire_target_h_payto" " 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" + " WHERE NOT (done OR policy_blocked)" + " AND 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)" - ); + ",rc.merchant_pub" + " FROM wire_targets wt" + " JOIN rc" + " USING (wire_target_h_payto);"); break; default: GNUNET_break (0); diff --git a/src/exchangedb/pg_reserves_in_insert.c b/src/exchangedb/pg_reserves_in_insert.c index 0fdc4a16c..314e89d8b 100644 --- a/src/exchangedb/pg_reserves_in_insert.c +++ b/src/exchangedb/pg_reserves_in_insert.c @@ -27,6 +27,8 @@ #include "pg_start.h" #include "pg_start_read_committed.h" #include "pg_commit.h" +#include "pg_preflight.h" +#include "pg_rollback.h" #include "pg_reserves_get.h" #include "pg_reserves_update.h" #include "pg_setup_wire_target.h" @@ -34,15 +36,13 @@ /** - * Generate event notification for the reserve - * change. + * Generate event notification for the reserve change. * - * @param pg plugin state * @param reserve_pub reserve to notfiy on + * @return string to pass to postgres for the notification */ -static void -notify_on_reserve (struct PostgresClosure *pg, - const struct TALER_ReservePublicKeyP *reserve_pub) +static char * +compute_notify_on_reserve (const struct TALER_ReservePublicKeyP *reserve_pub) { struct TALER_ReserveEventP rep = { .header.size = htons (sizeof (rep)), @@ -50,246 +50,868 @@ notify_on_reserve (struct PostgresClosure *pg, .reserve_pub = *reserve_pub }; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Notifying on reserve!\n"); - TEH_PG_event_notify (pg, - &rep.header, - NULL, - 0); + return GNUNET_PG_get_event_notify_channel (&rep.header); +} + + +static enum GNUNET_DB_QueryStatus +insert1 (struct PostgresClosure *pg, + const struct TALER_EXCHANGEDB_ReserveInInfo reserves[1], + struct GNUNET_TIME_Timestamp expiry, + struct GNUNET_TIME_Timestamp gc, + struct TALER_PaytoHashP h_payto, + char *const *notify_s, + struct GNUNET_TIME_Timestamp reserve_expiration, + bool *transaction_duplicate, + bool *conflict, + uint64_t *reserve_uuid, + enum GNUNET_DB_QueryStatus results[1]) +{ + enum GNUNET_DB_QueryStatus qs2; + PREPARE (pg, + "batch1_reserve_create", + "SELECT " + " out_reserve_found AS conflicted" + ",transaction_duplicate" + ",ruuid AS reserve_uuid" + " FROM exchange_do_batch_reserves_in_insert" + " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12);"); + + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (reserves[0].reserve_pub), + GNUNET_PQ_query_param_timestamp (&expiry), + GNUNET_PQ_query_param_timestamp (&gc), + GNUNET_PQ_query_param_uint64 (&reserves[0].wire_reference), + TALER_PQ_query_param_amount (reserves[0].balance), + GNUNET_PQ_query_param_string (reserves[0].exchange_account_name), + GNUNET_PQ_query_param_timestamp (&reserves[0].execution_time), + GNUNET_PQ_query_param_auto_from_type (&h_payto), + GNUNET_PQ_query_param_string (reserves[0].sender_account_details), + GNUNET_PQ_query_param_timestamp (&reserve_expiration), + GNUNET_PQ_query_param_string (notify_s[0]), + GNUNET_PQ_query_param_end + }; + + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_bool ("conflicted", + &conflict[0]), + GNUNET_PQ_result_spec_bool ("transaction_duplicate", + &transaction_duplicate[0]), + GNUNET_PQ_result_spec_uint64 ("reserve_uuid", + &reserve_uuid[0]), + GNUNET_PQ_result_spec_end + }; + + + TALER_payto_hash (reserves[0].sender_account_details, + &h_payto); + + qs2 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "batch1_reserve_create", + params, + rs); + + if (qs2 < 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to create reserves 1(%d)\n", + qs2); + results[0] = qs2; + return qs2; + } + GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs2); + if ((! conflict[0]) && transaction_duplicate[0]) + { + GNUNET_break (0); + TEH_PG_rollback (pg); + results[0] = GNUNET_DB_STATUS_HARD_ERROR; + return GNUNET_DB_STATUS_HARD_ERROR; + } + results[0] = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; + return qs2; +} + + +static enum GNUNET_DB_QueryStatus +insert2 (struct PostgresClosure *pg, + const struct TALER_EXCHANGEDB_ReserveInInfo reserves[2], + struct GNUNET_TIME_Timestamp expiry, + struct GNUNET_TIME_Timestamp gc, + struct TALER_PaytoHashP h_payto, + char *const*notify_s, + struct GNUNET_TIME_Timestamp reserve_expiration, + bool *transaction_duplicate, + bool *conflict, + uint64_t *reserve_uuid, + enum GNUNET_DB_QueryStatus results[1]) +{ + enum GNUNET_DB_QueryStatus qs1; + PREPARE (pg, + "batch2_reserve_create", + "SELECT " + "out_reserve_found AS conflicted" + ",out_reserve_found2 AS conflicted2" + ",transaction_duplicate" + ",transaction_duplicate2" + ",ruuid AS reserve_uuid" + ",ruuid2 AS reserve_uuid2" + " FROM exchange_do_batch2_reserves_insert" + " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22);"); + + struct GNUNET_PQ_QueryParam params[] = { + + GNUNET_PQ_query_param_auto_from_type (reserves[0].reserve_pub), + GNUNET_PQ_query_param_timestamp (&expiry), + GNUNET_PQ_query_param_timestamp (&gc), + GNUNET_PQ_query_param_uint64 (&reserves[0].wire_reference), + TALER_PQ_query_param_amount (reserves[0].balance), + GNUNET_PQ_query_param_string (reserves[0].exchange_account_name), + GNUNET_PQ_query_param_timestamp (&reserves[0].execution_time), + GNUNET_PQ_query_param_auto_from_type (&h_payto), + GNUNET_PQ_query_param_string (reserves[0].sender_account_details), + GNUNET_PQ_query_param_timestamp (&reserve_expiration), + GNUNET_PQ_query_param_string (notify_s[0]), + GNUNET_PQ_query_param_string (notify_s[1]), + + GNUNET_PQ_query_param_auto_from_type (reserves[1].reserve_pub), + GNUNET_PQ_query_param_uint64 (&reserves[1].wire_reference), + TALER_PQ_query_param_amount (reserves[1].balance), + GNUNET_PQ_query_param_string (reserves[1].exchange_account_name), + GNUNET_PQ_query_param_timestamp (&reserves[1].execution_time), + GNUNET_PQ_query_param_auto_from_type (&h_payto), + GNUNET_PQ_query_param_string (reserves[1].sender_account_details), + GNUNET_PQ_query_param_timestamp (&reserve_expiration), + GNUNET_PQ_query_param_end + }; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_bool ("conflicted", + &conflict[0]), + GNUNET_PQ_result_spec_bool ("conflicted2", + &conflict[1]), + GNUNET_PQ_result_spec_bool ("transaction_duplicate", + &transaction_duplicate[0]), + GNUNET_PQ_result_spec_bool ("transaction_duplicate2", + &transaction_duplicate[1]), + GNUNET_PQ_result_spec_uint64 ("reserve_uuid", + &reserve_uuid[0]), + GNUNET_PQ_result_spec_uint64 ("reserve_uuid2", + &reserve_uuid[1]), + GNUNET_PQ_result_spec_end + }; + + TALER_payto_hash (reserves[0].sender_account_details, + &h_payto); + TALER_payto_hash (reserves[1].sender_account_details, + &h_payto); + + + qs1 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "batch2_reserve_create", + params, + rs); + if (qs1 < 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to create reserves 2(%d)\n", + qs1); + results[0] = qs1; + return qs1; + } + + GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs1); + /* results[i] = (transaction_duplicate) + ? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS + : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;*/ + + if ( + ((! conflict[0]) && (transaction_duplicate[0])) + || ((! conflict[1]) && (transaction_duplicate[1])) + ) + { + GNUNET_break (0); + TEH_PG_rollback (pg); // ROLLBACK + results[0] = GNUNET_DB_STATUS_HARD_ERROR; + return GNUNET_DB_STATUS_HARD_ERROR; + } + results[0] = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; + return qs1; +} + + +static enum GNUNET_DB_QueryStatus +insert4 (struct PostgresClosure *pg, + const struct TALER_EXCHANGEDB_ReserveInInfo reserves[4], + struct GNUNET_TIME_Timestamp expiry, + struct GNUNET_TIME_Timestamp gc, + struct TALER_PaytoHashP h_payto, + char *const*notify_s, + struct GNUNET_TIME_Timestamp reserve_expiration, + bool *transaction_duplicate, + bool *conflict, + uint64_t *reserve_uuid, + enum GNUNET_DB_QueryStatus results[1]) +{ + enum GNUNET_DB_QueryStatus qs3; + PREPARE (pg, + "batch4_reserve_create", + "SELECT " + "out_reserve_found AS conflicted" + ",out_reserve_found2 AS conflicted2" + ",out_reserve_found3 AS conflicted3" + ",out_reserve_found4 AS conflicted4" + ",transaction_duplicate" + ",transaction_duplicate2" + ",transaction_duplicate3" + ",transaction_duplicate4" + ",ruuid AS reserve_uuid" + ",ruuid2 AS reserve_uuid2" + ",ruuid3 AS reserve_uuid3" + ",ruuid4 AS reserve_uuid4" + " FROM exchange_do_batch4_reserves_insert" + " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$30,$31,$32,$33,$34,$35,$36,$37,$38,$39, $40, $41,$42);"); + + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (reserves[0].reserve_pub), + GNUNET_PQ_query_param_timestamp (&expiry), + GNUNET_PQ_query_param_timestamp (&gc), + GNUNET_PQ_query_param_uint64 (&reserves[0].wire_reference), + TALER_PQ_query_param_amount (reserves[0].balance), + GNUNET_PQ_query_param_string (reserves[0].exchange_account_name), + GNUNET_PQ_query_param_timestamp (&reserves[0].execution_time), + GNUNET_PQ_query_param_auto_from_type (&h_payto), + GNUNET_PQ_query_param_string (reserves[0].sender_account_details), + GNUNET_PQ_query_param_timestamp (&reserve_expiration), + GNUNET_PQ_query_param_string (notify_s[0]), + GNUNET_PQ_query_param_string (notify_s[1]), + GNUNET_PQ_query_param_string (notify_s[2]), + GNUNET_PQ_query_param_string (notify_s[3]), + + GNUNET_PQ_query_param_auto_from_type (reserves[1].reserve_pub), + GNUNET_PQ_query_param_uint64 (&reserves[1].wire_reference), + TALER_PQ_query_param_amount (reserves[1].balance), + GNUNET_PQ_query_param_string (reserves[1].exchange_account_name), + GNUNET_PQ_query_param_timestamp (&reserves[1].execution_time), + GNUNET_PQ_query_param_auto_from_type (&h_payto), + GNUNET_PQ_query_param_string (reserves[1].sender_account_details), + GNUNET_PQ_query_param_timestamp (&reserve_expiration), + + GNUNET_PQ_query_param_auto_from_type (reserves[2].reserve_pub), + GNUNET_PQ_query_param_uint64 (&reserves[2].wire_reference), + TALER_PQ_query_param_amount (reserves[2].balance), + GNUNET_PQ_query_param_string (reserves[2].exchange_account_name), + GNUNET_PQ_query_param_timestamp (&reserves[2].execution_time), + GNUNET_PQ_query_param_auto_from_type (&h_payto), + GNUNET_PQ_query_param_string (reserves[2].sender_account_details), + GNUNET_PQ_query_param_timestamp (&reserve_expiration), + + GNUNET_PQ_query_param_auto_from_type (reserves[3].reserve_pub), + GNUNET_PQ_query_param_uint64 (&reserves[3].wire_reference), + TALER_PQ_query_param_amount (reserves[3].balance), + GNUNET_PQ_query_param_string (reserves[3].exchange_account_name), + GNUNET_PQ_query_param_timestamp (&reserves[3].execution_time), + GNUNET_PQ_query_param_auto_from_type (&h_payto), + GNUNET_PQ_query_param_string (reserves[3].sender_account_details), + GNUNET_PQ_query_param_timestamp (&reserve_expiration), + + GNUNET_PQ_query_param_end + }; + + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_bool ("conflicted", + &conflict[0]), + GNUNET_PQ_result_spec_bool ("conflicted2", + &conflict[1]), + GNUNET_PQ_result_spec_bool ("conflicted3", + &conflict[2]), + GNUNET_PQ_result_spec_bool ("conflicted4", + &conflict[3]), + GNUNET_PQ_result_spec_bool ("transaction_duplicate", + &transaction_duplicate[0]), + GNUNET_PQ_result_spec_bool ("transaction_duplicate2", + &transaction_duplicate[1]), + GNUNET_PQ_result_spec_bool ("transaction_duplicate3", + &transaction_duplicate[2]), + GNUNET_PQ_result_spec_bool ("transaction_duplicate4", + &transaction_duplicate[3]), + GNUNET_PQ_result_spec_uint64 ("reserve_uuid", + &reserve_uuid[0]), + GNUNET_PQ_result_spec_uint64 ("reserve_uuid2", + &reserve_uuid[1]), + GNUNET_PQ_result_spec_uint64 ("reserve_uuid3", + &reserve_uuid[2]), + GNUNET_PQ_result_spec_uint64 ("reserve_uuid4", + &reserve_uuid[3]), + GNUNET_PQ_result_spec_end + }; + + TALER_payto_hash (reserves[0].sender_account_details, + &h_payto); + TALER_payto_hash (reserves[1].sender_account_details, + &h_payto); + TALER_payto_hash (reserves[2].sender_account_details, + &h_payto); + TALER_payto_hash (reserves[3].sender_account_details, + &h_payto); + + qs3 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "batch4_reserve_create", + params, + rs); + if (qs3 < 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to create reserves4 (%d)\n", + qs3); + results[0] = qs3; + return qs3; + } + + GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs3); + + if ( + ((! conflict[0]) && (transaction_duplicate[0])) + || ((! conflict[1]) && (transaction_duplicate[1])) + || ((! conflict[2]) && (transaction_duplicate[2])) + || ((! conflict[3]) && (transaction_duplicate[3])) + ) + { + GNUNET_break (0); + TEH_PG_rollback (pg); + results[0] = GNUNET_DB_STATUS_HARD_ERROR; + return GNUNET_DB_STATUS_HARD_ERROR; + } + results[0] = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; + return qs3; +} + + +static enum GNUNET_DB_QueryStatus +insert8 (struct PostgresClosure *pg, + const struct TALER_EXCHANGEDB_ReserveInInfo reserves[8], + struct GNUNET_TIME_Timestamp expiry, + struct GNUNET_TIME_Timestamp gc, + struct TALER_PaytoHashP h_payto, + char *const*notify_s, + struct GNUNET_TIME_Timestamp reserve_expiration, + bool *transaction_duplicate, + bool *conflict, + uint64_t *reserve_uuid, + enum GNUNET_DB_QueryStatus results[1]) +{ + enum GNUNET_DB_QueryStatus qs3; + PREPARE (pg, + "batch8_reserve_create", + "SELECT " + "out_reserve_found AS conflicted" + ",out_reserve_found2 AS conflicted2" + ",out_reserve_found3 AS conflicted3" + ",out_reserve_found4 AS conflicted4" + ",out_reserve_found5 AS conflicted5" + ",out_reserve_found6 AS conflicted6" + ",out_reserve_found7 AS conflicted7" + ",out_reserve_found8 AS conflicted8" + ",transaction_duplicate" + ",transaction_duplicate2" + ",transaction_duplicate3" + ",transaction_duplicate4" + ",transaction_duplicate5" + ",transaction_duplicate6" + ",transaction_duplicate7" + ",transaction_duplicate8" + ",ruuid AS reserve_uuid" + ",ruuid2 AS reserve_uuid2" + ",ruuid3 AS reserve_uuid3" + ",ruuid4 AS reserve_uuid4" + ",ruuid5 AS reserve_uuid5" + ",ruuid6 AS reserve_uuid6" + ",ruuid7 AS reserve_uuid7" + ",ruuid8 AS reserve_uuid8" + " FROM exchange_do_batch8_reserves_insert" + " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$30,$31,$32,$33,$34,$35,$36,$37,$38,$39, $40, $41,$42,$43,$44,$45,$46,$47,$48,$49,$50,$51,$52,$53,$54,$55,$56,$57,$58,$59,$60,$61,$62,$63,$64,$65,$66,$67,$68,$69,$70,$71,$72,$73,$74,$75,$76,$77,$78,$79,$80,$81,$82);"); + + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (reserves[0].reserve_pub), + GNUNET_PQ_query_param_timestamp (&expiry), + GNUNET_PQ_query_param_timestamp (&gc), + GNUNET_PQ_query_param_uint64 (&reserves[0].wire_reference), + TALER_PQ_query_param_amount (reserves[0].balance), + GNUNET_PQ_query_param_string (reserves[0].exchange_account_name), + GNUNET_PQ_query_param_timestamp (&reserves[0].execution_time), + GNUNET_PQ_query_param_auto_from_type (&h_payto), + GNUNET_PQ_query_param_string (reserves[0].sender_account_details), + GNUNET_PQ_query_param_timestamp (&reserve_expiration), + GNUNET_PQ_query_param_string (notify_s[0]), + GNUNET_PQ_query_param_string (notify_s[1]), + GNUNET_PQ_query_param_string (notify_s[2]), + GNUNET_PQ_query_param_string (notify_s[3]), + GNUNET_PQ_query_param_string (notify_s[4]), + GNUNET_PQ_query_param_string (notify_s[5]), + GNUNET_PQ_query_param_string (notify_s[6]), + GNUNET_PQ_query_param_string (notify_s[7]), + + GNUNET_PQ_query_param_auto_from_type (reserves[1].reserve_pub), + GNUNET_PQ_query_param_uint64 (&reserves[1].wire_reference), + TALER_PQ_query_param_amount (reserves[1].balance), + GNUNET_PQ_query_param_string (reserves[1].exchange_account_name), + GNUNET_PQ_query_param_timestamp (&reserves[1].execution_time), + GNUNET_PQ_query_param_auto_from_type (&h_payto), + GNUNET_PQ_query_param_string (reserves[1].sender_account_details), + GNUNET_PQ_query_param_timestamp (&reserve_expiration), + + GNUNET_PQ_query_param_auto_from_type (reserves[2].reserve_pub), + GNUNET_PQ_query_param_uint64 (&reserves[2].wire_reference), + TALER_PQ_query_param_amount (reserves[2].balance), + GNUNET_PQ_query_param_string (reserves[2].exchange_account_name), + GNUNET_PQ_query_param_timestamp (&reserves[2].execution_time), + GNUNET_PQ_query_param_auto_from_type (&h_payto), + GNUNET_PQ_query_param_string (reserves[2].sender_account_details), + GNUNET_PQ_query_param_timestamp (&reserve_expiration), + + GNUNET_PQ_query_param_auto_from_type (reserves[3].reserve_pub), + GNUNET_PQ_query_param_uint64 (&reserves[3].wire_reference), + TALER_PQ_query_param_amount (reserves[3].balance), + GNUNET_PQ_query_param_string (reserves[3].exchange_account_name), + GNUNET_PQ_query_param_timestamp (&reserves[3].execution_time), + GNUNET_PQ_query_param_auto_from_type (&h_payto), + GNUNET_PQ_query_param_string (reserves[3].sender_account_details), + GNUNET_PQ_query_param_timestamp (&reserve_expiration), + + GNUNET_PQ_query_param_auto_from_type (reserves[4].reserve_pub), + GNUNET_PQ_query_param_uint64 (&reserves[4].wire_reference), + TALER_PQ_query_param_amount (reserves[4].balance), + GNUNET_PQ_query_param_string (reserves[4].exchange_account_name), + GNUNET_PQ_query_param_timestamp (&reserves[4].execution_time), + GNUNET_PQ_query_param_auto_from_type (&h_payto), + GNUNET_PQ_query_param_string (reserves[4].sender_account_details), + GNUNET_PQ_query_param_timestamp (&reserve_expiration), + + GNUNET_PQ_query_param_auto_from_type (reserves[5].reserve_pub), + GNUNET_PQ_query_param_uint64 (&reserves[5].wire_reference), + TALER_PQ_query_param_amount (reserves[5].balance), + GNUNET_PQ_query_param_string (reserves[5].exchange_account_name), + GNUNET_PQ_query_param_timestamp (&reserves[5].execution_time), + GNUNET_PQ_query_param_auto_from_type (&h_payto), + GNUNET_PQ_query_param_string (reserves[5].sender_account_details), + GNUNET_PQ_query_param_timestamp (&reserve_expiration), + + GNUNET_PQ_query_param_auto_from_type (reserves[6].reserve_pub), + GNUNET_PQ_query_param_uint64 (&reserves[6].wire_reference), + TALER_PQ_query_param_amount (reserves[6].balance), + GNUNET_PQ_query_param_string (reserves[6].exchange_account_name), + GNUNET_PQ_query_param_timestamp (&reserves[6].execution_time), + GNUNET_PQ_query_param_auto_from_type (&h_payto), + GNUNET_PQ_query_param_string (reserves[6].sender_account_details), + GNUNET_PQ_query_param_timestamp (&reserve_expiration), + + GNUNET_PQ_query_param_auto_from_type (reserves[7].reserve_pub), + GNUNET_PQ_query_param_uint64 (&reserves[7].wire_reference), + TALER_PQ_query_param_amount (reserves[7].balance), + GNUNET_PQ_query_param_string (reserves[7].exchange_account_name), + GNUNET_PQ_query_param_timestamp (&reserves[7].execution_time), + GNUNET_PQ_query_param_auto_from_type (&h_payto), + GNUNET_PQ_query_param_string (reserves[7].sender_account_details), + GNUNET_PQ_query_param_timestamp (&reserve_expiration), + + GNUNET_PQ_query_param_end + }; + + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_bool ("conflicted", + &conflict[0]), + GNUNET_PQ_result_spec_bool ("conflicted2", + &conflict[1]), + GNUNET_PQ_result_spec_bool ("conflicted3", + &conflict[2]), + GNUNET_PQ_result_spec_bool ("conflicted4", + &conflict[3]), + GNUNET_PQ_result_spec_bool ("conflicted5", + &conflict[4]), + GNUNET_PQ_result_spec_bool ("conflicted6", + &conflict[5]), + GNUNET_PQ_result_spec_bool ("conflicted7", + &conflict[6]), + GNUNET_PQ_result_spec_bool ("conflicted8", + &conflict[7]), + GNUNET_PQ_result_spec_bool ("transaction_duplicate", + &transaction_duplicate[0]), + GNUNET_PQ_result_spec_bool ("transaction_duplicate2", + &transaction_duplicate[1]), + GNUNET_PQ_result_spec_bool ("transaction_duplicate3", + &transaction_duplicate[2]), + GNUNET_PQ_result_spec_bool ("transaction_duplicate4", + &transaction_duplicate[3]), + GNUNET_PQ_result_spec_bool ("transaction_duplicate5", + &transaction_duplicate[4]), + GNUNET_PQ_result_spec_bool ("transaction_duplicate6", + &transaction_duplicate[5]), + GNUNET_PQ_result_spec_bool ("transaction_duplicate7", + &transaction_duplicate[6]), + GNUNET_PQ_result_spec_bool ("transaction_duplicate8", + &transaction_duplicate[7]), + GNUNET_PQ_result_spec_uint64 ("reserve_uuid", + &reserve_uuid[0]), + GNUNET_PQ_result_spec_uint64 ("reserve_uuid2", + &reserve_uuid[1]), + GNUNET_PQ_result_spec_uint64 ("reserve_uuid3", + &reserve_uuid[2]), + GNUNET_PQ_result_spec_uint64 ("reserve_uuid4", + &reserve_uuid[3]), + GNUNET_PQ_result_spec_uint64 ("reserve_uuid5", + &reserve_uuid[4]), + GNUNET_PQ_result_spec_uint64 ("reserve_uuid6", + &reserve_uuid[5]), + GNUNET_PQ_result_spec_uint64 ("reserve_uuid7", + &reserve_uuid[6]), + GNUNET_PQ_result_spec_uint64 ("reserve_uuid8", + &reserve_uuid[7]), + GNUNET_PQ_result_spec_end + }; + + TALER_payto_hash (reserves[0].sender_account_details, + &h_payto); + TALER_payto_hash (reserves[1].sender_account_details, + &h_payto); + TALER_payto_hash (reserves[2].sender_account_details, + &h_payto); + TALER_payto_hash (reserves[3].sender_account_details, + &h_payto); + TALER_payto_hash (reserves[4].sender_account_details, + &h_payto); + TALER_payto_hash (reserves[5].sender_account_details, + &h_payto); + TALER_payto_hash (reserves[6].sender_account_details, + &h_payto); + TALER_payto_hash (reserves[7].sender_account_details, + &h_payto); + + qs3 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "batch8_reserve_create", + params, + rs); + if (qs3 < 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to create reserves8 (%d)\n", + qs3); + results[0] = qs3; + return qs3; + } + + GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs3); + /* results[i] = (transaction_duplicate) + ? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS + : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;*/ + + if ( + ((! conflict[0]) && (transaction_duplicate[0])) + || ((! conflict[1]) && (transaction_duplicate[1])) + || ((! conflict[2]) && (transaction_duplicate[2])) + || ((! conflict[3]) && (transaction_duplicate[3])) + || ((! conflict[4]) && (transaction_duplicate[4])) + || ((! conflict[5]) && (transaction_duplicate[5])) + || ((! conflict[6]) && (transaction_duplicate[6])) + || ((! conflict[7]) && (transaction_duplicate[7])) + ) + { + GNUNET_break (0); + TEH_PG_rollback (pg); + results[0] = GNUNET_DB_STATUS_HARD_ERROR; + return GNUNET_DB_STATUS_HARD_ERROR; + } + results[0] = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; + return qs3; } enum GNUNET_DB_QueryStatus TEH_PG_reserves_in_insert (void *cls, - const struct TALER_ReservePublicKeyP *reserve_pub, - const struct TALER_Amount *balance, - struct GNUNET_TIME_Timestamp execution_time, - const char *sender_account_details, - const char *exchange_account_section, - uint64_t wire_ref) + const struct + TALER_EXCHANGEDB_ReserveInInfo *reserves, + unsigned int reserves_length, + unsigned int batch_size, + enum GNUNET_DB_QueryStatus *results) { struct PostgresClosure *pg = cls; enum GNUNET_DB_QueryStatus qs1; - struct TALER_EXCHANGEDB_Reserve reserve; + enum GNUNET_DB_QueryStatus qs2; + enum GNUNET_DB_QueryStatus qs4; + enum GNUNET_DB_QueryStatus qs5; struct GNUNET_TIME_Timestamp expiry; struct GNUNET_TIME_Timestamp gc; - uint64_t reserve_uuid; + struct TALER_PaytoHashP h_payto; + uint64_t reserve_uuid[reserves_length]; + bool transaction_duplicate[reserves_length]; + bool need_update = false; + bool t_duplicate = false; + struct GNUNET_TIME_Timestamp reserve_expiration + = GNUNET_TIME_relative_to_timestamp (pg->idle_reserve_expiration_time); + bool conflicts[reserves_length]; + char *notify_s[reserves_length]; + + if (GNUNET_OK != + TEH_PG_preflight (pg)) + { + GNUNET_break (0); + return GNUNET_DB_STATUS_HARD_ERROR; + } - reserve.pub = *reserve_pub; expiry = GNUNET_TIME_absolute_to_timestamp ( - GNUNET_TIME_absolute_add (execution_time.abs_time, + GNUNET_TIME_absolute_add (reserves->execution_time.abs_time, pg->idle_reserve_expiration_time)); gc = GNUNET_TIME_absolute_to_timestamp ( GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), pg->legal_reserve_expiration_time)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating reserve %s with expiration in %s\n", - TALER_B2S (reserve_pub), + TALER_B2S (&(reserves->reserve_pub)), GNUNET_STRINGS_relative_time_to_string ( pg->idle_reserve_expiration_time, GNUNET_NO)); + + if (GNUNET_OK != + TEH_PG_start_read_committed (pg, + "READ_COMMITED")) + { + GNUNET_break (0); + return GNUNET_DB_STATUS_HARD_ERROR; + } + /* Optimistically assume this is a new reserve, create balance for the first time; we do this before adding the actual transaction to "reserves_in", as for a new reserve it can't be a duplicate 'add' operation, and as the 'add' operation needs the reserve entry as a foreign key. */ + for (unsigned int i = 0; iconn, - "reserve_create", - params, - rs); - if (qs1 < 0) - return qs1; + const struct TALER_EXCHANGEDB_ReserveInInfo *reserve = &reserves[i]; + + notify_s[i] = compute_notify_on_reserve (reserve->reserve_pub); } - /* Create new incoming transaction, "ON CONFLICT DO NOTHING" - is again used to guard against duplicates. */ + unsigned int i = 0; + + while (i < reserves_length) { - enum GNUNET_DB_QueryStatus qs2; - enum GNUNET_DB_QueryStatus qs3; - struct TALER_PaytoHashP h_payto; - - qs3 = TEH_PG_setup_wire_target (pg, - sender_account_details, - &h_payto); - if (qs3 < 0) - return qs3; - /* We do not have the UUID, so insert by public key */ - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (&reserve.pub), - GNUNET_PQ_query_param_uint64 (&wire_ref), - TALER_PQ_query_param_amount (balance), - GNUNET_PQ_query_param_string (exchange_account_section), - GNUNET_PQ_query_param_auto_from_type (&h_payto), - GNUNET_PQ_query_param_timestamp (&execution_time), - GNUNET_PQ_query_param_end - }; - - PREPARE (pg, - "reserves_in_add_transaction", - "INSERT INTO reserves_in " - "(reserve_pub" - ",wire_reference" - ",credit_val" - ",credit_frac" - ",exchange_account_section" - ",wire_source_h_payto" - ",execution_date" - ") VALUES ($1, $2, $3, $4, $5, $6, $7)" - " ON CONFLICT DO NOTHING;"); - qs2 = GNUNET_PQ_eval_prepared_non_select (pg->conn, - "reserves_in_add_transaction", - params); - /* qs2 could be 0 as statement used 'ON CONFLICT DO NOTHING' */ - if (0 >= qs2) + unsigned int bs = GNUNET_MIN (batch_size, + reserves_length - i); + if (bs >= 8) { - if ( (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs2) && - (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs1) ) + qs1 = insert8 (pg, + &reserves[i], + expiry, + gc, + h_payto, + ¬ify_s[i], + reserve_expiration, + &transaction_duplicate[i], + &conflicts[i], + &reserve_uuid[i], + &results[i]); + + if (qs1<0) { - /* Conflict for the transaction, but the reserve was - just now created, that should be impossible. */ - GNUNET_break (0); /* should be impossible: reserve was fresh, - but transaction already known */ - return GNUNET_DB_STATUS_HARD_ERROR; + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to create reserve batch_8 (%d)\n", + qs1); + return qs1; } - /* Transaction was already known or error. We are finished. */ - return qs2; + need_update |= conflicts[i]; + need_update |= conflicts[i + 1]; + need_update |= conflicts[i + 2]; + need_update |= conflicts[i + 3]; + need_update |= conflicts[i + 4]; + need_update |= conflicts[i + 5]; + need_update |= conflicts[i + 6]; + need_update |= conflicts[i + 7]; + t_duplicate |= transaction_duplicate[i]; + t_duplicate |= transaction_duplicate[i + 1]; + t_duplicate |= transaction_duplicate[i + 2]; + t_duplicate |= transaction_duplicate[i + 3]; + t_duplicate |= transaction_duplicate[i + 4]; + t_duplicate |= transaction_duplicate[i + 5]; + t_duplicate |= transaction_duplicate[i + 6]; + t_duplicate |= transaction_duplicate[i + 7]; + i += 8; + continue; } - } - if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs1) - { - /* New reserve, we are finished */ - notify_on_reserve (pg, - reserve_pub); - return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; - } + switch (bs) + { + case 7: + case 6: + case 5: + case 4: + qs4 = insert4 (pg, + &reserves[i], + expiry, + gc, + h_payto, + ¬ify_s[i], + reserve_expiration, + &transaction_duplicate[i], + &conflicts[i], + &reserve_uuid[i], + &results[i]); - /* we were wrong with our optimistic assumption: - reserve did already exist, need to do an update instead */ + if (qs4<0) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to create reserve batch_4 (%d)\n", + qs4); + return qs4; + } + need_update |= conflicts[i]; + need_update |= conflicts[i + 1]; + need_update |= conflicts[i + 2]; + need_update |= conflicts[i + 3]; + t_duplicate |= transaction_duplicate[i]; + t_duplicate |= transaction_duplicate[i + 1]; + t_duplicate |= transaction_duplicate[i + 2]; + t_duplicate |= transaction_duplicate[i + 3]; + // fprintf(stdout, "reserve_uuid : %ld %ld %ld %ld\n", reserve_uuid[i], reserve_uuid[i+1], reserve_uuid[i+2], reserve_uuid[i+3]); + i += 4; + break; + case 3: + case 2: + qs5 = insert2 (pg, + &reserves[i], + expiry, + gc, + h_payto, + ¬ify_s[i], + reserve_expiration, + &transaction_duplicate[i], + &conflicts[i], + &reserve_uuid[i], + &results[i]); + if (qs5<0) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to create reserve batch_2 (%d)\n", + qs5); + return qs5; + } + need_update |= conflicts[i]; + need_update |= conflicts[i + 1]; + t_duplicate |= transaction_duplicate[i]; + t_duplicate |= transaction_duplicate[i + 1]; + results[i] = (t_duplicate) + ? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS + : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; + // fprintf(stdout, "reserve_uuid : %ld %ld\n", reserve_uuid[i], reserve_uuid[i+1]); + i += 2; + break; + case 1: + qs2 = insert1 (pg, + &reserves[i], + expiry, + gc, + h_payto, + ¬ify_s[i], + reserve_expiration, + &transaction_duplicate[i], + &conflicts[i], + &reserve_uuid[i], + &results[i]); + if (qs2<0) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to create reserve batch_1 (%d)\n)" + ,qs2); + return qs2; + } + need_update |= conflicts[i]; + t_duplicate |= transaction_duplicate[i]; + // fprintf(stdout, "reserve uuid : %ld c :%d t:%d\n", reserve_uuid[i], conflicts[i], transaction_duplicate[i]); + i += 1; + break; + case 0: + GNUNET_assert (0); + break; + } + } /* end while */ + // commit { - /* We need to move away from 'read committed' to serializable. - Also, we know that it should be safe to commit at this point. - (We are only run in a larger transaction for performance.) */ enum GNUNET_DB_QueryStatus cs; cs = TEH_PG_commit (pg); if (cs < 0) - return cs; - if (GNUNET_OK != - TEH_PG_start (pg, - "reserve-update-serializable")) { - GNUNET_break (0); - return GNUNET_DB_STATUS_HARD_ERROR; + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to commit\n"); + return cs; } } + if (! need_update) { - enum GNUNET_DB_QueryStatus reserve_exists; - - reserve_exists = TEH_PG_reserves_get (pg, - &reserve); - switch (reserve_exists) + goto exit; + } + // begin serializable + { + if (GNUNET_OK != + TEH_PG_start (pg, + "reserve-insert-continued")) { - case GNUNET_DB_STATUS_HARD_ERROR: GNUNET_break (0); - return reserve_exists; - case GNUNET_DB_STATUS_SOFT_ERROR: - return reserve_exists; - case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - /* First we got a conflict, but then we cannot select? Very strange. */ - GNUNET_break (0); - return GNUNET_DB_STATUS_SOFT_ERROR; - case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: - /* continued below */ - break; + return GNUNET_DB_STATUS_HARD_ERROR; } } + enum GNUNET_DB_QueryStatus qs3; + PREPARE (pg, + "reserves_update", + "SELECT" + " out_duplicate AS duplicate " + "FROM exchange_do_batch_reserves_update" + " ($1,$2,$3,$4,$5,$6,$7,$8);"); + for (unsigned int i = 0; i - TALER_amount_add (&updated_reserve.balance, - &reserve.balance, - balance)) + if (! conflicts[i]) + continue; { - /* currency overflow or incompatible currency */ - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Attempt to deposit incompatible amount into reserve\n"); - return GNUNET_DB_STATUS_HARD_ERROR; - } - updated_reserve.expiry = GNUNET_TIME_timestamp_max (expiry, - reserve.expiry); - updated_reserve.gc = GNUNET_TIME_timestamp_max (gc, - reserve.gc); - qs3 = TEH_PG_reserves_update (pg, - &updated_reserve); - switch (qs3) - { - case GNUNET_DB_STATUS_HARD_ERROR: - GNUNET_break (0); - return qs3; - case GNUNET_DB_STATUS_SOFT_ERROR: - return qs3; - case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - /* How can the UPDATE not work here? Very strange. */ - GNUNET_break (0); - return GNUNET_DB_STATUS_HARD_ERROR; - case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: - /* continued below */ - break; + bool duplicate; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (reserves[i].reserve_pub), + GNUNET_PQ_query_param_timestamp (&expiry), + GNUNET_PQ_query_param_uint64 (&reserves[i].wire_reference), + TALER_PQ_query_param_amount (reserves[i].balance), + GNUNET_PQ_query_param_string (reserves[i].exchange_account_name), + GNUNET_PQ_query_param_auto_from_type (&h_payto), + GNUNET_PQ_query_param_string (notify_s[i]), + GNUNET_PQ_query_param_end + }; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_bool ("duplicate", + &duplicate), + GNUNET_PQ_result_spec_end + }; + qs3 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "reserves_update", + params, + rs); + if (qs3<0) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to update reserves (%d)\n", + qs3); + results[i] = qs3; + return qs3; + } + results[i] = duplicate + ? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS + : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; } } - notify_on_reserve (pg, - reserve_pub); - /* Go back to original transaction mode */ + { enum GNUNET_DB_QueryStatus cs; cs = TEH_PG_commit (pg); if (cs < 0) return cs; - if (GNUNET_OK != - TEH_PG_start_read_committed (pg, - "reserve-insert-continued")) - { - GNUNET_break (0); - return GNUNET_DB_STATUS_HARD_ERROR; - } } - return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; + +exit: + for (unsigned int i = 0; iset_purse_balance = &TEH_PG_set_purse_balance; - plugin->batch_reserves_in_insert - = &TEH_PG_batch_reserves_in_insert; - plugin->batch2_reserves_in_insert - = &TEH_PG_batch2_reserves_in_insert; plugin->insert_kyc_attributes = &TEH_PG_insert_kyc_attributes; plugin->update_kyc_attributes diff --git a/src/exchangedb/test_exchangedb_batch_reserves_in_insert.c b/src/exchangedb/test_exchangedb_batch_reserves_in_insert.c deleted file mode 100644 index 1a1c60f31..000000000 --- a/src/exchangedb/test_exchangedb_batch_reserves_in_insert.c +++ /dev/null @@ -1,196 +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_by_j.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" - -/**o - * 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" - -/** - * Database plugin under test. - */ -static struct TALER_EXCHANGEDB_Plugin *plugin; - - -/** - * 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; - - 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; - } - - for (unsigned int i = 0; i< 8; i++) - { - static unsigned int batches[] = {1, 1, 2, 3, 4, 16, 64, 256}; - const char *sndr = "payto://x-taler-bank/localhost:8080/1"; - struct TALER_Amount value; - unsigned int batch_size = batches[i]; - struct GNUNET_TIME_Absolute now; - struct GNUNET_TIME_Timestamp ts; - struct GNUNET_TIME_Relative duration; - struct TALER_ReservePublicKeyP reserve_pubs[batch_size]; - struct TALER_EXCHANGEDB_ReserveInInfo reserves[batch_size]; - enum GNUNET_DB_QueryStatus results[batch_size]; - GNUNET_assert (GNUNET_OK == - TALER_string_to_amount (CURRENCY ":1.000010", - &value)); - now = GNUNET_TIME_absolute_get (); - ts = GNUNET_TIME_timestamp_get (); - - - for (unsigned int k = 0; kbatch_reserves_in_insert (plugin->cls, - reserves, - batch_size, - results)); - - - duration = GNUNET_TIME_absolute_get_duration (now); - fprintf (stdout, - "for a batchsize equal to %d it took %s\n", - batch_size, - GNUNET_STRINGS_relative_time_to_string (duration, - GNUNET_NO) ); - - } - result = 0; -drop: - GNUNET_break (GNUNET_OK == - plugin->drop_tables (plugin->cls)); -cleanup: - 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_link_data.c b/src/exchangedb/test_exchangedb_populate_link_data.c deleted file mode 100644 index 84e5ab883..000000000 --- a/src/exchangedb/test_exchangedb_populate_link_data.c +++ /dev/null @@ -1,534 +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_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" - -/** - * 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)) - -#define CURRENCY "EUR" -#define RSA_KEY_SIZE 1024 -#define ROUNDS 100 -#define NUM_ROWS 1000 -#define MELT_NEW_COINS 5 -#define DENOMINATIONS 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; -static int result; - -static struct TALER_TransferPrivateKeyP tprivs[TALER_CNC_KAPPA]; -static struct TALER_TransferPublicKeyP tpub; -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; - (void) ldl; -} - - -/** - * 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 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_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 *); - - for (unsigned int cnt = 0; cnt < MELT_NEW_COINS; cnt++) - { - struct GNUNET_TIME_Timestamp now = GNUNET_TIME_timestamp_get (); - - new_dkp[cnt] = create_denom_key_pair (RSA_KEY_SIZE, - now, - &value, - &fees); - GNUNET_assert (NULL != new_dkp[cnt]); - } - } - 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_CoinPubHashP c_hash; - unsigned int i = perm[j]; - uint64_t known_coin_id; - struct TALER_EXCHANGEDB_CollectableBlindcoin cbc; - if (i >= ROUNDS) - i = ROUNDS; /* throw-away slot, do not keep around */ - RND_BLK (&depos[i].coin.coin_pub); - ZR_BLK (&cbc); - TALER_denom_pub_hash (&new_dkp[(unsigned int)rand()%MELT_NEW_COINS]->pub, - &depos[i].coin.denom_pub_hash); - - - - { - struct TALER_EXCHANGEDB_RefreshRevealedCoin revealed_coins[MELT_NEW_COINS]; - - for (unsigned int p=0;pblinded_planchet; - struct TALER_BlindedRsaPlanchet *rp = &bp->details.rsa_blinded_planchet; - - /* h_coin_ev must be unique, but we only have MELT_NEW_COINS created - above for NUM_ROWS iterations; instead of making "all new" coins, - we simply randomize the hash here as nobody is checking for consistency - anyway ;-) */ - bp->cipher = TALER_DENOMINATION_RSA; - 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[(unsigned int)rand()%MELT_NEW_COINS]->pub, - &revealed_coin->h_denom_pub); - revealed_coin->exchange_vals = alg_values; - TALER_coin_ev_hash (bp, - &revealed_coin->h_denom_pub, - &revealed_coin->coin_envelope_hash); - GNUNET_assert (GNUNET_OK == - TALER_denom_sign_blinded (&revealed_coin->coin_sig, - &new_dkp[(unsigned int)rand()%MELT_NEW_COINS]->priv, - true, - bp)); - GNUNET_assert ( - GNUNET_OK == - TALER_denom_sign_blinded ( - &cbc.sig, - &new_dkp[(unsigned int)rand()%MELT_NEW_COINS]->priv, - false, - bp)); - } - GNUNET_assert (GNUNET_OK == - TALER_denom_sig_unblind (&depos[i].coin.denom_sig, - &cbc.sig, - &bks, - &c_hash, - &alg_values, - &new_dkp[(unsigned int)rand()%MELT_NEW_COINS]->pub)); - { - /* ENSURE_COIN_KNOWN */ - 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)); - } - /****GET melt_serial_id generated by default****/ - { - struct TALER_EXCHANGEDB_Melt ret_refresh_session; - - FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != - plugin->get_melt (plugin->cls, - &refresh[i].rc, - &ret_refresh_session, - &melt_serial_id)); - } - /**** INSERT REFRESH_REVEAL + TRANSFER_KEYS *****/ - { - static unsigned int cnt; - - RND_BLK (&tprivs); - RND_BLK (&tpub); - 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)); - cnt++; - // fprintf (stderr, "CNT: %u - %llu\n", cnt, (unsigned long long) melt_serial_id); - } - 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); - } - - /* { - struct TALER_CoinSpendPublicKeyP ocp; - uint64_t rrc_serial; - - FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != - plugin->get_old_coin_by_h_blind (plugin->cls, - &revealed_coins->coin_envelope_hash, - &ocp, - &rrc_serial)); - }*/ - } - 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); - 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 deleted file mode 100644 index 97273fc9e..000000000 --- a/src/exchangedb/test_exchangedb_populate_ready_deposit.c +++ /dev/null @@ -1,535 +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_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" - -/** - * 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 NUM_ROWS 1000000 -#define ROUNDS 10000 -#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; -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; -} - - - - -/** - * 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 READY DEPOSIT ****/ - 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_select_refunds_by_coin.c b/src/exchangedb/test_exchangedb_populate_select_refunds_by_coin.c deleted file mode 100644 index c094b2048..000000000 --- a/src/exchangedb/test_exchangedb_populate_select_refunds_by_coin.c +++ /dev/null @@ -1,602 +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" - -/** - * 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/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h index 3e40c985e..50a5c0efe 100644 --- a/src/include/taler_exchangedb_plugin.h +++ b/src/include/taler_exchangedb_plugin.h @@ -3479,46 +3479,6 @@ struct TALER_EXCHANGEDB_Plugin struct TALER_PaytoHashP *h_payto); - /** - * Insert a incoming transaction into reserves. New reserves are - * also created through this function. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param reserve_pub public key of the reserve - * @param balance the amount that has to be added to the reserve - * @param execution_time when was the amount added - * @param sender_account_details information about the sender's bank account, in payto://-format - * @param wire_reference unique reference identifying the wire transfer - * @return transaction status code - */ - enum GNUNET_DB_QueryStatus - (*reserves_in_insert)(void *cls, - const struct TALER_ReservePublicKeyP *reserve_pub, - const struct TALER_Amount *balance, - struct GNUNET_TIME_Timestamp execution_time, - const char *sender_account_details, - const char *exchange_account_name, - uint64_t wire_reference); - - - /** - * Insert a batch of incoming transaction into reserves. New reserves are - * also created through this function. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param reserves - * @param reserves_length length of the @a reserves array - * @param[out] results array of transaction status codes of length @a reserves_length, - * set to the status of the - */ - enum GNUNET_DB_QueryStatus - (*batch_reserves_in_insert)( - void *cls, - const struct TALER_EXCHANGEDB_ReserveInInfo *reserves, - unsigned int reserves_length, - enum GNUNET_DB_QueryStatus *results); - - /** * Insert a batch of incoming transaction into reserves. New reserves are * also created through this function. @@ -3530,7 +3490,7 @@ struct TALER_EXCHANGEDB_Plugin * set to the status of the */ enum GNUNET_DB_QueryStatus - (*batch2_reserves_in_insert)( + (*reserves_in_insert)( void *cls, const struct TALER_EXCHANGEDB_ReserveInInfo *reserves, unsigned int reserves_length, @@ -4102,13 +4062,6 @@ struct TALER_EXCHANGEDB_Plugin char **payto_uri); -/** - * Maximum number of results we return from iterate_matching_deposits(). - * - * Limit on the number of transactions we aggregate at once. - */ -#define TALER_EXCHANGEDB_MATCHING_DEPOSITS_LIMIT 10000 - /** * Aggregate all matching deposits for @a h_payto and * @a merchant_pub, returning the total amounts. -- cgit v1.2.3