aboutsummaryrefslogtreecommitdiff
path: root/src/mint
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2015-03-22 16:09:01 +0100
committerChristian Grothoff <christian@grothoff.org>2015-03-22 16:09:01 +0100
commit1277f8445d0497107c5bd41b35007480d6a4472a (patch)
treed6144643860085ba45f66e06748912acc83e6aa9 /src/mint
parentc2a42d5475daf23889c720734edbafc8c2ce4e4f (diff)
include fees in amounts being signed, check available balance on refresh
Diffstat (limited to 'src/mint')
-rw-r--r--src/mint/plugin_mintdb_postgres.c2
-rw-r--r--src/mint/taler-mint-httpd_db.c178
-rw-r--r--src/mint/taler-mint-httpd_db.h2
-rw-r--r--src/mint/taler-mint-httpd_deposit.c6
-rw-r--r--src/mint/taler-mint-httpd_refresh.c10
-rw-r--r--src/mint/taler-mint-httpd_responses.c14
-rw-r--r--src/mint/taler_mintdb_plugin.h28
-rw-r--r--src/mint/test_mint_db.c2
-rw-r--r--src/mint/test_mint_deposits.c8
9 files changed, 149 insertions, 101 deletions
diff --git a/src/mint/plugin_mintdb_postgres.c b/src/mint/plugin_mintdb_postgres.c
index 16b134350..1d7a965cf 100644
--- a/src/mint/plugin_mintdb_postgres.c
+++ b/src/mint/plugin_mintdb_postgres.c
@@ -1401,7 +1401,7 @@ postgres_insert_deposit (void *cls,
&denom_sig_enc);
json_wire_enc = json_dumps (deposit->wire, JSON_COMPACT);
TALER_amount_hton (&amount_nbo,
- &deposit->amount);
+ &deposit->amount_with_fee);
struct TALER_DB_QueryParam params[]= {
TALER_DB_QUERY_PARAM_PTR (&deposit->coin.coin_pub),
TALER_DB_QUERY_PARAM_PTR_SIZED (denom_pub_enc, denom_pub_enc_size),
diff --git a/src/mint/taler-mint-httpd_db.c b/src/mint/taler-mint-httpd_db.c
index d347126d9..b3e239c89 100644
--- a/src/mint/taler-mint-httpd_db.c
+++ b/src/mint/taler-mint-httpd_db.c
@@ -35,6 +35,64 @@
/**
+ * Calculate the total value of all transactions performed.
+ * Stores @a off plus the cost of all transactions in @a tl
+ * in @a ret.
+ *
+ * @param pos transaction list to process
+ * @param off offset to use as the starting value
+ * @param ret where the resulting total is to be stored
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on errors
+ */
+static int
+calculate_transaction_list_totals (struct TALER_MINT_DB_TransactionList *tl,
+ const struct TALER_Amount *off,
+ struct TALER_Amount *ret)
+{
+ struct TALER_Amount spent = *off;
+ struct TALER_MINT_DB_TransactionList *pos;
+
+ for (pos = tl; NULL != pos; pos = pos->next)
+ {
+ switch (pos->type)
+ {
+ case TALER_MINT_DB_TT_DEPOSIT:
+ if (GNUNET_OK !=
+ TALER_amount_add (&spent,
+ &spent,
+ &pos->details.deposit->amount_with_fee))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ break;
+ case TALER_MINT_DB_TT_REFRESH_MELT:
+ if (GNUNET_OK !=
+ TALER_amount_add (&spent,
+ &spent,
+ &pos->details.melt->amount_with_fee))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ 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! (#3625)
+ return GNUNET_SYSERR;
+ }
+ }
+ *ret = spent;
+ return GNUNET_OK;
+}
+
+
+/**
* 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
@@ -50,11 +108,9 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection,
{
struct TALER_MINTDB_Session *session;
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_refresh;
struct MintKeyState *mks;
struct TALER_MINT_DenomKeyIssuePriv *dki;
int ret;
@@ -76,7 +132,7 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection,
&deposit->h_contract,
deposit->transaction_id,
&deposit->merchant_pub,
- &deposit->amount);
+ &deposit->amount_with_fee);
}
mks = TALER_MINT_key_state_acquire ();
dki = TALER_MINT_get_denom_key (mks,
@@ -85,8 +141,6 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection,
&dki->issue.value);
TALER_amount_ntoh (&fee_deposit,
&dki->issue.fee_deposit);
- TALER_amount_ntoh (&fee_refresh,
- &dki->issue.fee_refresh);
TALER_MINT_key_state_release (mks);
if (GNUNET_OK !=
@@ -96,69 +150,29 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection,
GNUNET_break (0);
return TALER_MINT_reply_internal_db_error (connection);
}
+ /* fee for THIS transaction */
+ spent = deposit->amount_with_fee;
+ if (TALER_amount_cmp (&fee_deposit,
+ &spent) < 0)
+ {
+ return (MHD_YES ==
+ TALER_MINT_reply_external_error (connection,
+ "deposited amount smaller than depositing fee"))
+ ? GNUNET_NO : GNUNET_SYSERR;
+ }
+ /* add cost of all previous transactions */
tl = plugin->get_coin_transactions (plugin->cls,
session,
&deposit->coin.coin_pub);
- spent = fee_deposit; /* fee for THIS transaction */
if (GNUNET_OK !=
- TALER_amount_add (&spent,
- &spent,
- &deposit->amount))
+ calculate_transaction_list_totals (tl,
+ &spent,
+ &spent))
{
- GNUNET_break (0);
plugin->free_coin_transaction_list (plugin->cls,
tl);
return TALER_MINT_reply_internal_db_error (connection);
}
-
- for (pos = tl; NULL != pos; pos = pos->next)
- {
- switch (pos->type)
- {
- case TALER_MINT_DB_TT_DEPOSIT:
- if ( (GNUNET_OK !=
- TALER_amount_add (&spent,
- &spent,
- &pos->details.deposit->amount)) ||
- (GNUNET_OK !=
- TALER_amount_add (&spent,
- &spent,
- &fee_deposit)) )
- {
- GNUNET_break (0);
- plugin->free_coin_transaction_list (plugin->cls,
- tl);
- return TALER_MINT_reply_internal_db_error (connection);
- }
- break;
- case TALER_MINT_DB_TT_REFRESH_MELT:
- if ( (GNUNET_OK !=
- TALER_amount_add (&spent,
- &spent,
- &pos->details.melt->amount)) ||
- (GNUNET_OK !=
- TALER_amount_add (&spent,
- &spent,
- &fee_refresh)) )
- {
- GNUNET_break (0);
- plugin->free_coin_transaction_list (plugin->cls,
- tl);
- return TALER_MINT_reply_internal_db_error (connection);
- }
- 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! (#3625)
- break;
- }
- }
-
if (0 < TALER_amount_cmp (&spent,
&value))
{
@@ -197,7 +211,7 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection,
&deposit->h_contract,
deposit->transaction_id,
&deposit->merchant_pub,
- &deposit->amount);
+ &deposit->amount_with_fee);
}
@@ -501,8 +515,11 @@ refresh_accept_melts (struct MHD_Connection *connection,
{
struct TALER_MINT_DenomKeyIssue *dki;
struct TALER_MINT_DB_TransactionList *tl;
+ struct TALER_Amount fee_deposit;
+ struct TALER_Amount fee_refresh;
struct TALER_Amount coin_value;
struct TALER_Amount coin_residual;
+ struct TALER_Amount spent;
struct RefreshMelt melt;
int res;
@@ -518,26 +535,51 @@ refresh_accept_melts (struct MHD_Connection *connection,
"denom not found"))
? GNUNET_NO : GNUNET_SYSERR;
+ TALER_amount_ntoh (&fee_deposit,
+ &dki->fee_deposit);
+ TALER_amount_ntoh (&fee_refresh,
+ &dki->fee_refresh);
TALER_amount_ntoh (&coin_value,
&dki->value);
+ /* fee for THIS transaction; the melt amount includes the fee! */
+ spent = coin_details->melt_amount_with_fee;
+ if (TALER_amount_cmp (&fee_refresh,
+ &spent) < 0)
+ {
+ return (MHD_YES ==
+ TALER_MINT_reply_external_error (connection,
+ "melt amount smaller than melting fee"))
+ ? GNUNET_NO : GNUNET_SYSERR;
+ }
+ /* add historic transaction costs of this coin */
tl = plugin->get_coin_transactions (plugin->cls,
session,
&coin_public_info->coin_pub);
- /* FIXME: #3636: compute how much value is left with this coin and
- compare to `expected_value`! (subtract from "coin_value") */
- coin_residual = coin_value;
+ if (GNUNET_OK !=
+ calculate_transaction_list_totals (tl,
+ &spent,
+ &spent))
+ {
+ GNUNET_break (0);
+ plugin->free_coin_transaction_list (plugin->cls,
+ tl);
+ return TALER_MINT_reply_internal_db_error (connection);
+ }
/* Refuse to refresh when the coin does not have enough money left to
* pay the refreshing fees of the coin. */
-
- if (TALER_amount_cmp (&coin_residual,
- &coin_details->melt_amount) < 0)
+ if (TALER_amount_cmp (&coin_value,
+ &spent) < 0)
{
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_subtract (&coin_residual,
+ &spent,
+ &coin_details->melt_amount_with_fee));
res = (MHD_YES ==
TALER_MINT_reply_refresh_melt_insufficient_funds (connection,
&coin_public_info->coin_pub,
coin_value,
tl,
- coin_details->melt_amount,
+ coin_details->melt_amount_with_fee,
coin_residual))
? GNUNET_NO : GNUNET_SYSERR;
plugin->free_coin_transaction_list (plugin->cls,
@@ -550,7 +592,7 @@ refresh_accept_melts (struct MHD_Connection *connection,
melt.coin = *coin_public_info;
melt.coin_sig = coin_details->melt_sig;
melt.melt_hash = *melt_hash;
- melt.amount = coin_details->melt_amount;
+ melt.amount_with_fee = coin_details->melt_amount_with_fee;
if (GNUNET_OK !=
plugin->insert_refresh_melt (plugin->cls,
session,
diff --git a/src/mint/taler-mint-httpd_db.h b/src/mint/taler-mint-httpd_db.h
index aefbfc424..52e86f898 100644
--- a/src/mint/taler-mint-httpd_db.h
+++ b/src/mint/taler-mint-httpd_db.h
@@ -95,7 +95,7 @@ struct MeltDetails
* This amount includes the fees, so the final amount contributed
* to the melt is this value minus the fee for melting the coin.
*/
- struct TALER_Amount melt_amount;
+ struct TALER_Amount melt_amount_with_fee;
};
diff --git a/src/mint/taler-mint-httpd_deposit.c b/src/mint/taler-mint-httpd_deposit.c
index e411e0d8e..647cd8242 100644
--- a/src/mint/taler-mint-httpd_deposit.c
+++ b/src/mint/taler-mint-httpd_deposit.c
@@ -65,8 +65,8 @@ verify_and_execute_deposit (struct MHD_Connection *connection,
dr.h_contract = deposit->h_contract;
dr.h_wire = deposit->h_wire;
dr.transaction_id = GNUNET_htonll (deposit->transaction_id);
- TALER_amount_hton (&dr.amount,
- &deposit->amount);
+ TALER_amount_hton (&dr.amount_with_fee,
+ &deposit->amount_with_fee);
dr.coin_pub = deposit->coin.coin_pub;
if (GNUNET_OK !=
GNUNET_CRYPTO_ecdsa_verify (TALER_SIGNATURE_WALLET_DEPOSIT,
@@ -167,7 +167,7 @@ parse_and_handle_deposit_request (struct MHD_Connection *connection,
GNUNET_free (wire_enc);
deposit.wire = wire;
- deposit.amount = *amount;
+ deposit.amount_with_fee = *amount;
res = verify_and_execute_deposit (connection,
&deposit);
TALER_MINT_release_parsed_data (spec);
diff --git a/src/mint/taler-mint-httpd_refresh.c b/src/mint/taler-mint-httpd_refresh.c
index d4979288d..602fc67f6 100644
--- a/src/mint/taler-mint-httpd_refresh.c
+++ b/src/mint/taler-mint-httpd_refresh.c
@@ -109,8 +109,8 @@ handle_refresh_melt_binary (struct MHD_Connection *connection,
body.purpose.purpose = htonl (TALER_SIGNATURE_REFRESH_MELT_SESSION);
body.purpose.size = htonl (sizeof (struct RefreshMeltSessionSignature));
body.melt_hash = melt_hash;
- TALER_amount_hton (&body.amount,
- &coin_melt_details->melt_amount);
+ TALER_amount_hton (&body.amount_with_fee,
+ &coin_melt_details->melt_amount_with_fee);
if (GNUNET_OK != GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_REFRESH_MELT_SESSION,
&body.purpose,
@@ -252,7 +252,7 @@ get_coin_public_info (struct MHD_Connection *connection,
? GNUNET_NO : GNUNET_SYSERR;
}
r_melt_detail->melt_sig = melt_sig;
- r_melt_detail->melt_amount = amount;
+ r_melt_detail->melt_amount_with_fee = amount;
TALER_MINT_release_parsed_data (spec);
return GNUNET_OK;
}
@@ -288,8 +288,8 @@ verify_coin_public_info (struct MHD_Connection *connection,
body.purpose.size = htonl (sizeof (struct RefreshMeltCoinSignature));
body.purpose.purpose = htonl (TALER_SIGNATURE_REFRESH_MELT_COIN);
body.melt_hash = *melt_hash;
- TALER_amount_hton (&body.amount,
- &r_melt_detail->melt_amount);
+ TALER_amount_hton (&body.amount_with_fee,
+ &r_melt_detail->melt_amount_with_fee);
body.coin_pub = r_public_info->coin_pub;
if (GNUNET_OK !=
GNUNET_CRYPTO_ecdsa_verify (TALER_SIGNATURE_REFRESH_MELT_COIN,
diff --git a/src/mint/taler-mint-httpd_responses.c b/src/mint/taler-mint-httpd_responses.c
index a4b442152..681b2b922 100644
--- a/src/mint/taler-mint-httpd_responses.c
+++ b/src/mint/taler-mint-httpd_responses.c
@@ -299,7 +299,7 @@ TALER_MINT_reply_deposit_success (struct MHD_Connection *connection,
dc.h_contract = *h_contract;
dc.h_wire = *h_wire;
dc.transaction_id = GNUNET_htonll (transaction_id);
- TALER_amount_hton (&dc.amount,
+ TALER_amount_hton (&dc.amount_with_fee,
amount);
dc.coin_pub = *coin_pub;
dc.merchant = *merchant;
@@ -341,14 +341,14 @@ compile_transaction_history (const struct TALER_MINT_DB_TransactionList *tl)
const struct Deposit *deposit = pos->details.deposit;
type = "deposit";
- value = deposit->amount;
+ value = deposit->amount_with_fee;
dr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_DEPOSIT);
dr.purpose.size = htonl (sizeof (struct TALER_DepositRequest));
dr.h_contract = deposit->h_contract;
dr.h_wire = deposit->h_wire;
dr.transaction_id = GNUNET_htonll (deposit->transaction_id);
- TALER_amount_hton (&dr.amount,
- &deposit->amount);
+ TALER_amount_hton (&dr.amount_with_fee,
+ &deposit->amount_with_fee);
dr.coin_pub = deposit->coin.coin_pub;
transaction = TALER_JSON_from_ecdsa_sig (&dr.purpose,
&deposit->csig);
@@ -360,12 +360,12 @@ compile_transaction_history (const struct TALER_MINT_DB_TransactionList *tl)
const struct RefreshMelt *melt = pos->details.melt;
type = "melt";
- value = melt->amount;
+ value = melt->amount_with_fee;
ms.purpose.purpose = htonl (TALER_SIGNATURE_REFRESH_MELT_COIN);
ms.purpose.size = htonl (sizeof (struct RefreshMeltCoinSignature));
ms.melt_hash = melt->melt_hash;
- TALER_amount_hton (&ms.amount,
- &melt->amount);
+ TALER_amount_hton (&ms.amount_with_fee,
+ &melt->amount_with_fee);
ms.coin_pub = melt->coin.coin_pub;
transaction = TALER_JSON_from_ecdsa_sig (&ms.purpose,
&melt->coin_sig);
diff --git a/src/mint/taler_mintdb_plugin.h b/src/mint/taler_mintdb_plugin.h
index bc5cd69a6..83e373340 100644
--- a/src/mint/taler_mintdb_plugin.h
+++ b/src/mint/taler_mintdb_plugin.h
@@ -14,13 +14,13 @@
TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
*/
/**
- * @file mint/mint_db.h
+ * @file mint/taler_mintdb_plugin.h
* @brief Low-level (statement-level) database access for the mint
* @author Florian Dold
* @author Christian Grothoff
*/
-#ifndef MINT_DB_H
-#define MINT_DB_H
+#ifndef TALER_MINTDB_PLUGIN_H
+#define TALER_MINTDB_PLUGIN_H
#include <gnunet/gnunet_util_lib.h>
#include "taler_util.h"
@@ -87,6 +87,9 @@ struct CollectableBlindcoin
/**
* Denomination key (which coin was generated).
+ * FIXME: we should probably instead have the
+ * AMOUNT *including* fee in what is being signed
+ * as well!
*/
struct GNUNET_CRYPTO_rsa_PublicKey *denom_pub;
@@ -217,10 +220,10 @@ struct Deposit
uint64_t transaction_id;
/**
- * Fraction of the coin's remaining value to be deposited.
- * The coin is identified by @e coin_pub.
+ * Fraction of the coin's remaining value to be deposited, including
+ * depositing fee (if any). The coin is identified by @e coin_pub.
*/
- struct TALER_Amount amount;
+ struct TALER_Amount amount_with_fee;
};
@@ -296,11 +299,14 @@ struct RefreshMelt
struct GNUNET_HashCode melt_hash;
/**
- * How much value is being melted?
- * This amount includes the fees, so the final amount contributed
- * to the melt is this value minus the fee for melting the coin.
+ * How much value is being melted? This amount includes the fees,
+ * so the final amount contributed to the melt is this value minus
+ * the fee for melting the coin. We include the fee in what is
+ * being signed so that we can verify a reserve's remaining total
+ * balance without needing to access the respective denomination key
+ * information each time.
*/
- struct TALER_Amount amount;
+ struct TALER_Amount amount_with_fee;
};
@@ -397,7 +403,7 @@ struct Lock
const struct GNUNET_CRYPTO_EcdsaSignature coin_sig;
/**
- * How much value is being melted?
+ * How much value is being locked?
*/
struct TALER_Amount amount;
diff --git a/src/mint/test_mint_db.c b/src/mint/test_mint_db.c
index e4d312927..c80be70c3 100644
--- a/src/mint/test_mint_db.c
+++ b/src/mint/test_mint_db.c
@@ -286,7 +286,7 @@ run (void *cls,
deposit.wire = wire;
deposit.transaction_id =
GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
- deposit.amount = amount;
+ deposit.amount_with_fee = amount;
FAILIF (GNUNET_OK !=
plugin->insert_deposit (plugin->cls,
session, &deposit));
diff --git a/src/mint/test_mint_deposits.c b/src/mint/test_mint_deposits.c
index c829e6e10..4107c1aee 100644
--- a/src/mint/test_mint_deposits.c
+++ b/src/mint/test_mint_deposits.c
@@ -94,12 +94,12 @@ run (void *cls,
UINT64_MAX);
deposit->transaction_id = GNUNET_htonll (transaction_id);
/* Random amount */
- deposit->amount.value =
+ deposit->amount_with_fee.value =
htonl (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX));
- deposit->amount.fraction =
+ deposit->amount_with_fee.fraction =
htonl (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX));
- GNUNET_assert (strlen (MINT_CURRENCY) < sizeof (deposit->amount.currency));
- strcpy (deposit->amount.currency, MINT_CURRENCY);
+ GNUNET_assert (strlen (MINT_CURRENCY) < sizeof (deposit->amount_with_fee.currency));
+ strcpy (deposit->amount_with_fee.currency, MINT_CURRENCY);
/* Copy wireformat */
deposit->wire = json_loads (wire, 0, NULL);
EXITIF (GNUNET_OK !=