summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/exchange/taler-exchange-httpd_db.c115
-rw-r--r--src/exchange/taler-exchange-httpd_db.h6
-rw-r--r--src/exchange/taler-exchange-httpd_payback.c31
-rw-r--r--src/exchange/taler-exchange-httpd_responses.c65
-rw-r--r--src/exchange/taler-exchange-httpd_responses.h43
-rw-r--r--src/include/taler_error_codes.h65
6 files changed, 290 insertions, 35 deletions
diff --git a/src/exchange/taler-exchange-httpd_db.c b/src/exchange/taler-exchange-httpd_db.c
index cac700ab8..fe92d76bb 100644
--- a/src/exchange/taler-exchange-httpd_db.c
+++ b/src/exchange/taler-exchange-httpd_db.c
@@ -242,6 +242,8 @@ TEH_DB_execute_deposit (struct MHD_Connection *connection,
&deposit->merchant_pub,
&amount_without_fee);
}
+
+ /* FIXME: move the 'mks'-logic outside of _db.c? */
mks = TEH_KS_acquire ();
dki = TEH_KS_denomination_key_lookup (mks,
&deposit->coin.denom_pub,
@@ -250,7 +252,7 @@ TEH_DB_execute_deposit (struct MHD_Connection *connection,
{
TEH_KS_release (mks);
return TEH_RESPONSE_reply_internal_db_error (connection,
- TALER_EC_DEPOSIT_DB_DENOMINATION_KEY_UNKNOWN);
+ TALER_EC_DEPOSIT_DB_DENOMINATION_KEY_UNKNOWN);
}
TALER_amount_ntoh (&value,
&dki->issue.properties.value);
@@ -283,8 +285,9 @@ TEH_DB_execute_deposit (struct MHD_Connection *connection,
{
TEH_plugin->rollback (TEH_plugin->cls,
session);
- ret = TEH_RESPONSE_reply_deposit_insufficient_funds (connection,
- tl);
+ ret = TEH_RESPONSE_reply_coin_insufficient_funds (connection,
+ TALER_EC_DEPOSIT_INSUFFICIENT_FUNDS,
+ tl);
TEH_plugin->free_coin_transaction_list (TEH_plugin->cls,
tl);
return ret;
@@ -2264,18 +2267,114 @@ TEH_DB_execute_track_transaction (struct MHD_Connection *connection,
*
* @param connection the MHD connection to handle
* @param coin information about the coin
- * @param coin_bks blinding data of the coin (to be checked)
- * @param coin_sig signature of the coin
+ * @param value how much are coins of the @a coin's denomination worth?
+ * @param h_blind blinded coin to use for the lookup
+ * @param coin_sig signature of the coin (to be stored)
* @return MHD result code
*/
int
TEH_DB_execute_payback (struct MHD_Connection *connection,
const struct TALER_CoinPublicInfo *coin,
- const struct TALER_DenominationBlindingKeyP *coin_bks,
+ const struct TALER_Amount *value,
+ const struct GNUNET_HashCode *h_blind,
const struct TALER_CoinSpendSignatureP *coin_sig)
{
- GNUNET_break (0); /* not implemented (#3887) */
- return MHD_NO;
+ int ret;
+ struct TALER_EXCHANGEDB_Session *session;
+ struct TALER_EXCHANGEDB_TransactionList *tl;
+ struct TALER_EXCHANGEDB_CollectableBlindcoin collectable;
+ char wire_subject[42]; // FIXME: size? (#3887)
+ struct TALER_Amount amount;
+ struct TALER_Amount spent;
+ struct GNUNET_TIME_Absolute payback_deadline;
+
+ if (NULL == (session = TEH_plugin->get_session (TEH_plugin->cls)))
+ {
+ GNUNET_break (0);
+ return TEH_RESPONSE_reply_internal_db_error (connection,
+ TALER_EC_DB_SETUP_FAILED);
+ }
+
+ START_TRANSACTION (session, connection);
+
+ /* FIXME (#3887): not _exactly_ the right call, we need to get the
+ reserve's incoming wire transfer data, not 'collectable' */
+ ret = TEH_plugin->get_withdraw_info (TEH_plugin->cls,
+ session,
+ h_blind,
+ &collectable);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_break (0);
+ TEH_plugin->rollback (TEH_plugin->cls,
+ session);
+ return TEH_RESPONSE_reply_internal_db_error (connection,
+ TALER_EC_PAYBACK_DB_FETCH_FAILED);
+ }
+ if (GNUNET_NO == ret)
+ {
+ GNUNET_break_op (0);
+ TEH_plugin->rollback (TEH_plugin->cls,
+ session);
+ return TEH_RESPONSE_reply_payback_unknown (connection,
+ TALER_EC_PAYBACK_WITHDRAW_NOT_FOUND);
+ }
+
+ /* Calculate remaining balance. */
+ tl = TEH_plugin->get_coin_transactions (TEH_plugin->cls,
+ session,
+ &coin->coin_pub);
+ TALER_amount_get_zero (value->currency,
+ &spent);
+ if (GNUNET_OK !=
+ calculate_transaction_list_totals (tl,
+ &spent,
+ &spent))
+ {
+ GNUNET_break (0);
+ TEH_plugin->rollback (TEH_plugin->cls,
+ session);
+ TEH_plugin->free_coin_transaction_list (TEH_plugin->cls,
+ tl);
+ return TEH_RESPONSE_reply_internal_db_error (connection,
+ TALER_EC_PAYBACK_HISTORY_DB_ERROR);
+ }
+ TALER_amount_subtract (&amount,
+ value,
+ &spent);
+ if ( (0 == amount.fraction) &&
+ (0 == amount.value) )
+ {
+ GNUNET_break_op (0);
+ TEH_plugin->rollback (TEH_plugin->cls,
+ session);
+ ret = TEH_RESPONSE_reply_coin_insufficient_funds (connection,
+ TALER_EC_PAYBACK_COIN_BALANCE_ZERO,
+ tl);
+ TEH_plugin->free_coin_transaction_list (TEH_plugin->cls,
+ tl);
+ return ret;
+ }
+ TEH_plugin->free_coin_transaction_list (TEH_plugin->cls,
+ tl);
+
+ /* FIXME: add coin to list of wire transfers for payback */
+ // ret = TEH_plugin->(); // #3887
+ if (GNUNET_SYSERR == ret)
+ {
+ TALER_LOG_WARNING ("Failed to store /payback information in database\n");
+ TEH_plugin->rollback (TEH_plugin->cls,
+ session);
+ return TEH_RESPONSE_reply_internal_db_error (connection,
+ TALER_EC_PAYBACK_DB_PUT_FAILED);
+ }
+
+ COMMIT_TRANSACTION(session, connection);
+
+ return TEH_RESPONSE_reply_payback_success (connection,
+ wire_subject,
+ &amount,
+ payback_deadline);
}
diff --git a/src/exchange/taler-exchange-httpd_db.h b/src/exchange/taler-exchange-httpd_db.h
index 67c8665f2..520a6f59e 100644
--- a/src/exchange/taler-exchange-httpd_db.h
+++ b/src/exchange/taler-exchange-httpd_db.h
@@ -244,14 +244,16 @@ TEH_DB_execute_track_transaction (struct MHD_Connection *connection,
*
* @param connection the MHD connection to handle
* @param coin information about the coin
- * @param coin_bks blinding data of the coin (to be checked)
+ * @param value how much are coins of the @a coin's denomination worth?
+ * @param h_blind blinded coin to use for the lookup
* @param coin_sig signature of the coin
* @return MHD result code
*/
int
TEH_DB_execute_payback (struct MHD_Connection *connection,
const struct TALER_CoinPublicInfo *coin,
- const struct TALER_DenominationBlindingKeyP *coin_bks,
+ const struct TALER_Amount *value,
+ const struct GNUNET_HashCode *h_blind,
const struct TALER_CoinSpendSignatureP *coin_sig);
diff --git a/src/exchange/taler-exchange-httpd_payback.c b/src/exchange/taler-exchange-httpd_payback.c
index 2b33112d3..31235729e 100644
--- a/src/exchange/taler-exchange-httpd_payback.c
+++ b/src/exchange/taler-exchange-httpd_payback.c
@@ -56,7 +56,11 @@ verify_and_execute_payback (struct MHD_Connection *connection,
struct TEH_KS_StateHandle *key_state;
const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki;
struct TALER_PaybackRequestPS pr;
-
+ struct TALER_Amount value;
+ struct GNUNET_HashCode h_blind;
+ struct GNUNET_HashCode c_hash;
+ char *coin_ev;
+ size_t coin_ev_size;
/* check denomination exists and is in payback mode */
key_state = TEH_KS_acquire ();
@@ -71,6 +75,8 @@ verify_and_execute_payback (struct MHD_Connection *connection,
TALER_EC_PAYBACK_DENOMINATION_KEY_UNKNOWN,
"denom_pub");
}
+ TALER_amount_ntoh (&value,
+ &dki->issue.properties.value);
/* check denomination signature */
if (GNUNET_YES !=
@@ -104,9 +110,30 @@ verify_and_execute_payback (struct MHD_Connection *connection,
"coin_sig");
}
+ GNUNET_CRYPTO_hash (&coin->coin_pub.eddsa_pub,
+ sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
+ &c_hash);
+ if (GNUNET_YES !=
+ GNUNET_CRYPTO_rsa_blind (&c_hash,
+ &coin_bks->bks,
+ coin->denom_pub.rsa_public_key,
+ &coin_ev,
+ &coin_ev_size))
+ {
+ GNUNET_break (0);
+ return TEH_RESPONSE_reply_internal_error (connection,
+ TALER_EC_PAYBACK_BLINDING_FAILED,
+ "coin_bks");
+ }
+ GNUNET_CRYPTO_hash (coin_ev,
+ coin_ev_size,
+ &h_blind);
+ GNUNET_free (coin_ev);
+
return TEH_DB_execute_payback (connection,
coin,
- coin_bks,
+ &value,
+ &h_blind,
coin_sig);
}
diff --git a/src/exchange/taler-exchange-httpd_responses.c b/src/exchange/taler-exchange-httpd_responses.c
index 1caef3469..c78462532 100644
--- a/src/exchange/taler-exchange-httpd_responses.c
+++ b/src/exchange/taler-exchange-httpd_responses.c
@@ -436,6 +436,11 @@ compile_transaction_history (const struct TALER_EXCHANGEDB_TransactionList *tl)
const struct TALER_EXCHANGEDB_TransactionList *pos;
history = json_array ();
+ if (NULL == history)
+ {
+ GNUNET_break (0); /* out of memory!? */
+ return NULL;
+ }
for (pos = tl; NULL != pos; pos = pos->next)
{
switch (pos->type)
@@ -562,29 +567,33 @@ compile_transaction_history (const struct TALER_EXCHANGEDB_TransactionList *tl)
/**
- * Send proof that a /deposit 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.
+ * Send proof that a request is invalid to client because of
+ * insufficient funds. 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 ec error code to return
* @param tl transaction list to use to build reply
* @return MHD result code
*/
int
-TEH_RESPONSE_reply_deposit_insufficient_funds (struct MHD_Connection *connection,
- const struct TALER_EXCHANGEDB_TransactionList *tl)
+TEH_RESPONSE_reply_coin_insufficient_funds (struct MHD_Connection *connection,
+ enum TALER_ErrorCode ec,
+ const struct TALER_EXCHANGEDB_TransactionList *tl)
{
json_t *history;
history = compile_transaction_history (tl);
if (NULL == history)
- return TEH_RESPONSE_reply_internal_db_error (connection,
- TALER_EC_DEPOSIT_HISTORY_DB_ERROR_INSUFFICIENT_FUNDS);
+ return TEH_RESPONSE_reply_internal_error (connection,
+ TALER_EC_COIN_HISTORY_DB_ERROR_INSUFFICIENT_FUNDS,
+ "failed to convert transaction history to JSON");
return TEH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_FORBIDDEN,
"{s:s, s:I, s:o}",
"error", "insufficient funds",
- "code", (json_int_t) TALER_EC_DEPOSIT_INSUFFICIENT_FUNDS,
+ "code", (json_int_t) ec,
"history", history);
}
@@ -1286,4 +1295,44 @@ TEH_RESPONSE_reply_track_transfer_details (struct MHD_Connection *connection,
}
+
+/**
+ * A wallet asked for /payback, but we do not know anything
+ * about the original withdraw operation given. Generates a
+ * 404 reply.
+ *
+ * @param connection connection to the client
+ * @param ec Taler error code
+ * @return MHD result code
+ */
+int
+TEH_RESPONSE_reply_payback_unknown (struct MHD_Connection *connection,
+ enum TALER_ErrorCode ec)
+{
+ GNUNET_break (0); /* #3887 */
+ return MHD_NO;
+}
+
+
+/**
+ * A wallet asked for /payback, return the successful response.
+ *
+ * @param connection connection to the client
+ * @param wire_subject the wire subject we will use for the pay back operation
+ * @param amount the amount we will wire back
+ * @param payback_deadline deadline by which the exchange promises to pay
+ * @return MHD result code
+ */
+int
+TEH_RESPONSE_reply_payback_success (struct MHD_Connection *connection,
+ const char *wire_subject,
+ const struct TALER_Amount *amount,
+ struct GNUNET_TIME_Absolute payback_deadline)
+{
+ GNUNET_break (0); /* #3887 */
+ return MHD_NO;
+}
+
+
+
/* end of taler-exchange-httpd_responses.c */
diff --git a/src/exchange/taler-exchange-httpd_responses.h b/src/exchange/taler-exchange-httpd_responses.h
index 179ae0066..27b20d353 100644
--- a/src/exchange/taler-exchange-httpd_responses.h
+++ b/src/exchange/taler-exchange-httpd_responses.h
@@ -250,17 +250,20 @@ TEH_RESPONSE_reply_deposit_success (struct MHD_Connection *connection,
/**
- * Send proof that a /deposit 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.
+ * Send proof that a request is invalid to client because of
+ * insufficient funds. 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 ec error code to return
* @param tl transaction list to use to build reply
* @return MHD result code
*/
int
-TEH_RESPONSE_reply_deposit_insufficient_funds (struct MHD_Connection *connection,
- const struct TALER_EXCHANGEDB_TransactionList *tl);
+TEH_RESPONSE_reply_coin_insufficient_funds (struct MHD_Connection *connection,
+ enum TALER_ErrorCode ec,
+ const struct TALER_EXCHANGEDB_TransactionList *tl);
/**
@@ -556,4 +559,34 @@ TEH_RESPONSE_reply_refresh_link_success (struct MHD_Connection *connection,
const struct TEH_RESPONSE_LinkSessionInfo *sessions);
+/**
+ * A wallet asked for /payback, but we do not know anything
+ * about the original withdraw operation given. Generates a
+ * 404 reply.
+ *
+ * @param connection connection to the client
+ * @param ec Taler error code
+ * @return MHD result code
+ */
+int
+TEH_RESPONSE_reply_payback_unknown (struct MHD_Connection *connection,
+ enum TALER_ErrorCode ec);
+
+
+/**
+ * A wallet asked for /payback, return the successful response.
+ *
+ * @param connection connection to the client
+ * @param wire_subject the wire subject we will use for the pay back operation
+ * @param amount the amount we will wire back
+ * @param payback_deadline deadline by which the exchange promises to pay
+ * @return MHD result code
+ */
+int
+TEH_RESPONSE_reply_payback_success (struct MHD_Connection *connection,
+ const char *wire_subject,
+ const struct TALER_Amount *amount,
+ struct GNUNET_TIME_Absolute payback_deadline);
+
+
#endif
diff --git a/src/include/taler_error_codes.h b/src/include/taler_error_codes.h
index 3c48a6d44..84240c295 100644
--- a/src/include/taler_error_codes.h
+++ b/src/include/taler_error_codes.h
@@ -128,6 +128,17 @@ enum TALER_ErrorCode
*/
TALER_EC_PARAMETER_MALFORMED = 1009,
+ /**
+ * The exchange failed to obtain the transaction history of the
+ * given coin from the database while generating an insufficient
+ * funds errors. This can happen during /deposit or /payback requests.
+ * This response is provided with HTTP status code
+ * MHD_HTTP_INTERNAL_SERVER_ERROR.
+ */
+ TALER_EC_COIN_HISTORY_DB_ERROR_INSUFFICIENT_FUNDS = 1010,
+
+
+
/* ********** request-specific error codes ************* */
/**
@@ -230,7 +241,7 @@ enum TALER_ErrorCode
/**
* The exchange failed to obtain the transaction history of the
* given reserve from the database while generating an insufficient
- * funds errors.
+ * funds error.
* This response is provided with HTTP status code
* MHD_HTTP_INTERNAL_SERVER_ERROR.
*/
@@ -350,15 +361,6 @@ enum TALER_ErrorCode
TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_CONTRACT_HASH_CONFLICT = 1211,
/**
- * The exchange failed to obtain the transaction history of the
- * given coin from the database while generating an insufficient
- * funds errors.
- * This response is provided with HTTP status code
- * MHD_HTTP_INTERNAL_SERVER_ERROR.
- */
- TALER_EC_DEPOSIT_HISTORY_DB_ERROR_INSUFFICIENT_FUNDS = 1212,
-
- /**
* The exchange detected that the given account number
* is invalid for the selected wire format type.
* This response is provided
@@ -852,6 +854,49 @@ enum TALER_ErrorCode
*/
TALER_EC_PAYBACK_DENOMINATION_SIGNATURE_INVALID = 1852,
+ /**
+ * The exchange failed to access its own database about reserves.
+ * This response is provided with HTTP status code
+ * MHD_HTTP_INTERNAL_SERVER_ERROR.
+ */
+ TALER_EC_PAYBACK_DB_FETCH_FAILED = 1853,
+
+ /**
+ * The exchange could not find the corresponding withdraw operation.
+ * The request is denied. This response is provided with an HTTP
+ * status code of MHD_HTTP_NOT_FOUND.
+ */
+ TALER_EC_PAYBACK_WITHDRAW_NOT_FOUND = 1854,
+
+ /**
+ * The exchange obtained an internally inconsistent transaction
+ * history for the given coin. This response is provided with HTTP
+ * status code MHD_HTTP_INTERNAL_SERVER_ERROR.
+ */
+ TALER_EC_PAYBACK_HISTORY_DB_ERROR = 1855,
+
+ /**
+ * The exchange failed to store information about the payback to be
+ * performed in the database. This response is provided with HTTP
+ * status code MHD_HTTP_INTERNAL_SERVER_ERROR.
+ */
+ TALER_EC_PAYBACK_DB_PUT_FAILED = 1856,
+
+ /**
+ * The coin's remaining balance is zero. The request is denied.
+ * This response is provided with an HTTP status code of
+ * MHD_HTTP_FORBIDDEN.
+ */
+ TALER_EC_PAYBACK_COIN_BALANCE_ZERO = 1857,
+
+ /**
+ * The exchange failed to reproduce the coin's blinding.
+ * This response is provided with an HTTP status code of
+ * MHD_HTTP_INTERNAL_SERVER_ERROR.
+ */
+ TALER_EC_PAYBACK_BLINDING_FAILED = 1858,
+
+
/* *********** Merchant backend error codes ********* */