diff options
author | Christian Grothoff <christian@grothoff.org> | 2015-03-20 23:51:28 +0100 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2015-03-20 23:51:28 +0100 |
commit | 7d9a40327587ed99fb20f4c4a5669069c7a51e48 (patch) | |
tree | 40ed8371340ef3d36269e0c9d23c4daae23fb039 /src/mint/mint_db.c | |
parent | 0414fb51a9f219c37afc06ad2b309711e360c485 (diff) | |
download | exchange-7d9a40327587ed99fb20f4c4a5669069c7a51e48.tar.gz exchange-7d9a40327587ed99fb20f4c4a5669069c7a51e48.tar.bz2 exchange-7d9a40327587ed99fb20f4c4a5669069c7a51e48.zip |
first stab at establishing proper plugin API, main HTTP code compiles, other binaries FTBFS right now
Diffstat (limited to 'src/mint/mint_db.c')
-rw-r--r-- | src/mint/mint_db.c | 2241 |
1 files changed, 0 insertions, 2241 deletions
diff --git a/src/mint/mint_db.c b/src/mint/mint_db.c deleted file mode 100644 index 6832cdac9..000000000 --- a/src/mint/mint_db.c +++ /dev/null @@ -1,2241 +0,0 @@ -/* - 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 <http://www.gnu.org/licenses/> -*/ - -/** - * @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 - * when using other databases; so here we should enable - * alternative implementations by returning - * a more opaque DB handle. - */ -#include "platform.h" -#include "db_pq.h" -#include "taler_signatures.h" -#include "taler-mint-httpd_responses.h" -#include "mint_db.h" -#include <pthread.h> - - -/** - * Thread-local database connection. - * Contains a pointer to PGconn or NULL. - */ -static pthread_key_t db_conn_threadlocal; - - -#define QUERY_ERR(result) \ - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Query failed at %s:%u: %s\n", __FILE__, __LINE__, PQresultErrorMessage (result)) - -/** - * Database connection string, as read from - * the configuration. - */ -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)); \ - } while (0) - -/** - * Shorthand for exit jumps. - */ -#define EXITIF(cond) \ - do { \ - if (cond) { GNUNET_break (0); goto EXITIF_exit; } \ - } 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) - -/** - * 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 - * - * @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" - ",balance_currency VARCHAR(4) NOT NULL" - ",expiration_date INT8 NOT NULL" - ");"); - /* Create an index on the foreign key as it is not created automatically by PSQL */ - SQLEXEC ("CREATE INDEX reserves_in_reserve_pub_index" - " ON reserves_in (reserve_pub);"); - SQLEXEC ("CREATE TABLE IF NOT EXISTS collectable_blindcoins" - "(" - "blind_ev BYTEA PRIMARY KEY" - ",denom_pub BYTEA NOT NULL" /* FIXME: Make this a foreign key? */ - ",denom_sig BYTEA NOT NULL" - ",reserve_pub BYTEA REFERENCES reserves (reserve_pub) ON DELETE CASCADE" - ",reserve_sig BYTEA NOT NULL" - ");"); - SQLEXEC ("CREATE INDEX collectable_blindcoins_reserve_pub_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" /* FIXME: Link this as a foreign key? */ - ",denom_sig BYTEA NOT NULL" - ",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 CHECK (length(merchant_pub)=32)" - ",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. - * - * @param db_conn connection handle to initialize - * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure - */ -int -TALER_MINT_DB_prepare (PGconn *db_conn) -{ - PGresult *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); - - 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 ("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 ("update_reserve", - "UPDATE reserves " - "SET" - " current_balance_value=$2 " - ",current_balance_fraction=$3 " - ",expiration_date=$4 " - "WHERE reserve_pub=$1 ", - 4, NULL); - PREPARE ("create_reserves_in_transaction", - "INSERT INTO reserves_in (" - " reserve_pub," - " balance_value," - " balance_fraction," - " balance_currency," - " expiration_date) VALUES (" - " $1, $2, $3, $4, $5);", - 5, NULL); - PREPARE ("get_reserves_in_transactions", - "SELECT" - " balance_value" - ",balance_fraction" - ",balance_currency" - ",expiration_date" - " FROM reserves_in WHERE reserve_pub=$1", - 1, NULL); - PREPARE ("insert_collectable_blindcoin", - "INSERT INTO collectable_blindcoins ( " - " blind_ev" - ",denom_pub, denom_sig" - ",reserve_pub, reserve_sig) " - "VALUES ($1, $2, $3, $4, $5)", - 5, NULL); - PREPARE ("get_collectable_blindcoin", - "SELECT " - " denom_pub, denom_sig" - ",reserve_sig, reserve_pub " - "FROM collectable_blindcoins " - "WHERE blind_ev = $1", - 1, NULL); - PREPARE ("get_reserves_blindcoins", - "select" - " blind_ev" - ",denom_pub, denom_sig" - ",reserve_sig" - " FROM collectable_blindcoins" - " WHERE reserve_pub=$1;", - 1, NULL); - - /* FIXME: does it make sense to store these computed values in the DB? */ -#if 0 - 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 - - 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," - "denom_sig," - "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, $12" - ")", - 12, 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) AND" - "(transaction_id = $2) AND" - "(merchant_pub = $3)" - ")", - 3, NULL); - return GNUNET_OK; -#undef PREPARE -} - - -/** - * Close thread-local database connection when a thread is destroyed. - * - * @param closure we get from pthreads (the db handle) - */ -static void -db_conn_destroy (void *cls) -{ - PGconn *db_conn = cls; - - if (NULL != db_conn) - PQfinish (db_conn); -} - - -/** - * Initialize database subsystem. - * - * @param connection_cfg configuration to use to talk to DB - * @return #GNUNET_OK on success - */ -int -TALER_MINT_DB_init (const char *connection_cfg) -{ - if (0 != pthread_key_create (&db_conn_threadlocal, - &db_conn_destroy)) - { - LOG_ERROR ("Cannnot create pthread key.\n"); - return GNUNET_SYSERR; - } - TALER_MINT_db_connection_cfg_str = GNUNET_strdup (connection_cfg); - return GNUNET_OK; -} - - -/** - * 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 (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)) - { - LOG_ERROR ("Database connection failed: %s\n", - PQerrorMessage (db_conn)); - 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)) - { - GNUNET_break (0); - return NULL; - } - if (0 != pthread_setspecific (db_conn_threadlocal, - db_conn)) - { - GNUNET_break (0); - return NULL; - } - return db_conn; -} - - -/** - * Start a transaction. - * - * @param db_conn the database connection - * @return #GNUNET_OK on success - */ -int -TALER_MINT_DB_transaction (PGconn *db_conn) -{ - PGresult *result; - - result = PQexec (db_conn, - "BEGIN"); - if (PGRES_COMMAND_OK != - PQresultStatus (result)) - { - LOG_ERROR ("Failed to start transaction: %s\n", - PQresultErrorMessage (result)); - GNUNET_break (0); - PQclear (result); - return GNUNET_SYSERR; - } - - PQclear (result); - return GNUNET_OK; -} - - -/** - * Roll back the current transaction of a database connection. - * - * @param db_conn the database connection - * @return #GNUNET_OK on success - */ -void -TALER_MINT_DB_rollback (PGconn *db_conn) -{ - PGresult *result; - - result = PQexec (db_conn, - "ROLLBACK"); - GNUNET_break (PGRES_COMMAND_OK == - PQresultStatus (result)); - PQclear (result); -} - - -/** - * Commit the current transaction of a database connection. - * - * @param db_conn the database connection - * @return #GNUNET_OK on success - */ -int -TALER_MINT_DB_commit (PGconn *db_conn) -{ - PGresult *result; - - result = PQexec (db_conn, - "COMMIT"); - if (PGRES_COMMAND_OK != - PQresultStatus (result)) - { - GNUNET_break (0); - PQclear (result); - return GNUNET_SYSERR; - } - - PQclear (result); - return GNUNET_OK; -} - - -/** - * Get the summary of a reserve. - * - * @param db the database connection handle - * @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 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_END - }; - - if (NULL == reserve->pub) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - result = TALER_DB_exec_prepared (db, - "get_reserve", - params); - if (PGRES_TUPLES_OK != PQresultStatus (result)) - { - QUERY_ERR (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", - "balance_currency", - &reserve->balance)); - reserve->expiry.abs_value_us = GNUNET_ntohll (expiration_date_nbo); - PQclear (result); - return GNUNET_OK; - - EXITIF_exit: - PQclear (result); - return GNUNET_SYSERR; -} - - -/** - * 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 - }; - TALER_amount_hton (&balance_nbo, - &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. - * - * @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; - - result = NULL; - 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; - } - TALER_amount_hton (&balance_nbo, - 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 (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_DB_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 != PQresultStatus(result)) - { - QUERY_ERR (result); - goto rollback; - } - } - if (NULL != result) - PQclear (result); - result = NULL; - /* create new incoming transaction */ - 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_SIZED (&balance_nbo.currency, - TALER_DB_CURRENCY_LEN), - 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 != PQresultStatus(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; - reserve->balance = *balance; - reserve->expiry = expiry; - return GNUNET_OK; - } - /* Update reserve */ - struct Reserve updated_reserve; - updated_reserve.pub = reserve->pub; - - if (GNUNET_OK != - TALER_amount_add (&updated_reserve.balance, - &reserve->balance, - balance)) - { - return GNUNET_SYSERR; - } - 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: - PQclear (result); - TALER_MINT_DB_rollback (db); - return GNUNET_SYSERR; -} - - -/** - * Locate the response for a /withdraw request under the - * key of the hash of the blinded message. - * - * @param db_conn database connection to use - * @param h_blind hash of the blinded message - * @param collectable corresponding collectable coin (blind signature) - * if a coin is found - * @return #GNUNET_SYSERR on internal error - * #GNUNET_NO if the collectable was not found - * #GNUNET_YES on success - */ -int -TALER_MINT_DB_get_collectable_blindcoin (PGconn *db_conn, - const struct GNUNET_HashCode *h_blind, - struct CollectableBlindcoin *collectable) -{ - PGresult *result; - struct TALER_DB_QueryParam params[] = { - TALER_DB_QUERY_PARAM_PTR (h_blind), - TALER_DB_QUERY_PARAM_END - }; - struct GNUNET_CRYPTO_rsa_PublicKey *denom_pub; - struct GNUNET_CRYPTO_rsa_Signature *denom_sig; - char *denom_pub_enc; - char *denom_sig_enc; - size_t denom_pub_enc_size; - size_t denom_sig_enc_size; - int ret; - - ret = GNUNET_SYSERR; - denom_pub = NULL; - denom_pub_enc = NULL; - denom_sig_enc = NULL; - result = TALER_DB_exec_prepared (db_conn, - "get_collectable_blindcoin", - params); - - if (PGRES_TUPLES_OK != PQresultStatus (result)) - { - QUERY_ERR (result); - goto cleanup; - } - if (0 == PQntuples (result)) - { - ret = GNUNET_NO; - goto cleanup; - } - struct TALER_DB_ResultSpec rs[] = { - TALER_DB_RESULT_SPEC_VAR("denom_pub", &denom_pub_enc, &denom_pub_enc_size), - TALER_DB_RESULT_SPEC_VAR("denom_sig", &denom_sig_enc, &denom_sig_enc_size), - TALER_DB_RESULT_SPEC("reserve_sig", &collectable->reserve_sig), - TALER_DB_RESULT_SPEC("reserve_pub", &collectable->reserve_pub), - TALER_DB_RESULT_SPEC_END - }; - - if (GNUNET_OK != TALER_DB_extract_result (result, rs, 0)) - { - GNUNET_break (0); - goto cleanup; - } - denom_pub = GNUNET_CRYPTO_rsa_public_key_decode (denom_pub_enc, - denom_pub_enc_size); - denom_sig = GNUNET_CRYPTO_rsa_signature_decode (denom_sig_enc, - denom_sig_enc_size); - if ((NULL == denom_pub) || (NULL == denom_sig)) - { - GNUNET_break (0); - goto cleanup; - } - collectable->denom_pub = denom_pub; - collectable->sig = denom_sig; - ret = GNUNET_YES; - - cleanup: - PQclear (result); - GNUNET_free_non_null (denom_pub_enc); - GNUNET_free_non_null (denom_sig_enc); - if (GNUNET_YES != ret) - { if (NULL != denom_pub) - GNUNET_CRYPTO_rsa_public_key_free (denom_pub); - if (NULL != denom_sig) - GNUNET_CRYPTO_rsa_signature_free (denom_sig); - } - return ret; -} - - -/** - * Store collectable bit coin under the corresponding - * hash of the blinded message. - * - * @param db_conn database connection to use - * @param h_blind hash of the blinded message - * @param withdraw amount by which the reserve will be withdrawn with this - * transaction - * @param collectable corresponding collectable coin (blind signature) - * if a coin is found - * @return #GNUNET_SYSERR on internal error - * #GNUNET_NO if the collectable was not found - * #GNUNET_YES on success - */ -int -TALER_MINT_DB_insert_collectable_blindcoin (PGconn *db_conn, - const struct GNUNET_HashCode *h_blind, - struct TALER_Amount withdraw, - const struct CollectableBlindcoin *collectable) -{ - PGresult *result; - struct Reserve reserve; - char *denom_pub_enc = NULL; - char *denom_sig_enc = NULL; - size_t denom_pub_enc_size; - size_t denom_sig_enc_size; - int ret; - - ret = GNUNET_SYSERR; - denom_pub_enc_size = - GNUNET_CRYPTO_rsa_public_key_encode (collectable->denom_pub, - &denom_pub_enc); - denom_sig_enc_size = - GNUNET_CRYPTO_rsa_signature_encode (collectable->sig, - &denom_sig_enc); - struct TALER_DB_QueryParam params[] = { - TALER_DB_QUERY_PARAM_PTR (h_blind), - TALER_DB_QUERY_PARAM_PTR_SIZED (denom_pub_enc, denom_pub_enc_size - 1), - TALER_DB_QUERY_PARAM_PTR_SIZED (denom_sig_enc, denom_sig_enc_size - 1), /* DB doesn't like the trailing \0 */ - TALER_DB_QUERY_PARAM_PTR (&collectable->reserve_pub), - TALER_DB_QUERY_PARAM_PTR (&collectable->reserve_sig), - TALER_DB_QUERY_PARAM_END - }; - if (GNUNET_OK != TALER_MINT_DB_transaction (db_conn)) - goto cleanup; - result = TALER_DB_exec_prepared (db_conn, - "insert_collectable_blindcoin", - params); - if (PGRES_COMMAND_OK != PQresultStatus (result)) - { - QUERY_ERR (result); - goto rollback; - } - reserve.pub = (struct GNUNET_CRYPTO_EddsaPublicKey *) - &collectable->reserve_pub; - if (GNUNET_OK != TALER_MINT_DB_reserve_get (db_conn, - &reserve)) - goto rollback; - if (GNUNET_SYSERR == - TALER_amount_subtract (&reserve.balance, - &reserve.balance, - &withdraw)) - goto rollback; - if (GNUNET_OK != reserves_update (db_conn, &reserve)) - goto rollback; - if (GNUNET_OK == TALER_MINT_DB_commit (db_conn)) - { - ret = GNUNET_OK; - goto cleanup; - } - - rollback: - TALER_MINT_DB_rollback(db_conn); - cleanup: - PQclear (result); - GNUNET_free_non_null (denom_pub_enc); - GNUNET_free_non_null (denom_sig_enc); - return ret; -} - - -/** - * Get all of the transaction history associated with the specified - * reserve. - * - * @param db_conn connection to use - * @param reserve_pub public key of the reserve - * @return known transaction history (NULL if reserve is unknown) - */ -struct ReserveHistory * -TALER_MINT_DB_get_reserve_history (PGconn *db_conn, - const struct GNUNET_CRYPTO_EddsaPublicKey *reserve_pub) -{ - PGresult *result; - struct ReserveHistory *rh; - struct ReserveHistory *rh_head; - int rows; - int ret; - - result = NULL; - rh = NULL; - rh_head = NULL; - ret = GNUNET_SYSERR; - { - struct BankTransfer *bt; - struct TALER_DB_QueryParam params[] = { - TALER_DB_QUERY_PARAM_PTR (reserve_pub), - TALER_DB_QUERY_PARAM_END - }; - - result = TALER_DB_exec_prepared (db_conn, - "get_reserves_in_transactions", - params); - if (PGRES_TUPLES_OK != PQresultStatus (result)) - { - QUERY_ERR (result); - goto cleanup; - } - if (0 == (rows = PQntuples (result))) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Asked to fetch history for an unknown reserve.\n"); - goto cleanup; - } - while (0 < rows) - { - bt = GNUNET_new (struct BankTransfer); - if (GNUNET_OK != TALER_DB_extract_amount (result, - --rows, - "balance_value", - "balance_fraction", - "balance_currency", - &bt->amount)) - { - GNUNET_free (bt); - GNUNET_break (0); - goto cleanup; - } - (void) memcpy (&bt->reserve_pub, reserve_pub, sizeof (bt->reserve_pub)); - if (NULL != rh_head) - { - rh_head->next = GNUNET_new (struct ReserveHistory); - rh_head = rh_head->next; - } - else - { - rh_head = GNUNET_new (struct ReserveHistory); - rh = rh_head; - } - rh_head->type = TALER_MINT_DB_RO_BANK_TO_MINT; - rh_head->details.bank = bt; - } - } - PQclear (result); - result = NULL; - { - struct GNUNET_HashCode blind_ev; - struct GNUNET_CRYPTO_EddsaSignature reserve_sig; - struct CollectableBlindcoin *cbc; - char *denom_pub_enc; - char *denom_sig_enc; - size_t denom_pub_enc_size; - size_t denom_sig_enc_size; - - struct TALER_DB_QueryParam params[] = { - TALER_DB_QUERY_PARAM_PTR (reserve_pub), - TALER_DB_QUERY_PARAM_END - }; - result = TALER_DB_exec_prepared (db_conn, - "get_reserves_blindcoins", - params); - if (PGRES_TUPLES_OK != PQresultStatus (result)) - { - QUERY_ERR (result); - goto cleanup; - } - if (0 == (rows = PQntuples (result))) - { - ret = GNUNET_OK; /* Its OK if there are no withdrawls yet */ - goto cleanup; - } - struct TALER_DB_ResultSpec rs[] = { - TALER_DB_RESULT_SPEC ("blind_ev", &blind_ev), - TALER_DB_RESULT_SPEC_VAR ("denom_pub", &denom_pub_enc, &denom_pub_enc_size), - TALER_DB_RESULT_SPEC_VAR ("denom_sig", &denom_sig_enc, &denom_sig_enc_size), - TALER_DB_RESULT_SPEC ("reserve_sig", &reserve_sig), - TALER_DB_RESULT_SPEC_END - }; - GNUNET_assert (NULL != rh); - GNUNET_assert (NULL != rh_head); - GNUNET_assert (NULL == rh_head->next); - while (0 < rows) - { - if (GNUNET_YES != TALER_DB_extract_result (result, rs, --rows)) - { - GNUNET_break (0); - goto cleanup; - } - cbc = GNUNET_new (struct CollectableBlindcoin); - cbc->sig = GNUNET_CRYPTO_rsa_signature_decode (denom_sig_enc, - denom_sig_enc_size); - GNUNET_free (denom_sig_enc); - denom_sig_enc = NULL; - cbc->denom_pub = GNUNET_CRYPTO_rsa_public_key_decode (denom_pub_enc, - denom_pub_enc_size); - GNUNET_free (denom_pub_enc); - denom_pub_enc = NULL; - if ((NULL == cbc->sig) || (NULL == cbc->denom_pub)) - { - if (NULL != cbc->sig) - GNUNET_CRYPTO_rsa_signature_free (cbc->sig); - if (NULL != cbc->denom_pub) - GNUNET_CRYPTO_rsa_public_key_free (cbc->denom_pub); - GNUNET_free (cbc); - GNUNET_break (0); - goto cleanup; - } - (void) memcpy (&cbc->h_coin_envelope, &blind_ev, sizeof (blind_ev)); - (void) memcpy (&cbc->reserve_pub, reserve_pub, sizeof (cbc->reserve_pub)); - (void) memcpy (&cbc->reserve_sig, &reserve_sig, sizeof (cbc->reserve_sig)); - rh_head->next = GNUNET_new (struct ReserveHistory); - rh_head = rh_head->next; - rh_head->type = TALER_MINT_DB_RO_WITHDRAW_COIN; - rh_head->details.withdraw = cbc; - } - } - ret = GNUNET_OK; - - cleanup: - if (NULL != result) - PQclear (result); - if (GNUNET_SYSERR == ret) - { - TALER_MINT_DB_free_reserve_history (rh); - rh = NULL; - } - return rh; -} - - -/** - * Free memory associated with the given reserve history. - * - * @param rh history to free. - */ -void -TALER_MINT_DB_free_reserve_history (struct ReserveHistory *rh) -{ - struct BankTransfer *bt; - struct CollectableBlindcoin *cbc; - struct ReserveHistory *backref; - - while (NULL != rh) - { - switch(rh->type) - { - case TALER_MINT_DB_RO_BANK_TO_MINT: - bt = rh->details.bank; - if (NULL != bt->wire) - json_decref ((json_t *) bt->wire); /* FIXME: avoid cast? */ - GNUNET_free (bt); - break; - case TALER_MINT_DB_RO_WITHDRAW_COIN: - cbc = rh->details.withdraw; - GNUNET_CRYPTO_rsa_signature_free (cbc->sig); - GNUNET_CRYPTO_rsa_public_key_free (cbc->denom_pub); - GNUNET_free (cbc); - break; - } - backref = rh; - rh = rh->next; - GNUNET_free (backref); - } -} - - -/** - * Check if we have the specified deposit already in the database. - * - * @param db_conn database connection - * @param deposit deposit to search for - * @return #GNUNET_YES if we know this operation, - * #GNUNET_NO if this deposit is unknown to us - */ -int -TALER_MINT_DB_have_deposit (PGconn *db_conn, - const struct Deposit *deposit) -{ - struct TALER_DB_QueryParam params[] = { - TALER_DB_QUERY_PARAM_PTR (&deposit->coin.coin_pub), - TALER_DB_QUERY_PARAM_PTR (&deposit->transaction_id), - TALER_DB_QUERY_PARAM_PTR (&deposit->merchant_pub), - TALER_DB_QUERY_PARAM_END - }; - PGresult *result; - int ret; - - ret = GNUNET_SYSERR; - result = TALER_DB_exec_prepared (db_conn, - "get_deposit", - params); - if (PGRES_TUPLES_OK != - PQresultStatus (result)) - { - BREAK_DB_ERR (result); - goto cleanup; - } - - if (0 == PQntuples (result)) - { - ret = GNUNET_NO; - goto cleanup; - } - ret = GNUNET_YES; - - cleanup: - PQclear (result); - return ret; -} - - -/** - * Insert information about deposited coin into the - * database. - * - * @param db_conn connection to the database - * @param deposit deposit information to store - * @return #GNUNET_OK on success, #GNUNET_SYSERR on error - */ -int -TALER_MINT_DB_insert_deposit (PGconn *db_conn, - const struct Deposit *deposit) -{ - char *denom_pub_enc; - char *denom_sig_enc; - char *json_wire_enc; - PGresult *result; - struct TALER_AmountNBO amount_nbo; - size_t denom_pub_enc_size; - size_t denom_sig_enc_size; - int ret; - - ret = GNUNET_SYSERR; - denom_pub_enc_size = - GNUNET_CRYPTO_rsa_public_key_encode (deposit->coin.denom_pub, - &denom_pub_enc); - denom_sig_enc_size = - GNUNET_CRYPTO_rsa_signature_encode (deposit->coin.denom_sig, - &denom_sig_enc); - json_wire_enc = json_dumps (deposit->wire, JSON_COMPACT); - TALER_amount_hton (&amount_nbo, - &deposit->amount); - struct TALER_DB_QueryParam params[]= { - TALER_DB_QUERY_PARAM_PTR (&deposit->coin.coin_pub), - TALER_DB_QUERY_PARAM_PTR_SIZED (denom_pub_enc, denom_pub_enc_size), - TALER_DB_QUERY_PARAM_PTR_SIZED (denom_sig_enc, denom_sig_enc_size), - TALER_DB_QUERY_PARAM_PTR (&deposit->transaction_id), - TALER_DB_QUERY_PARAM_PTR (&amount_nbo.value), - TALER_DB_QUERY_PARAM_PTR (&amount_nbo.fraction), - TALER_DB_QUERY_PARAM_PTR_SIZED (amount_nbo.currency, - TALER_CURRENCY_LEN - 1), - TALER_DB_QUERY_PARAM_PTR (&deposit->merchant_pub), - TALER_DB_QUERY_PARAM_PTR (&deposit->h_contract), - TALER_DB_QUERY_PARAM_PTR (&deposit->h_wire), - TALER_DB_QUERY_PARAM_PTR (&deposit->csig), - TALER_DB_QUERY_PARAM_PTR_SIZED (json_wire_enc, - strlen (json_wire_enc)), - TALER_DB_QUERY_PARAM_END - }; - result = TALER_DB_exec_prepared (db_conn, "insert_deposit", params); - if (PGRES_COMMAND_OK != PQresultStatus (result)) - { - BREAK_DB_ERR (result); - goto cleanup; - } - ret = GNUNET_OK; - - cleanup: - PQclear (result); - GNUNET_free_non_null (denom_pub_enc); - GNUNET_free_non_null (denom_sig_enc); - GNUNET_free_non_null (json_wire_enc); - return ret; -} - - -/** - * Lookup refresh session data under the given public key. - * - * @param db_conn database handle to use - * @param refresh_session_pub public key to use for the lookup - * @param session[OUT] where to store the result - * @return #GNUNET_YES on success, - * #GNUNET_NO if not found, - * #GNUNET_SYSERR on DB failure - */ -int -TALER_MINT_DB_get_refresh_session (PGconn *db_conn, - const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub, - struct RefreshSession *session) -{ - // FIXME: check logic! - int res; - struct TALER_DB_QueryParam params[] = { - TALER_DB_QUERY_PARAM_PTR(refresh_session_pub), - TALER_DB_QUERY_PARAM_END - }; - - PGresult *result = TALER_DB_exec_prepared (db_conn, "get_refresh_session", 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)) - return GNUNET_NO; - - GNUNET_assert (1 == PQntuples (result)); - - /* We're done if the caller is only interested in - * whether the session exists or not */ - - if (NULL == session) - return GNUNET_YES; - - memset (session, 0, sizeof (struct RefreshSession)); - - struct TALER_DB_ResultSpec rs[] = { - TALER_DB_RESULT_SPEC("num_oldcoins", &session->num_oldcoins), - TALER_DB_RESULT_SPEC("num_newcoins", &session->num_newcoins), - TALER_DB_RESULT_SPEC("kappa", &session->kappa), - TALER_DB_RESULT_SPEC("noreveal_index", &session->noreveal_index), - TALER_DB_RESULT_SPEC_END - }; - - res = TALER_DB_extract_result (result, rs, 0); - - if (GNUNET_OK != res) - { - GNUNET_break (0); - PQclear (result); - return GNUNET_SYSERR; - } - - session->num_oldcoins = ntohs (session->num_oldcoins); - session->num_newcoins = ntohs (session->num_newcoins); - session->kappa = ntohs (session->kappa); - session->noreveal_index = ntohs (session->noreveal_index); - - PQclear (result); - return GNUNET_YES; -} - - -/** - * Store new refresh session data under the given public key. - * - * @param db_conn database handle to use - * @param refresh_session_pub public key to use to locate the session - * @param session session data to store - * @return #GNUNET_YES on success, - * #GNUNET_SYSERR on DB failure - */ -int -TALER_MINT_DB_create_refresh_session (PGconn *db_conn, - const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub, - const struct RefreshSession *session) -{ - // FIXME: actually store session data! - uint16_t noreveal_index; - struct TALER_DB_QueryParam params[] = { - TALER_DB_QUERY_PARAM_PTR(session_pub), - TALER_DB_QUERY_PARAM_PTR(&noreveal_index), - TALER_DB_QUERY_PARAM_END - }; - - noreveal_index = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1<<15); - noreveal_index = htonl (noreveal_index); - - PGresult *result = TALER_DB_exec_prepared (db_conn, "insert_refresh_session", params); - - if (PGRES_COMMAND_OK != PQresultStatus (result)) - { - BREAK_DB_ERR (result); - PQclear (result); - return GNUNET_SYSERR; - } - - PQclear (result); - return GNUNET_OK; -} - - -/** - * Store the given /refresh/melt request in the database. - * - * @param db_conn database connection - * @param session session key of the melt operation - * @param oldcoin_index index of the coin to store - * @param melt melt operation - * @return #GNUNET_OK on success - * #GNUNET_SYSERR on internal error - */ -int -TALER_MINT_DB_insert_refresh_melt (PGconn *db_conn, - const struct GNUNET_CRYPTO_EddsaPublicKey *session, - uint16_t oldcoin_index, - const struct RefreshMelt *melt) -{ - // FIXME: check logic! - uint16_t oldcoin_index_nbo = htons (oldcoin_index); - char *buf; - size_t buf_size; - PGresult *result; - - buf_size = GNUNET_CRYPTO_rsa_public_key_encode (melt->coin.denom_pub, - &buf); - { - struct TALER_DB_QueryParam params[] = { - TALER_DB_QUERY_PARAM_PTR(session), - TALER_DB_QUERY_PARAM_PTR(&oldcoin_index_nbo), - TALER_DB_QUERY_PARAM_PTR(&melt->coin.coin_pub), - TALER_DB_QUERY_PARAM_PTR_SIZED(buf, buf_size), - TALER_DB_QUERY_PARAM_END - }; - result = TALER_DB_exec_prepared (db_conn, "insert_refresh_melt", params); - } - GNUNET_free (buf); - if (PGRES_COMMAND_OK != PQresultStatus (result)) - { - BREAK_DB_ERR (result); - PQclear (result); - return GNUNET_SYSERR; - } - PQclear (result); - return GNUNET_OK; -} - - -/** - * Get information about melted coin details from the database. - * - * @param db_conn database connection - * @param session session key of the melt operation - * @param oldcoin_index index of the coin to retrieve - * @param melt melt data to fill in - * @return #GNUNET_OK on success - * #GNUNET_SYSERR on internal error - */ -int -TALER_MINT_DB_get_refresh_melt (PGconn *db_conn, - const struct GNUNET_CRYPTO_EddsaPublicKey *session, - uint16_t oldcoin_index, - struct RefreshMelt *melt) -{ - // FIXME: check logic! - GNUNET_break (0); - return GNUNET_SYSERR; -} - - -/** - * Store in the database which coin(s) we want to create - * in a given refresh operation. - * - * @param db_conn database connection - * @param session_pub refresh session key - * @param newcoin_index index of the coin to generate - * @param denom_pub denomination of the coin to create - * @return #GNUNET_OK on success - * #GNUNET_SYSERR on internal error - */ -int -TALER_MINT_DB_insert_refresh_order (PGconn *db_conn, - const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub, - uint16_t newcoin_index, - const struct GNUNET_CRYPTO_rsa_PublicKey *denom_pub) -{ - // FIXME: check logic - uint16_t newcoin_index_nbo = htons (newcoin_index); - char *buf; - size_t buf_size; - PGresult *result; - - buf_size = GNUNET_CRYPTO_rsa_public_key_encode (denom_pub, - &buf); - - { - struct TALER_DB_QueryParam params[] = { - TALER_DB_QUERY_PARAM_PTR (&newcoin_index_nbo), - TALER_DB_QUERY_PARAM_PTR (session_pub), - TALER_DB_QUERY_PARAM_PTR_SIZED (buf, buf_size), - TALER_DB_QUERY_PARAM_END - }; - result = TALER_DB_exec_prepared (db_conn, - "insert_refresh_order", - params); - } - GNUNET_free (buf); - if (PGRES_COMMAND_OK != PQresultStatus (result)) - { - BREAK_DB_ERR (result); - PQclear (result); - return GNUNET_SYSERR; - } - if (0 != strcmp ("1", PQcmdTuples (result))) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - PQclear (result); - return GNUNET_OK; -} - - -/** - * Lookup in the database the @a newcoin_index coin that we want to - * create in the given refresh operation. - * - * @param db_conn database connection - * @param session_pub refresh session key - * @param newcoin_index index of the coin to generate - * @param denom_pub denomination of the coin to create - * @return NULL on error (not found or internal error) - */ -struct GNUNET_CRYPTO_rsa_PublicKey * -TALER_MINT_DB_get_refresh_order (PGconn *db_conn, - const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub, - uint16_t newcoin_index) -{ - // FIXME: check logic - char *buf; - size_t buf_size; - struct GNUNET_CRYPTO_rsa_PublicKey *denom_pub; - uint16_t newcoin_index_nbo = htons (newcoin_index); - - struct TALER_DB_QueryParam params[] = { - TALER_DB_QUERY_PARAM_PTR(session_pub), - TALER_DB_QUERY_PARAM_PTR(&newcoin_index_nbo), - TALER_DB_QUERY_PARAM_END - }; - - PGresult *result = TALER_DB_exec_prepared (db_conn, "get_refresh_order", params); - - if (PGRES_TUPLES_OK != PQresultStatus (result)) - { - BREAK_DB_ERR (result); - PQclear (result); - return NULL; - } - - if (0 == PQntuples (result)) - { - PQclear (result); - /* FIXME: may want to distinguish between different error cases! */ - return NULL; - } - GNUNET_assert (1 == PQntuples (result)); - struct TALER_DB_ResultSpec rs[] = { - TALER_DB_RESULT_SPEC_VAR ("denom_pub", &buf, &buf_size), - TALER_DB_RESULT_SPEC_END - }; - if (GNUNET_OK != TALER_DB_extract_result (result, rs, 0)) - { - PQclear (result); - GNUNET_break (0); - return NULL; - } - PQclear (result); - denom_pub = GNUNET_CRYPTO_rsa_public_key_decode (buf, buf_size); - GNUNET_free (buf); - return denom_pub; -} - - - -/** - * Store information about the commitment of the - * given coin for the given refresh session in the database. - * - * @param db_conn database connection to use - * @param refresh_session_pub refresh session this commitment belongs to - * @param i set index (1st dimension) - * @param j coin index (2nd dimension), corresponds to refreshed (new) coins - * @param commit_coin coin commitment to store - * @return #GNUNET_OK on success - * #GNUNET_SYSERR on error - */ -int -TALER_MINT_DB_insert_refresh_commit_coin (PGconn *db_conn, - const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub, - unsigned int i, - unsigned int j, - const struct RefreshCommitCoin *commit_coin) -{ - // FIXME: check logic! - uint16_t cnc_index_nbo = htons (i); - uint16_t newcoin_index_nbo = htons (j); - struct TALER_DB_QueryParam params[] = { - TALER_DB_QUERY_PARAM_PTR(refresh_session_pub), - TALER_DB_QUERY_PARAM_PTR_SIZED(commit_coin->coin_ev, commit_coin->coin_ev_size), - TALER_DB_QUERY_PARAM_PTR(&cnc_index_nbo), - TALER_DB_QUERY_PARAM_PTR(&newcoin_index_nbo), - TALER_DB_QUERY_PARAM_PTR_SIZED(commit_coin->refresh_link->coin_priv_enc, - commit_coin->refresh_link->blinding_key_enc_size + - sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey)), - TALER_DB_QUERY_PARAM_END - }; - - PGresult *result = TALER_DB_exec_prepared (db_conn, "insert_refresh_commit_coin", params); - - if (PGRES_COMMAND_OK != PQresultStatus (result)) - { - BREAK_DB_ERR (result); - PQclear (result); - return GNUNET_SYSERR; - } - - if (0 != strcmp ("1", PQcmdTuples (result))) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - - PQclear (result); - return GNUNET_OK; -} - - -/** - * Obtain information about the commitment of the - * given coin of the given refresh session from the database. - * - * @param db_conn database connection to use - * @param refresh_session_pub refresh session the commitment belongs to - * @param i set index (1st dimension) - * @param j coin index (2nd dimension), corresponds to refreshed (new) coins - * @param commit_coin[OUT] coin commitment to return - * @return #GNUNET_OK on success - * #GNUNET_NO if not found - * #GNUNET_SYSERR on error - */ -int -TALER_MINT_DB_get_refresh_commit_coin (PGconn *db_conn, - const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub, - unsigned int cnc_index, - unsigned int newcoin_index, - struct RefreshCommitCoin *cc) -{ - // FIXME: check logic! - uint16_t cnc_index_nbo = htons (cnc_index); - uint16_t newcoin_index_nbo = htons (newcoin_index); - struct TALER_DB_QueryParam params[] = { - TALER_DB_QUERY_PARAM_PTR(refresh_session_pub), - TALER_DB_QUERY_PARAM_PTR(&cnc_index_nbo), - TALER_DB_QUERY_PARAM_PTR(&newcoin_index_nbo), - TALER_DB_QUERY_PARAM_END - }; - char *c_buf; - size_t c_buf_size; - char *rl_buf; - size_t rl_buf_size; - struct TALER_RefreshLinkEncrypted *rl; - - PGresult *result = TALER_DB_exec_prepared (db_conn, "get_refresh_commit_coin", params); - - if (PGRES_TUPLES_OK != PQresultStatus (result)) - { - BREAK_DB_ERR (result); - PQclear (result); - return GNUNET_SYSERR; - } - - if (0 == PQntuples (result)) - { - PQclear (result); - return GNUNET_NO; - } - - struct TALER_DB_ResultSpec rs[] = { - TALER_DB_RESULT_SPEC_VAR("coin_ev", &c_buf, &c_buf_size), - TALER_DB_RESULT_SPEC_VAR("link_vector_enc", &rl_buf, &rl_buf_size), - TALER_DB_RESULT_SPEC_END - }; - if (GNUNET_YES != TALER_DB_extract_result (result, rs, 0)) - { - PQclear (result); - return GNUNET_SYSERR; - } - PQclear (result); - if (rl_buf_size < sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey)) - { - GNUNET_free (c_buf); - GNUNET_free (rl_buf); - return GNUNET_SYSERR; - } - rl = TALER_refresh_link_encrypted_decode (rl_buf, - rl_buf_size); - GNUNET_free (rl_buf); - cc->refresh_link = rl; - cc->coin_ev = c_buf; - cc->coin_ev_size = c_buf_size; - return GNUNET_YES; -} - - -/** - * Store the commitment to the given (encrypted) refresh link data - * for the given refresh session. - * - * @param db_conn database connection to use - * @param refresh_session_pub public key of the refresh session this - * commitment belongs with - * @param i set index (1st dimension) - * @param j coin index (2nd dimension), corresponds to melted (old) coins - * @param commit_link link information to store - * @return #GNUNET_SYSERR on internal error, #GNUNET_OK on success - */ -int -TALER_MINT_DB_insert_refresh_commit_link (PGconn *db_conn, - const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub, - unsigned int i, - unsigned int j, - const struct RefreshCommitLink *commit_link) -{ - // FIXME: check logic! - uint16_t cnc_index_nbo = htons (i); - uint16_t oldcoin_index_nbo = htons (j); - struct TALER_DB_QueryParam params[] = { - TALER_DB_QUERY_PARAM_PTR(refresh_session_pub), - TALER_DB_QUERY_PARAM_PTR(&commit_link->transfer_pub), - TALER_DB_QUERY_PARAM_PTR(&cnc_index_nbo), - TALER_DB_QUERY_PARAM_PTR(&oldcoin_index_nbo), - TALER_DB_QUERY_PARAM_PTR(&commit_link->shared_secret_enc), - TALER_DB_QUERY_PARAM_END - }; - - PGresult *result = TALER_DB_exec_prepared (db_conn, - "insert_refresh_commit_link", - params); - if (PGRES_COMMAND_OK != PQresultStatus (result)) - { - BREAK_DB_ERR (result); - PQclear (result); - return GNUNET_SYSERR; - } - - if (0 != strcmp ("1", PQcmdTuples (result))) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - - PQclear (result); - return GNUNET_OK; -} - - -/** - * Obtain the commited (encrypted) refresh link data - * for the given refresh session. - * - * @param db_conn database connection to use - * @param refresh_session_pub public key of the refresh session this - * commitment belongs with - * @param i set index (1st dimension) - * @param j coin index (2nd dimension), corresponds to melted (old) coins - * @param cc[OUT] link information to return - * @return #GNUNET_SYSERR on internal error, - * #GNUNET_NO if commitment was not found - * #GNUNET_OK on success - */ -int -TALER_MINT_DB_get_refresh_commit_link (PGconn *db_conn, - const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub, - unsigned int cnc_index, - unsigned int oldcoin_index, - struct RefreshCommitLink *cc) -{ - // FIXME: check logic! - uint16_t cnc_index_nbo = htons (cnc_index); - uint16_t oldcoin_index_nbo = htons (oldcoin_index); - - struct TALER_DB_QueryParam params[] = { - TALER_DB_QUERY_PARAM_PTR(refresh_session_pub), - TALER_DB_QUERY_PARAM_PTR(&cnc_index_nbo), - TALER_DB_QUERY_PARAM_PTR(&oldcoin_index_nbo), - TALER_DB_QUERY_PARAM_END - }; - - PGresult *result = TALER_DB_exec_prepared (db_conn, - "get_refresh_commit_link", - params); - if (PGRES_TUPLES_OK != PQresultStatus (result)) - { - BREAK_DB_ERR (result); - PQclear (result); - return GNUNET_SYSERR; - } - - if (0 == PQntuples (result)) - { - PQclear (result); - return GNUNET_NO; - } - - struct TALER_DB_ResultSpec rs[] = { - TALER_DB_RESULT_SPEC("transfer_pub", &cc->transfer_pub), - TALER_DB_RESULT_SPEC("link_secret_enc", &cc->shared_secret_enc), - TALER_DB_RESULT_SPEC_END - }; - - if (GNUNET_YES != TALER_DB_extract_result (result, rs, 0)) - { - PQclear (result); - GNUNET_free (cc); - return GNUNET_SYSERR; - } - - PQclear (result); - return GNUNET_OK; -} - - -/** - * Insert signature of a new coin generated during refresh into - * the database indexed by the refresh session and the index - * of the coin. This data is later used should an old coin - * be used to try to obtain the private keys during "/refresh/link". - * - * @param db_conn database connection - * @param session_pub refresh session - * @param newcoin_index coin index - * @param ev_sig coin signature - * @return #GNUNET_OK on success - */ -int -TALER_MINT_DB_insert_refresh_collectable (PGconn *db_conn, - const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub, - uint16_t newcoin_index, - const struct GNUNET_CRYPTO_rsa_Signature *ev_sig) -{ - // FIXME: check logic! - uint16_t newcoin_index_nbo = htons (newcoin_index); - char *buf; - size_t buf_size; - PGresult *result; - - buf_size = GNUNET_CRYPTO_rsa_signature_encode (ev_sig, - &buf); - { - struct TALER_DB_QueryParam params[] = { - TALER_DB_QUERY_PARAM_PTR(session_pub), - TALER_DB_QUERY_PARAM_PTR(&newcoin_index_nbo), - TALER_DB_QUERY_PARAM_PTR_SIZED(buf, buf_size), - TALER_DB_QUERY_PARAM_END - }; - result = TALER_DB_exec_prepared (db_conn, - "insert_refresh_collectable", - params); - } - GNUNET_free (buf); - if (PGRES_COMMAND_OK != PQresultStatus (result)) - { - BREAK_DB_ERR (result); - PQclear (result); - return GNUNET_SYSERR; - } - PQclear (result); - return GNUNET_OK; -} - - -/** - * Obtain the link data of a coin, that is the encrypted link - * information, the denomination keys and the signatures. - * - * @param db_conn database connection - * @param coin_pub public key to use to retrieve linkage data - * @return all known link data for the coin - */ -struct LinkDataList * -TALER_db_get_link (PGconn *db_conn, - const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub) -{ - // FIXME: check logic! - struct LinkDataList *ldl; - struct LinkDataList *pos; - struct TALER_DB_QueryParam params[] = { - TALER_DB_QUERY_PARAM_PTR(coin_pub), - TALER_DB_QUERY_PARAM_END - }; - PGresult *result = TALER_DB_exec_prepared (db_conn, "get_link", params); - - ldl = NULL; - if (PGRES_TUPLES_OK != PQresultStatus (result)) - { - BREAK_DB_ERR (result); - PQclear (result); - return NULL; - } - - if (0 == PQntuples (result)) - { - PQclear (result); - return NULL; - } - - - int i = 0; - - for (i = 0; i < PQntuples (result); i++) - { - struct TALER_RefreshLinkEncrypted *link_enc; - struct GNUNET_CRYPTO_rsa_PublicKey *denom_pub; - struct GNUNET_CRYPTO_rsa_Signature *sig; - char *ld_buf; - size_t ld_buf_size; - char *pk_buf; - size_t pk_buf_size; - char *sig_buf; - size_t sig_buf_size; - struct TALER_DB_ResultSpec rs[] = { - TALER_DB_RESULT_SPEC_VAR("link_vector_enc", &ld_buf, &ld_buf_size), - TALER_DB_RESULT_SPEC_VAR("denom_pub", &pk_buf, &pk_buf_size), - TALER_DB_RESULT_SPEC_VAR("ev_sig", &sig_buf, &sig_buf_size), - TALER_DB_RESULT_SPEC_END - }; - - if (GNUNET_OK != TALER_DB_extract_result (result, rs, i)) - { - PQclear (result); - GNUNET_break (0); - TALER_db_link_data_list_free (ldl); - return NULL; - } - if (ld_buf_size < sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey)) - { - PQclear (result); - GNUNET_free (pk_buf); - GNUNET_free (sig_buf); - GNUNET_free (ld_buf); - TALER_db_link_data_list_free (ldl); - return NULL; - } - // FIXME: use util API for this! - link_enc = GNUNET_malloc (sizeof (struct TALER_RefreshLinkEncrypted) + - ld_buf_size - sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey)); - link_enc->blinding_key_enc = (const char *) &link_enc[1]; - link_enc->blinding_key_enc_size = ld_buf_size - sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey); - memcpy (link_enc->coin_priv_enc, - ld_buf, - ld_buf_size); - - sig = GNUNET_CRYPTO_rsa_signature_decode (sig_buf, - sig_buf_size); - denom_pub = GNUNET_CRYPTO_rsa_public_key_decode (pk_buf, - pk_buf_size); - GNUNET_free (pk_buf); - GNUNET_free (sig_buf); - GNUNET_free (ld_buf); - if ( (NULL == sig) || - (NULL == denom_pub) ) - { - if (NULL != denom_pub) - GNUNET_CRYPTO_rsa_public_key_free (denom_pub); - if (NULL != sig) - GNUNET_CRYPTO_rsa_signature_free (sig); - GNUNET_free (link_enc); - GNUNET_break (0); - PQclear (result); - TALER_db_link_data_list_free (ldl); - return NULL; - } - pos = GNUNET_new (struct LinkDataList); - pos->next = ldl; - pos->link_data_enc = link_enc; - pos->denom_pub = denom_pub; - pos->ev_sig = sig; - ldl = pos; - } - return ldl; -} - - -/** - * Free memory of the link data list. - * - * @param ldl link data list to release - */ -void -TALER_db_link_data_list_free (struct LinkDataList *ldl) -{ - GNUNET_break (0); // FIXME -} - - -/** - * Obtain shared secret and transfer public key from the public key of - * the coin. This information and the link information returned by - * #TALER_db_get_link() enable the owner of an old coin to determine - * the private keys of the new coins after the melt. - * - * - * @param db_conn database connection - * @param coin_pub public key of the coin - * @param transfer_pub[OUT] public transfer key - * @param shared_secret_enc[OUT] set to shared secret - * @return #GNUNET_OK on success, - * #GNUNET_NO on failure (not found) - * #GNUNET_SYSERR on internal failure (database issue) - */ -int -TALER_db_get_transfer (PGconn *db_conn, - const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub, - struct GNUNET_CRYPTO_EcdsaPublicKey *transfer_pub, - struct TALER_EncryptedLinkSecret *shared_secret_enc) -{ - // FIXME: check logic! - struct TALER_DB_QueryParam params[] = { - TALER_DB_QUERY_PARAM_PTR(coin_pub), - TALER_DB_QUERY_PARAM_END - }; - - PGresult *result = TALER_DB_exec_prepared (db_conn, "get_transfer", params); - - if (PGRES_TUPLES_OK != PQresultStatus (result)) - { - BREAK_DB_ERR (result); - PQclear (result); - return GNUNET_SYSERR; - } - - if (0 == PQntuples (result)) - { - PQclear (result); - return GNUNET_NO; - } - - if (1 != PQntuples (result)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "got %d tuples for get_transfer\n", - PQntuples (result)); - GNUNET_break (0); - return GNUNET_SYSERR; - } - - struct TALER_DB_ResultSpec rs[] = { - TALER_DB_RESULT_SPEC("transfer_pub", transfer_pub), - TALER_DB_RESULT_SPEC("link_secret_enc", shared_secret_enc), - TALER_DB_RESULT_SPEC_END - }; - - if (GNUNET_OK != TALER_DB_extract_result (result, rs, 0)) - { - PQclear (result); - GNUNET_break (0); - return GNUNET_SYSERR; - } - - PQclear (result); - return GNUNET_OK; -} - - - - -/** - * Compile a list of all (historic) transactions performed - * with the given coin (/refresh/melt and /deposit operations). - * - * @param db_conn database connection - * @param coin_pub coin to investigate - * @return list of transactions, NULL if coin is fresh - */ -struct TALER_MINT_DB_TransactionList * -TALER_MINT_DB_get_coin_transactions (PGconn *db_conn, - const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub) -{ - // FIXME: check logic! - GNUNET_break (0); // FIXME: implement! - return NULL; -} - - -/** - * Free linked list of transactions. - * - * @param list list to free - */ -void -TALER_MINT_DB_free_coin_transaction_list (struct TALER_MINT_DB_TransactionList *list) -{ - // FIXME: check logic! - GNUNET_break (0); -} - - -/* end of mint_db.c */ |