diff options
-rw-r--r-- | src/mint/mint.h | 30 | ||||
-rw-r--r-- | src/mint/mint_db.c | 932 | ||||
-rw-r--r-- | src/mint/mint_db.h | 447 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_db.c | 79 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_deposit.c | 23 | ||||
-rw-r--r-- | src/mint/test_mint_deposits.c | 40 |
6 files changed, 892 insertions, 659 deletions
diff --git a/src/mint/mint.h b/src/mint/mint.h index b29162b20..1e1221157 100644 --- a/src/mint/mint.h +++ b/src/mint/mint.h @@ -35,36 +35,6 @@ -/** - * Information we keep for a withdrawn coin to reproduce - * the /withdraw operation if needed, and to have proof - * that a reserve was drained by this amount. - */ -struct CollectableBlindcoin -{ - - /** - * Our signature over the (blinded) coin. - */ - struct GNUNET_CRYPTO_rsa_Signature *sig; - - /** - * Denomination key (which coin was generated). - */ - struct GNUNET_CRYPTO_rsa_PublicKey *denom_pub; - - /** - * Public key of the reserve that was drained. - */ - struct GNUNET_CRYPTO_EddsaPublicKey reserve_pub; - - /** - * Signature confirming the withdrawl, matching @e reserve_pub, - * @e denom_pub and @e h_blind. - */ - struct GNUNET_CRYPTO_EddsaSignature reserve_sig; -}; - /** * Global information for a refreshing session. diff --git a/src/mint/mint_db.c b/src/mint/mint_db.c index 0f233a5ae..dcde03dc1 100644 --- a/src/mint/mint_db.c +++ b/src/mint/mint_db.c @@ -54,127 +54,49 @@ static char *TALER_MINT_db_connection_cfg_str; } 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 - */ -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 - }; - char *sig_buf; - size_t sig_buf_size; - result = TALER_DB_exec_prepared (db_conn, - "get_collectable_blindcoins", - params); - - if (PGRES_TUPLES_OK != PQresultStatus (result)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Query failed: %s\n", - PQresultErrorMessage (result)); - PQclear (result); - return GNUNET_SYSERR; - } - if (0 == PQntuples (result)) - { - PQclear (result); - return GNUNET_NO; - } - struct TALER_DB_ResultSpec rs[] = { - TALER_DB_RESULT_SPEC_VAR("blind_sig", &sig_buf, &sig_buf_size), - 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); +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; - } - PQclear (result); + 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; } -/** - * 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 - */ int -TALER_MINT_DB_insert_collectable_blindcoin (PGconn *db_conn, - const struct GNUNET_HashCode *h_blind, - const struct CollectableBlindcoin *collectable) +TALER_TALER_DB_extract_amount (PGresult *result, + unsigned int row, + int indices[3], + struct TALER_Amount *denom) { - 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 - }; - - 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; - } + struct TALER_AmountNBO denom_nbo; + int res; - 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; - } - PQclear (result); - } + 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; } + int TALER_MINT_DB_get_reserve (PGconn *db_conn, const struct GNUNET_CRYPTO_EddsaPublicKey *reserve_pub, @@ -681,88 +603,51 @@ TALER_MINT_DB_prepare (PGconn *db_conn) } 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; - } - + 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); - 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; - } + 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; -} + 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)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Can't start transaction: %s\n", - PQresultErrorMessage (result)); - PQclear (result); - GNUNET_break (0); - return GNUNET_SYSERR; - } - + EXITIF_exit: + break_db_err (result); PQclear (result); - return GNUNET_OK; + return GNUNET_SYSERR; } @@ -1495,91 +1380,6 @@ TALER_MINT_DB_get_refresh_collectable (PGconn *db_conn, } - -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) -{ - uint16_t oldcoin_index_nbo = htons (oldcoin_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(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); - 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, @@ -1744,319 +1544,491 @@ TALER_db_get_transfer (PGconn *db_conn, } + + + +// Chaos +//////////////////////////////////////////////////////////////// +// Order + + + + + + +/** + * 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_deposits (PGconn *conn, int tmp) +TALER_MINT_DB_init (const char *connection_cfg) { - const char *tmp_str = (1 == tmp) ? "TEMPORARY" : ""; - char *sql; - PGresult *res; - int ret; + 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; +} + + +/** + * Get the thread-local database-handle. + * Connect to the db if the connection does not exist yet. + * + * @return 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; + } - 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; + if (GNUNET_OK != TALER_MINT_DB_prepare (db_conn)) + { + GNUNET_break (0); + return NULL; } - else - ret = GNUNET_OK; - PQclear (res); - return ret; + 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_prepare_deposits (PGconn *db_conn) +TALER_MINT_DB_transaction (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 = PQexec(db_conn, "BEGIN"); + if (PGRES_COMMAND_OK != PQresultStatus (result)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Can't start transaction: %s\n", + PQresultErrorMessage (result)); + PQclear (result); + GNUNET_break (0); + return GNUNET_SYSERR; + } - 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; +} + + +/** + * 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; + } - EXITIF_exit: - break_db_err (result); PQclear (result); - return GNUNET_SYSERR; + return GNUNET_OK; } +/** + * Commit the current transaction of a database connection. + * + * @param db_conn the database connection + * @return #GNUNET_OK on success + */ int -TALER_MINT_DB_insert_deposit (PGconn *db_conn, - const struct Deposit *deposit) +TALER_MINT_DB_commit (PGconn *db_conn) { - struct TALER_DB_QueryParam params[]= { - 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! - TALER_DB_QUERY_PARAM_PTR (&deposit->transaction_id), - TALER_DB_QUERY_PARAM_PTR (&deposit->purpose), // FIXME: enum Ok here? - TALER_DB_QUERY_PARAM_PTR (&deposit->amount.value), - TALER_DB_QUERY_PARAM_PTR (&deposit->amount.fraction), - TALER_DB_QUERY_PARAM_PTR_SIZED (deposit->amount.currency, - strlen (deposit->amount.currency)), - 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 (deposit->wire, - strlen ("FIXME")), // FIXME! json! - TALER_DB_QUERY_PARAM_END - }; PGresult *result; - result = TALER_DB_exec_prepared (db_conn, "insert_deposit", params); + result = PQexec(db_conn, + "COMMIT"); if (PGRES_COMMAND_OK != PQresultStatus (result)) { - break_db_err (result); PQclear (result); + GNUNET_break (0); return GNUNET_SYSERR; } + PQclear (result); return GNUNET_OK; } +/** + * 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_deposit (PGconn *db_conn, - const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub, - struct Deposit *deposit) +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 (coin_pub), + TALER_DB_QUERY_PARAM_PTR (h_blind), TALER_DB_QUERY_PARAM_END }; - PGresult *result; + char *sig_buf; + size_t sig_buf_size; - memset (deposit, 0, sizeof (struct Deposit)); result = TALER_DB_exec_prepared (db_conn, - "get_deposit", + "get_collectable_blindcoins", params); + if (PGRES_TUPLES_OK != PQresultStatus (result)) { - break_db_err (result); - goto EXITIF_exit; + 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; } - if (1 != PQntuples (result)) - { - GNUNET_break (0); - goto EXITIF_exit; - } + struct TALER_DB_ResultSpec rs[] = { + TALER_DB_RESULT_SPEC_VAR("blind_sig", &sig_buf, &sig_buf_size), + 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)) { - char *denom_sig_buf; - size_t denom_sig_buf_size; - char *dk_buf; - size_t dk_buf_size; - - struct TALER_DB_ResultSpec rs[] = { - TALER_DB_RESULT_SPEC ("coin_pub", &deposit->coin.coin_pub), - TALER_DB_RESULT_SPEC_VAR ("denom_pub", &dk_buf, &dk_buf_size), - TALER_DB_RESULT_SPEC_VAR ("denom_sig", &denom_sig_buf, &denom_sig_buf_size), - 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), - TALER_DB_RESULT_SPEC ("purpose", &deposit->purpose), - // FIXME: many fields missing... - TALER_DB_RESULT_SPEC_END - }; - 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)); - 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); + GNUNET_break (0); + PQclear (result); + return GNUNET_SYSERR; } - 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. + * Store collectable bit coin under the corresponding + * hash of the blinded message. * - * @param the database connection, or NULL on error + * @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 */ -PGconn * -TALER_MINT_DB_get_connection (void) +int +TALER_MINT_DB_insert_collectable_blindcoin (PGconn *db_conn, + const struct GNUNET_HashCode *h_blind, + const struct CollectableBlindcoin *collectable) { - PGconn *db_conn; + PGresult *result; + char *sig_buf; + size_t sig_buf_size; - if (NULL != (db_conn = pthread_getspecific (db_conn_threadlocal))) - return db_conn; + 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 + }; - db_conn = PQconnectdb (TALER_MINT_db_connection_cfg_str); + 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; + } - 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 (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; + } + PQclear (result); } + return GNUNET_OK; +} - if (GNUNET_OK != TALER_MINT_DB_prepare (db_conn)) + +/** + * 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), // FIXME + TALER_DB_QUERY_PARAM_END + }; + PGresult *result; + + result = TALER_DB_exec_prepared (db_conn, + "get_deposit", + params); + if (PGRES_TUPLES_OK != + PQresultStatus (result)) { - GNUNET_break (0); - return NULL; + break_db_err (result); + PQclear (result); + return GNUNET_SYSERR; } - if (0 != pthread_setspecific (db_conn_threadlocal, db_conn)) + + if (0 == PQntuples (result)) { - GNUNET_break (0); - return NULL; + PQclear (result); + return GNUNET_NO; } - return db_conn; + return GNUNET_YES; } /** - * Close thread-local database connection when a thread is destroyed. + * Insert information about deposited coin into the + * database. * - * @param closure we get from pthreads (the db handle) + * @param db_conn connection to the database + * @param deposit deposit information to store + * @return #GNUNET_OK on success, #GNUNET_SYSERR on error */ -static void -db_conn_destroy (void *cls) +int +TALER_MINT_DB_insert_deposit (PGconn *db_conn, + const struct Deposit *deposit) { - PGconn *db_conn = cls; - if (NULL != db_conn) - PQfinish (db_conn); + struct TALER_DB_QueryParam params[]= { + 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! + TALER_DB_QUERY_PARAM_PTR (&deposit->transaction_id), + TALER_DB_QUERY_PARAM_PTR (&deposit->amount.value), + TALER_DB_QUERY_PARAM_PTR (&deposit->amount.fraction), + TALER_DB_QUERY_PARAM_PTR_SIZED (deposit->amount.currency, + strlen (deposit->amount.currency)), + 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 (deposit->wire, + strlen ("FIXME")), // FIXME! json! + 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; } /** - * Initialize database subsystem. + * Test if the given /refresh/melt request is known to us. * - * @param connection_cfg configuration to use to talk to DB - * @return #GNUNET_OK on success + * @param db_conn database connection + * @param melt melt operation + * @return #GNUNET_YES if known, + * #GNUENT_NO if not, + * #GNUNET_SYSERR on internal error */ int -TALER_MINT_DB_init (const char *connection_cfg) +TALER_MINT_DB_have_refresh_melt (PGconn *db_conn, + const struct RefreshMelt *melt) { + uint16_t oldcoin_index_nbo = htons (melt->oldcoin_index); + struct TALER_DB_QueryParam params[] = { + TALER_DB_QUERY_PARAM_PTR(&melt->session_pub), + TALER_DB_QUERY_PARAM_PTR(&oldcoin_index_nbo), + TALER_DB_QUERY_PARAM_END + }; - if (0 != pthread_key_create (&db_conn_threadlocal, &db_conn_destroy)) + PGresult *result = TALER_DB_exec_prepared (db_conn, + "get_refresh_melt", + params); + if (PGRES_TUPLES_OK != PQresultStatus (result)) { - fprintf (stderr, - "Can't create pthread key.\n"); + break_db_err (result); + PQclear (result); return GNUNET_SYSERR; } - TALER_MINT_db_connection_cfg_str = GNUNET_strdup (connection_cfg); - return GNUNET_OK; + + if (0 == PQntuples (result)) + { + PQclear (result); + return GNUNET_NO; + } + GNUNET_break (1 == PQntuples (result)); + PQclear (result); + return GNUNET_YES; } + +/** + * Store the given /refresh/melt request in the database. + * + * @param db_conn database connection + * @param melt melt operation + * @return #GNUNET_OK on success + * #GNUNET_SYSERR on internal error + */ int -TALER_TALER_DB_extract_amount_nbo (PGresult *result, - unsigned int row, - int indices[3], - struct TALER_AmountNBO *denom_nbo) +TALER_MINT_DB_insert_refresh_melt (PGconn *db_conn, + const struct RefreshMelt *melt) { - 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) + uint16_t oldcoin_index_nbo = htons (melt->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(&melt->session_pub), + 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; - 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])); + } + 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_TALER_DB_extract_amount (PGresult *result, - unsigned int row, - int indices[3], - struct TALER_Amount *denom) +TALER_MINT_DB_get_refresh_melt (PGconn *db_conn, + const struct GNUNET_CRYPTO_EddsaPublicKey *session, + uint16_t oldcoin_index, + struct RefreshMelt *melt) { - struct TALER_AmountNBO denom_nbo; - int res; + GNUNET_break (0); + return GNUNET_SYSERR; +} - 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; + +/** + * 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) +{ + GNUNET_break (0); // FIXME: implement! + return NULL; } + + +/* end of mint_db.c */ diff --git a/src/mint/mint_db.h b/src/mint/mint_db.h index b38b82b94..6e1fb4753 100644 --- a/src/mint/mint_db.h +++ b/src/mint/mint_db.h @@ -30,57 +30,12 @@ #include "mint.h" -int -TALER_MINT_DB_prepare (PGconn *db_conn); - /** - * 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 + * FIXME. */ int -TALER_MINT_DB_get_collectable_blindcoin (PGconn *db_conn, - const struct GNUNET_HashCode *h_blind, - struct CollectableBlindcoin *collectable); - - -/** - * 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 - */ -int -TALER_MINT_DB_insert_collectable_blindcoin (PGconn *db_conn, - const struct GNUNET_HashCode *h_blind, - const struct CollectableBlindcoin *collectable); - - -int -TALER_MINT_DB_rollback (PGconn *db_conn); - - -int -TALER_MINT_DB_transaction (PGconn *db_conn); - - -int -TALER_MINT_DB_commit (PGconn *db_conn); - +TALER_MINT_DB_prepare (PGconn *db_conn); /** @@ -151,6 +106,9 @@ TALER_MINT_DB_update_reserve (PGconn *db_conn, + + + int TALER_MINT_DB_insert_refresh_order (PGconn *db_conn, uint16_t newcoin_index, @@ -163,8 +121,6 @@ TALER_MINT_DB_get_refresh_session (PGconn *db_conn, struct RefreshSession *r_session); - - /** * FIXME */ @@ -201,10 +157,6 @@ TALER_MINT_DB_insert_known_coin (PGconn *db_conn, const struct KnownCoin *known_coin); - - - - int TALER_MINT_DB_create_refresh_session (PGconn *db_conn, const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub); @@ -276,19 +228,6 @@ TALER_MINT_DB_set_reveal_ok (PGconn *db_conn, const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub); -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); - - -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); /** @@ -320,13 +259,139 @@ TALER_db_get_transfer (PGconn *db_conn, struct GNUNET_CRYPTO_EcdsaPublicKey *transfer_pub, struct GNUNET_HashCode *shared_secret_enc); + int -TALER_MINT_DB_init_deposits (PGconn *db_conn, int temporary); +TALER_TALER_DB_extract_amount (PGresult *result, + unsigned int row, + int indices[3], + struct TALER_Amount *denom); + +int +TALER_TALER_DB_extract_amount_nbo (PGresult *result, + unsigned int row, + int indices[3], + struct TALER_AmountNBO *denom_nbo); + + + +// Chaos +//////////////////////////////////////////////////////////////// +// Order + + + +/** + * Initialize database subsystem. + */ +int +TALER_MINT_DB_init (const char *connection_cfg); + + +/** + * Get the thread-local database-handle. + * Connect to the db if the connection does not exist yet. + * + * @param the database connection, or NULL on error + */ +PGconn * +TALER_MINT_DB_get_connection (void); + + +/** + * Start a transaction. + * + * @return #GNUNET_OK on success + */ +int +TALER_MINT_DB_transaction (PGconn *db_conn); + + +/** + * Commit a transaction. + * + * @return #GNUNET_OK on success + */ +int +TALER_MINT_DB_commit (PGconn *db_conn); + + +/** + * Abort/rollback a transaction. + * + * @return #GNUNET_OK on success + */ int -TALER_MINT_DB_prepare_deposits (PGconn *db_conn); +TALER_MINT_DB_rollback (PGconn *db_conn); + + + +/** + * Information we keep for a withdrawn coin to reproduce + * the /withdraw operation if needed, and to have proof + * that a reserve was drained by this amount. + */ +struct CollectableBlindcoin +{ + + /** + * Our signature over the (blinded) coin. + */ + struct GNUNET_CRYPTO_rsa_Signature *sig; + + /** + * Denomination key (which coin was generated). + */ + struct GNUNET_CRYPTO_rsa_PublicKey *denom_pub; + + /** + * Public key of the reserve that was drained. + */ + struct GNUNET_CRYPTO_EddsaPublicKey reserve_pub; + /** + * Signature confirming the withdrawl, matching @e reserve_pub, + * @e denom_pub and @e h_blind. + */ + struct GNUNET_CRYPTO_EddsaSignature reserve_sig; +}; + + +/** + * 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); + + +/** + * 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 + */ +int +TALER_MINT_DB_insert_collectable_blindcoin (PGconn *db_conn, + const struct GNUNET_HashCode *h_blind, + const struct CollectableBlindcoin *collectable); /** @@ -384,59 +449,253 @@ struct Deposit */ struct TALER_Amount amount; - /** - * Type of the deposit (also purpose of the signature). Either - * #TALER_SIGNATURE_DEPOSIT or #TALER_SIGNATURE_INCREMENTAL_DEPOSIT. - */ - uint32_t purpose; // FIXME: bad type, use ENUM! +}; -}; +/** + * 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, + * #GNUNET_SYSERR on internal error + */ +int +TALER_MINT_DB_have_deposit (PGconn *db_conn, + const struct Deposit *deposit); +/** + * 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); -// FIXME: with fractional deposits, we need more than -// just the coin key to lookup deposits... -int -TALER_MINT_DB_get_deposit (PGconn *db_conn, - const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub, - struct Deposit *r_deposit); +/** + * Specification for a /refresh/melt operation. + */ +struct RefreshMelt +{ + /** + * Information about the coin that is being melted. + */ + struct TALER_CoinPublicInfo coin; + /** + * Public key of the melting session. + */ + struct GNUNET_CRYPTO_EddsaPublicKey session_pub; + /** + * Signature over the melting operation. + */ + struct GNUNET_CRYPTO_EcdsaSignature coin_sig; + /** + * How much value is being melted? + */ + struct TALER_Amount amount; + + /** + * What is the index of this coin in the melting session? + */ + uint16_t oldcoin_index; + +}; /** - * Get the thread-local database-handle. - * Connect to the db if the connection does not exist yet. + * Test if the given /refresh/melt request is known to us. * - * @param the database connection, or NULL on error + * @param db_conn database connection + * @param melt melt operation + * @return #GNUNET_YES if known, + * #GNUENT_NO if not, + * #GNUNET_SYSERR on internal error */ -PGconn * -TALER_MINT_DB_get_connection (void); +int +TALER_MINT_DB_have_refresh_melt (PGconn *db_conn, + const struct RefreshMelt *melt); +/** + * Store the given /refresh/melt request in the database. + * + * @param db_conn database connection + * @param melt melt operation + * @return #GNUNET_OK on success + * #GNUNET_SYSERR on internal error + */ int -TALER_MINT_DB_init (const char *connection_cfg); +TALER_MINT_DB_insert_refresh_melt (PGconn *db_conn, + const struct RefreshMelt *melt); + + +/** + * 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); + + +/** + * Specification for a /lock operation. + */ +struct Lock +{ + /** + * Information about the coin that is being melted. + */ + struct TALER_CoinPublicInfo coin; + /** + * Signature over the melting operation. + */ + const struct GNUNET_CRYPTO_EcdsaSignature coin_sig; + /** + * How much value is being melted? + */ + struct TALER_Amount amount; + + // FIXME: more needed... +}; +/** + * Test if the given /lock request is known to us. + * + * @param db_conn database connection + * @param lock lock operation + * @return #GNUNET_YES if known, + * #GNUENT_NO if not, + * #GNUNET_SYSERR on internal error + */ int -TALER_TALER_DB_extract_amount (PGresult *result, - unsigned int row, - int indices[3], - struct TALER_Amount *denom); +TALER_MINT_DB_have_lock (PGconn *db_conn, + const struct Lock *lock); + +/** + * Store the given /lock request in the database. + * + * @param db_conn database connection + * @param lock lock operation + * @return #GNUNET_OK on success + * #GNUNET_SYSERR on internal error + */ int -TALER_TALER_DB_extract_amount_nbo (PGresult *result, - unsigned int row, - int indices[3], - struct TALER_AmountNBO *denom_nbo); +TALER_MINT_DB_insert_lock (PGconn *db_conn, + const struct Lock *lock); + + +/** + * Enumeration to classify the different types of transactions + * that can be done with a coin. + */ +enum TALER_MINT_DB_TransactionType +{ + /** + * /deposit operation. + */ + TALER_MINT_DB_TT_DEPOSIT = 0, + + /** + * /refresh/melt operation. + */ + TALER_MINT_DB_TT_REFRESH_MELT = 1, + + /** + * /lock operation. + */ + TALER_MINT_DB_TT_LOCK = 2 +}; + + +/** + * List of transactions we performed for a particular coin. + */ +struct TALER_MINT_DB_TransactionList +{ + + /** + * Next pointer in the NULL-terminated linked list. + */ + struct TALER_MINT_DB_TransactionList *next; + + /** + * Type of the transaction, determines what is stored in @e details. + */ + enum TALER_MINT_DB_TransactionType type; + + /** + * Details about the transaction, depending on @e type. + */ + union + { + + /** + * Details if transaction was a /deposit operation. + */ + struct Deposit *deposit; + + /** + * Details if transaction was a /refresh/melt operation. + */ + struct RefreshMelt *melt; + + /** + * Details if transaction was a /lock operation. + */ + struct Lock *lock; + + } details; + +}; + + +/** + * 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); + + +/** + * Free linked list of transactions. + * + * @param list list to free + */ +void +TALER_MINT_DB_free_coin_transaction_list (struct TALER_MINT_DB_TransactionList *list); + + + + #endif /* _NEURO_MINT_DB_H */ diff --git a/src/mint/taler-mint-httpd_db.c b/src/mint/taler-mint-httpd_db.c index f64e1508d..6dffbcd63 100644 --- a/src/mint/taler-mint-httpd_db.c +++ b/src/mint/taler-mint-httpd_db.c @@ -55,31 +55,35 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection, const struct Deposit *deposit) { PGconn *db_conn; - struct Deposit existing_deposit; - int res; + struct TALER_MINT_DB_TransactionList *tl; if (NULL == (db_conn = TALER_MINT_DB_get_connection ())) { GNUNET_break (0); return TALER_MINT_reply_internal_db_error (connection); } - res = TALER_MINT_DB_get_deposit (db_conn, - &deposit->coin.coin_pub, - &existing_deposit); - if (GNUNET_YES == res) + if (GNUNET_YES == + TALER_MINT_DB_have_deposit (db_conn, + deposit)) + { + return TALER_MINT_reply_deposit_success (connection, + &deposit->coin.coin_pub, + &deposit->h_wire, + &deposit->h_contract, + deposit->transaction_id, + &deposit->merchant_pub, + &deposit->amount); + } + if (GNUNET_OK != + TALER_MINT_DB_transaction (db_conn)) + { + GNUNET_break (0); + return TALER_MINT_reply_internal_db_error (connection); + } + tl = TALER_MINT_DB_get_coin_transactions (db_conn, + &deposit->coin.coin_pub); + if (NULL != tl) { - // FIXME: memory leak - // FIXME: memcmp will not actually work here - if (0 == memcmp (&existing_deposit, - deposit, - sizeof (struct Deposit))) - return TALER_MINT_reply_deposit_success (connection, - &deposit->coin.coin_pub, - &deposit->h_wire, - &deposit->h_contract, - deposit->transaction_id, - &deposit->merchant_pub, - &deposit->amount); // FIXME: in the future, check if there's enough credits // left on the coin. For now: refuse // FIXME: return more information here @@ -87,15 +91,9 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection, MHD_HTTP_FORBIDDEN, "{s:s}", "error", - "double spending"); + "double spending"); } - if (GNUNET_SYSERR == res) - { - GNUNET_break (0); - /* FIXME: return error message to client via MHD! */ - return MHD_NO; - } { struct KnownCoin known_coin; @@ -153,6 +151,14 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection, } + + + + + + + + /** * Sign a reserve's status with the current signing key. * FIXME: not sure why we do this. Should just return @@ -474,6 +480,7 @@ refresh_accept_melts (struct MHD_Connection *connection, struct KnownCoin known_coin; // money the customer gets by melting the current coin struct TALER_Amount coin_gain; + struct RefreshMelt melt; dki = &(TALER_MINT_get_denom_key (key_state, coin_public_infos[i].denom_pub)->issue); @@ -523,10 +530,17 @@ refresh_accept_melts (struct MHD_Connection *connection, return GNUNET_SYSERR; } + // FIXME: test first if coin was already melted + // in this session, etc. + + melt.coin = coin_public_infos[i]; + melt.session_pub = *session_pub; + // melt.coin_sig = FIXME; + // melt.amount = FIXME; + melt.oldcoin_index = i; if (GNUNET_OK != - TALER_MINT_DB_insert_refresh_melt (db_conn, session_pub, i, - &coin_public_infos[i].coin_pub, - coin_public_infos[i].denom_pub)) + TALER_MINT_DB_insert_refresh_melt (db_conn, + &melt)) { GNUNET_break (0); return GNUNET_SYSERR; @@ -934,9 +948,9 @@ TALER_MINT_db_execute_refresh_reveal (struct MHD_Connection *connection, for (j = 0; j < refresh_session.num_oldcoins; j++) { struct RefreshCommitLink commit_link; - struct GNUNET_CRYPTO_EcdsaPublicKey coin_pub; struct TALER_TransferSecret transfer_secret; struct TALER_LinkSecret shared_secret; + struct RefreshMelt melt; res = TALER_MINT_DB_get_refresh_commit_link (db_conn, refresh_session_pub, @@ -949,7 +963,10 @@ TALER_MINT_db_execute_refresh_reveal (struct MHD_Connection *connection, return MHD_NO; } - res = TALER_MINT_DB_get_refresh_melt (db_conn, refresh_session_pub, j, &coin_pub); + res = TALER_MINT_DB_get_refresh_melt (db_conn, + refresh_session_pub, + j, + &melt); if (GNUNET_OK != res) { GNUNET_break (0); @@ -962,7 +979,7 @@ TALER_MINT_db_execute_refresh_reveal (struct MHD_Connection *connection, /* FIXME: ECDHE/ECDSA-key type confusion! Can we reduce/avoid this? */ if (GNUNET_OK != GNUNET_CRYPTO_ecc_ecdh ((const struct GNUNET_CRYPTO_EcdhePrivateKey *) &transfer_privs[i+off][j], - (const struct GNUNET_CRYPTO_EcdhePublicKey *) &coin_pub, + (const struct GNUNET_CRYPTO_EcdhePublicKey *) &melt.coin.coin_pub, &transfer_secret.key)) { GNUNET_break (0); diff --git a/src/mint/taler-mint-httpd_deposit.c b/src/mint/taler-mint-httpd_deposit.c index 1e496d5a5..ec75c3ec0 100644 --- a/src/mint/taler-mint-httpd_deposit.c +++ b/src/mint/taler-mint-httpd_deposit.c @@ -112,8 +112,6 @@ verify_and_execute_deposit (struct MHD_Connection *connection, * * @param connection the MHD connection to handle * @param root root of the posted JSON - * @param purpose is this a #TALER_SIGNATURE_WALLET_DEPOSIT or - * #TALER_SIGNATURE_INCREMENTAL_WALLET_DEPOSIT // FIXME: bad type, use enum! * @param amount how much should be deposited * @param wire json describing the wire details (?) * @return MHD result code @@ -121,7 +119,6 @@ verify_and_execute_deposit (struct MHD_Connection *connection, static int parse_and_handle_deposit_request (struct MHD_Connection *connection, const json_t *root, - uint32_t purpose, const struct TALER_Amount *amount, const json_t *wire) { @@ -187,7 +184,6 @@ parse_and_handle_deposit_request (struct MHD_Connection *connection, GNUNET_free (wire_enc); deposit.wire = wire; - deposit.purpose = purpose; deposit.amount = *amount; res = verify_and_execute_deposit (connection, &deposit); @@ -223,9 +219,7 @@ TALER_MINT_handler_deposit (struct RequestHandler *rh, { json_t *json; json_t *wire; - const char *deposit_type; int res; - uint32_t purpose; struct TALER_Amount amount; json_t *f; @@ -240,7 +234,6 @@ TALER_MINT_handler_deposit (struct RequestHandler *rh, return MHD_YES; if (-1 == json_unpack (json, "{s:s, s:o, f:o}", - "type", &deposit_type, "wire", &wire, "f", &f)) { @@ -267,24 +260,8 @@ TALER_MINT_handler_deposit (struct RequestHandler *rh, json_decref (json); return MHD_YES; } - /* FIXME: use array search and enum, this is ugly */ - if (0 == strcmp ("DIRECT_DEPOSIT", deposit_type)) - purpose = TALER_SIGNATURE_WALLET_DEPOSIT; - else if (0 == strcmp ("INCREMENTAL_DEPOSIT", deposit_type)) - purpose = TALER_SIGNATURE_INCREMENTAL_WALLET_DEPOSIT; - else - { - GNUNET_break_op (0); - json_decref (wire); - json_decref (json); - return TALER_MINT_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s}", - "error", "Bad format"); - } res = parse_and_handle_deposit_request (connection, json, - purpose, &amount, wire); json_decref (wire); diff --git a/src/mint/test_mint_deposits.c b/src/mint/test_mint_deposits.c index 00664cbbf..045485b20 100644 --- a/src/mint/test_mint_deposits.c +++ b/src/mint/test_mint_deposits.c @@ -52,6 +52,44 @@ static int persistent; static int result; +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; +} + + static void do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { @@ -89,7 +127,7 @@ run (void *cls, char *const *args, const char *cfgfile, &do_shutdown, NULL); EXITIF (NULL == (conn = PQconnectdb(DB_URI))); EXITIF (GNUNET_OK != TALER_MINT_DB_init_deposits (conn, !persistent)); - EXITIF (GNUNET_OK != TALER_MINT_DB_prepare_deposits (conn)); + EXITIF (GNUNET_OK != TALER_MINT_DB_prepare (conn)); deposit = GNUNET_malloc (sizeof (struct Deposit) + sizeof (wire)); /* Makeup a random coin public key */ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, |