aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2015-01-29 00:09:48 +0100
committerChristian Grothoff <christian@grothoff.org>2015-01-29 00:09:48 +0100
commit8adde040ab5c3fdc40b06537d3bab1aa60ecc5e5 (patch)
tree66cf29710aa422971cc73adefbcc887e98be5f17
parentb162d2e45829469df5327ea25b2bab1ba1ebaab9 (diff)
towards proper implementation of /withdraw/status
-rw-r--r--src/mint/key_io.h1
-rw-r--r--src/mint/mint_db.c228
-rw-r--r--src/mint/mint_db.h182
-rw-r--r--src/mint/taler-mint-httpd_db.c227
-rw-r--r--src/mint/taler-mint-httpd_responses.c119
-rw-r--r--src/mint/taler-mint-httpd_responses.h21
-rw-r--r--src/util/amount.c42
7 files changed, 495 insertions, 325 deletions
diff --git a/src/mint/key_io.h b/src/mint/key_io.h
index 44665e379..a14866f47 100644
--- a/src/mint/key_io.h
+++ b/src/mint/key_io.h
@@ -42,6 +42,7 @@
struct TALER_MINT_SignKeyIssuePriv
{
struct GNUNET_CRYPTO_EddsaPrivateKey signkey_priv;
+
struct TALER_MINT_SignKeyIssue issue;
};
diff --git a/src/mint/mint_db.c b/src/mint/mint_db.c
index 5da2a5d46..0e448bf09 100644
--- a/src/mint/mint_db.c
+++ b/src/mint/mint_db.c
@@ -103,128 +103,6 @@ TALER_TALER_DB_extract_amount (PGresult *result,
}
-
-int
-TALER_MINT_DB_get_reserve (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *reserve_pub,
- struct Reserve *reserve)
-{
- PGresult *result;
- int res;
- struct TALER_DB_QueryParam params[] = {
- TALER_DB_QUERY_PARAM_PTR (reserve_pub),
- TALER_DB_QUERY_PARAM_END
- };
-
- result = TALER_DB_exec_prepared (db_conn, "get_reserve", params);
-
- if (PGRES_TUPLES_OK != PQresultStatus (result))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Query failed: %s\n", PQresultErrorMessage (result));
- PQclear (result);
- return GNUNET_SYSERR;
- }
-
- if (0 == PQntuples (result))
- {
- PQclear (result);
- return GNUNET_NO;
- }
-
- reserve->reserve_pub = *reserve_pub;
-
- struct TALER_DB_ResultSpec rs[] = {
- TALER_DB_RESULT_SPEC("status_sig", &reserve->status_sig),
- TALER_DB_RESULT_SPEC("status_sign_pub", &reserve->status_sign_pub),
- TALER_DB_RESULT_SPEC_END
- };
-
- res = TALER_DB_extract_result (result, rs, 0);
- if (GNUNET_SYSERR == res)
- {
- GNUNET_break (0);
- PQclear (result);
- return GNUNET_SYSERR;
- }
-
- {
- int fnums[] = {
- PQfnumber (result, "balance_value"),
- PQfnumber (result, "balance_fraction"),
- PQfnumber (result, "balance_currency"),
- };
- if (GNUNET_OK != TALER_TALER_DB_extract_amount_nbo (result, 0, fnums, &reserve->balance))
- {
- GNUNET_break (0);
- PQclear (result);
- return GNUNET_SYSERR;
- }
- }
-
- /* FIXME: Add expiration?? */
-
- PQclear (result);
- return GNUNET_OK;
-}
-
-
-/* If fresh is GNUNET_YES, set some fields to NULL as they are not actually valid */
-int
-TALER_MINT_DB_update_reserve (PGconn *db_conn,
- const struct Reserve *reserve,
- int fresh)
-{
- PGresult *result;
- uint64_t stamp_sec;
-
- stamp_sec = GNUNET_ntohll (GNUNET_TIME_absolute_ntoh (reserve->expiration).abs_value_us / 1000000);
-
- struct TALER_DB_QueryParam params[] = {
- TALER_DB_QUERY_PARAM_PTR (&reserve->reserve_pub),
- TALER_DB_QUERY_PARAM_PTR (&reserve->balance.value),
- TALER_DB_QUERY_PARAM_PTR (&reserve->balance.fraction),
- TALER_DB_QUERY_PARAM_PTR_SIZED (&reserve->balance.currency,
- strlen (reserve->balance.currency)),
- TALER_DB_QUERY_PARAM_PTR (&reserve->status_sig),
- TALER_DB_QUERY_PARAM_PTR (&reserve->status_sign_pub),
- TALER_DB_QUERY_PARAM_PTR (&stamp_sec),
- TALER_DB_QUERY_PARAM_END
- };
-
- /* set some fields to NULL if they are not actually valid */
-
- if (GNUNET_YES == fresh)
- {
- unsigned i;
- for (i = 4; i <= 7; i += 1)
- {
- params[i].data = NULL;
- params[i].size = 0;
- }
- }
-
- result = TALER_DB_exec_prepared (db_conn, "update_reserve", params);
-
- if (PGRES_COMMAND_OK != PQresultStatus (result))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Query failed: %s\n", PQresultErrorMessage (result));
- PQclear (result);
- return GNUNET_SYSERR;
- }
-
- if (0 != strcmp ("1", PQcmdTuples (result)))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Update failed (updated '%s' tupes instead of '1')\n",
- PQcmdTuples (result));
- return GNUNET_SYSERR;
- }
-
- PQclear (result);
- return GNUNET_OK;
-}
-
-
-
int
TALER_MINT_DB_prepare (PGconn *db_conn)
{
@@ -1560,9 +1438,6 @@ TALER_db_get_transfer (PGconn *db_conn,
-
-
-
/**
* Close thread-local database connection when a thread is destroyed.
*
@@ -1712,6 +1587,10 @@ TALER_MINT_DB_commit (PGconn *db_conn)
}
+
+
+
+
/**
* Locate the response for a /withdraw request under the
* key of the hash of the blinded message.
@@ -1729,6 +1608,7 @@ TALER_MINT_DB_get_collectable_blindcoin (PGconn *db_conn,
const struct GNUNET_HashCode *h_blind,
struct CollectableBlindcoin *collectable)
{
+ // FIXME: check logic!
PGresult *result;
struct TALER_DB_QueryParam params[] = {
TALER_DB_QUERY_PARAM_PTR (h_blind),
@@ -1792,6 +1672,7 @@ TALER_MINT_DB_insert_collectable_blindcoin (PGconn *db_conn,
const struct GNUNET_HashCode *h_blind,
const struct CollectableBlindcoin *collectable)
{
+ // FIXME: check logic!
PGresult *result;
char *sig_buf;
size_t sig_buf_size;
@@ -1835,6 +1716,95 @@ TALER_MINT_DB_insert_collectable_blindcoin (PGconn *db_conn,
/**
+ * Get all of the transaction history associated with the specified
+ * reserve.
+ *
+ * @param db_conn connection to use
+ * @param reserve_pub public key of the reserve
+ * @return known transaction history (NULL if reserve is unknown)
+ */
+struct ReserveHistory *
+TALER_MINT_DB_get_reserve_history (PGconn *db_conn,
+ const struct GNUNET_CRYPTO_EddsaPublicKey *reserve_pub)
+{
+ // FIXME: implement logic!
+ PGresult *result;
+ // int res;
+ struct TALER_DB_QueryParam params[] = {
+ TALER_DB_QUERY_PARAM_PTR (reserve_pub),
+ TALER_DB_QUERY_PARAM_END
+ };
+
+ result = TALER_DB_exec_prepared (db_conn, "get_reserve", params);
+
+ if (PGRES_TUPLES_OK != PQresultStatus (result))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Query failed: %s\n",
+ PQresultErrorMessage (result));
+ PQclear (result);
+ return NULL;
+ }
+
+ if (0 == PQntuples (result))
+ {
+ PQclear (result);
+ return NULL;
+ }
+#if 0
+ reserve->reserve_pub = *reserve_pub;
+
+ struct TALER_DB_ResultSpec rs[] = {
+ TALER_DB_RESULT_SPEC("status_sig", &reserve->status_sig),
+ TALER_DB_RESULT_SPEC("status_sign_pub", &reserve->status_sign_pub),
+ TALER_DB_RESULT_SPEC_END
+ };
+
+ res = TALER_DB_extract_result (result, rs, 0);
+ if (GNUNET_SYSERR == res)
+ {
+ GNUNET_break (0);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+
+ {
+ int fnums[] = {
+ PQfnumber (result, "balance_value"),
+ PQfnumber (result, "balance_fraction"),
+ PQfnumber (result, "balance_currency"),
+ };
+ if (GNUNET_OK != TALER_TALER_DB_extract_amount_nbo (result, 0, fnums, &reserve->balance))
+ {
+ GNUNET_break (0);
+ PQclear (result);
+ return GNUNET_SYSERR;
+ }
+ }
+
+ /* FIXME: Add expiration?? */
+
+ PQclear (result);
+ return GNUNET_OK;
+#endif
+ return NULL;
+}
+
+
+/**
+ * Free memory associated with the given reserve history.
+ *
+ * @param rh history to free.
+ */
+void
+TALER_MINT_DB_free_reserve_history (struct ReserveHistory *rh)
+{
+ // FIXME: implement
+ GNUNET_assert (0);
+}
+
+
+/**
* Check if we have the specified deposit already in the database.
*
* @param db_conn database connection
@@ -1846,6 +1816,7 @@ int
TALER_MINT_DB_have_deposit (PGconn *db_conn,
const struct Deposit *deposit)
{
+ // FIXME: check logic!
struct TALER_DB_QueryParam params[] = {
TALER_DB_QUERY_PARAM_PTR (&deposit->coin.coin_pub), // FIXME
TALER_DB_QUERY_PARAM_END
@@ -1884,6 +1855,7 @@ int
TALER_MINT_DB_insert_deposit (PGconn *db_conn,
const struct Deposit *deposit)
{
+ // FIXME: check logic!
struct TALER_DB_QueryParam params[]= {
TALER_DB_QUERY_PARAM_PTR (&deposit->coin.coin_pub),
TALER_DB_QUERY_PARAM_PTR (&deposit->coin.denom_pub), // FIXME!
@@ -1928,6 +1900,7 @@ int
TALER_MINT_DB_have_refresh_melt (PGconn *db_conn,
const struct RefreshMelt *melt)
{
+ // FIXME: check logic!
uint16_t oldcoin_index_nbo = htons (melt->oldcoin_index);
struct TALER_DB_QueryParam params[] = {
TALER_DB_QUERY_PARAM_PTR(&melt->session_pub),
@@ -1956,7 +1929,6 @@ TALER_MINT_DB_have_refresh_melt (PGconn *db_conn,
}
-
/**
* Store the given /refresh/melt request in the database.
*
@@ -1969,6 +1941,7 @@ int
TALER_MINT_DB_insert_refresh_melt (PGconn *db_conn,
const struct RefreshMelt *melt)
{
+ // FIXME: check logic!
uint16_t oldcoin_index_nbo = htons (melt->oldcoin_index);
char *buf;
size_t buf_size;
@@ -2014,6 +1987,7 @@ TALER_MINT_DB_get_refresh_melt (PGconn *db_conn,
uint16_t oldcoin_index,
struct RefreshMelt *melt)
{
+ // FIXME: check logic!
GNUNET_break (0);
return GNUNET_SYSERR;
}
@@ -2031,6 +2005,7 @@ struct TALER_MINT_DB_TransactionList *
TALER_MINT_DB_get_coin_transactions (PGconn *db_conn,
const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub)
{
+ // FIXME: check logic!
GNUNET_break (0); // FIXME: implement!
return NULL;
}
@@ -2044,6 +2019,7 @@ TALER_MINT_DB_get_coin_transactions (PGconn *db_conn,
void
TALER_MINT_DB_free_coin_transaction_list (struct TALER_MINT_DB_TransactionList *list)
{
+ // FIXME: check logic!
GNUNET_break (0);
}
diff --git a/src/mint/mint_db.h b/src/mint/mint_db.h
index ff14ba1e4..4cb2a5f1e 100644
--- a/src/mint/mint_db.h
+++ b/src/mint/mint_db.h
@@ -38,77 +38,6 @@ int
TALER_MINT_DB_prepare (PGconn *db_conn);
-/**
- * Reserve row. Corresponds to table 'reserves' in the mint's
- * database. FIXME: not sure this is how we want to store this
- * information. Also, may currently used in different ways in the
- * code, so we might need to separate the struct into different ones
- * depending on the context it is used in.
- */
-struct Reserve
-{
- /**
- * Signature over the purse.
- * Only valid if (blind_session_missing==GNUNET_YES).
- */
- struct GNUNET_CRYPTO_EddsaSignature status_sig;
-
- /**
- * Signature with purpose TALER_SIGNATURE_PURSE.
- * Only valid if (blind_session_missing==GNUNET_YES).
- */
- struct GNUNET_CRYPTO_EccSignaturePurpose status_sig_purpose;
-
- /**
- * Signing key used to sign the purse.
- * Only valid if (blind_session_missing==GNUNET_YES).
- */
- struct GNUNET_CRYPTO_EddsaPublicKey status_sign_pub;
-
- /**
- * Withdraw public key, identifies the purse.
- * Only the customer knows the corresponding private key.
- */
- struct GNUNET_CRYPTO_EddsaPublicKey reserve_pub;
-
- /**
- * Remaining balance in the purse. // FIXME: do not use NBO here!
- */
- struct TALER_AmountNBO balance;
-
- /**
- * Expiration date for the purse.
- */
- struct GNUNET_TIME_AbsoluteNBO expiration;
-};
-
-
-int
-TALER_MINT_DB_get_reserve (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *reserve_pub,
- struct Reserve *reserve_res);
-
-
-/**
- * Update information about a reserve.
- *
- * @param db_conn
- * @param reserve current reserve status
- * @param fresh FIXME
- * @return #GNUNET_OK on success
- */
-int
-TALER_MINT_DB_update_reserve (PGconn *db_conn,
- const struct Reserve *reserve,
- int fresh);
-
-
-
-
-
-
-
-
int
TALER_MINT_DB_insert_refresh_order (PGconn *db_conn,
uint16_t newcoin_index,
@@ -328,6 +257,34 @@ void
TALER_MINT_DB_rollback (PGconn *db_conn);
+/**
+ * Information we keep on a bank transfer that
+ * established a reserve.
+ */
+struct BankTransfer
+{
+
+ /**
+ * Public key of the reserve that was filled.
+ */
+ struct GNUNET_CRYPTO_EddsaPublicKey reserve_pub;
+
+ /**
+ * Amount that was transferred to the mint.
+ */
+ struct TALER_Amount amount;
+
+ /**
+ * Detailed wire information about the transaction.
+ */
+ const json_t *wire;
+
+};
+
+
+/* FIXME: add functions to add bank transfers to our DB
+ (and to test if we already did add one) */
+
/**
* Information we keep for a withdrawn coin to reproduce
@@ -360,6 +317,9 @@ struct CollectableBlindcoin
};
+/* FIXME: need call to convert CollectableBlindcoin to JSON (#3527) */
+
+
/**
* Locate the response for a /withdraw request under the
* key of the hash of the blinded message.
@@ -396,6 +356,86 @@ TALER_MINT_DB_insert_collectable_blindcoin (PGconn *db_conn,
const struct CollectableBlindcoin *collectable);
+
+/**
+ * Types of operations on a reserved.
+ */
+enum TALER_MINT_DB_ReserveOperation
+{
+ /**
+ * Money was deposited into the reserve via a bank transfer.
+ */
+ TALER_MINT_DB_RO_BANK_TO_MINT = 0,
+
+ /**
+ * A Coin was withdrawn from the reserve using /withdraw.
+ */
+ TALER_MINT_DB_RO_WITHDRAW_COIN = 1
+};
+
+
+/**
+ * Reserve history as a linked list. Lists all of the transactions
+ * associated with this reserve (such as the bank transfers that
+ * established the reserve and all /withdraw operations we have done
+ * since).
+ */
+struct ReserveHistory
+{
+
+ /**
+ * Next entry in the reserve history.
+ */
+ struct ReserveHistory *next;
+
+ /**
+ * Type of the event, determins @e details.
+ */
+ enum TALER_MINT_DB_ReserveOperation type;
+
+ /**
+ * Details of the operation, depending on @e type.
+ */
+ union
+ {
+
+ /**
+ * Details about a bank transfer to the mint.
+ */
+ struct BankTransfer *bank;
+
+ /**
+ * Details about a /withdraw operation.
+ */
+ struct CollectableBlindcoin *withdraw;
+
+ } details;
+
+};
+
+
+/**
+ * Get all of the transaction history associated with the specified
+ * reserve.
+ *
+ * @param db_conn connection to use
+ * @param reserve_pub public key of the reserve
+ * @return known transaction history (NULL if reserve is unknown)
+ */
+struct ReserveHistory *
+TALER_MINT_DB_get_reserve_history (PGconn *db_conn,
+ const struct GNUNET_CRYPTO_EddsaPublicKey *reserve_pub);
+
+
+/**
+ * Free memory associated with the given reserve history.
+ *
+ * @param rh history to free.
+ */
+void
+TALER_MINT_DB_free_reserve_history (struct ReserveHistory *rh);
+
+
/**
* Specification for a /deposit operation.
*/
diff --git a/src/mint/taler-mint-httpd_db.c b/src/mint/taler-mint-httpd_db.c
index c6f0fe2cb..bf10cd29e 100644
--- a/src/mint/taler-mint-httpd_db.c
+++ b/src/mint/taler-mint-httpd_db.c
@@ -22,12 +22,31 @@
* - actually abstract DB implementation (i.e. via plugin logic)
* (this file should remain largely unchanged with the exception
* of the PQ-specific DB handle types)
- * - /deposit: properly check existing deposits
- * - /deposit: properly perform commit (check return value)
- * - /deposit: check for leaks
- * - ALL: check API: given structs are usually not perfect, as they
- * often contain too many fields for the context
- * - ALL: check transactional behavior
+ * - /withdraw/sign: all
+ * + properly check all conditions and handle errors
+ * + properly check transaction logic
+ * + check for leaks
+ * + check low-level API
+ * - /refresh/melt: all
+ * + properly check all conditions and handle errors
+ * + properly check transaction logic
+ * + check for leaks
+ * + check low-level API
+ * - /refresh/commit: all
+ * + properly check all conditions and handle errors
+ * + properly check transaction logic
+ * + check for leaks
+ * + check low-level API
+ * - /refresh/reveal: all
+ * + properly check all conditions and handle errors
+ * + properly check transaction logic
+ * + check for leaks
+ * + check low-level API
+ * - /refresh/link: all
+ * + properly check all conditions and handle errors
+ * + properly check transaction logic
+ * + check for leaks
+ * + check low-level API
*/
#include "platform.h"
#include <pthread.h>
@@ -43,6 +62,26 @@
/**
+ * Get an amount in the mint's currency that is zero.
+ *
+ * @return zero amount in the mint's currency
+ */
+static struct TALER_Amount
+mint_amount_native_zero ()
+{
+ struct TALER_Amount amount;
+
+ memset (&amount,
+ 0,
+ sizeof (amount));
+ memcpy (amount.currency,
+ MINT_CURRENCY,
+ strlen (MINT_CURRENCY) + 1);
+ return amount;
+}
+
+
+/**
* Execute a deposit. The validity of the coin and signature
* have already been checked. The database must now check that
* the coin is not (double or over) spent, and execute the
@@ -58,6 +97,15 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection,
{
PGconn *db_conn;
struct TALER_MINT_DB_TransactionList *tl;
+ struct TALER_MINT_DB_TransactionList *pos;
+ struct TALER_Amount spent;
+ struct TALER_Amount value;
+ struct TALER_Amount fee_deposit;
+ struct TALER_Amount fee_withdraw;
+ struct TALER_Amount fee_refresh;
+ struct MintKeyState *mks;
+ struct TALER_MINT_DenomKeyIssuePriv *dki;
+ int ret;
if (NULL == (db_conn = TALER_MINT_DB_get_connection ()))
{
@@ -76,6 +124,14 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection,
&deposit->merchant_pub,
&deposit->amount);
}
+ mks = TALER_MINT_key_state_acquire ();
+ dki = TALER_MINT_get_denom_key (mks,
+ deposit->coin.denom_pub);
+ value = TALER_amount_ntoh (dki->issue.value);
+ fee_deposit = TALER_amount_ntoh (dki->issue.fee_deposit);
+ fee_refresh = TALER_amount_ntoh (dki->issue.fee_refresh);
+ TALER_MINT_key_state_release (mks);
+
if (GNUNET_OK !=
TALER_MINT_DB_transaction (db_conn))
{
@@ -84,19 +140,48 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection,
}
tl = TALER_MINT_DB_get_coin_transactions (db_conn,
&deposit->coin.coin_pub);
- if (NULL != tl)
+ spent = fee_withdraw; /* fee for THIS transaction */
+ /* FIXME: need to deal better with integer overflows
+ in the logic that follows! (change amount.c API!) */
+ spent = TALER_amount_add (spent,
+ deposit->amount);
+
+ for (pos = tl; NULL != pos; pos = pos->next)
{
- // FIXME: in the future, check if there's enough credits
- // left on the coin. For now: refuse
- // FIXME: return more information here
- TALER_MINT_DB_rollback (db_conn);
- return TALER_MINT_reply_json_pack (connection,
- MHD_HTTP_FORBIDDEN,
- "{s:s}",
- "error", "insufficient funds");
+ switch (pos->type)
+ {
+ case TALER_MINT_DB_TT_DEPOSIT:
+ spent = TALER_amount_add (spent,
+ pos->details.deposit->amount);
+ spent = TALER_amount_add (spent,
+ fee_deposit);
+ break;
+ case TALER_MINT_DB_TT_REFRESH_MELT:
+ spent = TALER_amount_add (spent,
+ pos->details.melt->amount);
+ spent = TALER_amount_add (spent,
+ fee_refresh);
+ break;
+ case TALER_MINT_DB_TT_LOCK:
+ /* should check if lock is still active,
+ and if it is for THIS operation; if
+ lock is inactive, delete it; if lock
+ is for THIS operation, ignore it;
+ if lock is for another operation,
+ count it! */
+ GNUNET_assert (0); // FIXME: not implemented!
+ break;
+ }
}
-
+ if (0 < TALER_amount_cmp (spent, value))
+ {
+ TALER_MINT_DB_rollback (db_conn);
+ ret = TALER_MINT_reply_insufficient_funds (connection,
+ tl);
+ TALER_MINT_DB_free_coin_transaction_list (tl);
+ return ret;
+ }
TALER_MINT_DB_free_coin_transaction_list (tl);
if (GNUNET_OK !=
@@ -124,37 +209,6 @@ 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
- * existing list of operations on the reserve.
- *
- * @param reserve the reserve to sign
- * @param key_state the key state containing the current
- * signing private key
- */
-static void
-sign_reserve (struct Reserve *reserve,
- struct MintKeyState *key_state)
-{
- reserve->status_sign_pub = key_state->current_sign_key_issue.issue.signkey_pub;
- reserve->status_sig_purpose.purpose = htonl (TALER_SIGNATURE_RESERVE_STATUS);
- reserve->status_sig_purpose.size = htonl (sizeof (struct Reserve) -
- offsetof (struct Reserve, status_sig_purpose));
- GNUNET_CRYPTO_eddsa_sign (&key_state->current_sign_key_issue.signkey_priv,
- &reserve->status_sig_purpose,
- &reserve->status_sig);
-}
-
-
/**
* Execute a /withdraw/status.
*
@@ -167,50 +221,25 @@ TALER_MINT_db_execute_withdraw_status (struct MHD_Connection *connection,
const struct GNUNET_CRYPTO_EddsaPublicKey *reserve_pub)
{
PGconn *db_conn;
+ struct ReserveHistory *rh;
int res;
- struct Reserve reserve;
- struct MintKeyState *key_state;
- int must_update = GNUNET_NO;
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_reserve (db_conn,
- reserve_pub,
- &reserve);
- /* check if these are really the matching error codes,
- seems odd... */
- if (GNUNET_SYSERR == res)
+ rh = TALER_MINT_DB_get_reserve_history (db_conn,
+ reserve_pub);
+ if (NULL == rh)
return TALER_MINT_reply_json_pack (connection,
MHD_HTTP_NOT_FOUND,
"{s:s}",
- "error",
- "Reserve not found");
- if (GNUNET_OK != res)
- {
- GNUNET_break (0);
- return TALER_MINT_reply_internal_error (connection,
- "Internal error");
- }
- key_state = TALER_MINT_key_state_acquire ();
- if (0 != memcmp (&key_state->current_sign_key_issue.issue.signkey_pub,
- &reserve.status_sign_pub,
- sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)))
- {
- sign_reserve (&reserve, key_state);
- must_update = GNUNET_YES;
- }
- if ((GNUNET_YES == must_update) &&
- (GNUNET_OK != TALER_MINT_DB_update_reserve (db_conn, &reserve, !must_update)))
- {
- GNUNET_break (0);
- return MHD_YES;
- }
- return TALER_MINT_reply_withdraw_status_success (connection,
- TALER_amount_ntoh (reserve.balance),
- GNUNET_TIME_absolute_ntoh (reserve.expiration));
+ "error", "Reserve not found");
+ res = TALER_MINT_reply_withdraw_status_success (connection,
+ rh);
+ TALER_MINT_DB_free_reserve_history (rh);
+ return res;
}
@@ -234,7 +263,7 @@ TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection,
const struct GNUNET_CRYPTO_EddsaSignature *signature)
{
PGconn *db_conn;
- struct Reserve db_reserve;
+ struct ReserveHistory *rh;
struct MintKeyState *key_state;
struct CollectableBlindcoin collectable;
struct TALER_MINT_DenomKeyIssuePriv *dki;
@@ -270,15 +299,9 @@ TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection,
return res;
}
GNUNET_assert (GNUNET_NO == res);
- res = TALER_MINT_DB_get_reserve (db_conn,
- reserve,
- &db_reserve);
- if (GNUNET_SYSERR == res)
- {
- GNUNET_break (0);
- return TALER_MINT_reply_internal_db_error (connection);
- }
- if (GNUNET_NO == res)
+ rh = TALER_MINT_DB_get_reserve_history (db_conn,
+ reserve);
+ if (NULL == rh)
return TALER_MINT_reply_json_pack (connection,
MHD_HTTP_NOT_FOUND,
"{s:s}",
@@ -298,6 +321,8 @@ TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection,
amount_required = TALER_amount_add (TALER_amount_ntoh (dki->issue.value),
TALER_amount_ntoh (dki->issue.fee_withdraw));
+ // FIX LOGIC!
+#if 0
if (0 < TALER_amount_cmp (amount_required,
TALER_amount_ntoh (db_reserve.balance)))
return TALER_MINT_reply_json_pack (connection,
@@ -329,6 +354,8 @@ TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection,
GNUNET_break (0);
return TALER_MINT_reply_internal_db_error (connection);
}
+#endif
+
collectable.denom_pub = (struct GNUNET_CRYPTO_rsa_PublicKey *) denomination_pub;
collectable.sig = sig;
collectable.reserve_pub = *reserve;
@@ -401,21 +428,6 @@ refresh_accept_denoms (struct MHD_Connection *connection,
}
-/**
- * Get an amount in the mint's currency that is zero.
- *
- * @return zero amount in the mint's currency
- */
-static struct TALER_Amount
-mint_amount_native_zero ()
-{
- struct TALER_Amount amount;
-
- memset (&amount, 0, sizeof (amount));
- memcpy (amount.currency, MINT_CURRENCY, strlen (MINT_CURRENCY) + 1);
-
- return amount;
-}
/**
@@ -1290,3 +1302,6 @@ TALER_MINT_db_execute_refresh_link (struct MHD_Connection *connection,
json_decref (root);
return res;
}
+
+
+/* end of taler-mint-httpd_db.c */
diff --git a/src/mint/taler-mint-httpd_responses.c b/src/mint/taler-mint-httpd_responses.c
index 307e6ec17..bad87429c 100644
--- a/src/mint/taler-mint-httpd_responses.c
+++ b/src/mint/taler-mint-httpd_responses.c
@@ -309,31 +309,132 @@ TALER_MINT_reply_deposit_success (struct MHD_Connection *connection,
/**
+ * Send proof that a /deposit, /refresh/melt or /lock request is
+ * invalid to client. This function will create a message with all of
+ * the operations affecting the coin that demonstrate that the coin
+ * has insufficient value.
+ *
+ * @param connection connection to the client
+ * @param tl transaction list to use to build reply
+ * @return MHD result code
+ */
+int
+TALER_MINT_reply_insufficient_funds (struct MHD_Connection *connection,
+ const struct TALER_MINT_DB_TransactionList *tl)
+{
+ const struct TALER_MINT_DB_TransactionList *pos;
+ int ret;
+
+ // FIXME: implement properly!
+ for (pos = tl; NULL != pos; pos = pos->next)
+ {
+ switch (pos->type)
+ {
+ case TALER_MINT_DB_TT_DEPOSIT:
+ /* FIXME: add operation details to json reply */
+ break;
+ case TALER_MINT_DB_TT_REFRESH_MELT:
+ /* FIXME: add operation details to json reply */
+ break;
+ case TALER_MINT_DB_TT_LOCK:
+ /* FIXME: add operation details to json reply */
+ break;
+ }
+ }
+
+ ret = TALER_MINT_reply_json_pack (connection,
+ MHD_HTTP_FORBIDDEN,
+ "{s:s}",
+ "error", "insufficient funds");
+ return ret;
+}
+
+
+/**
* Send reserve status information to client.
*
* @param connection connection to the client
- * @param balance current reserve balance
- * @param expiration when will the reserve expire
+ * @param rh reserve history to return
* @return MHD result code
*/
int
TALER_MINT_reply_withdraw_status_success (struct MHD_Connection *connection,
- const struct TALER_Amount balance,
- struct GNUNET_TIME_Absolute expiration)
+ const struct ReserveHistory *rh)
{
+ struct TALER_Amount deposit_total;
+ struct TALER_Amount withdraw_total;
+ struct TALER_Amount balance;
+ struct TALER_Amount value;
json_t *json_balance;
- json_t *json_expiration;
+ json_t *json_history;
int ret;
+ struct MintKeyState *key_state;
+ const struct ReserveHistory *pos;
+ struct TALER_MINT_DenomKeyIssuePriv *dki;
+
+ json_history = json_array ();
+ ret = 0;
+ for (pos = rh; NULL != pos; pos = pos->next)
+ {
+ switch (pos->type)
+ {
+ case TALER_MINT_DB_RO_BANK_TO_MINT:
+ if (0 == ret)
+ deposit_total = pos->details.bank->amount;
+ else
+ deposit_total = TALER_amount_add (deposit_total,
+ pos->details.bank->amount);
+ ret = 1;
+ json_array_append_new (json_history,
+ json_pack ("{s:s, s:o, s:o}",
+ "type", "DEPOSIT",
+ "wire", pos->details.bank->wire,
+ "amount", TALER_JSON_from_amount (pos->details.bank->amount)));
+ break;
+ case TALER_MINT_DB_RO_WITHDRAW_COIN:
+ break;
+ }
+ }
+
+ key_state = TALER_MINT_key_state_acquire ();
+ ret = 0;
+ for (pos = rh; NULL != pos; pos = pos->next)
+ {
+ switch (pos->type)
+ {
+ case TALER_MINT_DB_RO_BANK_TO_MINT:
+ break;
+ case TALER_MINT_DB_RO_WITHDRAW_COIN:
+ dki = TALER_MINT_get_denom_key (key_state,
+ pos->details.withdraw->denom_pub);
+ value = TALER_amount_ntoh (dki->issue.value);
+ if (0 == ret)
+ withdraw_total = value;
+ else
+ withdraw_total = TALER_amount_add (withdraw_total,
+ value);
+ ret = 1;
+ /* FIXME: add `struct CollectableBlindcoin` as JSON here as well! (#3527) */
+ json_array_append_new (json_history,
+ json_pack ("{s:s, s:o, s:o}",
+ "type", "WITHDRAW",
+ "amount", TALER_JSON_from_amount (value)));
+
+ break;
+ }
+ }
+ TALER_MINT_key_state_release (key_state);
+ balance = TALER_amount_subtract (deposit_total,
+ withdraw_total);
json_balance = TALER_JSON_from_amount (balance);
- json_expiration = TALER_JSON_from_abs (expiration);
ret = TALER_MINT_reply_json_pack (connection,
MHD_HTTP_OK,
"{s:o, s:o}",
"balance", json_balance,
- "expiration", json_expiration);
+ "history", json_history);
+ json_decref (json_history);
json_decref (json_balance);
- json_decref (json_expiration);
return ret;
}
@@ -354,7 +455,7 @@ TALER_MINT_reply_withdraw_sign_success (struct MHD_Connection *connection,
char *sig_buf;
int ret;
- /* FIXME: use TALER_JSON_from_sig here instead! */
+ /* FIXME: use TALER_JSON_from_sig here instead!? */
sig_buf_size = GNUNET_CRYPTO_rsa_signature_encode (collectable->sig,
&sig_buf);
sig_json = TALER_JSON_from_data (sig_buf,
diff --git a/src/mint/taler-mint-httpd_responses.h b/src/mint/taler-mint-httpd_responses.h
index f8a671e18..5e2f98638 100644
--- a/src/mint/taler-mint-httpd_responses.h
+++ b/src/mint/taler-mint-httpd_responses.h
@@ -182,17 +182,30 @@ TALER_MINT_reply_deposit_success (struct MHD_Connection *connection,
/**
+ * Send proof that a /deposit, /refresh/melt or /lock request is
+ * invalid to client. This function will create a message with all of
+ * the operations affecting the coin that demonstrate that the coin
+ * has insufficient value.
+ *
+ * @param connection connection to the client
+ * @param tl transaction list to use to build reply
+ * @return MHD result code
+ */
+int
+TALER_MINT_reply_insufficient_funds (struct MHD_Connection *connection,
+ const struct TALER_MINT_DB_TransactionList *tl);
+
+
+/**
* Send reserve status information to client.
*
* @param connection connection to the client
- * @param balance current reserve balance
- * @param expiration when will the reserve expire
+ * @param rh reserve history to return
* @return MHD result code
*/
int
TALER_MINT_reply_withdraw_status_success (struct MHD_Connection *connection,
- struct TALER_Amount balance,
- struct GNUNET_TIME_Absolute expiration);
+ const struct ReserveHistory *rh);
/**
diff --git a/src/util/amount.c b/src/util/amount.c
index bb5bf0d5b..65fac78e3 100644
--- a/src/util/amount.c
+++ b/src/util/amount.c
@@ -19,6 +19,12 @@
* @author Sree Harsha Totakura <sreeharsha@totakura.in>
* @author Florian Dold
* @author Benedikt Mueller
+ *
+ * TODO:
+ * - the way this library currently deals with underflow/overflow
+ * is insufficient; just going for UINT32_MAX on overflow
+ * will not do; similar issues for incompatible currencies;
+ * we need some more explicit logic to say 'bogus value',
*/
#include "platform.h"
#include "taler_util.h"
@@ -169,7 +175,8 @@ TALER_amount_ntoh (struct TALER_AmountNBO dn)
* @return result of the comparison
*/
int
-TALER_amount_cmp (struct TALER_Amount a1, struct TALER_Amount a2)
+TALER_amount_cmp (struct TALER_Amount a1,
+ struct TALER_Amount a2)
{
a1 = TALER_amount_normalize (a1);
a2 = TALER_amount_normalize (a2);
@@ -195,7 +202,8 @@ TALER_amount_cmp (struct TALER_Amount a1, struct TALER_Amount a2)
* @return (a1-a2) or 0 if a2>=a1
*/
struct TALER_Amount
-TALER_amount_subtract (struct TALER_Amount a1, struct TALER_Amount a2)
+TALER_amount_subtract (struct TALER_Amount a1,
+ struct TALER_Amount a2)
{
a1 = TALER_amount_normalize (a1);
a2 = TALER_amount_normalize (a2);
@@ -233,7 +241,8 @@ TALER_amount_subtract (struct TALER_Amount a1, struct TALER_Amount a2)
* @return sum of a1 and a2
*/
struct TALER_Amount
-TALER_amount_add (struct TALER_Amount a1, struct TALER_Amount a2)
+TALER_amount_add (struct TALER_Amount a1,
+ struct TALER_Amount a2)
{
a1 = TALER_amount_normalize (a1);
a2 = TALER_amount_normalize (a2);
@@ -243,17 +252,25 @@ TALER_amount_add (struct TALER_Amount a1, struct TALER_Amount a2)
if (0 == a1.currency[0])
{
- memcpy (a2.currency, a1.currency, TALER_CURRENCY_LEN);
+ memcpy (a2.currency,
+ a1.currency,
+ TALER_CURRENCY_LEN);
}
if (0 == a2.currency[0])
{
- memcpy (a1.currency, a2.currency, TALER_CURRENCY_LEN);
+ memcpy (a1.currency,
+ a2.currency,
+ TALER_CURRENCY_LEN);
}
- if (0 != a1.currency[0] && 0 != memcmp (a1.currency, a2.currency, TALER_CURRENCY_LEN))
+ if ( (0 != a1.currency[0]) &&
+ (0 != memcmp (a1.currency,
+ a2.currency,
+ TALER_CURRENCY_LEN)) )
{
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "adding mismatching currencies\n");
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "adding mismatching currencies\n");
}
if (a1.value < a2.value)
@@ -312,11 +329,18 @@ TALER_amount_to_string (struct TALER_Amount amount)
n = (n * 10) % (AMOUNT_FRAC_BASE);
}
tail[i] = 0;
- len = GNUNET_asprintf (&result, "%s:%lu.%s", curr, (unsigned long) amount.value, tail);
+ len = GNUNET_asprintf (&result,
+ "%s:%lu.%s",
+ curr,
+ (unsigned long) amount.value,
+ tail);
}
else
{
- len = GNUNET_asprintf (&result, "%s:%lu", curr, (unsigned long) amount.value);
+ len = GNUNET_asprintf (&result,
+ "%s:%lu",
+ curr,
+ (unsigned long) amount.value);
}
GNUNET_assert (len > 0);
return result;