aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mint/mint.h30
-rw-r--r--src/mint/mint_db.c932
-rw-r--r--src/mint/mint_db.h447
-rw-r--r--src/mint/taler-mint-httpd_db.c79
-rw-r--r--src/mint/taler-mint-httpd_deposit.c23
-rw-r--r--src/mint/test_mint_deposits.c40
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,