towards proper implementation of /withdraw/status
This commit is contained in:
parent
b162d2e458
commit
8adde040ab
@ -42,6 +42,7 @@
|
||||
struct TALER_MINT_SignKeyIssuePriv
|
||||
{
|
||||
struct GNUNET_CRYPTO_EddsaPrivateKey signkey_priv;
|
||||
|
||||
struct TALER_MINT_SignKeyIssue issue;
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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 */
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user