towards proper implementation of /withdraw/status

This commit is contained in:
Christian Grothoff 2015-01-29 00:09:48 +01:00
parent b162d2e458
commit 8adde040ab
7 changed files with 495 additions and 325 deletions

View File

@ -42,6 +42,7 @@
struct TALER_MINT_SignKeyIssuePriv
{
struct GNUNET_CRYPTO_EddsaPrivateKey signkey_priv;
struct TALER_MINT_SignKeyIssue issue;
};

View File

@ -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;
@ -1834,6 +1715,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.
*
@ -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);
}

View File

@ -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.
*/

View File

@ -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>
@ -42,6 +61,26 @@
#include "taler-mint-httpd_keystate.h"
/**
* 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
@ -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 */

View File

@ -308,32 +308,133 @@ 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,

View File

@ -181,18 +181,31 @@ TALER_MINT_reply_deposit_success (struct MHD_Connection *connection,
const struct TALER_Amount *amount);
/**
* 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);
/**

View File

@ -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;