exchange/src/mint/mint_db.c

2064 lines
59 KiB
C
Raw Normal View History

2015-01-08 18:37:20 +01:00
/*
This file is part of TALER
(C) 2014 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 Database access for the mint
* @author Florian Dold
*/
#include "platform.h"
#include "taler_db_lib.h"
#include "taler_signatures.h"
#include "taler-mint-httpd_responses.h"
2015-01-08 18:37:20 +01:00
#include "mint_db.h"
#include "mint.h"
#include <pthread.h>
/**
* Thread-local database connection.
* Contains a pointer to PGconn or NULL.
*/
static pthread_key_t db_conn_threadlocal;
/**
* 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)
/**
* 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
*/
2015-01-08 18:37:20 +01:00
int
TALER_MINT_DB_get_collectable_blindcoin (PGconn *db_conn,
const struct GNUNET_HashCode *h_blind,
2015-01-08 18:37:20 +01:00
struct CollectableBlindcoin *collectable)
{
PGresult *result;
struct TALER_DB_QueryParam params[] = {
TALER_DB_QUERY_PARAM_PTR (h_blind),
2015-01-08 18:37:20 +01:00
TALER_DB_QUERY_PARAM_END
};
char *sig_buf;
size_t sig_buf_size;
result = TALER_DB_exec_prepared (db_conn,
"get_collectable_blindcoins",
params);
2015-01-08 18:37:20 +01:00
if (PGRES_TUPLES_OK != PQresultStatus (result))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Query failed: %s\n",
PQresultErrorMessage (result));
2015-01-08 18:37:20 +01:00
PQclear (result);
return GNUNET_SYSERR;
}
if (0 == PQntuples (result))
{
PQclear (result);
return GNUNET_NO;
}
struct TALER_DB_ResultSpec rs[] = {
TALER_DB_RESULT_SPEC_VAR("blind_sig", &sig_buf, &sig_buf_size),
2015-01-08 18:37:20 +01:00
TALER_DB_RESULT_SPEC("denom_pub", &collectable->denom_pub),
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);
PQclear (result);
return GNUNET_SYSERR;
}
PQclear (result);
return GNUNET_OK;
}
/**
* 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 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
*/
2015-01-08 18:37:20 +01:00
int
TALER_MINT_DB_insert_collectable_blindcoin (PGconn *db_conn,
const struct GNUNET_HashCode *h_blind,
2015-01-08 18:37:20 +01:00
const struct CollectableBlindcoin *collectable)
{
PGresult *result;
char *sig_buf;
size_t sig_buf_size;
sig_buf_size = GNUNET_CRYPTO_rsa_signature_encode (collectable->sig,
&sig_buf);
{
struct TALER_DB_QueryParam params[] = {
TALER_DB_QUERY_PARAM_PTR (&h_blind),
TALER_DB_QUERY_PARAM_PTR_SIZED (sig_buf, sig_buf_size),
TALER_DB_QUERY_PARAM_PTR (&collectable->denom_pub),
TALER_DB_QUERY_PARAM_PTR (&collectable->reserve_pub),
TALER_DB_QUERY_PARAM_PTR (&collectable->reserve_sig),
TALER_DB_QUERY_PARAM_END
};
2015-01-08 18:37:20 +01:00
result = TALER_DB_exec_prepared (db_conn,
"insert_collectable_blindcoins",
params);
if (PGRES_COMMAND_OK != PQresultStatus (result))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Query failed: %s\n",
PQresultErrorMessage (result));
PQclear (result);
return GNUNET_SYSERR;
}
2015-01-08 18:37:20 +01:00
if (0 != strcmp ("1", PQcmdTuples (result)))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Insert failed (updated '%s' tupes instead of '1')\n",
PQcmdTuples (result));
PQclear (result);
return GNUNET_SYSERR;
}
2015-01-08 18:37:20 +01:00
PQclear (result);
}
return GNUNET_OK;
}
int
TALER_MINT_DB_get_reserve (PGconn *db_conn,
const struct GNUNET_CRYPTO_EddsaPublicKey *reserve_pub,
struct Reserve *reserve)
{
PGresult *result;
int res;
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_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;
}
reserve->reserve_pub = *reserve_pub;
struct TALER_DB_ResultSpec rs[] = {
TALER_DB_RESULT_SPEC("status_sig", &reserve->status_sig),
TALER_DB_RESULT_SPEC("status_sign_pub", &reserve->status_sign_pub),
TALER_DB_RESULT_SPEC_END
};
res = TALER_DB_extract_result (result, rs, 0);
if (GNUNET_SYSERR == res)
{
GNUNET_break (0);
PQclear (result);
return GNUNET_SYSERR;
}
{
int fnums[] = {
PQfnumber (result, "balance_value"),
PQfnumber (result, "balance_fraction"),
PQfnumber (result, "balance_currency"),
};
if (GNUNET_OK != TALER_TALER_DB_extract_amount_nbo (result, 0, fnums, &reserve->balance))
{
GNUNET_break (0);
PQclear (result);
return GNUNET_SYSERR;
}
}
/* FIXME: Add expiration?? */
PQclear (result);
return GNUNET_OK;
}
/* If fresh is GNUNET_YES, set some fields to NULL as they are not actually valid */
int
TALER_MINT_DB_update_reserve (PGconn *db_conn,
const struct Reserve *reserve,
int fresh)
{
PGresult *result;
uint64_t stamp_sec;
stamp_sec = GNUNET_ntohll (GNUNET_TIME_absolute_ntoh (reserve->expiration).abs_value_us / 1000000);
struct TALER_DB_QueryParam params[] = {
TALER_DB_QUERY_PARAM_PTR (&reserve->reserve_pub),
TALER_DB_QUERY_PARAM_PTR (&reserve->balance.value),
TALER_DB_QUERY_PARAM_PTR (&reserve->balance.fraction),
TALER_DB_QUERY_PARAM_PTR_SIZED (&reserve->balance.currency,
strlen (reserve->balance.currency)),
TALER_DB_QUERY_PARAM_PTR (&reserve->status_sig),
TALER_DB_QUERY_PARAM_PTR (&reserve->status_sign_pub),
TALER_DB_QUERY_PARAM_PTR (&stamp_sec),
TALER_DB_QUERY_PARAM_END
};
/* set some fields to NULL if they are not actually valid */
if (GNUNET_YES == fresh)
{
unsigned i;
for (i = 4; i <= 7; i += 1)
{
params[i].data = NULL;
params[i].size = 0;
}
}
result = TALER_DB_exec_prepared (db_conn, "update_reserve", params);
if (PGRES_COMMAND_OK != PQresultStatus (result))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Query failed: %s\n", PQresultErrorMessage (result));
PQclear (result);
return GNUNET_SYSERR;
}
if (0 != strcmp ("1", PQcmdTuples (result)))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Update failed (updated '%s' tupes instead of '1')\n",
PQcmdTuples (result));
return GNUNET_SYSERR;
}
PQclear (result);
return GNUNET_OK;
}
int
TALER_MINT_DB_prepare (PGconn *db_conn)
{
PGresult *result;
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 "
"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);
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 "
"WHERE reserve_pub=$1 ",
9, 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);
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? */
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);
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);
if (GNUNET_OK != TALER_MINT_DB_prepare_deposits (db_conn))
{
GNUNET_break (0);
return GNUNET_SYSERR;
}
return GNUNET_OK;
}
/**
* Roll back the current transaction of a database connection.
*
* @param db_conn the database connection
* @return GNUNET_OK on success
*/
int
TALER_MINT_DB_rollback (PGconn *db_conn)
{
PGresult *result;
result = PQexec(db_conn, "ROLLBACK");
if (PGRES_COMMAND_OK != PQresultStatus (result))
{
PQclear (result);
GNUNET_break (0);
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
*/
int
TALER_MINT_DB_commit (PGconn *db_conn)
{
PGresult *result;
result = PQexec(db_conn, "COMMIT");
if (PGRES_COMMAND_OK != PQresultStatus (result))
{
PQclear (result);
GNUNET_break (0);
return GNUNET_SYSERR;
}
PQclear (result);
return GNUNET_OK;
}
/**
* 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))
{
2015-01-27 14:55:05 +01:00
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Can't start transaction: %s\n",
PQresultErrorMessage (result));
2015-01-08 18:37:20 +01:00
PQclear (result);
GNUNET_break (0);
return GNUNET_SYSERR;
}
PQclear (result);
return GNUNET_OK;
}
/**
* Insert a refresh order into the database.
*/
int
TALER_MINT_DB_insert_refresh_order (PGconn *db_conn,
uint16_t newcoin_index,
const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub,
const struct GNUNET_CRYPTO_rsa_PublicKey *denom_pub)
2015-01-08 18:37:20 +01:00
{
uint16_t newcoin_index_nbo = htons (newcoin_index);
2015-01-27 14:55:05 +01:00
char *buf;
size_t buf_size;
PGresult *result;
2015-01-08 18:37:20 +01:00
2015-01-27 14:55:05 +01:00
buf_size = GNUNET_CRYPTO_rsa_public_key_encode (denom_pub,
&buf);
2015-01-08 18:37:20 +01:00
2015-01-27 14:55:05 +01:00
{
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);
2015-01-08 18:37:20 +01:00
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;
}
int
TALER_MINT_DB_get_refresh_session (PGconn *db_conn,
const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
struct RefreshSession *session)
{
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))
{
2015-01-27 14:55:05 +01:00
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Query failed: %s\n",
PQresultErrorMessage (result));
2015-01-08 18:37:20 +01:00
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));
session->session_pub = *refresh_session_pub;
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("reveal_ok", &session->reveal_ok),
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;
}
if (TALER_DB_field_isnull (result, 0, "session_commit_sig"))
session->has_commit_sig = GNUNET_NO;
else
session->has_commit_sig = GNUNET_YES;
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;
}
int
TALER_MINT_DB_get_known_coin (PGconn *db_conn,
const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub,
2015-01-08 18:37:20 +01:00
struct KnownCoin *known_coin)
{
int res;
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_known_coin", params);
if (PGRES_TUPLES_OK != PQresultStatus (result))
{
2015-01-27 14:55:05 +01:00
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Query failed: %s\n",
PQresultErrorMessage (result));
2015-01-08 18:37:20 +01:00
PQclear (result);
return GNUNET_SYSERR;
}
if (0 == PQntuples (result))
return GNUNET_NO;
GNUNET_assert (1 == PQntuples (result));
/* extract basic information about the known coin */
{
struct TALER_DB_ResultSpec rs[] = {
TALER_DB_RESULT_SPEC("coin_pub", &known_coin->public_info.coin_pub),
TALER_DB_RESULT_SPEC("denom_pub", &known_coin->public_info.denom_pub),
TALER_DB_RESULT_SPEC("denom_sig", &known_coin->public_info.denom_sig),
TALER_DB_RESULT_SPEC_END
};
if (GNUNET_OK != (res = TALER_DB_extract_result (result, rs, 0)))
{
GNUNET_break (0);
PQclear (result);
return GNUNET_SYSERR;
}
}
/* extract the expended amount of the coin */
2015-01-27 14:55:05 +01:00
if (GNUNET_OK !=
TALER_DB_extract_amount (result,
0,
"expended_value",
"expended_fraction",
"expended_currency",
&known_coin->expended_balance))
2015-01-08 18:37:20 +01:00
{
GNUNET_break (0);
PQclear (result);
return GNUNET_SYSERR;
}
/* extract the refresh session of the coin or mark it as missing */
{
struct TALER_DB_ResultSpec rs[] = {
TALER_DB_RESULT_SPEC("refresh_session_pub", &known_coin->refresh_session_pub),
TALER_DB_RESULT_SPEC_END
};
if (GNUNET_SYSERR == (res = TALER_DB_extract_result (result, rs, 0)))
{
GNUNET_break (0);
PQclear (result);
return GNUNET_SYSERR;
}
if (GNUNET_NO == res)
{
known_coin->is_refreshed = GNUNET_NO;
2015-01-27 14:55:05 +01:00
memset (&known_coin->refresh_session_pub,
0,
sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
2015-01-08 18:37:20 +01:00
}
else
{
known_coin->is_refreshed = GNUNET_YES;
}
}
PQclear (result);
return GNUNET_YES;
}
int
TALER_MINT_DB_create_refresh_session (PGconn *db_conn,
const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub)
{
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;
}
int
TALER_MINT_DB_set_commit_signature (PGconn *db_conn,
const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub,
const struct GNUNET_CRYPTO_EddsaSignature *commit_sig)
{
GNUNET_break (0);
return GNUNET_SYSERR;
}
int
TALER_MINT_DB_set_reveal_ok (PGconn *db_conn,
const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub)
{
struct TALER_DB_QueryParam params[] = {
TALER_DB_QUERY_PARAM_PTR(session_pub),
TALER_DB_QUERY_PARAM_END
};
PGresult *result = TALER_DB_exec_prepared (db_conn, "set_reveal_ok", 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;
}
int
TALER_MINT_DB_update_known_coin (PGconn *db_conn,
const struct KnownCoin *known_coin)
{
struct TALER_AmountNBO expended_nbo = TALER_amount_hton (known_coin->expended_balance);
struct TALER_DB_QueryParam params[] = {
TALER_DB_QUERY_PARAM_PTR(&known_coin->public_info.coin_pub),
TALER_DB_QUERY_PARAM_PTR(&known_coin->public_info.denom_pub),
TALER_DB_QUERY_PARAM_PTR(&known_coin->public_info.denom_sig),
TALER_DB_QUERY_PARAM_PTR(&expended_nbo.value),
TALER_DB_QUERY_PARAM_PTR(&expended_nbo.fraction),
TALER_DB_QUERY_PARAM_PTR_SIZED(expended_nbo.currency, strlen (expended_nbo.currency)),
TALER_DB_QUERY_PARAM_PTR(&known_coin->refresh_session_pub),
TALER_DB_QUERY_PARAM_END
};
if (GNUNET_NO == known_coin->is_refreshed)
{
// Mind the magic index!
params[6].data = NULL;
params[6].size = 0;
}
PGresult *result = TALER_DB_exec_prepared (db_conn, "update_known_coin", params);
if (PGRES_COMMAND_OK != PQresultStatus (result))
{
break_db_err (result);
PQclear (result);
return GNUNET_SYSERR;
}
if (0 != strcmp ("1", PQcmdTuples (result)))
{
PQclear (result);
// return 'no' here (don't fail) so that we can
// insert if update fails (=> "upsert")
return GNUNET_NO;
}
PQclear (result);
return GNUNET_YES;
}
int
TALER_MINT_DB_insert_known_coin (PGconn *db_conn,
const struct KnownCoin *known_coin)
{
struct TALER_AmountNBO expended_nbo = TALER_amount_hton (known_coin->expended_balance);
struct TALER_DB_QueryParam params[] = {
TALER_DB_QUERY_PARAM_PTR(&known_coin->public_info.coin_pub),
TALER_DB_QUERY_PARAM_PTR(&known_coin->public_info.denom_pub),
TALER_DB_QUERY_PARAM_PTR(&known_coin->public_info.denom_sig),
TALER_DB_QUERY_PARAM_PTR(&expended_nbo.value),
TALER_DB_QUERY_PARAM_PTR(&expended_nbo.fraction),
TALER_DB_QUERY_PARAM_PTR_SIZED(&expended_nbo.currency, strlen (expended_nbo.currency)),
TALER_DB_QUERY_PARAM_PTR(&known_coin->refresh_session_pub),
TALER_DB_QUERY_PARAM_END
};
if (GNUNET_NO == known_coin->is_refreshed)
{
// Mind the magic index!
params[6].data = NULL;
params[6].size = 0;
}
PGresult *result = TALER_DB_exec_prepared (db_conn, "insert_known_coin", params);
if (PGRES_COMMAND_OK != PQresultStatus (result))
{
break_db_err (result);
PQclear (result);
return GNUNET_SYSERR;
}
if (0 != strcmp ("1", PQcmdTuples (result)))
{
PQclear (result);
// return 'no' here (don't fail) so that we can
// update if insert fails (=> "upsert")
return GNUNET_NO;
}
PQclear (result);
return GNUNET_YES;
}
int
2015-01-27 18:35:17 +01:00
TALER_MINT_DB_upsert_known_coin (PGconn *db_conn,
struct KnownCoin *known_coin)
2015-01-08 18:37:20 +01:00
{
int ret;
ret = TALER_MINT_DB_update_known_coin (db_conn, known_coin);
if (GNUNET_SYSERR == ret)
{
GNUNET_break (0);
return GNUNET_SYSERR;
}
if (GNUNET_YES == ret)
return GNUNET_YES;
return TALER_MINT_DB_insert_known_coin (db_conn, known_coin);
}
2015-01-27 18:35:17 +01:00
/**
* 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
* @param j
* @param commit_link link information to store
* @return #GNUNET_SYSERR on internal error, #GNUNET_OK on success
*/
2015-01-08 18:37:20 +01:00
int
TALER_MINT_DB_insert_refresh_commit_link (PGconn *db_conn,
2015-01-27 18:35:17 +01:00
const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
int i, int j,
const struct RefreshCommitLink *commit_link)
2015-01-08 18:37:20 +01:00
{
2015-01-27 18:35:17 +01:00
uint16_t cnc_index_nbo = htons (i);
uint16_t oldcoin_index_nbo = htons (j);
2015-01-08 18:37:20 +01:00
struct TALER_DB_QueryParam params[] = {
2015-01-27 18:35:17 +01:00
TALER_DB_QUERY_PARAM_PTR(refresh_session_pub),
2015-01-08 18:37:20 +01:00
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),
2015-01-27 18:49:02 +01:00
TALER_DB_QUERY_PARAM_PTR(&commit_link->shared_secret_enc),
2015-01-08 18:37:20 +01:00
TALER_DB_QUERY_PARAM_END
};
2015-01-27 18:35:17 +01:00
PGresult *result = TALER_DB_exec_prepared (db_conn,
"insert_refresh_commit_link",
params);
2015-01-08 18:37:20 +01:00
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;
}
int
TALER_MINT_DB_get_refresh_commit_link (PGconn *db_conn,
const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
2015-01-27 14:55:05 +01:00
int cnc_index,
int oldcoin_index,
2015-01-08 18:37:20 +01:00
struct RefreshCommitLink *cc)
{
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
};
2015-01-27 18:35:17 +01:00
PGresult *result = TALER_DB_exec_prepared (db_conn,
"get_refresh_commit_link",
params);
2015-01-08 18:37:20 +01:00
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),
2015-01-27 18:49:02 +01:00
TALER_DB_RESULT_SPEC("link_secret_enc", &cc->shared_secret_enc),
2015-01-08 18:37:20 +01:00
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);
2015-01-27 18:35:17 +01:00
return GNUNET_OK;
}
int
TALER_MINT_DB_insert_refresh_commit_coin (PGconn *db_conn,
const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
int i, int j,
const struct RefreshCommitCoin *commit_coin)
{
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;
2015-01-08 18:37:20 +01:00
}
int
TALER_MINT_DB_get_refresh_commit_coin (PGconn *db_conn,
const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
2015-01-27 14:55:05 +01:00
int cnc_index,
int newcoin_index,
2015-01-08 18:37:20 +01:00
struct RefreshCommitCoin *cc)
{
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
};
2015-01-27 18:35:17 +01:00
char *c_buf;
size_t c_buf_size;
char *rl_buf;
size_t rl_buf_size;
struct TALER_RefreshLinkEncrypted *rl;
2015-01-08 18:37:20 +01:00
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[] = {
2015-01-27 18:35:17 +01:00
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),
2015-01-08 18:37:20 +01:00
TALER_DB_RESULT_SPEC_END
};
if (GNUNET_YES != TALER_DB_extract_result (result, rs, 0))
{
PQclear (result);
return GNUNET_SYSERR;
}
PQclear (result);
2015-01-27 18:35:17 +01:00
if (rl_buf_size < sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey))
{
GNUNET_free (c_buf);
GNUNET_free (rl_buf);
return GNUNET_SYSERR;
}
rl = GNUNET_malloc (sizeof (struct TALER_RefreshLinkEncrypted) +
rl_buf_size - sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey));
rl->blinding_key_enc = (const char *) &rl[1];
rl->blinding_key_enc_size = rl_buf_size - sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey);
memcpy (rl->coin_priv_enc,
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;
2015-01-08 18:37:20 +01:00
return GNUNET_YES;
}
2015-01-27 14:55:05 +01:00
struct GNUNET_CRYPTO_rsa_PublicKey *
2015-01-08 18:37:20 +01:00
TALER_MINT_DB_get_refresh_order (PGconn *db_conn,
uint16_t newcoin_index,
2015-01-27 14:55:05 +01:00
const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub)
2015-01-08 18:37:20 +01:00
{
2015-01-27 14:55:05 +01:00
char *buf;
size_t buf_size;
struct GNUNET_CRYPTO_rsa_PublicKey *denom_pub;
2015-01-08 18:37:20 +01:00
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);
2015-01-27 14:55:05 +01:00
return NULL;
2015-01-08 18:37:20 +01:00
}
if (0 == PQntuples (result))
{
PQclear (result);
2015-01-27 14:55:05 +01:00
/* FIXME: may want to distinguish between different error cases! */
return NULL;
2015-01-08 18:37:20 +01:00
}
GNUNET_assert (1 == PQntuples (result));
struct TALER_DB_ResultSpec rs[] = {
2015-01-27 14:55:05 +01:00
TALER_DB_RESULT_SPEC_VAR ("denom_pub", &buf, &buf_size),
2015-01-08 18:37:20 +01:00
TALER_DB_RESULT_SPEC_END
};
if (GNUNET_OK != TALER_DB_extract_result (result, rs, 0))
{
PQclear (result);
GNUNET_break (0);
2015-01-27 14:55:05 +01:00
return NULL;
2015-01-08 18:37:20 +01:00
}
PQclear (result);
2015-01-27 14:55:05 +01:00
denom_pub = GNUNET_CRYPTO_rsa_public_key_decode (buf, buf_size);
GNUNET_free (buf);
return denom_pub;
2015-01-08 18:37:20 +01:00
}
int
TALER_MINT_DB_insert_refresh_collectable (PGconn *db_conn,
uint16_t newcoin_index,
const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub,
const struct GNUNET_CRYPTO_rsa_Signature *ev_sig)
2015-01-08 18:37:20 +01:00
{
uint16_t newcoin_index_nbo = htons (newcoin_index);
2015-01-27 14:55:05 +01:00
char *buf;
size_t buf_size;
PGresult *result;
2015-01-08 18:37:20 +01:00
2015-01-27 14:55:05 +01:00
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);
2015-01-08 18:37:20 +01:00
if (PGRES_COMMAND_OK != PQresultStatus (result))
{
break_db_err (result);
PQclear (result);
return GNUNET_SYSERR;
}
PQclear (result);
return GNUNET_OK;
}
2015-01-27 14:55:05 +01:00
struct GNUNET_CRYPTO_rsa_Signature *
2015-01-08 18:37:20 +01:00
TALER_MINT_DB_get_refresh_collectable (PGconn *db_conn,
uint16_t newcoin_index,
2015-01-27 14:55:05 +01:00
const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub)
2015-01-08 18:37:20 +01:00
{
2015-01-27 14:55:05 +01:00
struct GNUNET_CRYPTO_rsa_Signature *ev_sig;
char *buf;
size_t buf_size;
2015-01-08 18:37:20 +01:00
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_collectable", params);
if (PGRES_TUPLES_OK != PQresultStatus (result))
{
break_db_err (result);
PQclear (result);
2015-01-27 14:55:05 +01:00
return NULL;
2015-01-08 18:37:20 +01:00
}
if (0 == PQntuples (result))
{
PQclear (result);
2015-01-27 14:55:05 +01:00
/* FIXME: may want to distinguish between different error cases! */
return NULL;
2015-01-08 18:37:20 +01:00
}
GNUNET_assert (1 == PQntuples (result));
struct TALER_DB_ResultSpec rs[] = {
2015-01-27 14:55:05 +01:00
TALER_DB_RESULT_SPEC_VAR("ev_sig", &buf, &buf_size),
2015-01-08 18:37:20 +01:00
TALER_DB_RESULT_SPEC_END
};
if (GNUNET_OK != TALER_DB_extract_result (result, rs, 0))
{
PQclear (result);
GNUNET_break (0);
2015-01-27 14:55:05 +01:00
return NULL;
2015-01-08 18:37:20 +01:00
}
PQclear (result);
2015-01-27 14:55:05 +01:00
ev_sig = GNUNET_CRYPTO_rsa_signature_decode (buf,
buf_size);
GNUNET_free (buf);
return ev_sig;
2015-01-08 18:37:20 +01:00
}
int
TALER_MINT_DB_insert_refresh_melt (PGconn *db_conn,
const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub,
uint16_t oldcoin_index,
const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub,
const struct GNUNET_CRYPTO_rsa_PublicKey *denom_pub)
2015-01-08 18:37:20 +01:00
{
uint16_t oldcoin_index_nbo = htons (oldcoin_index);
2015-01-27 14:55:05 +01:00
char *buf;
size_t buf_size;
PGresult *result;
2015-01-08 18:37:20 +01:00
2015-01-27 14:55:05 +01:00
buf_size = GNUNET_CRYPTO_rsa_public_key_encode (denom_pub,
&buf);
{
struct TALER_DB_QueryParam params[] = {
TALER_DB_QUERY_PARAM_PTR(session_pub),
TALER_DB_QUERY_PARAM_PTR(&oldcoin_index_nbo),
TALER_DB_QUERY_PARAM_PTR(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);
2015-01-08 18:37:20 +01:00
if (PGRES_COMMAND_OK != PQresultStatus (result))
{
break_db_err (result);
PQclear (result);
return GNUNET_SYSERR;
}
PQclear (result);
return GNUNET_OK;
}
int
TALER_MINT_DB_get_refresh_melt (PGconn *db_conn,
const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub,
uint16_t oldcoin_index,
struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub)
{
uint16_t oldcoin_index_nbo = htons (oldcoin_index);
struct TALER_DB_QueryParam params[] = {
TALER_DB_QUERY_PARAM_PTR(session_pub),
TALER_DB_QUERY_PARAM_PTR(&oldcoin_index_nbo),
TALER_DB_QUERY_PARAM_END
};
PGresult *result = TALER_DB_exec_prepared (db_conn, "get_refresh_melt", 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;
}
GNUNET_assert (1 == PQntuples (result));
struct TALER_DB_ResultSpec rs[] = {
TALER_DB_RESULT_SPEC("coin_pub", coin_pub),
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;
}
int
TALER_db_get_link (PGconn *db_conn,
const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub,
LinkIterator link_iter,
void *cls)
{
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);
if (PGRES_TUPLES_OK != PQresultStatus (result))
{
break_db_err (result);
PQclear (result);
return GNUNET_SYSERR;
}
if (0 == PQntuples (result))
{
PQclear (result);
return GNUNET_NO;
}
int i = 0;
int res;
for (i = 0; i < PQntuples (result); i++)
{
2015-01-27 18:35:17 +01:00
struct TALER_RefreshLinkEncrypted *link_enc;
2015-01-27 14:55:05 +01:00
struct GNUNET_CRYPTO_rsa_PublicKey *denom_pub;
struct GNUNET_CRYPTO_rsa_Signature *sig;
2015-01-27 18:35:17 +01:00
char *ld_buf;
size_t ld_buf_size;
2015-01-27 14:55:05 +01:00
char *pk_buf;
size_t pk_buf_size;
char *sig_buf;
size_t sig_buf_size;
2015-01-08 18:37:20 +01:00
struct TALER_DB_ResultSpec rs[] = {
2015-01-27 18:35:17 +01:00
TALER_DB_RESULT_SPEC_VAR("link_vector_enc", &ld_buf, &ld_buf_size),
2015-01-27 14:55:05 +01:00
TALER_DB_RESULT_SPEC_VAR("denom_pub", &pk_buf, &pk_buf_size),
TALER_DB_RESULT_SPEC_VAR("ev_sig", &sig_buf, &sig_buf_size),
2015-01-08 18:37:20 +01:00
TALER_DB_RESULT_SPEC_END
};
if (GNUNET_OK != TALER_DB_extract_result (result, rs, i))
{
PQclear (result);
GNUNET_break (0);
return GNUNET_SYSERR;
}
2015-01-27 18:35:17 +01:00
if (ld_buf_size < sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey))
{
PQclear (result);
GNUNET_free (pk_buf);
GNUNET_free (sig_buf);
GNUNET_free (ld_buf);
GNUNET_break (0);
return GNUNET_SYSERR;
}
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);
2015-01-27 14:55:05 +01:00
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);
2015-01-27 18:35:17 +01:00
GNUNET_free (ld_buf);
2015-01-27 14:55:05 +01:00
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);
2015-01-27 18:35:17 +01:00
GNUNET_free (link_enc);
2015-01-27 14:55:05 +01:00
GNUNET_break (0);
2015-01-27 18:35:17 +01:00
PQclear (result);
2015-01-27 14:55:05 +01:00
return GNUNET_SYSERR;
}
if (GNUNET_OK != (res = link_iter (cls,
2015-01-27 18:35:17 +01:00
link_enc,
2015-01-27 14:55:05 +01:00
denom_pub,
sig)))
2015-01-08 18:37:20 +01:00
{
GNUNET_assert (GNUNET_SYSERR != res);
2015-01-27 14:55:05 +01:00
GNUNET_CRYPTO_rsa_signature_free (sig);
GNUNET_CRYPTO_rsa_public_key_free (denom_pub);
2015-01-27 18:35:17 +01:00
GNUNET_free (link_enc);
2015-01-08 18:37:20 +01:00
PQclear (result);
return res;
}
2015-01-27 14:55:05 +01:00
GNUNET_CRYPTO_rsa_signature_free (sig);
GNUNET_CRYPTO_rsa_public_key_free (denom_pub);
2015-01-27 18:35:17 +01:00
GNUNET_free (link_enc);
2015-01-08 18:37:20 +01:00
}
return GNUNET_OK;
}
int
TALER_db_get_transfer (PGconn *db_conn,
const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub,
struct GNUNET_CRYPTO_EcdsaPublicKey *transfer_pub,
2015-01-27 18:35:17 +01:00
struct GNUNET_HashCode *shared_secret_enc)
2015-01-08 18:37:20 +01:00
{
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))
{
2015-01-27 18:35:17 +01:00
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"got %d tuples for get_transfer\n",
PQntuples (result));
2015-01-08 18:37:20 +01:00
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;
}
int
TALER_MINT_DB_init_deposits (PGconn *conn, int tmp)
{
const char *tmp_str = (1 == tmp) ? "TEMPORARY" : "";
char *sql;
PGresult *res;
int ret;
res = NULL;
(void) GNUNET_asprintf (&sql,
"CREATE %1$s 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_value INT4 NOT NULL"
",amount_fraction INT4 NOT NULL"
",amount_currency VARCHAR(4) 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"
")",
tmp_str);
res = PQexec (conn, sql);
GNUNET_free (sql);
if (PGRES_COMMAND_OK != PQresultStatus (res))
{
break_db_err (res);
ret = GNUNET_SYSERR;
}
else
ret = GNUNET_OK;
PQclear (res);
return ret;
}
int
TALER_MINT_DB_prepare_deposits (PGconn *db_conn)
{
PGresult *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);
return GNUNET_OK;
EXITIF_exit:
break_db_err (result);
PQclear (result);
return GNUNET_SYSERR;
}
int
TALER_MINT_DB_insert_deposit (PGconn *db_conn,
const struct Deposit *deposit)
{
struct TALER_DB_QueryParam params[]= {
2015-01-27 23:06:23 +01:00
TALER_DB_QUERY_PARAM_PTR (&deposit->coin.coin_pub),
TALER_DB_QUERY_PARAM_PTR (&deposit->coin.denom_pub), // FIXME!
TALER_DB_QUERY_PARAM_PTR (&deposit->coin.denom_sig), // FIXME!
2015-01-08 18:37:20 +01:00
TALER_DB_QUERY_PARAM_PTR (&deposit->transaction_id),
2015-01-27 23:06:23 +01:00
TALER_DB_QUERY_PARAM_PTR (&deposit->purpose), // FIXME: enum Ok here?
2015-01-08 18:37:20 +01:00
TALER_DB_QUERY_PARAM_PTR (&deposit->amount.value),
TALER_DB_QUERY_PARAM_PTR (&deposit->amount.fraction),
2015-01-27 23:06:23 +01:00
TALER_DB_QUERY_PARAM_PTR_SIZED (deposit->amount.currency,
strlen (deposit->amount.currency)),
2015-01-08 18:37:20 +01:00
TALER_DB_QUERY_PARAM_PTR (&deposit->merchant_pub),
TALER_DB_QUERY_PARAM_PTR (&deposit->h_contract),
TALER_DB_QUERY_PARAM_PTR (&deposit->h_wire),
2015-01-27 23:06:23 +01:00
TALER_DB_QUERY_PARAM_PTR (&deposit->csig),
TALER_DB_QUERY_PARAM_PTR_SIZED (deposit->wire,
strlen ("FIXME")), // FIXME! json!
2015-01-08 18:37:20 +01:00
TALER_DB_QUERY_PARAM_END
};
PGresult *result;
result = TALER_DB_exec_prepared (db_conn, "insert_deposit", params);
if (PGRES_COMMAND_OK != PQresultStatus (result))
{
break_db_err (result);
PQclear (result);
return GNUNET_SYSERR;
}
PQclear (result);
return GNUNET_OK;
}
2015-01-27 14:55:05 +01:00
2015-01-08 18:37:20 +01:00
int
TALER_MINT_DB_get_deposit (PGconn *db_conn,
2015-01-27 23:06:23 +01:00
const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub,
struct Deposit *deposit)
2015-01-08 18:37:20 +01:00
{
struct TALER_DB_QueryParam params[] = {
TALER_DB_QUERY_PARAM_PTR (coin_pub),
TALER_DB_QUERY_PARAM_END
};
PGresult *result;
2015-01-27 23:06:23 +01:00
memset (deposit, 0, sizeof (struct Deposit));
result = TALER_DB_exec_prepared (db_conn,
"get_deposit",
params);
2015-01-08 18:37:20 +01:00
if (PGRES_TUPLES_OK != PQresultStatus (result))
{
break_db_err (result);
goto EXITIF_exit;
}
if (0 == PQntuples (result))
{
PQclear (result);
return GNUNET_NO;
}
if (1 != PQntuples (result))
{
GNUNET_break (0);
goto EXITIF_exit;
}
{
2015-01-27 23:06:23 +01:00
char *denom_sig_buf;
size_t denom_sig_buf_size;
2015-01-27 14:55:05 +01:00
char *dk_buf;
size_t dk_buf_size;
2015-01-27 23:06:23 +01:00
2015-01-08 18:37:20 +01:00
struct TALER_DB_ResultSpec rs[] = {
2015-01-27 23:06:23 +01:00
TALER_DB_RESULT_SPEC ("coin_pub", &deposit->coin.coin_pub),
2015-01-27 14:55:05 +01:00
TALER_DB_RESULT_SPEC_VAR ("denom_pub", &dk_buf, &dk_buf_size),
2015-01-27 23:06:23 +01:00
TALER_DB_RESULT_SPEC_VAR ("denom_sig", &denom_sig_buf, &denom_sig_buf_size),
2015-01-08 18:37:20 +01:00
TALER_DB_RESULT_SPEC ("transaction_id", &deposit->transaction_id),
TALER_DB_RESULT_SPEC ("merchant_pub", &deposit->merchant_pub),
TALER_DB_RESULT_SPEC ("h_contract", &deposit->h_contract),
TALER_DB_RESULT_SPEC ("h_wire", &deposit->h_wire),
2015-01-27 23:06:23 +01:00
TALER_DB_RESULT_SPEC ("purpose", &deposit->purpose),
// FIXME: many fields missing...
2015-01-08 18:37:20 +01:00
TALER_DB_RESULT_SPEC_END
};
2015-01-27 14:55:05 +01:00
EXITIF (GNUNET_OK !=
TALER_DB_extract_result (result, rs, 0));
EXITIF (GNUNET_OK !=
TALER_DB_extract_amount (result, 0,
"amount_value",
"amount_fraction",
"amount_currency",
&deposit->amount));
2015-01-27 23:06:23 +01:00
deposit->coin.denom_sig
= GNUNET_CRYPTO_rsa_signature_decode (denom_sig_buf,
denom_sig_buf_size);
deposit->coin.denom_pub
= GNUNET_CRYPTO_rsa_public_key_decode (dk_buf,
dk_buf_size);
2015-01-08 18:37:20 +01:00
}
PQclear (result);
return GNUNET_OK;
EXITIF_exit:
PQclear (result);
GNUNET_free_non_null (deposit);
deposit = NULL;
return GNUNET_SYSERR;
}
/**
* Get the thread-local database-handle.
* Connect to the db if the connection does not exist yet.
*
* @param the database connection, or NULL on error
*/
PGconn *
TALER_MINT_DB_get_connection (void)
{
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))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"db connection failed: %s\n",
PQerrorMessage (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;
}
/**
* 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
2015-01-28 14:57:55 +01:00
* @return #GNUNET_OK on success
2015-01-08 18:37:20 +01:00
*/
int
TALER_MINT_DB_init (const char *connection_cfg)
{
if (0 != pthread_key_create (&db_conn_threadlocal, &db_conn_destroy))
{
fprintf (stderr,
"Can't create pthread key.\n");
return GNUNET_SYSERR;
}
TALER_MINT_db_connection_cfg_str = GNUNET_strdup (connection_cfg);
return GNUNET_OK;
}
2015-01-28 14:57:55 +01:00
int
TALER_TALER_DB_extract_amount_nbo (PGresult *result,
unsigned int row,
int indices[3],
struct TALER_AmountNBO *denom_nbo)
{
if ((indices[0] < 0) || (indices[1] < 0) || (indices[2] < 0))
return GNUNET_NO;
if (sizeof (uint32_t) != PQgetlength (result, row, indices[0]))
return GNUNET_SYSERR;
if (sizeof (uint32_t) != PQgetlength (result, row, indices[1]))
return GNUNET_SYSERR;
if (PQgetlength (result, row, indices[2]) > TALER_CURRENCY_LEN)
return GNUNET_SYSERR;
denom_nbo->value = *(uint32_t *) PQgetvalue (result, row, indices[0]);
denom_nbo->fraction = *(uint32_t *) PQgetvalue (result, row, indices[1]);
memset (denom_nbo->currency, 0, TALER_CURRENCY_LEN);
memcpy (denom_nbo->currency, PQgetvalue (result, row, indices[2]), PQgetlength (result, row, indices[2]));
return GNUNET_OK;
}
int
TALER_TALER_DB_extract_amount (PGresult *result,
unsigned int row,
int indices[3],
struct TALER_Amount *denom)
{
struct TALER_AmountNBO denom_nbo;
int res;
res = TALER_TALER_DB_extract_amount_nbo (result, row, indices, &denom_nbo);
if (GNUNET_OK != res)
return res;
*denom = TALER_amount_ntoh (denom_nbo);
return GNUNET_OK;
}