aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
m---------contrib/gana0
-rw-r--r--src/exchange/taler-exchange-httpd_db.c72
-rw-r--r--src/exchange/taler-exchange-httpd_db.h16
-rw-r--r--src/exchange/taler-exchange-httpd_deposit.c18
-rw-r--r--src/exchange/taler-exchange-httpd_melt.c18
-rw-r--r--src/exchange/taler-exchange-httpd_recoup.c18
-rw-r--r--src/exchangedb/plugin_exchangedb_postgres.c42
-rw-r--r--src/exchangedb/test_exchangedb.c6
-rw-r--r--src/include/taler_exchangedb_plugin.h28
9 files changed, 163 insertions, 55 deletions
diff --git a/contrib/gana b/contrib/gana
-Subproject c0fedb8d45c41fb283fec714b48278e6661d51b
+Subproject f805e4f09b45262cbbb6184659754e15aedfadf
diff --git a/src/exchange/taler-exchange-httpd_db.c b/src/exchange/taler-exchange-httpd_db.c
index dfef63c4c..b0e495226 100644
--- a/src/exchange/taler-exchange-httpd_db.c
+++ b/src/exchange/taler-exchange-httpd_db.c
@@ -41,6 +41,78 @@
/**
+ * Ensure coin is known in the database, and handle conflicts and errors.
+ *
+ * @param coin the coin to make known
+ * @param connection MHD request context
+ * @param session database session and transaction to use
+ * @param[out] mhd_ret set to MHD status on error
+ * @return transaction status, negative on error (@a mhd_ret will be set in this case)
+ */
+enum GNUNET_DB_QueryStatus
+TEH_make_coin_known (const struct TALER_CoinPublicInfo *coin,
+ struct MHD_Connection *connection,
+ struct TALER_EXCHANGEDB_Session *session,
+ MHD_RESULT *mhd_ret)
+{
+ enum TALER_EXCHANGEDB_CoinKnownStatus cks;
+
+ /* make sure coin is 'known' in database */
+ cks = TEH_plugin->ensure_coin_known (TEH_plugin->cls,
+ session,
+ coin);
+ switch (cks)
+ {
+ case TALER_EXCHANGEDB_CKS_ADDED:
+ return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
+ case TALER_EXCHANGEDB_CKS_PRESENT:
+ return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
+ case TALER_EXCHANGEDB_CKS_SOFT_FAIL:
+ return GNUNET_DB_STATUS_SOFT_ERROR;
+ case TALER_EXCHANGEDB_CKS_HARD_FAIL:
+ *mhd_ret
+ = TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_DB_COIN_HISTORY_STORE_ERROR,
+ "could not persist coin data");
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ case TALER_EXCHANGEDB_CKS_CONFLICT:
+ break;
+ }
+
+ {
+ struct TALER_EXCHANGEDB_TransactionList *tl;
+ enum GNUNET_DB_QueryStatus qs;
+
+ qs = TEH_plugin->get_coin_transactions (TEH_plugin->cls,
+ session,
+ &coin->coin_pub,
+ GNUNET_NO,
+ &tl);
+ if (0 > qs)
+ {
+ if (GNUNET_DB_STATUS_HARD_ERROR == qs)
+ *mhd_ret = TALER_MHD_reply_with_error (
+ connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_DEPOSIT_HISTORY_DB_ERROR,
+ "could not fetch coin transaction history");
+ return qs;
+ }
+ *mhd_ret
+ = TEH_RESPONSE_reply_coin_insufficient_funds (
+ connection,
+ TALER_EC_COIN_CONFLICTING_DENOMINATION_KEY,
+ &coin->coin_pub,
+ tl);
+ TEH_plugin->free_coin_transaction_list (TEH_plugin->cls,
+ tl);
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ }
+}
+
+
+/**
* Run a database transaction for @a connection.
* Starts a transaction and calls @a cb. Upon success,
* attempts to commit the transaction. Upon soft failures,
diff --git a/src/exchange/taler-exchange-httpd_db.h b/src/exchange/taler-exchange-httpd_db.h
index e0948d029..bc127b275 100644
--- a/src/exchange/taler-exchange-httpd_db.h
+++ b/src/exchange/taler-exchange-httpd_db.h
@@ -27,6 +27,22 @@
/**
+ * Ensure coin is known in the database, and handle conflicts and errors.
+ *
+ * @param coin the coin to make known
+ * @param connection MHD request context
+ * @param session database session and transaction to use
+ * @param[out] mhd_ret set to MHD status on error
+ * @return transaction status, negative on error (@a mhd_ret will be set in this case)
+ */
+enum GNUNET_DB_QueryStatus
+TEH_make_coin_known (const struct TALER_CoinPublicInfo *coin,
+ struct MHD_Connection *connection,
+ struct TALER_EXCHANGEDB_Session *session,
+ MHD_RESULT *mhd_ret);
+
+
+/**
* Function implementing a database transaction. Runs the transaction
* logic; IF it returns a non-error code, the transaction logic MUST
* NOT queue a MHD response. IF it returns an hard error, the
diff --git a/src/exchange/taler-exchange-httpd_deposit.c b/src/exchange/taler-exchange-httpd_deposit.c
index 30f754b6d..0b810220a 100644
--- a/src/exchange/taler-exchange-httpd_deposit.c
+++ b/src/exchange/taler-exchange-httpd_deposit.c
@@ -218,18 +218,12 @@ deposit_transaction (void *cls,
enum GNUNET_DB_QueryStatus qs;
/* make sure coin is 'known' in database */
- qs = TEH_plugin->ensure_coin_known (TEH_plugin->cls,
- session,
- &deposit->coin);
- if (GNUNET_DB_STATUS_HARD_ERROR == qs)
- {
- *mhd_ret
- = TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_DB_COIN_HISTORY_STORE_ERROR,
- "could not persist coin data");
- return GNUNET_DB_STATUS_HARD_ERROR;
- }
+ qs = TEH_make_coin_known (&deposit->coin,
+ connection,
+ session,
+ mhd_ret);
+ if (qs < 0)
+ return qs;
/* Theoretically, someone other threat may have received
and committed the deposit in the meantime. Check now
diff --git a/src/exchange/taler-exchange-httpd_melt.c b/src/exchange/taler-exchange-httpd_melt.c
index 7e332d24f..0af0da04a 100644
--- a/src/exchange/taler-exchange-httpd_melt.c
+++ b/src/exchange/taler-exchange-httpd_melt.c
@@ -311,18 +311,12 @@ melt_transaction (void *cls,
/* First, make sure coin is 'known' in database */
if (! rmc->coin_is_dirty)
{
- qs = TEH_plugin->ensure_coin_known (TEH_plugin->cls,
- session,
- &rmc->refresh_session.coin);
- if (GNUNET_DB_STATUS_HARD_ERROR == qs)
- {
- *mhd_ret
- = TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_DB_COIN_HISTORY_STORE_ERROR,
- "could not persist coin data");
- return GNUNET_DB_STATUS_HARD_ERROR;
- }
+ qs = TEH_make_coin_known (&rmc->refresh_session.coin,
+ connection,
+ session,
+ mhd_ret);
+ if (qs < 0)
+ return qs;
}
/* Check if we already created a matching refresh_session */
diff --git a/src/exchange/taler-exchange-httpd_recoup.c b/src/exchange/taler-exchange-httpd_recoup.c
index d9969d90a..b3ea90f5c 100644
--- a/src/exchange/taler-exchange-httpd_recoup.c
+++ b/src/exchange/taler-exchange-httpd_recoup.c
@@ -133,18 +133,12 @@ recoup_transaction (void *cls,
int existing_recoup_found;
/* make sure coin is 'known' in database */
- qs = TEH_plugin->ensure_coin_known (TEH_plugin->cls,
- session,
- pc->coin);
- if (GNUNET_DB_STATUS_HARD_ERROR == qs)
- {
- *mhd_ret
- = TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_DB_COIN_HISTORY_STORE_ERROR,
- "could not persist coin data");
- return GNUNET_DB_STATUS_HARD_ERROR;
- }
+ qs = TEH_make_coin_known (&rmc->refresh_session.coin,
+ connection,
+ session,
+ mhd_ret);
+ if (qs < 0)
+ return qs;
/* Check whether a recoup is allowed, and if so, to which
reserve / account the money should go */
diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c
index 0f96f0e86..8e45d6711 100644
--- a/src/exchangedb/plugin_exchangedb_postgres.c
+++ b/src/exchangedb/plugin_exchangedb_postgres.c
@@ -3187,7 +3187,7 @@ postgres_count_known_coins (void *cls,
* @param coin the coin that must be made known
* @return database transaction status, non-negative on success
*/
-static enum GNUNET_DB_QueryStatus
+static enum TALER_EXCHANGEDB_CoinKnownStatus
postgres_ensure_coin_known (void *cls,
struct TALER_EXCHANGEDB_Session *session,
const struct TALER_CoinPublicInfo *coin)
@@ -3207,33 +3207,45 @@ postgres_ensure_coin_known (void *cls,
#endif
/* check if the coin is already known */
+ // FIXME: modify to not also fetch the RSA signature, needlessly costly!
qs = postgres_get_known_coin (pc,
session,
&coin->coin_pub,
&known_coin);
- if (0 > qs)
- {
- GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
- return GNUNET_SYSERR;
- }
- if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
+ switch (qs)
{
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ return TALER_EXCHANGEDB_CKS_SOFT_FAIL;
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ return TALER_EXCHANGEDB_CKS_HARD_FAIL;
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
GNUNET_CRYPTO_rsa_signature_free (known_coin.denom_sig.rsa_signature);
- return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; /* no change! */
+ if (0 == GNUNET_memcmp (&known_coin.denom_pub_hash,
+ &coin->denom_pub_hash))
+ return TALER_EXCHANGEDB_CKS_PRESENT;
+ GNUNET_break_op (0);
+ return TALER_EXCHANGEDB_CKS_CONFLICT;
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ break;
}
- GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs);
+
/* if not known, insert it */
qs = insert_known_coin (pc,
session,
coin);
- if (0 >= qs)
+ switch (qs)
{
- if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
- qs = GNUNET_DB_STATUS_HARD_ERROR; /* should be impossible */
- GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
- return qs;
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ return TALER_EXCHANGEDB_CKS_SOFT_FAIL;
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ return TALER_EXCHANGEDB_CKS_HARD_FAIL;
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ GNUNET_break (0);
+ return TALER_EXCHANGEDB_CKS_HARD_FAIL;
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ break;
}
- return qs;
+ return TALER_EXCHANGEDB_CKS_ADDED;
}
diff --git a/src/exchangedb/test_exchangedb.c b/src/exchangedb/test_exchangedb.c
index 8567c87cb..c9b5c6ce7 100644
--- a/src/exchangedb/test_exchangedb.c
+++ b/src/exchangedb/test_exchangedb.c
@@ -559,7 +559,7 @@ test_melting (struct TALER_EXCHANGEDB_Session *session)
session,
&refresh_session.rc,
&ret_refresh_session));
- FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
+ FAILIF (TALER_EXCHANGEDB_CKS_ADDED !=
plugin->ensure_coin_known (plugin->cls,
session,
&refresh_session.coin));
@@ -1746,7 +1746,7 @@ run (void *cls)
deposit.coin.denom_sig = cbc.sig;
deadline = GNUNET_TIME_absolute_get ();
(void) GNUNET_TIME_round_abs (&deadline);
- FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
+ FAILIF (TALER_EXCHANGEDB_CKS_ADDED !=
plugin->ensure_coin_known (plugin->cls,
session,
&deposit.coin));
@@ -1921,7 +1921,7 @@ run (void *cls)
deposit.refund_deadline = deadline;
deposit.wire_deadline = deadline;
result = 8;
- FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
+ FAILIF (TALER_EXCHANGEDB_CKS_ADDED !=
plugin->ensure_coin_known (plugin->cls,
session,
&deposit.coin));
diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h
index a12aaa426..8b4e63cd7 100644
--- a/src/include/taler_exchangedb_plugin.h
+++ b/src/include/taler_exchangedb_plugin.h
@@ -1841,7 +1841,33 @@ struct TALER_EXCHANGEDB_Plugin
* @param coin the coin that must be made known
* @return database transaction status, non-negative on success
*/
- enum GNUNET_DB_QueryStatus
+ enum TALER_EXCHANGEDB_CoinKnownStatus
+ {
+ /**
+ * The coin was successfully added.
+ */
+ TALER_EXCHANGEDB_CKS_ADDED = 1,
+
+ /**
+ * The coin was already present.
+ */
+ TALER_EXCHANGEDB_CKS_PRESENT = 0,
+
+ /**
+ * Serialization failure.
+ */
+ TALER_EXCHANGEDB_CKS_SOFT_FAIL = -1,
+
+ /**
+ * Hard database failure.
+ */
+ TALER_EXCHANGEDB_CKS_HARD_FAIL = -2,
+
+ /**
+ * Conflicting coin (different denomination key) already in database.
+ */
+ TALER_EXCHANGEDB_CKS_CONFLICT = -3,
+ }
(*ensure_coin_known)(void *cls,
struct TALER_EXCHANGEDB_Session *session,
const struct TALER_CoinPublicInfo *coin);