From e6943f5a9e4fd6599a1ae15951c04bafddfe1a4d Mon Sep 17 00:00:00 2001 From: Sree Harsha Totakura Date: Thu, 5 Mar 2015 15:59:22 +0100 Subject: [PATCH 01/17] Add testcase for DB layer --- src/mint/Makefile.am | 11 +++++- src/mint/test_mint_db.c | 81 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 src/mint/test_mint_db.c diff --git a/src/mint/Makefile.am b/src/mint/Makefile.am index af0b48e84..19fba62f0 100644 --- a/src/mint/Makefile.am +++ b/src/mint/Makefile.am @@ -101,7 +101,8 @@ taler_mint_dbinit_LDFLAGS = $(POSTGRESQL_LDFLAGS) check_PROGRAMS = \ test-mint-deposits \ - test-mint-common + test-mint-common \ + test-mint-db test_mint_deposits_SOURCES = \ test_mint_deposits.c @@ -120,3 +121,11 @@ test_mint_common_LDADD = \ $(top_srcdir)/src/util/libtalerutil.la \ $(top_srcdir)/src/pq/libtalerpq.la \ -lgnunetutil + +test_mint_db_SOURCES = \ + test_mint_db.c +test_mint_db_LDADD = \ + libtalermint_common.la \ + $(top_srcdir)/src/util/libtalerutil.la \ + $(top_srcdir)/src/pq/libtalerpq.la \ + -lgnunetutil diff --git a/src/mint/test_mint_db.c b/src/mint/test_mint_db.c new file mode 100644 index 000000000..4fa84eb38 --- /dev/null +++ b/src/mint/test_mint_db.c @@ -0,0 +1,81 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors) + + 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, If not, see +*/ + +/** + * @file mint/test_mint_db.c + * @brief test cases for DB interaction functions + * @author Sree Harsha Totakura + */ + +#include "platform.h" +#include "mint_db.h" + +static int result; + + +/** + * Main function that will be run by the scheduler. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param config configuration + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *config) +{ + PGconn *db; + + db = NULL; + if (GNUNET_OK != TALER_MINT_DB_init ("postgres:///taler")) + { + result = 1; + return; + } + if (GNUNET_OK != TALER_MINT_DB_create_tables (GNUNET_YES)) + { + result = 2; + goto drop; + } + if (NULL == (db = TALER_MINT_DB_get_connection(GNUNET_YES))) + { + result = 3; + goto drop; + } + result = 0; + drop: + if (NULL != db) + GNUNET_break (GNUNET_OK == TALER_MINT_DB_drop_temporary (db)); +} + + +int +main (int argc, char *const argv[]) +{ + static const struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + result = -1; + if (GNUNET_OK != + GNUNET_PROGRAM_run (argc, argv, + "test-mint-db", + "Test cases for mint database helper functions.", + options, &run, NULL)) + return 3; + return result; +} From bc55152b0a60b9fa68e00971d07ee91bc7a63856 Mon Sep 17 00:00:00 2001 From: Sree Harsha Totakura Date: Thu, 5 Mar 2015 16:05:06 +0100 Subject: [PATCH 02/17] Move table creation logic to DB layer. Also support temporary schema creation for the sake of testing --- src/mint/mint_db.c | 211 ++++++++++++++++++++++++++++++++- src/mint/mint_db.h | 22 +++- src/mint/taler-mint-dbinit.c | 187 +---------------------------- src/mint/taler-mint-httpd_db.c | 14 +-- 4 files changed, 239 insertions(+), 195 deletions(-) diff --git a/src/mint/mint_db.c b/src/mint/mint_db.c index 786d04ac7..91d6705c3 100644 --- a/src/mint/mint_db.c +++ b/src/mint/mint_db.c @@ -13,11 +13,13 @@ You should have received a copy of the GNU General Public License along with TALER; see the file COPYING. If not, If not, see */ + /** * @file mint_db.c * @brief Low-level (statement-level) database access for the mint * @author Florian Dold * @author Christian Grothoff + * @author Sree Harsha Totakura * * TODO: * - The mint_db.h-API should ideally be what we need to port @@ -32,6 +34,7 @@ #include "mint_db.h" #include + /** * Thread-local database connection. * Contains a pointer to PGconn or NULL. @@ -45,7 +48,6 @@ static pthread_key_t db_conn_threadlocal; */ static char *TALER_MINT_db_connection_cfg_str; - #define break_db_err(result) do { \ GNUNET_break(0); \ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Database failure: %s\n", PQresultErrorMessage (result)); \ @@ -60,6 +62,213 @@ static char *TALER_MINT_db_connection_cfg_str; } while (0) +#define SQLEXEC_(conn, sql, result) \ + do { \ + result = PQexec (conn, sql); \ + if (PGRES_COMMAND_OK != PQresultStatus (result)) \ + { \ + break_db_err (result); \ + PQclear (result); result = NULL; \ + goto SQLEXEC_fail; \ + } \ + PQclear (result); result = NULL; \ + } while (0) + + +/** + * Set the given connection to use a temporary schema + * + * @param db the database connection + * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon error + */ +static int +set_temporary_schema (PGconn *db) +{ + PGresult *result; + + SQLEXEC_(db, + "CREATE SCHEMA IF NOT EXISTS " TALER_TEMP_SCHEMA_NAME ";" + "SET search_path to " TALER_TEMP_SCHEMA_NAME ";", + result); + return GNUNET_OK; + SQLEXEC_fail: + return GNUNET_SYSERR; +} + + +/** + * Drop the temporary taler schema. This is only useful for testcases + * + * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure + */ +int +TALER_MINT_DB_drop_temporary (PGconn *db) +{ + PGresult *result; + + SQLEXEC_ (db, + "DROP SCHEMA " TALER_TEMP_SCHEMA_NAME " CASCADE;", + result); + return GNUNET_OK; + SQLEXEC_fail: + return GNUNET_SYSERR; +} + + +/** + * Create the necessary tables if they are not present + * + * @param temporary should we use a temporary schema + * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure + */ +int +TALER_MINT_DB_create_tables (int temporary) +{ + PGresult *result; + PGconn *conn; + + result = NULL; + conn = PQconnectdb (TALER_MINT_db_connection_cfg_str); + if (CONNECTION_OK != PQstatus (conn)) + { + LOG_ERROR ("Database connection failed: %s\n", + PQerrorMessage (conn)); + GNUNET_break (0); + return GNUNET_SYSERR; + } + if ((GNUNET_YES == temporary) + && (GNUNET_SYSERR == set_temporary_schema (conn))) + { + PQfinish (conn); + return GNUNET_SYSERR; + } +#define SQLEXEC(sql) SQLEXEC_(conn, sql, result); + /* reserves table is for summarization of a reserve. It is updated when new + funds are added and existing funds are withdrawn */ + SQLEXEC ("CREATE TABLE IF NOT EXISTS reserves" + "(" + " reserve_pub BYTEA PRIMARY KEY" + ",current_balance_value INT4 NOT NULL" + ",current_balance_fraction INT4 NOT NULL" + ",balance_currency VARCHAR(4) NOT NULL" + ",expiration_date INT8 NOT NULL" + ")"); + /* reserves_in table collects the transactions which transfer funds into the + reserve. The amount and expiration date for the corresponding reserve are + updated when new transfer funds are added. The rows of this table + correspond to each incoming transaction. */ + SQLEXEC("CREATE TABLE IF NOT EXISTS reserves_in" + "(" + " reserve_pub BYTEA REFERENCES reserves (reserve_pub) ON DELETE CASCADE" + ",balance_value INT4 NOT NULL" + ",balance_fraction INT4 NOT NULL" + ",expiration_date INT8 NOT NULL" + ");"); + result = PQexec (conn, + "CREATE INDEX reserves_in_index ON reserves_in (reserve_pub);"); + if (PGRES_COMMAND_OK != PQresultStatus (result)) + { + ExecStatusType status = PQresultStatus (result); + PQclear (result); + result = NULL; + goto SQLEXEC_fail; + } + PQclear (result); + SQLEXEC ("CREATE TABLE IF NOT EXISTS collectable_blindcoins" + "(" + "blind_ev BYTEA PRIMARY KEY" + ",blind_ev_sig BYTEA NOT NULL" + ",denom_pub BYTEA NOT NULL" + ",reserve_sig BYTEA NOT NULL" + ",reserve_pub BYTEA REFERENCES reserves (reserve_pub) ON DELETE CASCADE" + ");" + "CREATE INDEX collectable_blindcoins_index ON" + " collectable_blindcoins(reserve_pub)"); + SQLEXEC("CREATE TABLE IF NOT EXISTS known_coins " + "(" + " coin_pub BYTEA NOT NULL PRIMARY KEY" + ",denom_pub BYTEA NOT NULL" + ",denom_sig BYTEA NOT NULL" + ",expended_value INT4 NOT NULL" + ",expended_fraction INT4 NOT NULL" + ",expended_currency VARCHAR(4) NOT NULL" + ",refresh_session_pub BYTEA" + ")"); + SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_sessions " + "(" + " session_pub BYTEA PRIMARY KEY CHECK (length(session_pub) = 32)" + ",session_melt_sig BYTEA" + ",session_commit_sig BYTEA" + ",noreveal_index INT2 NOT NULL" + // non-zero if all reveals were ok + // and the new coin signatures are ready + ",reveal_ok BOOLEAN NOT NULL DEFAULT false" + ") "); + SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_order " + "( " + " session_pub BYTEA NOT NULL REFERENCES refresh_sessions (session_pub)" + ",newcoin_index INT2 NOT NULL " + ",denom_pub BYTEA NOT NULL " + ",PRIMARY KEY (session_pub, newcoin_index)" + ") "); + SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_commit_link" + "(" + " session_pub BYTEA NOT NULL REFERENCES refresh_sessions (session_pub)" + ",transfer_pub BYTEA NOT NULL" + ",link_secret_enc BYTEA NOT NULL" + // index of the old coin in the customer's request + ",oldcoin_index INT2 NOT NULL" + // index for cut and choose, + // ranges from 0 to kappa-1 + ",cnc_index INT2 NOT NULL" + ")"); + SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_commit_coin" + "(" + " session_pub BYTEA NOT NULL REFERENCES refresh_sessions (session_pub) " + ",link_vector_enc BYTEA NOT NULL" + // index of the new coin in the customer's request + ",newcoin_index INT2 NOT NULL" + // index for cut and choose, + ",cnc_index INT2 NOT NULL" + ",coin_ev BYTEA NOT NULL" + ")"); + SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_melt" + "(" + " session_pub BYTEA NOT NULL REFERENCES refresh_sessions (session_pub) " + ",coin_pub BYTEA NOT NULL REFERENCES known_coins (coin_pub) " + ",denom_pub BYTEA NOT NULL " + ",oldcoin_index INT2 NOT NULL" + ")"); + SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_collectable" + "(" + " session_pub BYTEA NOT NULL REFERENCES refresh_sessions (session_pub) " + ",ev_sig BYTEA NOT NULL" + ",newcoin_index INT2 NOT NULL" + ")"); + SQLEXEC("CREATE TABLE IF NOT EXISTS deposits " + "( " + " coin_pub BYTEA NOT NULL PRIMARY KEY CHECK (length(coin_pub)=32)" + ",denom_pub BYTEA NOT NULL CHECK (length(denom_pub)=32)" + ",transaction_id INT8 NOT NULL" + ",amount_currency VARCHAR(4) NOT NULL" + ",amount_value INT4 NOT NULL" + ",amount_fraction INT4 NOT NULL" + ",merchant_pub BYTEA NOT NULL" + ",h_contract BYTEA NOT NULL CHECK (length(h_contract)=64)" + ",h_wire BYTEA NOT NULL CHECK (length(h_wire)=64)" + ",coin_sig BYTEA NOT NULL CHECK (length(coin_sig)=64)" + ",wire TEXT NOT NULL" + ")"); +#undef SQLEXEC + PQfinish (conn); + return GNUNET_OK; + + SQLEXEC_fail: + PQfinish (conn); + return GNUNET_SYSERR; +} + + /** * Setup prepared statements. * diff --git a/src/mint/mint_db.h b/src/mint/mint_db.h index a32cbd773..b6bc46e3e 100644 --- a/src/mint/mint_db.h +++ b/src/mint/mint_db.h @@ -42,12 +42,32 @@ TALER_MINT_DB_init (const char *connection_cfg); * Get the thread-local database-handle. * Connect to the db if the connection does not exist yet. * + * @param temporary #GNUNET_YES to use a temporary schema; #GNUNET_NO to use the + * database default one * @param the database connection, or NULL on error */ PGconn * -TALER_MINT_DB_get_connection (void); +TALER_MINT_DB_get_connection (int temporary); +/** + * Drop the temporary taler schema. This is only useful for testcases + * + * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure + */ +int +TALER_MINT_DB_drop_temporary (PGconn *db); + + +/** + * Create the necessary tables if they are not present + * + * @param temporary should we use a temporary schema + * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure + */ +int +TALER_MINT_DB_create_tables (int temporary); + /** * Setup prepared statements. FIXME: should this be part of the API, * or just internal to "TALER_MINT_DB_get_connection()"? diff --git a/src/mint/taler-mint-dbinit.c b/src/mint/taler-mint-dbinit.c index 7611802ea..c5b0ae4c3 100644 --- a/src/mint/taler-mint-dbinit.c +++ b/src/mint/taler-mint-dbinit.c @@ -36,192 +36,7 @@ static PGconn *db_conn; static char *TALER_MINT_db_connection_cfg_str; -static int -TALER_MINT_init_withdraw_tables (PGconn *conn) -{ - PGresult *result; - result = PQexec (conn, - "CREATE TABLE IF NOT EXISTS reserves" - "(" - " reserve_pub BYTEA PRIMARY KEY" - ",balance_value INT4 NOT NULL" - ",balance_fraction INT4 NOT NULL" - ",balance_currency VARCHAR(4) NOT NULL" - ",status_sig BYTEA" - ",status_sign_pub BYTEA" - ",expiration_date INT8 NOT NULL" - ")"); - if (PGRES_COMMAND_OK != PQresultStatus(result)) - { - break_db_err (result); - return GNUNET_SYSERR; - } - PQclear (result); - result = PQexec (conn, - "CREATE TABLE IF NOT EXISTS collectable_blindcoins" - "(" - "blind_ev BYTEA PRIMARY KEY" - ",blind_ev_sig BYTEA NOT NULL" - ",denom_pub BYTEA NOT NULL" - ",reserve_sig BYTEA NOT NULL" - ",reserve_pub BYTEA NOT NULL REFERENCES reserves (reserve_pub)" - ")"); - if (PGRES_COMMAND_OK != PQresultStatus(result)) - { - break_db_err (result); - return GNUNET_SYSERR; - } - PQclear (result); - - result = PQexec (conn, - "CREATE TABLE IF NOT EXISTS known_coins " - "(" - " coin_pub BYTEA NOT NULL PRIMARY KEY" - ",denom_pub BYTEA NOT NULL" - ",denom_sig BYTEA NOT NULL" - ",expended_value INT4 NOT NULL" - ",expended_fraction INT4 NOT NULL" - ",expended_currency VARCHAR(4) NOT NULL" - ",refresh_session_pub BYTEA" - ")"); - if (PGRES_COMMAND_OK != PQresultStatus(result)) - { - break_db_err (result); - return GNUNET_SYSERR; - } - PQclear (result); - - result = PQexec (conn, - "CREATE TABLE IF NOT EXISTS refresh_sessions " - "(" - " session_pub BYTEA PRIMARY KEY CHECK (length(session_pub) = 32)" - ",session_melt_sig BYTEA" - ",session_commit_sig BYTEA" - ",noreveal_index INT2 NOT NULL" - // non-zero if all reveals were ok - // and the new coin signatures are ready - ",reveal_ok BOOLEAN NOT NULL DEFAULT false" - ") "); - if (PGRES_COMMAND_OK != PQresultStatus(result)) - { - break_db_err (result); - return GNUNET_SYSERR; - } - PQclear (result); - - result = PQexec (conn, - "CREATE TABLE IF NOT EXISTS refresh_order " - "( " - " session_pub BYTEA NOT NULL REFERENCES refresh_sessions (session_pub)" - ",newcoin_index INT2 NOT NULL " - ",denom_pub BYTEA NOT NULL " - ",PRIMARY KEY (session_pub, newcoin_index)" - ") "); - - if (PGRES_COMMAND_OK != PQresultStatus(result)) - { - break_db_err (result); - return GNUNET_SYSERR; - } - PQclear (result); - - - result = PQexec (conn, - "CREATE TABLE IF NOT EXISTS refresh_commit_link" - "(" - " session_pub BYTEA NOT NULL REFERENCES refresh_sessions (session_pub)" - ",transfer_pub BYTEA NOT NULL" - ",link_secret_enc BYTEA NOT NULL" - // index of the old coin in the customer's request - ",oldcoin_index INT2 NOT NULL" - // index for cut and choose, - // ranges from 0 to kappa-1 - ",cnc_index INT2 NOT NULL" - ")"); - - if (PGRES_COMMAND_OK != PQresultStatus(result)) - { - break_db_err (result); - return GNUNET_SYSERR; - } - PQclear (result); - - result = PQexec (conn, - "CREATE TABLE IF NOT EXISTS refresh_commit_coin" - "(" - " session_pub BYTEA NOT NULL REFERENCES refresh_sessions (session_pub) " - ",link_vector_enc BYTEA NOT NULL" - // index of the new coin in the customer's request - ",newcoin_index INT2 NOT NULL" - // index for cut and choose, - ",cnc_index INT2 NOT NULL" - ",coin_ev BYTEA NOT NULL" - ")"); - - if (PGRES_COMMAND_OK != PQresultStatus(result)) - { - break_db_err (result); - return GNUNET_SYSERR; - } - PQclear (result); - - result = PQexec (conn, - "CREATE TABLE IF NOT EXISTS refresh_melt" - "(" - " session_pub BYTEA NOT NULL REFERENCES refresh_sessions (session_pub) " - ",coin_pub BYTEA NOT NULL REFERENCES known_coins (coin_pub) " - ",denom_pub BYTEA NOT NULL " - ",oldcoin_index INT2 NOT NULL" - ")"); - - if (PGRES_COMMAND_OK != PQresultStatus(result)) - { - break_db_err (result); - return GNUNET_SYSERR; - } - PQclear (result); - - result = PQexec (conn, - "CREATE TABLE IF NOT EXISTS refresh_collectable" - "(" - " session_pub BYTEA NOT NULL REFERENCES refresh_sessions (session_pub) " - ",ev_sig BYTEA NOT NULL" - ",newcoin_index INT2 NOT NULL" - ")"); - - if (PGRES_COMMAND_OK != PQresultStatus(result)) - { - break_db_err (result); - return GNUNET_SYSERR; - } - PQclear (result); - - result = PQexec (conn, - "CREATE TABLE IF NOT EXISTS deposits " - "( " - " coin_pub BYTEA NOT NULL PRIMARY KEY CHECK (length(coin_pub)=32)" - ",denom_pub BYTEA NOT NULL CHECK (length(denom_pub)=32)" - ",transaction_id INT8 NOT NULL" - ",amount_currency VARCHAR(4) NOT NULL" - ",amount_value INT4 NOT NULL" - ",amount_fraction INT4 NOT NULL" - ",merchant_pub BYTEA NOT NULL" - ",h_contract BYTEA NOT NULL CHECK (length(h_contract)=64)" - ",h_wire BYTEA NOT NULL CHECK (length(h_wire)=64)" - ",coin_sig BYTEA NOT NULL CHECK (length(coin_sig)=64)" - ",wire TEXT NOT NULL" - ")"); - - if (PGRES_COMMAND_OK != PQresultStatus(result)) - { - break_db_err (result); - return GNUNET_SYSERR; - } - PQclear (result); - - return GNUNET_OK; -} /** @@ -271,7 +86,7 @@ main (int argc, char *const *argv) return 1; } - if (GNUNET_OK != TALER_MINT_init_withdraw_tables (db_conn)) + if (GNUNET_OK != TALER_MINT_DB_create_tables (db_conn)) { fprintf (stderr, "Failed to initialize database.\n"); return 1; diff --git a/src/mint/taler-mint-httpd_db.c b/src/mint/taler-mint-httpd_db.c index 19fcb1c12..d5613c0dc 100644 --- a/src/mint/taler-mint-httpd_db.c +++ b/src/mint/taler-mint-httpd_db.c @@ -85,7 +85,7 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection, struct TALER_MINT_DenomKeyIssuePriv *dki; int ret; - if (NULL == (db_conn = TALER_MINT_DB_get_connection ())) + if (NULL == (db_conn = TALER_MINT_DB_get_connection (GNUNET_NO))) { GNUNET_break (0); return TALER_MINT_reply_internal_db_error (connection); @@ -203,7 +203,7 @@ TALER_MINT_db_execute_withdraw_status (struct MHD_Connection *connection, struct ReserveHistory *rh; int res; - if (NULL == (db_conn = TALER_MINT_DB_get_connection ())) + if (NULL == (db_conn = TALER_MINT_DB_get_connection (GNUNET_NO))) { GNUNET_break (0); return TALER_MINT_reply_internal_db_error (connection); @@ -264,7 +264,7 @@ TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection, blinded_msg_len, &h_blind); - if (NULL == (db_conn = TALER_MINT_DB_get_connection ())) + if (NULL == (db_conn = TALER_MINT_DB_get_connection (GNUNET_NO))) { GNUNET_break (0); return TALER_MINT_reply_internal_db_error (connection); @@ -521,7 +521,7 @@ TALER_MINT_db_execute_refresh_melt (struct MHD_Connection *connection, int res; unsigned int i; - if (NULL == (db_conn = TALER_MINT_DB_get_connection ())) + if (NULL == (db_conn = TALER_MINT_DB_get_connection (GNUNET_NO))) { GNUNET_break (0); return TALER_MINT_reply_internal_db_error (connection); @@ -650,7 +650,7 @@ TALER_MINT_db_execute_refresh_commit (struct MHD_Connection *connection, unsigned int j; int res; - if (NULL == (db_conn = TALER_MINT_DB_get_connection ())) + if (NULL == (db_conn = TALER_MINT_DB_get_connection (GNUNET_NO))) { GNUNET_break (0); return TALER_MINT_reply_internal_db_error (connection); @@ -1034,7 +1034,7 @@ TALER_MINT_db_execute_refresh_reveal (struct MHD_Connection *connection, unsigned int j; unsigned int off; - if (NULL == (db_conn = TALER_MINT_DB_get_connection ())) + if (NULL == (db_conn = TALER_MINT_DB_get_connection (GNUNET_NO))) { GNUNET_break (0); return TALER_MINT_reply_internal_db_error (connection); @@ -1202,7 +1202,7 @@ TALER_MINT_db_execute_refresh_link (struct MHD_Connection *connection, struct TALER_EncryptedLinkSecret shared_secret_enc; struct LinkDataList *ldl; - if (NULL == (db_conn = TALER_MINT_DB_get_connection ())) + if (NULL == (db_conn = TALER_MINT_DB_get_connection (GNUNET_NO))) { GNUNET_break (0); return TALER_MINT_reply_internal_db_error (connection); From 73d3144a13abe53169eeb01e00cf496a23673466 Mon Sep 17 00:00:00 2001 From: Sree Harsha Totakura Date: Thu, 5 Mar 2015 16:06:06 +0100 Subject: [PATCH 03/17] Fix missing declaration --- src/mint/mint_db.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mint/mint_db.h b/src/mint/mint_db.h index b6bc46e3e..b36823803 100644 --- a/src/mint/mint_db.h +++ b/src/mint/mint_db.h @@ -27,6 +27,7 @@ #include #include "taler_util.h" +#define TALER_TEMP_SCHEMA_NAME "taler_temporary" /** * Initialize database subsystem. From f7b5cf02ae0f25af55032e32bc09f21b81b551e7 Mon Sep 17 00:00:00 2001 From: Sree Harsha Totakura Date: Thu, 5 Mar 2015 16:08:55 +0100 Subject: [PATCH 04/17] Fix ResultSpec processing --- src/pq/db_pq.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/pq/db_pq.c b/src/pq/db_pq.c index f63fe765e..bfa929c4e 100644 --- a/src/pq/db_pq.c +++ b/src/pq/db_pq.c @@ -94,7 +94,7 @@ TALER_DB_extract_result (PGresult *result, { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "field '%s' does not exist in result\n", - rs->fname); + rs[i].fname); return GNUNET_SYSERR; } @@ -111,26 +111,28 @@ TALER_DB_extract_result (PGresult *result, (rs[i].dst_size != len) ) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "field '%s' has wrong size (got %d, expected %d)\n", + "field '%s' has wrong size (got %u, expected %u)\n", rs[i].fname, - (int) len, - (int) rs->dst_size); - for (j=0;jdst_size) - *(void**) rs->dst = GNUNET_malloc (*rs->result_size = len); - memcpy (rs->dst, - res, - len); + if (0 == rs[i].dst_size) + { + *rs[i].result_size = len; + *((void **) rs[i].dst) = GNUNET_malloc (len); + rs[i].dst = *((void **) rs[i].dst); + } + memcpy (rs[i].dst, res, len); } if (GNUNET_YES == had_null) return GNUNET_NO; From 7a37751446e061816631e66ab0ba28da8bd6d203 Mon Sep 17 00:00:00 2001 From: Sree Harsha Totakura Date: Thu, 5 Mar 2015 16:10:42 +0100 Subject: [PATCH 05/17] Fix broken compilation: add temporary flag to DB_get_connection() --- src/mint/mint_db.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/mint/mint_db.c b/src/mint/mint_db.c index 91d6705c3..354bb7008 100644 --- a/src/mint/mint_db.c +++ b/src/mint/mint_db.c @@ -747,18 +747,18 @@ TALER_MINT_DB_init (const char *connection_cfg) * Get the thread-local database-handle. * Connect to the db if the connection does not exist yet. * + * @param temporary #GNUNET_YES to use a temporary schema; #GNUNET_NO to use the + * database default one * @return the database connection, or NULL on error */ PGconn * -TALER_MINT_DB_get_connection (void) +TALER_MINT_DB_get_connection (int temporary) { PGconn *db_conn; if (NULL != (db_conn = pthread_getspecific (db_conn_threadlocal))) return db_conn; - db_conn = PQconnectdb (TALER_MINT_db_connection_cfg_str); - if (CONNECTION_OK != PQstatus (db_conn)) { @@ -767,7 +767,12 @@ TALER_MINT_DB_get_connection (void) GNUNET_break (0); return NULL; } - + if ((GNUNET_YES == temporary) + && (GNUNET_SYSERR == set_temporary_schema(db_conn))) + { + GNUNET_break (0); + return NULL; + } if (GNUNET_OK != TALER_MINT_DB_prepare (db_conn)) { From 4494cf7b61a6cea7b6db667836259ab70d75637d Mon Sep 17 00:00:00 2001 From: Sree Harsha Totakura Date: Thu, 5 Mar 2015 16:11:38 +0100 Subject: [PATCH 06/17] Fix some prepared statements --- src/mint/mint_db.c | 34 ++++++++++------------------------ 1 file changed, 10 insertions(+), 24 deletions(-) diff --git a/src/mint/mint_db.c b/src/mint/mint_db.c index 354bb7008..268b22a00 100644 --- a/src/mint/mint_db.c +++ b/src/mint/mint_db.c @@ -282,9 +282,10 @@ TALER_MINT_DB_prepare (PGconn *db_conn) result = PQprepare (db_conn, "get_reserve", "SELECT " - " balance_value, balance_fraction, balance_currency " - ",expiration_date, blind_session_pub, blind_session_priv" - ",status_sig, status_sign_pub " + "current_balance_value" + ",current_balance_fraction" + ",balance_currency " + ",expiration_date " "FROM reserves " "WHERE reserve_pub=$1 " "LIMIT 1; ", @@ -300,14 +301,11 @@ TALER_MINT_DB_prepare (PGconn *db_conn) result = PQprepare (db_conn, "update_reserve", "UPDATE reserves " "SET" - " balance_value=$2 " - ",balance_fraction=$3 " - ",balance_currency=$4 " - ",status_sig=$5 " - ",status_sign_pub=$6 " - ",expiration_date=$7 " + " current_balance_value=$2 " + ",current_balance_fraction=$3 " + ",expiration_date=$4 " "WHERE reserve_pub=$1 ", - 9, NULL); + 4, NULL); if (PGRES_COMMAND_OK != PQresultStatus(result)) { break_db_err (result); @@ -343,21 +341,8 @@ TALER_MINT_DB_prepare (PGconn *db_conn) } PQclear (result); - result = PQprepare (db_conn, "insert_reserve_order", - "SELECT " - " blind_ev, blind_ev_sig, denom_pub, reserve_sig, reserve_pub " - "FROM collectable_blindcoins " - "WHERE blind_session_pub = $1", - 1, NULL); - if (PGRES_COMMAND_OK != PQresultStatus(result)) - { - break_db_err (result); - PQclear (result); - return GNUNET_SYSERR; - } - PQclear (result); - /* FIXME: does it make sense to store these computed values in the DB? */ +#if 0 result = PQprepare (db_conn, "get_refresh_session", "SELECT " " (SELECT count(*) FROM refresh_melt WHERE session_pub = $1)::INT2 as num_oldcoins " @@ -378,6 +363,7 @@ TALER_MINT_DB_prepare (PGconn *db_conn) return GNUNET_SYSERR; } PQclear (result); +#endif result = PQprepare (db_conn, "get_known_coin", "SELECT " From 2ac21b63293a3e40ea5903fc2eed158353068611 Mon Sep 17 00:00:00 2001 From: Sree Harsha Totakura Date: Thu, 5 Mar 2015 16:16:38 +0100 Subject: [PATCH 07/17] Add DB_reserve_get() to get a summary of the reserve --- src/mint/mint_db.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++ src/mint/mint_db.h | 16 +++++++++++++ 2 files changed, 76 insertions(+) diff --git a/src/mint/mint_db.c b/src/mint/mint_db.c index 268b22a00..b9f30ac3f 100644 --- a/src/mint/mint_db.c +++ b/src/mint/mint_db.c @@ -848,6 +848,66 @@ TALER_MINT_DB_commit (PGconn *db_conn) } +/** + * Get the summary of a reserve. + * + * @param db the database connection handle + * @param reserve_pub the public key identifying the reserve + * @param balance the amount existing in the reserve (will be filled) + * @param expiry expiration of the reserve (will be filled) + * @return #GNUNET_OK upon success; #GNUNET_NO when the given reserve is not + * found; #GNUNET_SYSERR upon failure + */ +int +TALER_MINT_DB_reserve_get (PGconn *db, + struct GNUNET_CRYPTO_EddsaPublicKey *reserve_pub, + struct TALER_Amount *balance, + struct GNUNET_TIME_Absolute *expiry) +{ + PGresult *result; + uint64_t expiration_date_nbo; + struct TALER_DB_QueryParam params[] = { + TALER_DB_QUERY_PARAM_PTR(reserve_pub), + TALER_DB_QUERY_PARAM_END + }; + + result = TALER_DB_exec_prepared (db, + "get_reserve", + params); + if (PGRES_TUPLES_OK != PQresultStatus (result)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Query failed: %s\n", + PQresultErrorMessage (result)); + PQclear (result); + return GNUNET_SYSERR; + } + if (0 == PQntuples (result)) + { + PQclear (result); + return GNUNET_NO; + } + struct TALER_DB_ResultSpec rs[] = { + TALER_DB_RESULT_SPEC("expiration_date", &expiration_date_nbo), + TALER_DB_RESULT_SPEC_END + }; + EXITIF (GNUNET_OK != TALER_DB_extract_result (result, rs, 0)); + EXITIF (GNUNET_OK != + TALER_DB_extract_amount (result, 0, + "current_balance_value", + "current_balance_fraction", + "current_balance_currency", + balance)); + expiry->abs_value_us = GNUNET_ntohll (expiration_date_nbo); + PQclear (result); + return GNUNET_OK; + + EXITIF_exit: + PQclear (result); + return GNUNET_SYSERR; +} + + diff --git a/src/mint/mint_db.h b/src/mint/mint_db.h index b36823803..b80f750b0 100644 --- a/src/mint/mint_db.h +++ b/src/mint/mint_db.h @@ -169,6 +169,22 @@ struct CollectableBlindcoin }; +/** + * Get the summary of a reserve. + * + * @param db the database connection handle + * @param reserve_pub the public key identifying the reserve + * @param balance the amount existing in the reserve (will be filled) + * @param expiry expiration of the reserve (will be filled) + * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure + */ +int +TALER_MINT_DB_reserve_get (PGconn *db, + struct GNUNET_CRYPTO_EddsaPublicKey *reserve_pub, + struct TALER_Amount *balance, + struct GNUNET_TIME_Absolute *expiry); + + /* FIXME: need call to convert CollectableBlindcoin to JSON (#3527) */ From 494e71b9a6e1d6942c758dadda8c8946c99137d2 Mon Sep 17 00:00:00 2001 From: Sree Harsha Totakura Date: Thu, 5 Mar 2015 16:31:33 +0100 Subject: [PATCH 08/17] Use a reserve structure --- src/mint/mint_db.c | 24 +++++++++++++----------- src/mint/mint_db.h | 32 ++++++++++++++++++++++++++------ 2 files changed, 39 insertions(+), 17 deletions(-) diff --git a/src/mint/mint_db.c b/src/mint/mint_db.c index b9f30ac3f..e029d0567 100644 --- a/src/mint/mint_db.c +++ b/src/mint/mint_db.c @@ -852,25 +852,27 @@ TALER_MINT_DB_commit (PGconn *db_conn) * Get the summary of a reserve. * * @param db the database connection handle - * @param reserve_pub the public key identifying the reserve - * @param balance the amount existing in the reserve (will be filled) - * @param expiry expiration of the reserve (will be filled) - * @return #GNUNET_OK upon success; #GNUNET_NO when the given reserve is not - * found; #GNUNET_SYSERR upon failure + * @param reserve the reserve data. The public key of the reserve should be set + * in this structure; it is used to query the database. The balance + * and expiration are then filled accordingly. + * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure */ int TALER_MINT_DB_reserve_get (PGconn *db, - struct GNUNET_CRYPTO_EddsaPublicKey *reserve_pub, - struct TALER_Amount *balance, - struct GNUNET_TIME_Absolute *expiry) + struct Reserve *reserve) { PGresult *result; uint64_t expiration_date_nbo; struct TALER_DB_QueryParam params[] = { - TALER_DB_QUERY_PARAM_PTR(reserve_pub), + TALER_DB_QUERY_PARAM_PTR(reserve->pub), TALER_DB_QUERY_PARAM_END }; + if (NULL == reserve->pub) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } result = TALER_DB_exec_prepared (db, "get_reserve", params); @@ -897,8 +899,8 @@ TALER_MINT_DB_reserve_get (PGconn *db, "current_balance_value", "current_balance_fraction", "current_balance_currency", - balance)); - expiry->abs_value_us = GNUNET_ntohll (expiration_date_nbo); + &reserve->balance)); + reserve->expiry.abs_value_us = GNUNET_ntohll (expiration_date_nbo); PQclear (result); return GNUNET_OK; diff --git a/src/mint/mint_db.h b/src/mint/mint_db.h index b80f750b0..b26c70b26 100644 --- a/src/mint/mint_db.h +++ b/src/mint/mint_db.h @@ -137,6 +137,27 @@ struct BankTransfer /* FIXME: add functions to add bank transfers to our DB (and to test if we already did add one) (#3633) */ +/** + * A summary of a Reserve + */ +struct Reserve +{ + /** + * The reserve's public key. This uniquely identifies the reserve + */ + struct GNUNET_CRYPTO_EddsaPublicKey *pub; + + /** + * The balance amount existing in the reserve + */ + struct TALER_Amount balance; + + /** + * The expiration date of this reserve + */ + struct GNUNET_TIME_Absolute expiry; +}; + /** * Information we keep for a withdrawn coin to reproduce @@ -173,16 +194,15 @@ struct CollectableBlindcoin * Get the summary of a reserve. * * @param db the database connection handle - * @param reserve_pub the public key identifying the reserve - * @param balance the amount existing in the reserve (will be filled) - * @param expiry expiration of the reserve (will be filled) + * @param reserve the reserve data. The public key of the reserve should be set + * in this structure; it is used to query the database. The balance + * and expiration are then filled accordingly. * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure */ int TALER_MINT_DB_reserve_get (PGconn *db, - struct GNUNET_CRYPTO_EddsaPublicKey *reserve_pub, - struct TALER_Amount *balance, - struct GNUNET_TIME_Absolute *expiry); + struct Reserve *reserve); + /* FIXME: need call to convert CollectableBlindcoin to JSON (#3527) */ From f92af896f8a2f07aba3a90434b2ee3aa51b45149 Mon Sep 17 00:00:00 2001 From: Sree Harsha Totakura Date: Thu, 5 Mar 2015 16:45:31 +0100 Subject: [PATCH 09/17] db: No special handling for failed INDEX creation --- src/mint/mint_db.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/mint/mint_db.c b/src/mint/mint_db.c index e029d0567..b84af0f22 100644 --- a/src/mint/mint_db.c +++ b/src/mint/mint_db.c @@ -164,16 +164,8 @@ TALER_MINT_DB_create_tables (int temporary) ",balance_fraction INT4 NOT NULL" ",expiration_date INT8 NOT NULL" ");"); - result = PQexec (conn, - "CREATE INDEX reserves_in_index ON reserves_in (reserve_pub);"); - if (PGRES_COMMAND_OK != PQresultStatus (result)) - { - ExecStatusType status = PQresultStatus (result); - PQclear (result); - result = NULL; - goto SQLEXEC_fail; - } - PQclear (result); + /* Create an index on the foreign key as it is not created automatically by PSQL */ + SQLEXEC ("CREATE INDEX reserves_in_index ON reserves_in (reserve_pub);"); SQLEXEC ("CREATE TABLE IF NOT EXISTS collectable_blindcoins" "(" "blind_ev BYTEA PRIMARY KEY" From a3e7b3af82fc3b805b6e01114dbaa2fd0d299a25 Mon Sep 17 00:00:00 2001 From: Sree Harsha Totakura Date: Thu, 5 Mar 2015 17:05:51 +0100 Subject: [PATCH 10/17] db: Use macro while creating prepared statements --- src/mint/mint_db.c | 637 +++++++++++++++++---------------------------- 1 file changed, 233 insertions(+), 404 deletions(-) diff --git a/src/mint/mint_db.c b/src/mint/mint_db.c index b84af0f22..a58959f94 100644 --- a/src/mint/mint_db.c +++ b/src/mint/mint_db.c @@ -272,417 +272,246 @@ TALER_MINT_DB_prepare (PGconn *db_conn) { PGresult *result; - result = PQprepare (db_conn, "get_reserve", - "SELECT " - "current_balance_value" - ",current_balance_fraction" - ",balance_currency " - ",expiration_date " - "FROM reserves " - "WHERE reserve_pub=$1 " - "LIMIT 1; ", - 1, NULL); - if (PGRES_COMMAND_OK != PQresultStatus(result)) - { - break_db_err (result); - PQclear (result); - return GNUNET_SYSERR; - } - PQclear (result); +#define PREPARE(name, sql, ...) \ + do { \ + result = PQprepare (db_conn, name, sql, __VA_ARGS__); \ + if (PGRES_COMMAND_OK != PQresultStatus (result)) \ + { \ + break_db_err (result); \ + PQclear (result); result = NULL; \ + return GNUNET_SYSERR; \ + } \ + PQclear (result); result = NULL; \ + } while (0); - result = PQprepare (db_conn, "update_reserve", - "UPDATE reserves " - "SET" - " current_balance_value=$2 " - ",current_balance_fraction=$3 " - ",expiration_date=$4 " - "WHERE reserve_pub=$1 ", - 4, NULL); - if (PGRES_COMMAND_OK != PQresultStatus(result)) - { - break_db_err (result); - PQclear (result); - return GNUNET_SYSERR; - } - PQclear (result); - result = PQprepare (db_conn, "insert_collectable_blindcoins", - "INSERT INTO collectable_blindcoins ( " - " blind_ev, blind_ev_sig " - ",denom_pub, reserve_pub, reserve_sig) " - "VALUES ($1, $2, $3, $4, $5)", - 6, NULL); - if (PGRES_COMMAND_OK != PQresultStatus(result)) - { - break_db_err (result); - PQclear (result); - return GNUNET_SYSERR; - } - PQclear (result); - - result = PQprepare (db_conn, "get_collectable_blindcoins", - "SELECT " - "blind_ev_sig, denom_pub, reserve_sig, reserve_pub " - "FROM collectable_blindcoins " - "WHERE blind_ev = $1", - 1, NULL); - if (PGRES_COMMAND_OK != PQresultStatus(result)) - { - break_db_err (result); - PQclear (result); - return GNUNET_SYSERR; - } - PQclear (result); + PREPARE ("get_reserve", + "SELECT " + "current_balance_value" + ",current_balance_fraction" + ",balance_currency " + ",expiration_date " + "FROM reserves " + "WHERE reserve_pub=$1 " + "LIMIT 1; ", + 1, NULL); + PREPARE ("update_reserve", + "UPDATE reserves " + "SET" + " current_balance_value=$2 " + ",current_balance_fraction=$3 " + ",expiration_date=$4 " + "WHERE reserve_pub=$1 ", + 4, NULL); + PREPARE ("insert_collectable_blindcoins", + "INSERT INTO collectable_blindcoins ( " + " blind_ev, blind_ev_sig " + ",denom_pub, reserve_pub, reserve_sig) " + "VALUES ($1, $2, $3, $4, $5)", + 6, NULL); + PREPARE ("get_collectable_blindcoins", + "SELECT " + "blind_ev_sig, denom_pub, reserve_sig, reserve_pub " + "FROM collectable_blindcoins " + "WHERE blind_ev = $1", + 1, NULL); /* FIXME: does it make sense to store these computed values in the DB? */ #if 0 - result = PQprepare (db_conn, "get_refresh_session", - "SELECT " - " (SELECT count(*) FROM refresh_melt WHERE session_pub = $1)::INT2 as num_oldcoins " - ",(SELECT count(*) FROM refresh_blind_session_keys " - " WHERE session_pub = $1 and cnc_index = 0)::INT2 as num_newcoins " - ",(SELECT count(*) FROM refresh_blind_session_keys " - " WHERE session_pub = $1 and newcoin_index = 0)::INT2 as kappa " - ",noreveal_index" - ",session_commit_sig " - ",reveal_ok " - "FROM refresh_sessions " - "WHERE session_pub = $1", - 1, NULL); - if (PGRES_COMMAND_OK != PQresultStatus(result)) - { - break_db_err (result); - PQclear (result); - return GNUNET_SYSERR; - } - PQclear (result); + PREPARE ("get_refresh_session", + "SELECT " + " (SELECT count(*) FROM refresh_melt WHERE session_pub = $1)::INT2 as num_oldcoins " + ",(SELECT count(*) FROM refresh_blind_session_keys " + " WHERE session_pub = $1 and cnc_index = 0)::INT2 as num_newcoins " + ",(SELECT count(*) FROM refresh_blind_session_keys " + " WHERE session_pub = $1 and newcoin_index = 0)::INT2 as kappa " + ",noreveal_index" + ",session_commit_sig " + ",reveal_ok " + "FROM refresh_sessions " + "WHERE session_pub = $1", + 1, NULL); #endif - result = PQprepare (db_conn, "get_known_coin", - "SELECT " - " coin_pub, denom_pub, denom_sig " - ",expended_value, expended_fraction, expended_currency " - ",refresh_session_pub " - "FROM known_coins " - "WHERE coin_pub = $1", - 1, NULL); - if (PGRES_COMMAND_OK != PQresultStatus(result)) - { - break_db_err (result); - PQclear (result); - return GNUNET_SYSERR; - } - PQclear (result); - - result = PQprepare (db_conn, "update_known_coin", - "UPDATE known_coins " - "SET " - " denom_pub = $2 " - ",denom_sig = $3 " - ",expended_value = $4 " - ",expended_fraction = $5 " - ",expended_currency = $6 " - ",refresh_session_pub = $7 " - "WHERE " - " coin_pub = $1 ", - 7, NULL); - if (PGRES_COMMAND_OK != PQresultStatus(result)) - { - break_db_err (result); - PQclear (result); - return GNUNET_SYSERR; - } - PQclear (result); - - result = PQprepare (db_conn, "insert_known_coin", - "INSERT INTO known_coins (" - " coin_pub" - ",denom_pub" - ",denom_sig" - ",expended_value" - ",expended_fraction" - ",expended_currency" - ",refresh_session_pub" - ")" - "VALUES ($1,$2,$3,$4,$5,$6,$7)", - 7, NULL); - if (PGRES_COMMAND_OK != PQresultStatus(result)) - { - break_db_err (result); - PQclear (result); - return GNUNET_SYSERR; - } - PQclear (result); - - result = PQprepare (db_conn, "get_refresh_commit_link", - "SELECT " - " transfer_pub " - ",link_secret_enc " - "FROM refresh_commit_link " - "WHERE session_pub = $1 AND cnc_index = $2 AND oldcoin_index = $3", - 3, NULL); - if (PGRES_COMMAND_OK != PQresultStatus(result)) - { - break_db_err (result); - PQclear (result); - return GNUNET_SYSERR; - } - PQclear (result); - - result = PQprepare (db_conn, "get_refresh_commit_coin", - "SELECT " - " link_vector_enc " - ",coin_ev " - "FROM refresh_commit_coin " - "WHERE session_pub = $1 AND cnc_index = $2 AND newcoin_index = $3", - 3, NULL); - if (PGRES_COMMAND_OK != PQresultStatus(result)) - { - break_db_err (result); - PQclear (result); - return GNUNET_SYSERR; - } - PQclear (result); - - result = PQprepare (db_conn, "insert_refresh_order", - "INSERT INTO refresh_order ( " - " newcoin_index " - ",session_pub " - ",denom_pub " - ") " - "VALUES ($1, $2, $3) ", - 3, NULL); - if (PGRES_COMMAND_OK != PQresultStatus(result)) - { - break_db_err (result); - PQclear (result); - return GNUNET_SYSERR; - } - PQclear (result); - - result = PQprepare (db_conn, "insert_refresh_melt", - "INSERT INTO refresh_melt ( " - " session_pub " - ",oldcoin_index " - ",coin_pub " - ",denom_pub " - ") " - "VALUES ($1, $2, $3, $4) ", - 3, NULL); - if (PGRES_COMMAND_OK != PQresultStatus(result)) - { - break_db_err (result); - PQclear (result); - return GNUNET_SYSERR; - } - PQclear (result); - - result = PQprepare (db_conn, "get_refresh_order", - "SELECT denom_pub " - "FROM refresh_order " - "WHERE session_pub = $1 AND newcoin_index = $2", - 2, NULL); - if (PGRES_COMMAND_OK != PQresultStatus(result)) - { - break_db_err (result); - PQclear (result); - return GNUNET_SYSERR; - } - PQclear (result); - - result = PQprepare (db_conn, "get_refresh_collectable", - "SELECT ev_sig " - "FROM refresh_collectable " - "WHERE session_pub = $1 AND newcoin_index = $2", - 2, NULL); - if (PGRES_COMMAND_OK != PQresultStatus(result)) - { - break_db_err (result); - PQclear (result); - return GNUNET_SYSERR; - } - PQclear (result); - - result = PQprepare (db_conn, "get_refresh_melt", - "SELECT coin_pub " - "FROM refresh_melt " - "WHERE session_pub = $1 AND oldcoin_index = $2", - 2, NULL); - if (PGRES_COMMAND_OK != PQresultStatus(result)) - { - break_db_err (result); - PQclear (result); - return GNUNET_SYSERR; - } - PQclear (result); - - result = PQprepare (db_conn, "insert_refresh_session", - "INSERT INTO refresh_sessions ( " - " session_pub " - ",noreveal_index " - ") " - "VALUES ($1, $2) ", - 2, NULL); - if (PGRES_COMMAND_OK != PQresultStatus(result)) - { - break_db_err (result); - PQclear (result); - return GNUNET_SYSERR; - } - PQclear (result); - - result = PQprepare (db_conn, "insert_refresh_commit_link", - "INSERT INTO refresh_commit_link ( " - " session_pub " - ",transfer_pub " - ",cnc_index " - ",oldcoin_index " - ",link_secret_enc " - ") " - "VALUES ($1, $2, $3, $4, $5) ", - 5, NULL); - if (PGRES_COMMAND_OK != PQresultStatus(result)) - { - break_db_err (result); - PQclear (result); - return GNUNET_SYSERR; - } - PQclear (result); - - result = PQprepare (db_conn, "insert_refresh_commit_coin", - "INSERT INTO refresh_commit_coin ( " - " session_pub " - ",coin_ev " - ",cnc_index " - ",newcoin_index " - ",link_vector_enc " - ") " - "VALUES ($1, $2, $3, $4, $5) ", - 5, NULL); - if (PGRES_COMMAND_OK != PQresultStatus(result)) - { - break_db_err (result); - PQclear (result); - return GNUNET_SYSERR; - } - PQclear (result); - - result = PQprepare (db_conn, "insert_refresh_collectable", - "INSERT INTO refresh_collectable ( " - " session_pub " - ",newcoin_index " - ",ev_sig " - ") " - "VALUES ($1, $2, $3) ", - 3, NULL); - if (PGRES_COMMAND_OK != PQresultStatus(result)) - { - break_db_err (result); - PQclear (result); - return GNUNET_SYSERR; - } - PQclear (result); - - result = PQprepare (db_conn, "set_reveal_ok", - "UPDATE refresh_sessions " - "SET reveal_ok = TRUE " - "WHERE session_pub = $1 ", - 1, NULL); - if (PGRES_COMMAND_OK != PQresultStatus(result)) - { - break_db_err (result); - PQclear (result); - return GNUNET_SYSERR; - } - PQclear (result); - - result = PQprepare (db_conn, "get_link", - "SELECT link_vector_enc, ro.denom_pub, ev_sig " - "FROM refresh_melt rm " - " JOIN refresh_order ro USING (session_pub) " - " JOIN refresh_commit_coin rcc USING (session_pub) " - " JOIN refresh_sessions rs USING (session_pub) " - " JOIN refresh_collectable rc USING (session_pub) " - "WHERE rm.coin_pub = $1 " - "AND ro.newcoin_index = rcc.newcoin_index " - "AND ro.newcoin_index = rc.newcoin_index " - "AND rcc.cnc_index = rs.noreveal_index % ( " - " SELECT count(*) FROM refresh_commit_coin rcc2 " - " WHERE rcc2.newcoin_index = 0 AND rcc2.session_pub = rs.session_pub " - " ) ", - 1, NULL); - if (PGRES_COMMAND_OK != PQresultStatus(result)) - { - break_db_err (result); - PQclear (result); - return GNUNET_SYSERR; - } - PQclear (result); - - result = PQprepare (db_conn, "get_transfer", - "SELECT transfer_pub, link_secret_enc " - "FROM refresh_melt rm " - " JOIN refresh_commit_link rcl USING (session_pub) " - " JOIN refresh_sessions rs USING (session_pub) " - "WHERE rm.coin_pub = $1 " - "AND rm.oldcoin_index = rcl.oldcoin_index " - "AND rcl.cnc_index = rs.noreveal_index % ( " - " SELECT count(*) FROM refresh_commit_coin rcc2 " - " WHERE newcoin_index = 0 AND rcc2.session_pub = rm.session_pub " - " ) ", - 1, NULL); - if (PGRES_COMMAND_OK != PQresultStatus(result)) - { - break_db_err (result); - PQclear (result); - return GNUNET_SYSERR; - } - PQclear (result); - - result = PQprepare (db_conn, "insert_deposit", - "INSERT INTO deposits (" - "coin_pub," - "denom_pub," - "transaction_id," - "amount_value," - "amount_fraction," - "amount_currency," - "merchant_pub," - "h_contract," - "h_wire," - "coin_sig," - "wire" - ") VALUES (" - "$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11" - ")", - 11, NULL); - EXITIF (PGRES_COMMAND_OK != PQresultStatus(result)); - PQclear (result); - - result = PQprepare (db_conn, "get_deposit", - "SELECT " - "coin_pub," - "denom_pub," - "transaction_id," - "amount_value," - "amount_fraction," - "amount_currency," - "merchant_pub," - "h_contract," - "h_wire," - "coin_sig" - " FROM deposits WHERE (" - "coin_pub = $1" - ")", - 1, NULL); - EXITIF (PGRES_COMMAND_OK != PQresultStatus(result)); - PQclear (result); - + PREPARE ("get_known_coin", + "SELECT " + " coin_pub, denom_pub, denom_sig " + ",expended_value, expended_fraction, expended_currency " + ",refresh_session_pub " + "FROM known_coins " + "WHERE coin_pub = $1", + 1, NULL); + PREPARE ("update_known_coin", + "UPDATE known_coins " + "SET " + " denom_pub = $2 " + ",denom_sig = $3 " + ",expended_value = $4 " + ",expended_fraction = $5 " + ",expended_currency = $6 " + ",refresh_session_pub = $7 " + "WHERE " + " coin_pub = $1 ", + 7, NULL); + PREPARE ("insert_known_coin", + "INSERT INTO known_coins (" + " coin_pub" + ",denom_pub" + ",denom_sig" + ",expended_value" + ",expended_fraction" + ",expended_currency" + ",refresh_session_pub" + ")" + "VALUES ($1,$2,$3,$4,$5,$6,$7)", + 7, NULL); + PREPARE ("get_refresh_commit_link", + "SELECT " + " transfer_pub " + ",link_secret_enc " + "FROM refresh_commit_link " + "WHERE session_pub = $1 AND cnc_index = $2 AND oldcoin_index = $3", + 3, NULL); + PREPARE ("get_refresh_commit_coin", + "SELECT " + " link_vector_enc " + ",coin_ev " + "FROM refresh_commit_coin " + "WHERE session_pub = $1 AND cnc_index = $2 AND newcoin_index = $3", + 3, NULL); + PREPARE ("insert_refresh_order", + "INSERT INTO refresh_order ( " + " newcoin_index " + ",session_pub " + ",denom_pub " + ") " + "VALUES ($1, $2, $3) ", + 3, NULL); + PREPARE ("insert_refresh_melt", + "INSERT INTO refresh_melt ( " + " session_pub " + ",oldcoin_index " + ",coin_pub " + ",denom_pub " + ") " + "VALUES ($1, $2, $3, $4) ", + 3, NULL); + PREPARE ("get_refresh_order", + "SELECT denom_pub " + "FROM refresh_order " + "WHERE session_pub = $1 AND newcoin_index = $2", + 2, NULL); + PREPARE ("get_refresh_collectable", + "SELECT ev_sig " + "FROM refresh_collectable " + "WHERE session_pub = $1 AND newcoin_index = $2", + 2, NULL); + PREPARE ("get_refresh_melt", + "SELECT coin_pub " + "FROM refresh_melt " + "WHERE session_pub = $1 AND oldcoin_index = $2", + 2, NULL); + PREPARE ("insert_refresh_session", + "INSERT INTO refresh_sessions ( " + " session_pub " + ",noreveal_index " + ") " + "VALUES ($1, $2) ", + 2, NULL); + PREPARE ("insert_refresh_commit_link", + "INSERT INTO refresh_commit_link ( " + " session_pub " + ",transfer_pub " + ",cnc_index " + ",oldcoin_index " + ",link_secret_enc " + ") " + "VALUES ($1, $2, $3, $4, $5) ", + 5, NULL); + PREPARE ("insert_refresh_commit_coin", + "INSERT INTO refresh_commit_coin ( " + " session_pub " + ",coin_ev " + ",cnc_index " + ",newcoin_index " + ",link_vector_enc " + ") " + "VALUES ($1, $2, $3, $4, $5) ", + 5, NULL); + PREPARE ("insert_refresh_collectable", + "INSERT INTO refresh_collectable ( " + " session_pub " + ",newcoin_index " + ",ev_sig " + ") " + "VALUES ($1, $2, $3) ", + 3, NULL); + PREPARE ("set_reveal_ok", + "UPDATE refresh_sessions " + "SET reveal_ok = TRUE " + "WHERE session_pub = $1 ", + 1, NULL); + PREPARE ("get_link", + "SELECT link_vector_enc, ro.denom_pub, ev_sig " + "FROM refresh_melt rm " + " JOIN refresh_order ro USING (session_pub) " + " JOIN refresh_commit_coin rcc USING (session_pub) " + " JOIN refresh_sessions rs USING (session_pub) " + " JOIN refresh_collectable rc USING (session_pub) " + "WHERE rm.coin_pub = $1 " + "AND ro.newcoin_index = rcc.newcoin_index " + "AND ro.newcoin_index = rc.newcoin_index " + "AND rcc.cnc_index = rs.noreveal_index % ( " + " SELECT count(*) FROM refresh_commit_coin rcc2 " + " WHERE rcc2.newcoin_index = 0 AND rcc2.session_pub = rs.session_pub " + " ) ", + 1, NULL); + PREPARE ("get_transfer", + "SELECT transfer_pub, link_secret_enc " + "FROM refresh_melt rm " + " JOIN refresh_commit_link rcl USING (session_pub) " + " JOIN refresh_sessions rs USING (session_pub) " + "WHERE rm.coin_pub = $1 " + "AND rm.oldcoin_index = rcl.oldcoin_index " + "AND rcl.cnc_index = rs.noreveal_index % ( " + " SELECT count(*) FROM refresh_commit_coin rcc2 " + " WHERE newcoin_index = 0 AND rcc2.session_pub = rm.session_pub " + " ) ", + 1, NULL); + PREPARE ("insert_deposit", + "INSERT INTO deposits (" + "coin_pub," + "denom_pub," + "transaction_id," + "amount_value," + "amount_fraction," + "amount_currency," + "merchant_pub," + "h_contract," + "h_wire," + "coin_sig," + "wire" + ") VALUES (" + "$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11" + ")", + 11, NULL); + PREPARE ("get_deposit", + "SELECT " + "coin_pub," + "denom_pub," + "transaction_id," + "amount_value," + "amount_fraction," + "amount_currency," + "merchant_pub," + "h_contract," + "h_wire," + "coin_sig" + " FROM deposits WHERE (" + "coin_pub = $1" + ")", + 1, NULL); return GNUNET_OK; - - EXITIF_exit: - break_db_err (result); - PQclear (result); - return GNUNET_SYSERR; +#undef PREPARE } From c2ee5efa50c43ea46c8f83070d580369aa1dadbd Mon Sep 17 00:00:00 2001 From: Sree Harsha Totakura Date: Thu, 5 Mar 2015 17:34:54 +0100 Subject: [PATCH 11/17] util: use const whenever applicable --- src/include/taler_amount_lib.h | 4 ++-- src/util/amount.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/include/taler_amount_lib.h b/src/include/taler_amount_lib.h index 72f5d4ffd..1f31e1498 100644 --- a/src/include/taler_amount_lib.h +++ b/src/include/taler_amount_lib.h @@ -99,7 +99,7 @@ TALER_string_to_amount (const char *str, * @return amount in network representation */ struct TALER_AmountNBO -TALER_amount_hton (struct TALER_Amount d); +TALER_amount_hton (const struct TALER_Amount d); /** @@ -109,7 +109,7 @@ TALER_amount_hton (struct TALER_Amount d); * @return amount in host representation */ struct TALER_Amount -TALER_amount_ntoh (struct TALER_AmountNBO dn); +TALER_amount_ntoh (const struct TALER_AmountNBO dn); /** diff --git a/src/util/amount.c b/src/util/amount.c index cc0cdd6e3..9bdc0fd93 100644 --- a/src/util/amount.c +++ b/src/util/amount.c @@ -139,7 +139,7 @@ TALER_string_to_amount (const char *str, * FIXME */ struct TALER_AmountNBO -TALER_amount_hton (struct TALER_Amount d) +TALER_amount_hton (const struct TALER_Amount d) { struct TALER_AmountNBO dn; dn.value = htonl (d.value); @@ -154,7 +154,7 @@ TALER_amount_hton (struct TALER_Amount d) * FIXME */ struct TALER_Amount -TALER_amount_ntoh (struct TALER_AmountNBO dn) +TALER_amount_ntoh (const struct TALER_AmountNBO dn) { struct TALER_Amount d; d.value = ntohl (dn.value); From 0438dac4eff968eb717dd895c38c4d33162ec907 Mon Sep 17 00:00:00 2001 From: Sree Harsha Totakura Date: Thu, 5 Mar 2015 17:53:15 +0100 Subject: [PATCH 12/17] -rename --- src/mint/mint_db.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/mint/mint_db.c b/src/mint/mint_db.c index a58959f94..07ec56776 100644 --- a/src/mint/mint_db.c +++ b/src/mint/mint_db.c @@ -48,7 +48,7 @@ static pthread_key_t db_conn_threadlocal; */ static char *TALER_MINT_db_connection_cfg_str; -#define break_db_err(result) do { \ +#define BREAK_DB_ERR(result) do { \ GNUNET_break(0); \ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Database failure: %s\n", PQresultErrorMessage (result)); \ } while (0) @@ -67,7 +67,7 @@ static char *TALER_MINT_db_connection_cfg_str; result = PQexec (conn, sql); \ if (PGRES_COMMAND_OK != PQresultStatus (result)) \ { \ - break_db_err (result); \ + BREAK_DB_ERR (result); \ PQclear (result); result = NULL; \ goto SQLEXEC_fail; \ } \ @@ -277,7 +277,7 @@ TALER_MINT_DB_prepare (PGconn *db_conn) result = PQprepare (db_conn, name, sql, __VA_ARGS__); \ if (PGRES_COMMAND_OK != PQresultStatus (result)) \ { \ - break_db_err (result); \ + BREAK_DB_ERR (result); \ PQclear (result); result = NULL; \ return GNUNET_SYSERR; \ } \ @@ -973,7 +973,7 @@ TALER_MINT_DB_have_deposit (PGconn *db_conn, if (PGRES_TUPLES_OK != PQresultStatus (result)) { - break_db_err (result); + BREAK_DB_ERR (result); PQclear (result); return GNUNET_SYSERR; } @@ -1022,7 +1022,7 @@ TALER_MINT_DB_insert_deposit (PGconn *db_conn, result = TALER_DB_exec_prepared (db_conn, "insert_deposit", params); if (PGRES_COMMAND_OK != PQresultStatus (result)) { - break_db_err (result); + BREAK_DB_ERR (result); PQclear (result); return GNUNET_SYSERR; } @@ -1138,7 +1138,7 @@ TALER_MINT_DB_create_refresh_session (PGconn *db_conn, if (PGRES_COMMAND_OK != PQresultStatus (result)) { - break_db_err (result); + BREAK_DB_ERR (result); PQclear (result); return GNUNET_SYSERR; } @@ -1207,7 +1207,7 @@ TALER_MINT_DB_insert_refresh_melt (PGconn *db_conn, GNUNET_free (buf); if (PGRES_COMMAND_OK != PQresultStatus (result)) { - break_db_err (result); + BREAK_DB_ERR (result); PQclear (result); return GNUNET_SYSERR; } @@ -1278,7 +1278,7 @@ TALER_MINT_DB_insert_refresh_order (PGconn *db_conn, GNUNET_free (buf); if (PGRES_COMMAND_OK != PQresultStatus (result)) { - break_db_err (result); + BREAK_DB_ERR (result); PQclear (result); return GNUNET_SYSERR; } @@ -1323,7 +1323,7 @@ TALER_MINT_DB_get_refresh_order (PGconn *db_conn, if (PGRES_TUPLES_OK != PQresultStatus (result)) { - break_db_err (result); + BREAK_DB_ERR (result); PQclear (result); return NULL; } @@ -1390,7 +1390,7 @@ TALER_MINT_DB_insert_refresh_commit_coin (PGconn *db_conn, if (PGRES_COMMAND_OK != PQresultStatus (result)) { - break_db_err (result); + BREAK_DB_ERR (result); PQclear (result); return GNUNET_SYSERR; } @@ -1445,7 +1445,7 @@ TALER_MINT_DB_get_refresh_commit_coin (PGconn *db_conn, if (PGRES_TUPLES_OK != PQresultStatus (result)) { - break_db_err (result); + BREAK_DB_ERR (result); PQclear (result); return GNUNET_SYSERR; } @@ -1519,7 +1519,7 @@ TALER_MINT_DB_insert_refresh_commit_link (PGconn *db_conn, params); if (PGRES_COMMAND_OK != PQresultStatus (result)) { - break_db_err (result); + BREAK_DB_ERR (result); PQclear (result); return GNUNET_SYSERR; } @@ -1572,7 +1572,7 @@ TALER_MINT_DB_get_refresh_commit_link (PGconn *db_conn, params); if (PGRES_TUPLES_OK != PQresultStatus (result)) { - break_db_err (result); + BREAK_DB_ERR (result); PQclear (result); return GNUNET_SYSERR; } @@ -1641,7 +1641,7 @@ TALER_MINT_DB_insert_refresh_collectable (PGconn *db_conn, GNUNET_free (buf); if (PGRES_COMMAND_OK != PQresultStatus (result)) { - break_db_err (result); + BREAK_DB_ERR (result); PQclear (result); return GNUNET_SYSERR; } @@ -1674,7 +1674,7 @@ TALER_db_get_link (PGconn *db_conn, ldl = NULL; if (PGRES_TUPLES_OK != PQresultStatus (result)) { - break_db_err (result); + BREAK_DB_ERR (result); PQclear (result); return NULL; } @@ -1805,7 +1805,7 @@ TALER_db_get_transfer (PGconn *db_conn, if (PGRES_TUPLES_OK != PQresultStatus (result)) { - break_db_err (result); + BREAK_DB_ERR (result); PQclear (result); return GNUNET_SYSERR; } From 376183ac6a0f042235b75a76ea500bb74f270615 Mon Sep 17 00:00:00 2001 From: Sree Harsha Totakura Date: Thu, 5 Mar 2015 17:53:41 +0100 Subject: [PATCH 13/17] db: fix compile warning in taler-mint-dbinit.c --- src/mint/taler-mint-dbinit.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mint/taler-mint-dbinit.c b/src/mint/taler-mint-dbinit.c index c5b0ae4c3..8106b54c4 100644 --- a/src/mint/taler-mint-dbinit.c +++ b/src/mint/taler-mint-dbinit.c @@ -22,6 +22,7 @@ #include #include #include "taler_util.h" +#include "mint_db.h" #define break_db_err(result) do { \ GNUNET_break(0); \ @@ -86,7 +87,7 @@ main (int argc, char *const *argv) return 1; } - if (GNUNET_OK != TALER_MINT_DB_create_tables (db_conn)) + if (GNUNET_OK != TALER_MINT_DB_create_tables (GNUNET_NO)) { fprintf (stderr, "Failed to initialize database.\n"); return 1; From c62dc613ce44b9c671e9cc9328ceb0a078c4ca4e Mon Sep 17 00:00:00 2001 From: Sree Harsha Totakura Date: Thu, 5 Mar 2015 17:55:19 +0100 Subject: [PATCH 14/17] db: Add QUERY_ERR macro to log failed queries --- src/mint/mint_db.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/mint/mint_db.c b/src/mint/mint_db.c index 07ec56776..0bd888221 100644 --- a/src/mint/mint_db.c +++ b/src/mint/mint_db.c @@ -42,6 +42,9 @@ static pthread_key_t db_conn_threadlocal; +#define QUERY_ERR(result) \ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s: query failed: %s\n", __FUNCTION__, PQresultErrorMessage (result)) + /** * Database connection string, as read from * the configuration. @@ -699,9 +702,7 @@ TALER_MINT_DB_reserve_get (PGconn *db, params); if (PGRES_TUPLES_OK != PQresultStatus (result)) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Query failed: %s\n", - PQresultErrorMessage (result)); + QUERY_ERR (result); PQclear (result); return GNUNET_SYSERR; } From 129920ef8bc15ce6d3c1329c2e935dce1da285f0 Mon Sep 17 00:00:00 2001 From: Sree Harsha Totakura Date: Thu, 5 Mar 2015 18:16:32 +0100 Subject: [PATCH 15/17] db: Implement reserves_in_insert() --- src/mint/mint_db.c | 112 +++++++++++++++++++++++++++++++++++++++++++++ src/mint/mint_db.h | 17 +++++++ 2 files changed, 129 insertions(+) diff --git a/src/mint/mint_db.c b/src/mint/mint_db.c index 0bd888221..744845b78 100644 --- a/src/mint/mint_db.c +++ b/src/mint/mint_db.c @@ -297,6 +297,23 @@ TALER_MINT_DB_prepare (PGconn *db_conn) "WHERE reserve_pub=$1 " "LIMIT 1; ", 1, NULL); + PREPARE ("create_reserve", + "INSERT INTO reserves (" + " reserve_pub," + " current_balance_value," + " current_balance_fraction," + " balance_currency," + " expiration_date) VALUES (" + "$1, $2, $3, $4, $5);", + 5, NULL); + PREPARE ("create_reserves_in_transaction", + "INSERT INTO reserves_in (" + " reserve_pub," + " balance_value," + " balance_fraction," + " expiration_date) VALUES (" + " $1, $2, $3, $4);", + 4, NULL); PREPARE ("update_reserve", "UPDATE reserves " "SET" @@ -732,8 +749,103 @@ TALER_MINT_DB_reserve_get (PGconn *db, } +/** + * Insert a incoming transaction into reserves. New reserves are also created + * through this function. + * + * @param db the database connection handle + * @param reserve the reserve structure. The public key of the reserve should + * be set here. Upon successful execution of this function, the + * balance and expiration of the reserve will be updated. + * @param balance the amount that has to be added to the reserve + * @param expiry the new expiration time for the reserve + * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failures + */ +int +TALER_MINT_DB_reserves_in_insert (PGconn *db, + struct Reserve *reserve, + const struct TALER_Amount *balance, + const struct GNUNET_TIME_Absolute *expiry) +{ + struct TALER_AmountNBO balance_nbo; + struct GNUNET_TIME_AbsoluteNBO expiry_nbo; + PGresult *result; + int reserve_exists; + if (NULL == reserve) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + if (GNUNET_OK != TALER_MINT_DB_transaction (db)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + reserve_exists = TALER_MINT_DB_reserve_get (db, reserve); + if (GNUNET_SYSERR == reserve_exists) + { + TALER_MINT_DB_rollback (db); + return GNUNET_SYSERR; + } + balance_nbo = TALER_amount_hton (*balance); + expiry_nbo = GNUNET_TIME_absolute_hton (*expiry); + if (GNUNET_NO == reserve_exists) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Reserve does not exist; creating a new one\n"); + struct TALER_DB_QueryParam params[] = { + TALER_DB_QUERY_PARAM_PTR_SIZED (reserve->pub, sizeof (reserve->pub)), + TALER_DB_QUERY_PARAM_PTR (&balance_nbo.value), + TALER_DB_QUERY_PARAM_PTR (&balance_nbo.fraction), + TALER_DB_QUERY_PARAM_PTR_SIZED (balance_nbo.currency, + TALER_CURRENCY_LEN), + TALER_DB_QUERY_PARAM_PTR (&expiry_nbo), + TALER_DB_QUERY_PARAM_END + }; + result = TALER_DB_exec_prepared (db, + "create_reserve", + params); + if (PGRES_COMMAND_OK != result) + { + QUERY_ERR (result); + goto rollback; + } + } + PQclear (result); result = NULL; + /* create new incoming transaction */ + struct TALER_DB_QueryParam params[] = { + TALER_DB_QUERY_PARAM_PTR_SIZED (reserve->pub, sizeof (reserve->pub)), + TALER_DB_QUERY_PARAM_PTR (&balance_nbo.value), + TALER_DB_QUERY_PARAM_PTR (&balance_nbo.fraction), + TALER_DB_QUERY_PARAM_PTR (&expiry_nbo), + TALER_DB_QUERY_PARAM_END + }; + result = TALER_DB_exec_prepared (db, + "create_reserves_in_transaction", + params); + if (PGRES_COMMAND_OK != result) + { + QUERY_ERR (result); + goto rollback; + } + PQclear (result); result = NULL; + if (GNUNET_NO == reserve_exists) + { + if (GNUNET_OK != TALER_MINT_DB_commit (db)) + return GNUNET_SYSERR; + (void) memcpy (&reserve->balance, balance, sizeof (balance)); + reserve->expiry = *expiry; + return GNUNET_OK; + } + /* FIXME: Update reserve */ + return GNUNET_OK; + rollback: + PQclear (result); + TALER_MINT_DB_rollback (db); + return GNUNET_SYSERR; +} /** diff --git a/src/mint/mint_db.h b/src/mint/mint_db.h index b26c70b26..2c0b6dd75 100644 --- a/src/mint/mint_db.h +++ b/src/mint/mint_db.h @@ -204,6 +204,23 @@ TALER_MINT_DB_reserve_get (PGconn *db, struct Reserve *reserve); +/** + * Insert a incoming transaction into reserves. New reserves are also created + * through this function. + * + * @param db the database connection handle + * @param reserve the reserve structure. The public key of the reserve should + * be set here. Upon successful execution of this function, the + * balance and expiration of the reserve will be updated. + * @param balance the amount that has to be added to the reserve + * @param expiry the new expiration time for the reserve + * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failures + */ +int +TALER_MINT_DB_reserves_in_insert (PGconn *db, + struct Reserve *reserve, + const struct TALER_Amount *balance, + const struct GNUNET_TIME_Absolute *expiry); /* FIXME: need call to convert CollectableBlindcoin to JSON (#3527) */ From cee173a8e242e3536c1013e92fd1a01912a2a8e8 Mon Sep 17 00:00:00 2001 From: Sree Harsha Totakura Date: Thu, 5 Mar 2015 23:40:54 +0100 Subject: [PATCH 16/17] -sync --- src/mint/mint_db.c | 86 +++++++++++++++++++++++++++++++++++++--------- src/mint/mint_db.h | 4 +-- 2 files changed, 71 insertions(+), 19 deletions(-) diff --git a/src/mint/mint_db.c b/src/mint/mint_db.c index 744845b78..71e222008 100644 --- a/src/mint/mint_db.c +++ b/src/mint/mint_db.c @@ -306,14 +306,6 @@ TALER_MINT_DB_prepare (PGconn *db_conn) " expiration_date) VALUES (" "$1, $2, $3, $4, $5);", 5, NULL); - PREPARE ("create_reserves_in_transaction", - "INSERT INTO reserves_in (" - " reserve_pub," - " balance_value," - " balance_fraction," - " expiration_date) VALUES (" - " $1, $2, $3, $4);", - 4, NULL); PREPARE ("update_reserve", "UPDATE reserves " "SET" @@ -322,6 +314,14 @@ TALER_MINT_DB_prepare (PGconn *db_conn) ",expiration_date=$4 " "WHERE reserve_pub=$1 ", 4, NULL); + PREPARE ("create_reserves_in_transaction", + "INSERT INTO reserves_in (" + " reserve_pub," + " balance_value," + " balance_fraction," + " expiration_date) VALUES (" + " $1, $2, $3, $4);", + 4, NULL); PREPARE ("insert_collectable_blindcoins", "INSERT INTO collectable_blindcoins ( " " blind_ev, blind_ev_sig " @@ -749,6 +749,48 @@ TALER_MINT_DB_reserve_get (PGconn *db, } +/** + * Updates a reserve with the data from the given reserve structure. + * + * @param db the database connection + * @param reserve the reserve structure whose data will be used to update the + * corresponding record in the database. + * @return #GNUNET_OK upon successful update; #GNUNET_SYSERR upon any error + */ +int +reserves_update (PGconn *db, + struct Reserve *reserve) +{ + PGresult *result; + struct TALER_AmountNBO balance_nbo; + struct GNUNET_TIME_AbsoluteNBO expiry_nbo; + int ret; + + if ((NULL == reserve) || (NULL == reserve->pub)) + return GNUNET_SYSERR; + ret = GNUNET_OK; + struct TALER_DB_QueryParam params[] = { + TALER_DB_QUERY_PARAM_PTR (reserve->pub), + TALER_DB_QUERY_PARAM_PTR (&balance_nbo.value), + TALER_DB_QUERY_PARAM_PTR (&balance_nbo.fraction), + TALER_DB_QUERY_PARAM_PTR (&expiry_nbo), + TALER_DB_QUERY_PARAM_END + }; + balance_nbo = TALER_amount_hton (reserve->balance); + expiry_nbo = GNUNET_TIME_absolute_hton (reserve->expiry); + result = TALER_DB_exec_prepared (db, + "update_reserve", + params); + if (PGRES_COMMAND_OK != PQresultStatus(result)) + { + QUERY_ERR (result); + ret = GNUNET_SYSERR; + } + PQclear (result); + return ret; +} + + /** * Insert a incoming transaction into reserves. New reserves are also created * through this function. @@ -764,8 +806,8 @@ TALER_MINT_DB_reserve_get (PGconn *db, int TALER_MINT_DB_reserves_in_insert (PGconn *db, struct Reserve *reserve, - const struct TALER_Amount *balance, - const struct GNUNET_TIME_Absolute *expiry) + const struct TALER_Amount balance, + const struct GNUNET_TIME_Absolute expiry) { struct TALER_AmountNBO balance_nbo; struct GNUNET_TIME_AbsoluteNBO expiry_nbo; @@ -788,8 +830,8 @@ TALER_MINT_DB_reserves_in_insert (PGconn *db, TALER_MINT_DB_rollback (db); return GNUNET_SYSERR; } - balance_nbo = TALER_amount_hton (*balance); - expiry_nbo = GNUNET_TIME_absolute_hton (*expiry); + balance_nbo = TALER_amount_hton (balance); + expiry_nbo = GNUNET_TIME_absolute_hton (expiry); if (GNUNET_NO == reserve_exists) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, @@ -806,7 +848,7 @@ TALER_MINT_DB_reserves_in_insert (PGconn *db, result = TALER_DB_exec_prepared (db, "create_reserve", params); - if (PGRES_COMMAND_OK != result) + if (PGRES_COMMAND_OK != PQresultStatus(result)) { QUERY_ERR (result); goto rollback; @@ -815,7 +857,7 @@ TALER_MINT_DB_reserves_in_insert (PGconn *db, PQclear (result); result = NULL; /* create new incoming transaction */ struct TALER_DB_QueryParam params[] = { - TALER_DB_QUERY_PARAM_PTR_SIZED (reserve->pub, sizeof (reserve->pub)), + TALER_DB_QUERY_PARAM_PTR (reserve->pub), TALER_DB_QUERY_PARAM_PTR (&balance_nbo.value), TALER_DB_QUERY_PARAM_PTR (&balance_nbo.fraction), TALER_DB_QUERY_PARAM_PTR (&expiry_nbo), @@ -834,11 +876,21 @@ TALER_MINT_DB_reserves_in_insert (PGconn *db, { if (GNUNET_OK != TALER_MINT_DB_commit (db)) return GNUNET_SYSERR; - (void) memcpy (&reserve->balance, balance, sizeof (balance)); - reserve->expiry = *expiry; + reserve->balance = balance; + reserve->expiry = expiry; return GNUNET_OK; } - /* FIXME: Update reserve */ + /* Update reserve */ + struct Reserve updated_reserve; + updated_reserve.pub = reserve->pub; + updated_reserve.balance = TALER_amount_add (reserve->balance, balance); + updated_reserve.expiry = GNUNET_TIME_absolute_max (expiry, reserve->expiry); + if (GNUNET_OK != reserves_update (db, &updated_reserve)) + goto rollback; + if (GNUNET_OK != TALER_MINT_DB_commit (db)) + return GNUNET_SYSERR; + reserve->balance = updated_reserve.balance; + reserve->expiry = updated_reserve.expiry; return GNUNET_OK; rollback: diff --git a/src/mint/mint_db.h b/src/mint/mint_db.h index 2c0b6dd75..74f0c2d14 100644 --- a/src/mint/mint_db.h +++ b/src/mint/mint_db.h @@ -219,8 +219,8 @@ TALER_MINT_DB_reserve_get (PGconn *db, int TALER_MINT_DB_reserves_in_insert (PGconn *db, struct Reserve *reserve, - const struct TALER_Amount *balance, - const struct GNUNET_TIME_Absolute *expiry); + const struct TALER_Amount balance, + const struct GNUNET_TIME_Absolute expiry); /* FIXME: need call to convert CollectableBlindcoin to JSON (#3527) */ From 3c7168aad2d61d27ce340fb7337ec7f49add75c7 Mon Sep 17 00:00:00 2001 From: Sree Harsha Totakura Date: Fri, 6 Mar 2015 01:15:46 +0100 Subject: [PATCH 17/17] Added testcase for reserves_in_insert() --- src/mint/mint_db.c | 14 ++++++++++---- src/mint/test_mint_db.c | 20 ++++++++++++++++++++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/mint/mint_db.c b/src/mint/mint_db.c index 71e222008..2797f2169 100644 --- a/src/mint/mint_db.c +++ b/src/mint/mint_db.c @@ -43,7 +43,7 @@ static pthread_key_t db_conn_threadlocal; #define QUERY_ERR(result) \ - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s: query failed: %s\n", __FUNCTION__, PQresultErrorMessage (result)) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Query failed at %s:%u: %s\n", __FILE__, __LINE__, PQresultErrorMessage (result)) /** * Database connection string, as read from @@ -77,6 +77,12 @@ static char *TALER_MINT_db_connection_cfg_str; PQclear (result); result = NULL; \ } while (0) +/** + * This the length of the currency strings (without 0-termination) we use. Note + * that we need to use this at the DB layer instead of TALER_CURRENCY_LEN as the + * DB only needs to store 3 bytes instead of 8 bytes. + */ +#define TALER_DB_CURRENCY_LEN 3 /** * Set the given connection to use a temporary schema @@ -837,11 +843,11 @@ TALER_MINT_DB_reserves_in_insert (PGconn *db, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Reserve does not exist; creating a new one\n"); struct TALER_DB_QueryParam params[] = { - TALER_DB_QUERY_PARAM_PTR_SIZED (reserve->pub, sizeof (reserve->pub)), + TALER_DB_QUERY_PARAM_PTR (reserve->pub), TALER_DB_QUERY_PARAM_PTR (&balance_nbo.value), TALER_DB_QUERY_PARAM_PTR (&balance_nbo.fraction), TALER_DB_QUERY_PARAM_PTR_SIZED (balance_nbo.currency, - TALER_CURRENCY_LEN), + TALER_DB_CURRENCY_LEN), TALER_DB_QUERY_PARAM_PTR (&expiry_nbo), TALER_DB_QUERY_PARAM_END }; @@ -866,7 +872,7 @@ TALER_MINT_DB_reserves_in_insert (PGconn *db, result = TALER_DB_exec_prepared (db, "create_reserves_in_transaction", params); - if (PGRES_COMMAND_OK != result) + if (PGRES_COMMAND_OK != PQresultStatus(result)) { QUERY_ERR (result); goto rollback; diff --git a/src/mint/test_mint_db.c b/src/mint/test_mint_db.c index 4fa84eb38..192bc1e09 100644 --- a/src/mint/test_mint_db.c +++ b/src/mint/test_mint_db.c @@ -39,6 +39,10 @@ run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *config) { PGconn *db; + struct GNUNET_CRYPTO_EddsaPublicKey pub; + struct Reserve reserve; + struct GNUNET_TIME_Absolute expiry; + struct TALER_Amount amount; db = NULL; if (GNUNET_OK != TALER_MINT_DB_init ("postgres:///taler")) @@ -56,6 +60,22 @@ run (void *cls, char *const *args, const char *cfgfile, result = 3; goto drop; } + GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, + &pub, sizeof (pub)); + reserve.pub = &pub; + amount.value = 1; + amount.fraction = 1; + strcpy (amount.currency, "EUR"); + expiry = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), + GNUNET_TIME_UNIT_HOURS); + if (GNUNET_OK != TALER_MINT_DB_reserves_in_insert (db, + &reserve, + amount, + expiry)) + { + result = 4; + goto drop; + } result = 0; drop: if (NULL != db)