fix #3716: make sure amount-API offers proper checks against overflow and other issues
This commit is contained in:
parent
08958c73e8
commit
23bf1eee74
@ -25,10 +25,27 @@
|
|||||||
/**
|
/**
|
||||||
* Number of characters (plus 1 for 0-termination) we use to
|
* Number of characters (plus 1 for 0-termination) we use to
|
||||||
* represent currency names (i.e. EUR, USD, etc.). We use
|
* represent currency names (i.e. EUR, USD, etc.). We use
|
||||||
* 8 for alignment (!).
|
* 4 for alignment as 3 characters are typical and we need a
|
||||||
|
* 0-terminator. So do not change this.
|
||||||
*/
|
*/
|
||||||
#define TALER_CURRENCY_LEN 4
|
#define TALER_CURRENCY_LEN 4
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The "fraction" value in a `struct TALER_Amount` represents which
|
||||||
|
* fraction of the "main" value?
|
||||||
|
*
|
||||||
|
* Note that we need sub-cent precision here as transaction fees might
|
||||||
|
* be that low, and as we want to support microdonations.
|
||||||
|
*/
|
||||||
|
#define TALER_AMOUNT_FRAC_BASE 1000000
|
||||||
|
|
||||||
|
/**
|
||||||
|
* How many digits behind the comma are required to represent the
|
||||||
|
* fractional value in human readable decimal format? Must match
|
||||||
|
* lg(#TALER_AMOUNT_FRAC_BASE).
|
||||||
|
*/
|
||||||
|
#define TALER_AMOUNT_FRAC_LEN 6
|
||||||
|
|
||||||
|
|
||||||
GNUNET_NETWORK_STRUCT_BEGIN
|
GNUNET_NETWORK_STRUCT_BEGIN
|
||||||
|
|
||||||
@ -41,12 +58,12 @@ struct TALER_AmountNBO
|
|||||||
/**
|
/**
|
||||||
* Value in the main currency, in NBO.
|
* Value in the main currency, in NBO.
|
||||||
*/
|
*/
|
||||||
uint32_t value;
|
uint64_t value GNUNET_PACKED;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Additinal fractional value, in NBO.
|
* Additinal fractional value, in NBO.
|
||||||
*/
|
*/
|
||||||
uint32_t fraction;
|
uint32_t fraction GNUNET_PACKED;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Type of the currency being represented.
|
* Type of the currency being represented.
|
||||||
@ -65,7 +82,7 @@ struct TALER_Amount
|
|||||||
/**
|
/**
|
||||||
* Value (numerator of fraction)
|
* Value (numerator of fraction)
|
||||||
*/
|
*/
|
||||||
uint32_t value;
|
uint64_t value;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fraction (denominator of fraction)
|
* Fraction (denominator of fraction)
|
||||||
@ -73,7 +90,8 @@ struct TALER_Amount
|
|||||||
uint32_t fraction;
|
uint32_t fraction;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Currency string, left adjusted and padded with zeros.
|
* Currency string, left adjusted and padded with zeros. All zeros
|
||||||
|
* for "invalid" values.
|
||||||
*/
|
*/
|
||||||
char currency[TALER_CURRENCY_LEN];
|
char currency[TALER_CURRENCY_LEN];
|
||||||
};
|
};
|
||||||
@ -92,82 +110,123 @@ TALER_string_to_amount (const char *str,
|
|||||||
struct TALER_Amount *denom);
|
struct TALER_Amount *denom);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value of "zero" in a particular currency.
|
||||||
|
*
|
||||||
|
* @param cur currency description
|
||||||
|
* @param denom denomination to write the result to
|
||||||
|
* @return #GNUNET_OK if @a cur is a valid currency specification,
|
||||||
|
* #GNUNET_SYSERR if it is invalid.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
TALER_amount_get_zero (const char *cur,
|
||||||
|
struct TALER_Amount *denom);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert amount from host to network representation.
|
* Convert amount from host to network representation.
|
||||||
*
|
*
|
||||||
|
* @param res where to store amount in network representation
|
||||||
* @param d amount in host representation
|
* @param d amount in host representation
|
||||||
* @return amount in network representation
|
|
||||||
*/
|
*/
|
||||||
struct TALER_AmountNBO
|
void
|
||||||
TALER_amount_hton (const struct TALER_Amount d);
|
TALER_amount_hton (struct TALER_AmountNBO *res,
|
||||||
|
const struct TALER_Amount *d);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert amount from network to host representation.
|
* Convert amount from network to host representation.
|
||||||
*
|
*
|
||||||
|
* @param res where to store amount in host representation
|
||||||
* @param d amount in network representation
|
* @param d amount in network representation
|
||||||
* @return amount in host representation
|
|
||||||
*/
|
*/
|
||||||
struct TALER_Amount
|
void
|
||||||
TALER_amount_ntoh (const struct TALER_AmountNBO dn);
|
TALER_amount_ntoh (struct TALER_Amount *res,
|
||||||
|
const struct TALER_AmountNBO *dn);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compare the value/fraction of two amounts. Does not compare the currency,
|
* Compare the value/fraction of two amounts. Does not compare the currency.
|
||||||
* i.e. comparing amounts with the same value and fraction but different
|
* Comparing amounts of different currencies will cause the program to abort().
|
||||||
* currency would return 0.
|
* If unsure, check with #TALER_amount_cmp_currency() first to be sure that
|
||||||
|
* the currencies of the two amounts are identical.
|
||||||
*
|
*
|
||||||
* @param a1 first amount
|
* @param a1 first amount
|
||||||
* @param a2 second amount
|
* @param a2 second amount
|
||||||
* @return result of the comparison
|
* @return result of the comparison
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
TALER_amount_cmp (struct TALER_Amount a1,
|
TALER_amount_cmp (const struct TALER_Amount *a1,
|
||||||
struct TALER_Amount a2);
|
const struct TALER_Amount *a2);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test if @a a1 and @a a2 are the same currency.
|
||||||
|
*
|
||||||
|
* @param a1 amount to test
|
||||||
|
* @param a2 amount to test
|
||||||
|
* @return #GNUNET_YES if @a a1 and @a a2 are the same currency
|
||||||
|
* #GNUNET_NO if the currencies are different
|
||||||
|
* #GNUNET_SYSERR if either amount is invalid
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
TALER_amount_cmp_currency (const struct TALER_Amount *a1,
|
||||||
|
const struct TALER_Amount *a2);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform saturating subtraction of amounts.
|
* Perform saturating subtraction of amounts.
|
||||||
*
|
*
|
||||||
|
* @param diff where to store (@a a1 - @a a2), or invalid if @a a2 > @a a1
|
||||||
* @param a1 amount to subtract from
|
* @param a1 amount to subtract from
|
||||||
* @param a2 amount to subtract
|
* @param a2 amount to subtract
|
||||||
* @return (a1-a2) or 0 if a2>=a1
|
* @return #GNUNET_OK if the subtraction worked,
|
||||||
|
* #GNUNET_NO if @a a1 = @a a2
|
||||||
|
* #GNUNET_SYSERR if @a a2 > @a a1 or currencies are incompatible;
|
||||||
|
* @a diff is set to invalid
|
||||||
*/
|
*/
|
||||||
struct TALER_Amount
|
int
|
||||||
TALER_amount_subtract (struct TALER_Amount a1,
|
TALER_amount_subtract (struct TALER_Amount *diff,
|
||||||
struct TALER_Amount a2);
|
const struct TALER_Amount *a1,
|
||||||
|
const struct TALER_Amount *a2);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform saturating addition of amounts
|
* Perform addition of amounts.
|
||||||
*
|
*
|
||||||
|
* @param sum where to store @a a1 + @a a2, set to "invalid" on overflow
|
||||||
* @param a1 first amount to add
|
* @param a1 first amount to add
|
||||||
* @param a2 second amount to add
|
* @param a2 second amount to add
|
||||||
* @return sum of a1 and a2
|
* @return #GNUNET_OK if the addition worked,
|
||||||
|
* #GNUNET_SYSERR on overflow
|
||||||
*/
|
*/
|
||||||
struct TALER_Amount
|
int
|
||||||
TALER_amount_add (struct TALER_Amount a1,
|
TALER_amount_add (struct TALER_Amount *sum,
|
||||||
struct TALER_Amount a2);
|
const struct TALER_Amount *a1,
|
||||||
|
const struct TALER_Amount *a2);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Normalize the given amount.
|
* Normalize the given amount.
|
||||||
*
|
*
|
||||||
* @param amout amount to normalize
|
* @param amount amount to normalize
|
||||||
* @return normalized amount
|
* @return #GNUNET_OK if normalization worked
|
||||||
|
* #GNUNET_NO if value was already normalized
|
||||||
|
* #GNUNET_SYSERR if value was invalid or could not be normalized
|
||||||
*/
|
*/
|
||||||
struct TALER_Amount
|
int
|
||||||
TALER_amount_normalize (struct TALER_Amount amount);
|
TALER_amount_normalize (struct TALER_Amount *amount);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert amount to string.
|
* Convert amount to string.
|
||||||
*
|
*
|
||||||
* @param amount amount to convert to string
|
* @param amount amount to convert to string
|
||||||
* @return freshly allocated string representation
|
* @return freshly allocated string representation,
|
||||||
|
* NULL if the @a amount was invalid
|
||||||
*/
|
*/
|
||||||
char *
|
char *
|
||||||
TALER_amount_to_string (struct TALER_Amount amount);
|
TALER_amount_to_string (const struct TALER_Amount *amount);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -39,7 +39,7 @@
|
|||||||
* @return a json object describing the amount
|
* @return a json object describing the amount
|
||||||
*/
|
*/
|
||||||
json_t *
|
json_t *
|
||||||
TALER_JSON_from_amount (struct TALER_Amount amount);
|
TALER_JSON_from_amount (const struct TALER_Amount *amount);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -412,10 +412,14 @@ parse_json_denomkey (struct TALER_MINT_DenomPublicKey **_denom_key,
|
|||||||
denom_key_issue.start = GNUNET_TIME_absolute_hton (valid_from);
|
denom_key_issue.start = GNUNET_TIME_absolute_hton (valid_from);
|
||||||
denom_key_issue.expire_withdraw = GNUNET_TIME_absolute_hton (withdraw_valid_until);
|
denom_key_issue.expire_withdraw = GNUNET_TIME_absolute_hton (withdraw_valid_until);
|
||||||
denom_key_issue.expire_spend = GNUNET_TIME_absolute_hton (deposit_valid_until);
|
denom_key_issue.expire_spend = GNUNET_TIME_absolute_hton (deposit_valid_until);
|
||||||
denom_key_issue.value = TALER_amount_hton (value);
|
TALER_amount_hton (&denom_key_issue.value,
|
||||||
denom_key_issue.fee_withdraw = TALER_amount_hton (fee_withdraw);
|
&value);
|
||||||
denom_key_issue.fee_deposit = TALER_amount_hton (fee_deposit);
|
TALER_amount_hton (&denom_key_issue.fee_withdraw,
|
||||||
denom_key_issue.fee_refresh = TALER_amount_hton (fee_refresh);
|
&fee_withdraw);
|
||||||
|
TALER_amount_hton (&denom_key_issue.fee_deposit,
|
||||||
|
&fee_deposit);
|
||||||
|
TALER_amount_hton (&denom_key_issue.fee_refresh,
|
||||||
|
&fee_refresh);
|
||||||
EXITIF (GNUNET_SYSERR ==
|
EXITIF (GNUNET_SYSERR ==
|
||||||
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_DENOM,
|
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_DENOM,
|
||||||
&denom_key_issue.purpose,
|
&denom_key_issue.purpose,
|
||||||
|
@ -807,7 +807,8 @@ reserves_update (PGconn *db,
|
|||||||
TALER_DB_QUERY_PARAM_PTR (&expiry_nbo),
|
TALER_DB_QUERY_PARAM_PTR (&expiry_nbo),
|
||||||
TALER_DB_QUERY_PARAM_END
|
TALER_DB_QUERY_PARAM_END
|
||||||
};
|
};
|
||||||
balance_nbo = TALER_amount_hton (reserve->balance);
|
TALER_amount_hton (&balance_nbo,
|
||||||
|
&reserve->balance);
|
||||||
expiry_nbo = GNUNET_TIME_absolute_hton (reserve->expiry);
|
expiry_nbo = GNUNET_TIME_absolute_hton (reserve->expiry);
|
||||||
result = TALER_DB_exec_prepared (db,
|
result = TALER_DB_exec_prepared (db,
|
||||||
"update_reserve",
|
"update_reserve",
|
||||||
@ -837,7 +838,7 @@ reserves_update (PGconn *db,
|
|||||||
int
|
int
|
||||||
TALER_MINT_DB_reserves_in_insert (PGconn *db,
|
TALER_MINT_DB_reserves_in_insert (PGconn *db,
|
||||||
struct Reserve *reserve,
|
struct Reserve *reserve,
|
||||||
const struct TALER_Amount balance,
|
const struct TALER_Amount *balance,
|
||||||
const struct GNUNET_TIME_Absolute expiry)
|
const struct GNUNET_TIME_Absolute expiry)
|
||||||
{
|
{
|
||||||
struct TALER_AmountNBO balance_nbo;
|
struct TALER_AmountNBO balance_nbo;
|
||||||
@ -862,7 +863,8 @@ TALER_MINT_DB_reserves_in_insert (PGconn *db,
|
|||||||
TALER_MINT_DB_rollback (db);
|
TALER_MINT_DB_rollback (db);
|
||||||
return GNUNET_SYSERR;
|
return GNUNET_SYSERR;
|
||||||
}
|
}
|
||||||
balance_nbo = TALER_amount_hton (balance);
|
TALER_amount_hton (&balance_nbo,
|
||||||
|
balance);
|
||||||
expiry_nbo = GNUNET_TIME_absolute_hton (expiry);
|
expiry_nbo = GNUNET_TIME_absolute_hton (expiry);
|
||||||
if (GNUNET_NO == reserve_exists)
|
if (GNUNET_NO == reserve_exists)
|
||||||
{
|
{
|
||||||
@ -907,19 +909,27 @@ TALER_MINT_DB_reserves_in_insert (PGconn *db,
|
|||||||
QUERY_ERR (result);
|
QUERY_ERR (result);
|
||||||
goto rollback;
|
goto rollback;
|
||||||
}
|
}
|
||||||
PQclear (result); result = NULL;
|
PQclear (result);
|
||||||
|
result = NULL;
|
||||||
if (GNUNET_NO == reserve_exists)
|
if (GNUNET_NO == reserve_exists)
|
||||||
{
|
{
|
||||||
if (GNUNET_OK != TALER_MINT_DB_commit (db))
|
if (GNUNET_OK != TALER_MINT_DB_commit (db))
|
||||||
return GNUNET_SYSERR;
|
return GNUNET_SYSERR;
|
||||||
reserve->balance = balance;
|
reserve->balance = *balance;
|
||||||
reserve->expiry = expiry;
|
reserve->expiry = expiry;
|
||||||
return GNUNET_OK;
|
return GNUNET_OK;
|
||||||
}
|
}
|
||||||
/* Update reserve */
|
/* Update reserve */
|
||||||
struct Reserve updated_reserve;
|
struct Reserve updated_reserve;
|
||||||
updated_reserve.pub = reserve->pub;
|
updated_reserve.pub = reserve->pub;
|
||||||
updated_reserve.balance = TALER_amount_add (reserve->balance, balance);
|
|
||||||
|
if (GNUNET_OK !=
|
||||||
|
TALER_amount_add (&updated_reserve.balance,
|
||||||
|
&reserve->balance,
|
||||||
|
balance))
|
||||||
|
{
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
}
|
||||||
updated_reserve.expiry = GNUNET_TIME_absolute_max (expiry, reserve->expiry);
|
updated_reserve.expiry = GNUNET_TIME_absolute_max (expiry, reserve->expiry);
|
||||||
if (GNUNET_OK != reserves_update (db, &updated_reserve))
|
if (GNUNET_OK != reserves_update (db, &updated_reserve))
|
||||||
goto rollback;
|
goto rollback;
|
||||||
@ -1350,7 +1360,8 @@ TALER_MINT_DB_insert_deposit (PGconn *db_conn,
|
|||||||
GNUNET_CRYPTO_rsa_signature_encode (deposit->coin.denom_sig,
|
GNUNET_CRYPTO_rsa_signature_encode (deposit->coin.denom_sig,
|
||||||
&denom_sig_enc);
|
&denom_sig_enc);
|
||||||
json_wire_enc = json_dumps (deposit->wire, JSON_COMPACT);
|
json_wire_enc = json_dumps (deposit->wire, JSON_COMPACT);
|
||||||
amount_nbo = TALER_amount_hton (deposit->amount);
|
TALER_amount_hton (&amount_nbo,
|
||||||
|
&deposit->amount);
|
||||||
struct TALER_DB_QueryParam params[]= {
|
struct TALER_DB_QueryParam params[]= {
|
||||||
TALER_DB_QUERY_PARAM_PTR (&deposit->coin.coin_pub),
|
TALER_DB_QUERY_PARAM_PTR (&deposit->coin.coin_pub),
|
||||||
TALER_DB_QUERY_PARAM_PTR_SIZED (denom_pub_enc, denom_pub_enc_size),
|
TALER_DB_QUERY_PARAM_PTR_SIZED (denom_pub_enc, denom_pub_enc_size),
|
||||||
|
@ -224,7 +224,7 @@ TALER_MINT_DB_reserve_get (PGconn *db,
|
|||||||
int
|
int
|
||||||
TALER_MINT_DB_reserves_in_insert (PGconn *db,
|
TALER_MINT_DB_reserves_in_insert (PGconn *db,
|
||||||
struct Reserve *reserve,
|
struct Reserve *reserve,
|
||||||
const struct TALER_Amount balance,
|
const struct TALER_Amount *balance,
|
||||||
const struct GNUNET_TIME_Absolute expiry);
|
const struct GNUNET_TIME_Absolute expiry);
|
||||||
|
|
||||||
|
|
||||||
|
@ -34,26 +34,6 @@
|
|||||||
#include "taler-mint-httpd_keystate.h"
|
#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
|
* Execute a deposit. The validity of the coin and signature
|
||||||
* have already been checked. The database must now check that
|
* have already been checked. The database must now check that
|
||||||
@ -99,9 +79,12 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection,
|
|||||||
mks = TALER_MINT_key_state_acquire ();
|
mks = TALER_MINT_key_state_acquire ();
|
||||||
dki = TALER_MINT_get_denom_key (mks,
|
dki = TALER_MINT_get_denom_key (mks,
|
||||||
deposit->coin.denom_pub);
|
deposit->coin.denom_pub);
|
||||||
value = TALER_amount_ntoh (dki->issue.value);
|
TALER_amount_ntoh (&value,
|
||||||
fee_deposit = TALER_amount_ntoh (dki->issue.fee_deposit);
|
&dki->issue.value);
|
||||||
fee_refresh = TALER_amount_ntoh (dki->issue.fee_refresh);
|
TALER_amount_ntoh (&fee_deposit,
|
||||||
|
&dki->issue.fee_deposit);
|
||||||
|
TALER_amount_ntoh (&fee_refresh,
|
||||||
|
&dki->issue.fee_refresh);
|
||||||
TALER_MINT_key_state_release (mks);
|
TALER_MINT_key_state_release (mks);
|
||||||
|
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
@ -113,26 +96,49 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection,
|
|||||||
tl = TALER_MINT_DB_get_coin_transactions (db_conn,
|
tl = TALER_MINT_DB_get_coin_transactions (db_conn,
|
||||||
&deposit->coin.coin_pub);
|
&deposit->coin.coin_pub);
|
||||||
spent = fee_deposit; /* fee for THIS transaction */
|
spent = fee_deposit; /* fee for THIS transaction */
|
||||||
/* FIXME: need to deal better with integer overflows
|
if (GNUNET_OK !=
|
||||||
in the logic that follows! (change amount.c API! -- #3637) */
|
TALER_amount_add (&spent,
|
||||||
spent = TALER_amount_add (spent,
|
&spent,
|
||||||
deposit->amount);
|
&deposit->amount))
|
||||||
|
{
|
||||||
|
GNUNET_break (0);
|
||||||
|
TALER_MINT_DB_free_coin_transaction_list (tl);
|
||||||
|
return TALER_MINT_reply_internal_db_error (connection);
|
||||||
|
}
|
||||||
|
|
||||||
for (pos = tl; NULL != pos; pos = pos->next)
|
for (pos = tl; NULL != pos; pos = pos->next)
|
||||||
{
|
{
|
||||||
switch (pos->type)
|
switch (pos->type)
|
||||||
{
|
{
|
||||||
case TALER_MINT_DB_TT_DEPOSIT:
|
case TALER_MINT_DB_TT_DEPOSIT:
|
||||||
spent = TALER_amount_add (spent,
|
if ( (GNUNET_OK !=
|
||||||
pos->details.deposit->amount);
|
TALER_amount_add (&spent,
|
||||||
spent = TALER_amount_add (spent,
|
&spent,
|
||||||
fee_deposit);
|
&pos->details.deposit->amount)) ||
|
||||||
|
(GNUNET_OK !=
|
||||||
|
TALER_amount_add (&spent,
|
||||||
|
&spent,
|
||||||
|
&fee_deposit)) )
|
||||||
|
{
|
||||||
|
GNUNET_break (0);
|
||||||
|
TALER_MINT_DB_free_coin_transaction_list (tl);
|
||||||
|
return TALER_MINT_reply_internal_db_error (connection);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case TALER_MINT_DB_TT_REFRESH_MELT:
|
case TALER_MINT_DB_TT_REFRESH_MELT:
|
||||||
spent = TALER_amount_add (spent,
|
if ( (GNUNET_OK !=
|
||||||
pos->details.melt->amount);
|
TALER_amount_add (&spent,
|
||||||
spent = TALER_amount_add (spent,
|
&spent,
|
||||||
fee_refresh);
|
&pos->details.melt->amount)) ||
|
||||||
|
(GNUNET_OK !=
|
||||||
|
TALER_amount_add (&spent,
|
||||||
|
&spent,
|
||||||
|
&fee_refresh)) )
|
||||||
|
{
|
||||||
|
GNUNET_break (0);
|
||||||
|
TALER_MINT_DB_free_coin_transaction_list (tl);
|
||||||
|
return TALER_MINT_reply_internal_db_error (connection);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case TALER_MINT_DB_TT_LOCK:
|
case TALER_MINT_DB_TT_LOCK:
|
||||||
/* should check if lock is still active,
|
/* should check if lock is still active,
|
||||||
@ -146,7 +152,8 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (0 < TALER_amount_cmp (spent, value))
|
if (0 < TALER_amount_cmp (&spent,
|
||||||
|
&value))
|
||||||
{
|
{
|
||||||
TALER_MINT_DB_rollback (db_conn);
|
TALER_MINT_DB_rollback (db_conn);
|
||||||
ret = TALER_MINT_reply_deposit_insufficient_funds (connection,
|
ret = TALER_MINT_reply_deposit_insufficient_funds (connection,
|
||||||
@ -251,6 +258,7 @@ TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection,
|
|||||||
struct TALER_Amount withdraw_total;
|
struct TALER_Amount withdraw_total;
|
||||||
struct TALER_Amount balance;
|
struct TALER_Amount balance;
|
||||||
struct TALER_Amount value;
|
struct TALER_Amount value;
|
||||||
|
struct TALER_Amount fee_withdraw;
|
||||||
struct GNUNET_HashCode h_blind;
|
struct GNUNET_HashCode h_blind;
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
@ -318,8 +326,20 @@ TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* calculate amount required including fees */
|
/* calculate amount required including fees */
|
||||||
amount_required = TALER_amount_add (TALER_amount_ntoh (dki->issue.value),
|
TALER_amount_ntoh (&value,
|
||||||
TALER_amount_ntoh (dki->issue.fee_withdraw));
|
&dki->issue.value);
|
||||||
|
TALER_amount_ntoh (&fee_withdraw,
|
||||||
|
&dki->issue.fee_withdraw);
|
||||||
|
|
||||||
|
if (GNUNET_OK !=
|
||||||
|
TALER_amount_add (&amount_required,
|
||||||
|
&value,
|
||||||
|
&fee_withdraw))
|
||||||
|
{
|
||||||
|
TALER_MINT_DB_rollback (db_conn);
|
||||||
|
TALER_MINT_key_state_release (key_state);
|
||||||
|
return TALER_MINT_reply_internal_db_error (connection);
|
||||||
|
}
|
||||||
|
|
||||||
/* calculate balance of the reserve */
|
/* calculate balance of the reserve */
|
||||||
res = 0;
|
res = 0;
|
||||||
@ -331,29 +351,45 @@ TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection,
|
|||||||
if (0 == (res & 1))
|
if (0 == (res & 1))
|
||||||
deposit_total = pos->details.bank->amount;
|
deposit_total = pos->details.bank->amount;
|
||||||
else
|
else
|
||||||
deposit_total = TALER_amount_add (deposit_total,
|
if (GNUNET_OK !=
|
||||||
pos->details.bank->amount);
|
TALER_amount_add (&deposit_total,
|
||||||
|
&deposit_total,
|
||||||
|
&pos->details.bank->amount))
|
||||||
|
{
|
||||||
|
TALER_MINT_DB_rollback (db_conn);
|
||||||
|
TALER_MINT_key_state_release (key_state);
|
||||||
|
return TALER_MINT_reply_internal_db_error (connection);
|
||||||
|
}
|
||||||
res |= 1;
|
res |= 1;
|
||||||
break;
|
break;
|
||||||
case TALER_MINT_DB_RO_WITHDRAW_COIN:
|
case TALER_MINT_DB_RO_WITHDRAW_COIN:
|
||||||
tdki = TALER_MINT_get_denom_key (key_state,
|
tdki = TALER_MINT_get_denom_key (key_state,
|
||||||
pos->details.withdraw->denom_pub);
|
pos->details.withdraw->denom_pub);
|
||||||
value = TALER_amount_ntoh (tdki->issue.value);
|
TALER_amount_ntoh (&value,
|
||||||
|
&tdki->issue.value);
|
||||||
if (0 == (res & 2))
|
if (0 == (res & 2))
|
||||||
withdraw_total = value;
|
withdraw_total = value;
|
||||||
else
|
else
|
||||||
withdraw_total = TALER_amount_add (withdraw_total,
|
if (GNUNET_OK !=
|
||||||
value);
|
TALER_amount_add (&withdraw_total,
|
||||||
|
&withdraw_total,
|
||||||
|
&value))
|
||||||
|
{
|
||||||
|
TALER_MINT_DB_rollback (db_conn);
|
||||||
|
TALER_MINT_key_state_release (key_state);
|
||||||
|
return TALER_MINT_reply_internal_db_error (connection);
|
||||||
|
}
|
||||||
res |= 2;
|
res |= 2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GNUNET_break (0 > TALER_amount_cmp (withdraw_total,
|
/* All reserve balances should be non-negative */
|
||||||
deposit_total));
|
GNUNET_break (GNUNET_SYSERR !=
|
||||||
balance = TALER_amount_subtract (deposit_total,
|
TALER_amount_subtract (&balance,
|
||||||
withdraw_total);
|
&deposit_total,
|
||||||
if (0 < TALER_amount_cmp (amount_required,
|
&withdraw_total));
|
||||||
balance))
|
if (0 < TALER_amount_cmp (&amount_required,
|
||||||
|
&balance))
|
||||||
{
|
{
|
||||||
TALER_MINT_key_state_release (key_state);
|
TALER_MINT_key_state_release (key_state);
|
||||||
TALER_MINT_DB_rollback (db_conn);
|
TALER_MINT_DB_rollback (db_conn);
|
||||||
@ -450,7 +486,8 @@ refresh_accept_melts (struct MHD_Connection *connection,
|
|||||||
"denom not found"))
|
"denom not found"))
|
||||||
? GNUNET_NO : GNUNET_SYSERR;
|
? GNUNET_NO : GNUNET_SYSERR;
|
||||||
|
|
||||||
coin_value = TALER_amount_ntoh (dki->value);
|
TALER_amount_ntoh (&coin_value,
|
||||||
|
&dki->value);
|
||||||
tl = TALER_MINT_DB_get_coin_transactions (db_conn,
|
tl = TALER_MINT_DB_get_coin_transactions (db_conn,
|
||||||
&coin_public_info->coin_pub);
|
&coin_public_info->coin_pub);
|
||||||
/* FIXME: #3636: compute how much value is left with this coin and
|
/* FIXME: #3636: compute how much value is left with this coin and
|
||||||
@ -459,8 +496,8 @@ refresh_accept_melts (struct MHD_Connection *connection,
|
|||||||
/* Refuse to refresh when the coin does not have enough money left to
|
/* Refuse to refresh when the coin does not have enough money left to
|
||||||
* pay the refreshing fees of the coin. */
|
* pay the refreshing fees of the coin. */
|
||||||
|
|
||||||
if (TALER_amount_cmp (coin_residual,
|
if (TALER_amount_cmp (&coin_residual,
|
||||||
coin_details->melt_amount) < 0)
|
&coin_details->melt_amount) < 0)
|
||||||
{
|
{
|
||||||
res = (MHD_YES ==
|
res = (MHD_YES ==
|
||||||
TALER_MINT_reply_refresh_melt_insufficient_funds (connection,
|
TALER_MINT_reply_refresh_melt_insufficient_funds (connection,
|
||||||
|
@ -65,7 +65,8 @@ verify_and_execute_deposit (struct MHD_Connection *connection,
|
|||||||
dr.h_contract = deposit->h_contract;
|
dr.h_contract = deposit->h_contract;
|
||||||
dr.h_wire = deposit->h_wire;
|
dr.h_wire = deposit->h_wire;
|
||||||
dr.transaction_id = GNUNET_htonll (deposit->transaction_id);
|
dr.transaction_id = GNUNET_htonll (deposit->transaction_id);
|
||||||
dr.amount = TALER_amount_hton (deposit->amount);
|
TALER_amount_hton (&dr.amount,
|
||||||
|
&deposit->amount);
|
||||||
dr.coin_pub = deposit->coin.coin_pub;
|
dr.coin_pub = deposit->coin.coin_pub;
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
GNUNET_CRYPTO_ecdsa_verify (TALER_SIGNATURE_WALLET_DEPOSIT,
|
GNUNET_CRYPTO_ecdsa_verify (TALER_SIGNATURE_WALLET_DEPOSIT,
|
||||||
|
@ -114,6 +114,19 @@ static json_t *
|
|||||||
denom_key_issue_to_json (struct GNUNET_CRYPTO_rsa_PublicKey *pk,
|
denom_key_issue_to_json (struct GNUNET_CRYPTO_rsa_PublicKey *pk,
|
||||||
const struct TALER_MINT_DenomKeyIssue *dki)
|
const struct TALER_MINT_DenomKeyIssue *dki)
|
||||||
{
|
{
|
||||||
|
struct TALER_Amount value;
|
||||||
|
struct TALER_Amount fee_withdraw;
|
||||||
|
struct TALER_Amount fee_deposit;
|
||||||
|
struct TALER_Amount fee_refresh;
|
||||||
|
|
||||||
|
TALER_amount_ntoh (&value,
|
||||||
|
&dki->value);
|
||||||
|
TALER_amount_ntoh (&fee_withdraw,
|
||||||
|
&dki->fee_withdraw);
|
||||||
|
TALER_amount_ntoh (&fee_deposit,
|
||||||
|
&dki->fee_deposit);
|
||||||
|
TALER_amount_ntoh (&fee_refresh,
|
||||||
|
&dki->fee_refresh);
|
||||||
return
|
return
|
||||||
json_pack ("{s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o}",
|
json_pack ("{s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o}",
|
||||||
"master_sig",
|
"master_sig",
|
||||||
@ -128,13 +141,13 @@ denom_key_issue_to_json (struct GNUNET_CRYPTO_rsa_PublicKey *pk,
|
|||||||
"denom_pub",
|
"denom_pub",
|
||||||
TALER_JSON_from_rsa_public_key (pk),
|
TALER_JSON_from_rsa_public_key (pk),
|
||||||
"value",
|
"value",
|
||||||
TALER_JSON_from_amount (TALER_amount_ntoh (dki->value)),
|
TALER_JSON_from_amount (&value),
|
||||||
"fee_withdraw",
|
"fee_withdraw",
|
||||||
TALER_JSON_from_amount (TALER_amount_ntoh (dki->fee_withdraw)),
|
TALER_JSON_from_amount (&fee_withdraw),
|
||||||
"fee_deposit",
|
"fee_deposit",
|
||||||
TALER_JSON_from_amount (TALER_amount_ntoh (dki->fee_deposit)),
|
TALER_JSON_from_amount (&fee_deposit),
|
||||||
"fee_refresh",
|
"fee_refresh",
|
||||||
TALER_JSON_from_amount (TALER_amount_ntoh (dki->fee_refresh)));
|
TALER_JSON_from_amount (&fee_refresh));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -878,8 +878,10 @@ TALER_MINT_parse_amount_json (struct MHD_Connection *connection,
|
|||||||
json_int_t value;
|
json_int_t value;
|
||||||
json_int_t fraction;
|
json_int_t fraction;
|
||||||
const char *currency;
|
const char *currency;
|
||||||
struct TALER_Amount a;
|
|
||||||
|
|
||||||
|
memset (amount,
|
||||||
|
0,
|
||||||
|
sizeof (struct TALER_Amount));
|
||||||
if (-1 == json_unpack (f,
|
if (-1 == json_unpack (f,
|
||||||
"{s:I, s:I, s:s}",
|
"{s:I, s:I, s:s}",
|
||||||
"value", &value,
|
"value", &value,
|
||||||
@ -897,7 +899,7 @@ TALER_MINT_parse_amount_json (struct MHD_Connection *connection,
|
|||||||
}
|
}
|
||||||
if ( (value < 0) ||
|
if ( (value < 0) ||
|
||||||
(fraction < 0) ||
|
(fraction < 0) ||
|
||||||
(value > UINT32_MAX) ||
|
(value > UINT64_MAX) ||
|
||||||
(fraction > UINT32_MAX) )
|
(fraction > UINT32_MAX) )
|
||||||
{
|
{
|
||||||
LOG_WARNING ("Amount specified not in allowed range\n");
|
LOG_WARNING ("Amount specified not in allowed range\n");
|
||||||
@ -922,11 +924,11 @@ TALER_MINT_parse_amount_json (struct MHD_Connection *connection,
|
|||||||
return GNUNET_SYSERR;
|
return GNUNET_SYSERR;
|
||||||
return GNUNET_NO;
|
return GNUNET_NO;
|
||||||
}
|
}
|
||||||
a.value = (uint32_t) value;
|
amount->value = (uint64_t) value;
|
||||||
a.fraction = (uint32_t) fraction;
|
amount->fraction = (uint32_t) fraction;
|
||||||
GNUNET_assert (strlen (MINT_CURRENCY) < TALER_CURRENCY_LEN);
|
GNUNET_assert (strlen (MINT_CURRENCY) < TALER_CURRENCY_LEN);
|
||||||
strcpy (a.currency, MINT_CURRENCY);
|
strcpy (amount->currency, MINT_CURRENCY);
|
||||||
*amount = TALER_amount_normalize (a);
|
TALER_amount_normalize (amount);
|
||||||
return GNUNET_OK;
|
return GNUNET_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,6 +82,8 @@ handle_refresh_melt_binary (struct MHD_Connection *connection,
|
|||||||
struct TALER_Amount cost;
|
struct TALER_Amount cost;
|
||||||
struct TALER_Amount total_cost;
|
struct TALER_Amount total_cost;
|
||||||
struct TALER_Amount melt;
|
struct TALER_Amount melt;
|
||||||
|
struct TALER_Amount value;
|
||||||
|
struct TALER_Amount fee_withdraw;
|
||||||
struct TALER_Amount total_melt;
|
struct TALER_Amount total_melt;
|
||||||
|
|
||||||
/* check that signature from the session public key is ok */
|
/* check that signature from the session public key is ok */
|
||||||
@ -107,7 +109,8 @@ handle_refresh_melt_binary (struct MHD_Connection *connection,
|
|||||||
body.purpose.purpose = htonl (TALER_SIGNATURE_REFRESH_MELT_SESSION);
|
body.purpose.purpose = htonl (TALER_SIGNATURE_REFRESH_MELT_SESSION);
|
||||||
body.purpose.size = htonl (sizeof (struct RefreshMeltSessionSignature));
|
body.purpose.size = htonl (sizeof (struct RefreshMeltSessionSignature));
|
||||||
body.melt_hash = melt_hash;
|
body.melt_hash = melt_hash;
|
||||||
body.amount = TALER_amount_hton (coin_melt_details->melt_amount);
|
TALER_amount_hton (&body.amount,
|
||||||
|
&coin_melt_details->melt_amount);
|
||||||
|
|
||||||
if (GNUNET_OK != GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_REFRESH_MELT_SESSION,
|
if (GNUNET_OK != GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_REFRESH_MELT_SESSION,
|
||||||
&body.purpose,
|
&body.purpose,
|
||||||
@ -130,11 +133,22 @@ handle_refresh_melt_binary (struct MHD_Connection *connection,
|
|||||||
{
|
{
|
||||||
dki = &TALER_MINT_get_denom_key (key_state,
|
dki = &TALER_MINT_get_denom_key (key_state,
|
||||||
denom_pubs[i])->issue;
|
denom_pubs[i])->issue;
|
||||||
cost = TALER_amount_add (TALER_amount_ntoh (dki->value),
|
TALER_amount_ntoh (&value,
|
||||||
TALER_amount_ntoh (dki->fee_withdraw));
|
&dki->value);
|
||||||
|
TALER_amount_ntoh (&fee_withdraw,
|
||||||
|
&dki->fee_withdraw);
|
||||||
// FIXME: #3637
|
// FIXME: #3637
|
||||||
total_cost = TALER_amount_add (cost,
|
if ( (GNUNET_OK !=
|
||||||
total_cost);
|
TALER_amount_add (&cost,
|
||||||
|
&value,
|
||||||
|
&fee_withdraw)) ||
|
||||||
|
(GNUNET_OK !=
|
||||||
|
TALER_amount_add (&total_cost,
|
||||||
|
&cost,
|
||||||
|
&total_cost)) )
|
||||||
|
{
|
||||||
|
// FIXME...
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: badness, use proper way to set to zero...
|
// FIXME: badness, use proper way to set to zero...
|
||||||
@ -146,13 +160,18 @@ handle_refresh_melt_binary (struct MHD_Connection *connection,
|
|||||||
// melt = coin_values[i]; // FIXME: #3636!
|
// melt = coin_values[i]; // FIXME: #3636!
|
||||||
|
|
||||||
// FIXME: #3637
|
// FIXME: #3637
|
||||||
total_melt = TALER_amount_add (melt,
|
if (GNUNET_OK !=
|
||||||
total_melt);
|
TALER_amount_add (&total_melt,
|
||||||
|
&melt,
|
||||||
|
&total_melt))
|
||||||
|
{
|
||||||
|
// FIXME ...
|
||||||
|
}
|
||||||
}
|
}
|
||||||
TALER_MINT_key_state_release (key_state);
|
TALER_MINT_key_state_release (key_state);
|
||||||
if (0 !=
|
if (0 !=
|
||||||
TALER_amount_cmp (total_cost,
|
TALER_amount_cmp (&total_cost,
|
||||||
total_melt) )
|
&total_melt) )
|
||||||
{
|
{
|
||||||
/* We require total value of coins being melted and
|
/* We require total value of coins being melted and
|
||||||
total value of coins being generated to match! */
|
total value of coins being generated to match! */
|
||||||
@ -269,7 +288,8 @@ verify_coin_public_info (struct MHD_Connection *connection,
|
|||||||
body.purpose.size = htonl (sizeof (struct RefreshMeltCoinSignature));
|
body.purpose.size = htonl (sizeof (struct RefreshMeltCoinSignature));
|
||||||
body.purpose.purpose = htonl (TALER_SIGNATURE_REFRESH_MELT_COIN);
|
body.purpose.purpose = htonl (TALER_SIGNATURE_REFRESH_MELT_COIN);
|
||||||
body.melt_hash = *melt_hash;
|
body.melt_hash = *melt_hash;
|
||||||
body.amount = TALER_amount_hton (r_melt_detail->melt_amount);
|
TALER_amount_hton (&body.amount,
|
||||||
|
&r_melt_detail->melt_amount);
|
||||||
body.coin_pub = r_public_info->coin_pub;
|
body.coin_pub = r_public_info->coin_pub;
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
GNUNET_CRYPTO_ecdsa_verify (TALER_SIGNATURE_REFRESH_MELT_COIN,
|
GNUNET_CRYPTO_ecdsa_verify (TALER_SIGNATURE_REFRESH_MELT_COIN,
|
||||||
|
@ -299,7 +299,8 @@ TALER_MINT_reply_deposit_success (struct MHD_Connection *connection,
|
|||||||
dc.h_contract = *h_contract;
|
dc.h_contract = *h_contract;
|
||||||
dc.h_wire = *h_wire;
|
dc.h_wire = *h_wire;
|
||||||
dc.transaction_id = GNUNET_htonll (transaction_id);
|
dc.transaction_id = GNUNET_htonll (transaction_id);
|
||||||
dc.amount = TALER_amount_hton (*amount);
|
TALER_amount_hton (&dc.amount,
|
||||||
|
amount);
|
||||||
dc.coin_pub = *coin_pub;
|
dc.coin_pub = *coin_pub;
|
||||||
dc.merchant = *merchant;
|
dc.merchant = *merchant;
|
||||||
TALER_MINT_keys_sign (&dc.purpose,
|
TALER_MINT_keys_sign (&dc.purpose,
|
||||||
@ -346,7 +347,8 @@ compile_transaction_history (const struct TALER_MINT_DB_TransactionList *tl)
|
|||||||
dr.h_contract = deposit->h_contract;
|
dr.h_contract = deposit->h_contract;
|
||||||
dr.h_wire = deposit->h_wire;
|
dr.h_wire = deposit->h_wire;
|
||||||
dr.transaction_id = GNUNET_htonll (deposit->transaction_id);
|
dr.transaction_id = GNUNET_htonll (deposit->transaction_id);
|
||||||
dr.amount = TALER_amount_hton (deposit->amount);
|
TALER_amount_hton (&dr.amount,
|
||||||
|
&deposit->amount);
|
||||||
dr.coin_pub = deposit->coin.coin_pub;
|
dr.coin_pub = deposit->coin.coin_pub;
|
||||||
transaction = TALER_JSON_from_ecdsa_sig (&dr.purpose,
|
transaction = TALER_JSON_from_ecdsa_sig (&dr.purpose,
|
||||||
&deposit->csig);
|
&deposit->csig);
|
||||||
@ -362,7 +364,8 @@ compile_transaction_history (const struct TALER_MINT_DB_TransactionList *tl)
|
|||||||
ms.purpose.purpose = htonl (TALER_SIGNATURE_REFRESH_MELT_COIN);
|
ms.purpose.purpose = htonl (TALER_SIGNATURE_REFRESH_MELT_COIN);
|
||||||
ms.purpose.size = htonl (sizeof (struct RefreshMeltCoinSignature));
|
ms.purpose.size = htonl (sizeof (struct RefreshMeltCoinSignature));
|
||||||
ms.melt_hash = melt->melt_hash;
|
ms.melt_hash = melt->melt_hash;
|
||||||
ms.amount = TALER_amount_hton (melt->amount);
|
TALER_amount_hton (&ms.amount,
|
||||||
|
&melt->amount);
|
||||||
ms.coin_pub = melt->coin.coin_pub;
|
ms.coin_pub = melt->coin.coin_pub;
|
||||||
transaction = TALER_JSON_from_ecdsa_sig (&ms.purpose,
|
transaction = TALER_JSON_from_ecdsa_sig (&ms.purpose,
|
||||||
&melt->coin_sig);
|
&melt->coin_sig);
|
||||||
@ -382,7 +385,7 @@ compile_transaction_history (const struct TALER_MINT_DB_TransactionList *tl)
|
|||||||
json_array_append_new (history,
|
json_array_append_new (history,
|
||||||
json_pack ("{s:s, s:o}",
|
json_pack ("{s:s, s:o}",
|
||||||
"type", type,
|
"type", type,
|
||||||
"amount", TALER_JSON_from_amount (value),
|
"amount", TALER_JSON_from_amount (&value),
|
||||||
"signature", transaction));
|
"signature", transaction));
|
||||||
}
|
}
|
||||||
return history;
|
return history;
|
||||||
@ -419,7 +422,7 @@ TALER_MINT_reply_deposit_insufficient_funds (struct MHD_Connection *connection,
|
|||||||
*
|
*
|
||||||
* @param rh reserve history to JSON-ify
|
* @param rh reserve history to JSON-ify
|
||||||
* @param balance[OUT] set to current reserve balance
|
* @param balance[OUT] set to current reserve balance
|
||||||
* @return json representation of the @a rh
|
* @return json representation of the @a rh, NULL on error
|
||||||
*/
|
*/
|
||||||
static json_t *
|
static json_t *
|
||||||
compile_reserve_history (const struct ReserveHistory *rh,
|
compile_reserve_history (const struct ReserveHistory *rh,
|
||||||
@ -446,14 +449,20 @@ compile_reserve_history (const struct ReserveHistory *rh,
|
|||||||
if (0 == ret)
|
if (0 == ret)
|
||||||
deposit_total = pos->details.bank->amount;
|
deposit_total = pos->details.bank->amount;
|
||||||
else
|
else
|
||||||
deposit_total = TALER_amount_add (deposit_total,
|
if (GNUNET_OK !=
|
||||||
pos->details.bank->amount);
|
TALER_amount_add (&deposit_total,
|
||||||
|
&deposit_total,
|
||||||
|
&pos->details.bank->amount))
|
||||||
|
{
|
||||||
|
json_decref (json_history);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
ret = 1;
|
ret = 1;
|
||||||
json_array_append_new (json_history,
|
json_array_append_new (json_history,
|
||||||
json_pack ("{s:s, s:o, s:o}",
|
json_pack ("{s:s, s:o, s:o}",
|
||||||
"type", "DEPOSIT",
|
"type", "DEPOSIT",
|
||||||
"wire", pos->details.bank->wire,
|
"wire", pos->details.bank->wire,
|
||||||
"amount", TALER_JSON_from_amount (pos->details.bank->amount)));
|
"amount", TALER_JSON_from_amount (&pos->details.bank->amount)));
|
||||||
break;
|
break;
|
||||||
case TALER_MINT_DB_RO_WITHDRAW_COIN:
|
case TALER_MINT_DB_RO_WITHDRAW_COIN:
|
||||||
break;
|
break;
|
||||||
@ -472,12 +481,20 @@ compile_reserve_history (const struct ReserveHistory *rh,
|
|||||||
|
|
||||||
dki = TALER_MINT_get_denom_key (key_state,
|
dki = TALER_MINT_get_denom_key (key_state,
|
||||||
pos->details.withdraw->denom_pub);
|
pos->details.withdraw->denom_pub);
|
||||||
value = TALER_amount_ntoh (dki->issue.value);
|
TALER_amount_ntoh (&value,
|
||||||
|
&dki->issue.value);
|
||||||
if (0 == ret)
|
if (0 == ret)
|
||||||
withdraw_total = value;
|
withdraw_total = value;
|
||||||
else
|
else
|
||||||
withdraw_total = TALER_amount_add (withdraw_total,
|
if (GNUNET_OK !=
|
||||||
value);
|
TALER_amount_add (&withdraw_total,
|
||||||
|
&withdraw_total,
|
||||||
|
&value))
|
||||||
|
{
|
||||||
|
TALER_MINT_key_state_release (key_state);
|
||||||
|
json_decref (json_history);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
ret = 1;
|
ret = 1;
|
||||||
wr.purpose.purpose = htonl (TALER_SIGNATURE_WITHDRAW);
|
wr.purpose.purpose = htonl (TALER_SIGNATURE_WITHDRAW);
|
||||||
wr.purpose.size = htonl (sizeof (struct TALER_WithdrawRequest));
|
wr.purpose.size = htonl (sizeof (struct TALER_WithdrawRequest));
|
||||||
@ -493,15 +510,22 @@ compile_reserve_history (const struct ReserveHistory *rh,
|
|||||||
json_pack ("{s:s, s:o, s:o}",
|
json_pack ("{s:s, s:o, s:o}",
|
||||||
"type", "WITHDRAW",
|
"type", "WITHDRAW",
|
||||||
"signature", transaction,
|
"signature", transaction,
|
||||||
"amount", TALER_JSON_from_amount (value)));
|
"amount", TALER_JSON_from_amount (&value)));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TALER_MINT_key_state_release (key_state);
|
TALER_MINT_key_state_release (key_state);
|
||||||
|
|
||||||
*balance = TALER_amount_subtract (deposit_total,
|
if (GNUNET_SYSERR ==
|
||||||
withdraw_total);
|
TALER_amount_subtract (balance,
|
||||||
|
&deposit_total,
|
||||||
|
&withdraw_total))
|
||||||
|
{
|
||||||
|
GNUNET_break (0);
|
||||||
|
json_decref (json_history);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
return json_history;
|
return json_history;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -524,7 +548,10 @@ TALER_MINT_reply_withdraw_status_success (struct MHD_Connection *connection,
|
|||||||
|
|
||||||
json_history = compile_reserve_history (rh,
|
json_history = compile_reserve_history (rh,
|
||||||
&balance);
|
&balance);
|
||||||
json_balance = TALER_JSON_from_amount (balance);
|
if (NULL == json_history)
|
||||||
|
return TALER_MINT_reply_internal_error (connection,
|
||||||
|
"balance calculation failure");
|
||||||
|
json_balance = TALER_JSON_from_amount (&balance);
|
||||||
ret = TALER_MINT_reply_json_pack (connection,
|
ret = TALER_MINT_reply_json_pack (connection,
|
||||||
MHD_HTTP_OK,
|
MHD_HTTP_OK,
|
||||||
"{s:o, s:o}",
|
"{s:o, s:o}",
|
||||||
@ -556,7 +583,10 @@ TALER_MINT_reply_withdraw_sign_insufficient_funds (struct MHD_Connection *connec
|
|||||||
|
|
||||||
json_history = compile_reserve_history (rh,
|
json_history = compile_reserve_history (rh,
|
||||||
&balance);
|
&balance);
|
||||||
json_balance = TALER_JSON_from_amount (balance);
|
if (NULL == json_history)
|
||||||
|
return TALER_MINT_reply_internal_error (connection,
|
||||||
|
"balance calculation failure");
|
||||||
|
json_balance = TALER_JSON_from_amount (&balance);
|
||||||
ret = TALER_MINT_reply_json_pack (connection,
|
ret = TALER_MINT_reply_json_pack (connection,
|
||||||
MHD_HTTP_PAYMENT_REQUIRED,
|
MHD_HTTP_PAYMENT_REQUIRED,
|
||||||
"{s:s, s:o, s:o}",
|
"{s:s, s:o, s:o}",
|
||||||
@ -625,9 +655,9 @@ TALER_MINT_reply_refresh_melt_insufficient_funds (struct MHD_Connection *connect
|
|||||||
"error", "insufficient funds",
|
"error", "insufficient funds",
|
||||||
"coin-pub", TALER_JSON_from_data (coin_pub,
|
"coin-pub", TALER_JSON_from_data (coin_pub,
|
||||||
sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)),
|
sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)),
|
||||||
"original-value", TALER_JSON_from_amount (coin_value),
|
"original-value", TALER_JSON_from_amount (&coin_value),
|
||||||
"residual-value", TALER_JSON_from_amount (residual),
|
"residual-value", TALER_JSON_from_amount (&residual),
|
||||||
"requested-value", TALER_JSON_from_amount (requested),
|
"requested-value", TALER_JSON_from_amount (&requested),
|
||||||
"history", history);
|
"history", history);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,10 +233,14 @@ hash_coin_type (const struct CoinTypeParams *p,
|
|||||||
sizeof (struct CoinTypeNBO));
|
sizeof (struct CoinTypeNBO));
|
||||||
p_nbo.duration_spend = GNUNET_TIME_relative_hton (p->duration_spend);
|
p_nbo.duration_spend = GNUNET_TIME_relative_hton (p->duration_spend);
|
||||||
p_nbo.duration_withdraw = GNUNET_TIME_relative_hton (p->duration_withdraw);
|
p_nbo.duration_withdraw = GNUNET_TIME_relative_hton (p->duration_withdraw);
|
||||||
p_nbo.value = TALER_amount_hton (p->value);
|
TALER_amount_hton (&p_nbo.value,
|
||||||
p_nbo.fee_withdraw = TALER_amount_hton (p->fee_withdraw);
|
&p->value);
|
||||||
p_nbo.fee_deposit = TALER_amount_hton (p->fee_deposit);
|
TALER_amount_hton (&p_nbo.fee_withdraw,
|
||||||
p_nbo.fee_refresh = TALER_amount_hton (p->fee_refresh);
|
&p->fee_withdraw);
|
||||||
|
TALER_amount_hton (&p_nbo.fee_deposit,
|
||||||
|
&p->fee_deposit);
|
||||||
|
TALER_amount_hton (&p_nbo.fee_refresh,
|
||||||
|
&p->fee_refresh);
|
||||||
p_nbo.rsa_keysize = htonl (p->rsa_keysize);
|
p_nbo.rsa_keysize = htonl (p->rsa_keysize);
|
||||||
GNUNET_CRYPTO_hash (&p_nbo,
|
GNUNET_CRYPTO_hash (&p_nbo,
|
||||||
sizeof (struct CoinTypeNBO),
|
sizeof (struct CoinTypeNBO),
|
||||||
@ -273,7 +277,7 @@ get_cointype_dir (const struct CoinTypeParams *p)
|
|||||||
GNUNET_assert (HASH_CUTOFF <= strlen (hash_str) + 1);
|
GNUNET_assert (HASH_CUTOFF <= strlen (hash_str) + 1);
|
||||||
hash_str[HASH_CUTOFF] = 0;
|
hash_str[HASH_CUTOFF] = 0;
|
||||||
|
|
||||||
val_str = TALER_amount_to_string (p->value);
|
val_str = TALER_amount_to_string (&p->value);
|
||||||
for (i = 0; i < strlen (val_str); i++)
|
for (i = 0; i < strlen (val_str); i++)
|
||||||
if ( (':' == val_str[i]) ||
|
if ( (':' == val_str[i]) ||
|
||||||
('.' == val_str[i]) )
|
('.' == val_str[i]) )
|
||||||
@ -687,11 +691,14 @@ create_denomkey_issue (const struct CoinTypeParams *params,
|
|||||||
dki->issue.expire_spend =
|
dki->issue.expire_spend =
|
||||||
GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_add (params->anchor,
|
GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_add (params->anchor,
|
||||||
params->duration_spend));
|
params->duration_spend));
|
||||||
dki->issue.value = TALER_amount_hton (params->value);
|
TALER_amount_hton (&dki->issue.value,
|
||||||
dki->issue.fee_withdraw = TALER_amount_hton (params->fee_withdraw);
|
¶ms->value);
|
||||||
dki->issue.fee_deposit = TALER_amount_hton (params->fee_deposit);
|
TALER_amount_hton (&dki->issue.fee_withdraw,
|
||||||
dki->issue.fee_refresh = TALER_amount_hton (params->fee_refresh);
|
¶ms->fee_withdraw);
|
||||||
|
TALER_amount_hton (&dki->issue.fee_deposit,
|
||||||
|
¶ms->fee_deposit);
|
||||||
|
TALER_amount_hton (&dki->issue.fee_refresh,
|
||||||
|
¶ms->fee_refresh);
|
||||||
dki->issue.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_DENOM);
|
dki->issue.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_DENOM);
|
||||||
dki->issue.purpose.size = htonl (sizeof (struct TALER_MINT_DenomKeyIssuePriv) -
|
dki->issue.purpose.size = htonl (sizeof (struct TALER_MINT_DenomKeyIssuePriv) -
|
||||||
offsetof (struct TALER_MINT_DenomKeyIssuePriv,
|
offsetof (struct TALER_MINT_DenomKeyIssuePriv,
|
||||||
|
@ -161,9 +161,11 @@ reservemod_add (struct TALER_Amount denom)
|
|||||||
"balance_fraction",
|
"balance_fraction",
|
||||||
"balance_currency",
|
"balance_currency",
|
||||||
&old_denom));
|
&old_denom));
|
||||||
new_denom = TALER_amount_add (old_denom,
|
TALER_amount_add (&new_denom,
|
||||||
denom);
|
&old_denom,
|
||||||
new_denom_nbo = TALER_amount_hton (new_denom);
|
&denom);
|
||||||
|
TALER_amount_hton (&new_denom_nbo,
|
||||||
|
&new_denom);
|
||||||
result = PQexecParams (db_conn,
|
result = PQexecParams (db_conn,
|
||||||
"UPDATE reserves"
|
"UPDATE reserves"
|
||||||
" SET balance_value = $1, balance_fraction = $2, status_sig = NULL, status_sign_pub = NULL"
|
" SET balance_value = $1, balance_fraction = $2, status_sig = NULL, status_sign_pub = NULL"
|
||||||
|
@ -30,16 +30,6 @@
|
|||||||
#include "taler_util.h"
|
#include "taler_util.h"
|
||||||
#include <gcrypt.h>
|
#include <gcrypt.h>
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#define AMOUNT_FRAC_BASE 1000000
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#define AMOUNT_FRAC_LEN 6
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse money amount description, in the format "A:B.C".
|
* Parse money amount description, in the format "A:B.C".
|
||||||
@ -53,159 +43,260 @@ int
|
|||||||
TALER_string_to_amount (const char *str,
|
TALER_string_to_amount (const char *str,
|
||||||
struct TALER_Amount *denom)
|
struct TALER_Amount *denom)
|
||||||
{
|
{
|
||||||
size_t i; // pos in str
|
size_t i;
|
||||||
int n; // number tmp
|
int n;
|
||||||
size_t c; // currency pos
|
uint32_t b;
|
||||||
uint32_t b; // base for suffix
|
const char *colon;
|
||||||
|
const char *value;
|
||||||
|
|
||||||
memset (denom,
|
memset (denom,
|
||||||
0,
|
0,
|
||||||
sizeof (struct TALER_Amount));
|
sizeof (struct TALER_Amount));
|
||||||
|
/* skip leading whitespace */
|
||||||
|
while (isspace(str[0]))
|
||||||
|
str++;
|
||||||
|
if ('\0' == str[0])
|
||||||
|
{
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
||||||
|
"Null before currency\n");
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
}
|
||||||
|
/* parse currency */
|
||||||
|
colon = strchr (str, (int) ':');
|
||||||
|
if ( (NULL == colon) ||
|
||||||
|
((colon - str) >= TALER_CURRENCY_LEN) )
|
||||||
|
{
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
||||||
|
"Invalid currency specified before colon: `%s'",
|
||||||
|
str);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
memcpy (denom->currency,
|
||||||
|
str,
|
||||||
|
colon - str);
|
||||||
|
/* skip colon */
|
||||||
|
value = colon + 1;
|
||||||
|
if ('\0' == value[0])
|
||||||
|
{
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
||||||
|
"Null before value\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* parse value */
|
||||||
i = 0;
|
i = 0;
|
||||||
while (isspace(str[i]))
|
while ('.' != value[i])
|
||||||
i++;
|
|
||||||
|
|
||||||
if (0 == str[i])
|
|
||||||
{
|
{
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
if ('\0' == value[i])
|
||||||
"null before currency\n");
|
|
||||||
return GNUNET_SYSERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
c = 0;
|
|
||||||
while (str[i] != ':')
|
|
||||||
{
|
|
||||||
if (0 == str[i])
|
|
||||||
{
|
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
|
||||||
"null before colon");
|
|
||||||
return GNUNET_SYSERR;
|
|
||||||
}
|
|
||||||
if (c > 3)
|
|
||||||
{
|
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
|
||||||
"currency too long\n");
|
|
||||||
return GNUNET_SYSERR;
|
|
||||||
}
|
|
||||||
denom->currency[c] = str[i];
|
|
||||||
c++;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// skip colon
|
|
||||||
i++;
|
|
||||||
|
|
||||||
if (0 == str[i])
|
|
||||||
{
|
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
|
||||||
"null before value\n");
|
|
||||||
return GNUNET_SYSERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (str[i] != '.')
|
|
||||||
{
|
|
||||||
if (0 == str[i])
|
|
||||||
{
|
{
|
||||||
return GNUNET_OK;
|
return GNUNET_OK;
|
||||||
}
|
}
|
||||||
n = str[i] - '0';
|
if ( (str[i] < '0') || (str[i] > '9') )
|
||||||
if (n < 0 || n > 9)
|
|
||||||
{
|
{
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
||||||
"invalid character '%c' before comma at %u\n",
|
"Invalid character `%c'\n",
|
||||||
(char) n,
|
str[i]);
|
||||||
i);
|
goto fail;
|
||||||
return GNUNET_SYSERR;
|
}
|
||||||
|
n = str[i] - '0';
|
||||||
|
if (denom->value * 10 + n < denom->value)
|
||||||
|
{
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
||||||
|
"Value too large\n");
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
denom->value = (denom->value * 10) + n;
|
denom->value = (denom->value * 10) + n;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// skip the dot
|
/* skip the dot */
|
||||||
i++;
|
i++;
|
||||||
|
|
||||||
if (0 == str[i])
|
/* parse fraction */
|
||||||
|
if ('\0' == str[i])
|
||||||
{
|
{
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
||||||
"null after dot");
|
"Null after dot");
|
||||||
return GNUNET_SYSERR;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
b = TALER_AMOUNT_FRAC_BASE / 10;
|
||||||
b = 100000;
|
while ('\0' != str[i])
|
||||||
|
|
||||||
while (0 != str[i])
|
|
||||||
{
|
{
|
||||||
|
if (0 == b)
|
||||||
|
{
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
||||||
|
"Fractional value too small (only %u digits supported)",
|
||||||
|
(unsigned int) TALER_AMOUNT_FRAC_LEN);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if ( (str[i] < '0') || (str[i] > '9') )
|
||||||
|
{
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
||||||
|
"Error after comma");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
n = str[i] - '0';
|
n = str[i] - '0';
|
||||||
if ( (0 == b) || (n < 0) || (n > 9) )
|
|
||||||
{
|
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
|
||||||
"error after comma");
|
|
||||||
return GNUNET_SYSERR;
|
|
||||||
}
|
|
||||||
denom->fraction += n * b;
|
denom->fraction += n * b;
|
||||||
b /= 10;
|
b /= 10;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
return GNUNET_OK;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
/* set currency to 'invalid' to prevent accidental use */
|
||||||
|
memset (denom->currency,
|
||||||
|
0,
|
||||||
|
TALER_CURRENCY_LEN);
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert amount from host to network representation.
|
||||||
|
*
|
||||||
|
* @param res where to store amount in network representation
|
||||||
|
* @param d amount in host representation
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
TALER_amount_hton (struct TALER_AmountNBO *res,
|
||||||
|
const struct TALER_Amount *d)
|
||||||
|
{
|
||||||
|
res->value = GNUNET_htonll (d->value);
|
||||||
|
res->fraction = htonl (d->fraction);
|
||||||
|
memcpy (res->currency,
|
||||||
|
d->currency,
|
||||||
|
TALER_CURRENCY_LEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert amount from network to host representation.
|
||||||
|
*
|
||||||
|
* @param res where to store amount in host representation
|
||||||
|
* @param d amount in network representation
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
TALER_amount_ntoh (struct TALER_Amount *res,
|
||||||
|
const struct TALER_AmountNBO *dn)
|
||||||
|
{
|
||||||
|
res->value = GNUNET_ntohll (dn->value);
|
||||||
|
res->fraction = ntohl (dn->fraction);
|
||||||
|
memcpy (res->currency,
|
||||||
|
dn->currency,
|
||||||
|
TALER_CURRENCY_LEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value of "zero" in a particular currency.
|
||||||
|
*
|
||||||
|
* @param cur currency description
|
||||||
|
* @param denom denomination to write the result to
|
||||||
|
* @return #GNUNET_OK if @a cur is a valid currency specification,
|
||||||
|
* #GNUNET_SYSERR if it is invalid.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
TALER_amount_get_zero (const char *cur,
|
||||||
|
struct TALER_Amount *denom)
|
||||||
|
{
|
||||||
|
size_t slen;
|
||||||
|
|
||||||
|
slen = strlen (cur);
|
||||||
|
if (slen >= TALER_CURRENCY_LEN)
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
memset (denom,
|
||||||
|
0,
|
||||||
|
sizeof (struct TALER_Amount));
|
||||||
|
memcpy (denom->currency,
|
||||||
|
cur,
|
||||||
|
slen);
|
||||||
return GNUNET_OK;
|
return GNUNET_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FIXME
|
* Set @a a to "invalid".
|
||||||
|
*
|
||||||
|
* @param a amount to set to invalid
|
||||||
*/
|
*/
|
||||||
struct TALER_AmountNBO
|
static void
|
||||||
TALER_amount_hton (const struct TALER_Amount d)
|
invalidate (struct TALER_Amount *a)
|
||||||
{
|
{
|
||||||
struct TALER_AmountNBO dn;
|
memset (a,
|
||||||
dn.value = htonl (d.value);
|
0,
|
||||||
dn.fraction = htonl (d.fraction);
|
sizeof (struct TALER_Amount));
|
||||||
memcpy (dn.currency, d.currency, TALER_CURRENCY_LEN);
|
|
||||||
|
|
||||||
return dn;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FIXME
|
* Test if @a a is valid
|
||||||
|
*
|
||||||
|
* @param a amount to test
|
||||||
|
* @return #GNUNET_YES if valid,
|
||||||
|
* #GNUNET_NO if invalid
|
||||||
*/
|
*/
|
||||||
struct TALER_Amount
|
static int
|
||||||
TALER_amount_ntoh (const struct TALER_AmountNBO dn)
|
test_valid (const struct TALER_Amount *a)
|
||||||
{
|
{
|
||||||
struct TALER_Amount d;
|
return ('\0' != a->currency[0]);
|
||||||
d.value = ntohl (dn.value);
|
|
||||||
d.fraction = ntohl (dn.fraction);
|
|
||||||
memcpy (d.currency, dn.currency, TALER_CURRENCY_LEN);
|
|
||||||
|
|
||||||
return d;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compare the value/fraction of two amounts. Does not compare the currency,
|
* Test if @a a1 and @a a2 are the same currency.
|
||||||
* i.e. comparing amounts with the same value and fraction but different
|
*
|
||||||
* currency would return 0.
|
* @param a1 amount to test
|
||||||
|
* @param a2 amount to test
|
||||||
|
* @return #GNUNET_YES if @a a1 and @a a2 are the same currency
|
||||||
|
* #GNUNET_NO if the currencies are different,
|
||||||
|
* #GNUNET_SYSERR if either amount is invalid
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
TALER_amount_cmp_currency (const struct TALER_Amount *a1,
|
||||||
|
const struct TALER_Amount *a2)
|
||||||
|
{
|
||||||
|
if ( (GNUNET_NO == test_valid (a1)) ||
|
||||||
|
(GNUNET_NO == test_valid (a2)) )
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
if (0 == strcmp (a1->currency,
|
||||||
|
a2->currency))
|
||||||
|
return GNUNET_YES;
|
||||||
|
return GNUNET_NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compare the value/fraction of two amounts. Does not compare the currency.
|
||||||
|
* Comparing amounts of different currencies will cause the program to abort().
|
||||||
|
* If unsure, check with #TALER_amount_cmp_currency() first to be sure that
|
||||||
|
* the currencies of the two amounts are identical.
|
||||||
*
|
*
|
||||||
* @param a1 first amount
|
* @param a1 first amount
|
||||||
* @param a2 second amount
|
* @param a2 second amount
|
||||||
* @return result of the comparison
|
* @return result of the comparison
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
TALER_amount_cmp (struct TALER_Amount a1,
|
TALER_amount_cmp (const struct TALER_Amount *a1,
|
||||||
struct TALER_Amount a2)
|
const struct TALER_Amount *a2)
|
||||||
{
|
{
|
||||||
a1 = TALER_amount_normalize (a1);
|
struct TALER_Amount n1;
|
||||||
a2 = TALER_amount_normalize (a2);
|
struct TALER_Amount n2;
|
||||||
if (a1.value == a2.value)
|
|
||||||
|
GNUNET_assert (GNUNET_YES ==
|
||||||
|
TALER_amount_cmp_currency (a1, a2));
|
||||||
|
n1 = *a1;
|
||||||
|
n2 = *a2;
|
||||||
|
TALER_amount_normalize (&n1);
|
||||||
|
TALER_amount_normalize (&n2);
|
||||||
|
if (n1.value == n2.value)
|
||||||
{
|
{
|
||||||
if (a1.fraction < a2.fraction)
|
if (n1.fraction < n2.fraction)
|
||||||
return -1;
|
return -1;
|
||||||
if (a1.fraction > a2.fraction)
|
if (n1.fraction > n2.fraction)
|
||||||
return 1;
|
return 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (a1.value < a2.value)
|
if (n1.value < n2.value)
|
||||||
return -1;
|
return -1;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -214,109 +305,142 @@ TALER_amount_cmp (struct TALER_Amount a1,
|
|||||||
/**
|
/**
|
||||||
* Perform saturating subtraction of amounts.
|
* Perform saturating subtraction of amounts.
|
||||||
*
|
*
|
||||||
|
* @param diff where to store (@a a1 - @a a2), or invalid if @a a2 > @a a1
|
||||||
* @param a1 amount to subtract from
|
* @param a1 amount to subtract from
|
||||||
* @param a2 amount to subtract
|
* @param a2 amount to subtract
|
||||||
* @return (a1-a2) or 0 if a2>=a1
|
* @return #GNUNET_OK if the subtraction worked,
|
||||||
|
* #GNUNET_NO if @a a1 = @a a2
|
||||||
|
* #GNUNET_SYSERR if @a a2 > @a a1 or currencies are incompatible;
|
||||||
|
* @a diff is set to invalid
|
||||||
*/
|
*/
|
||||||
struct TALER_Amount
|
int
|
||||||
TALER_amount_subtract (struct TALER_Amount a1,
|
TALER_amount_subtract (struct TALER_Amount *diff,
|
||||||
struct TALER_Amount a2)
|
const struct TALER_Amount *a1,
|
||||||
|
const struct TALER_Amount *a2)
|
||||||
{
|
{
|
||||||
a1 = TALER_amount_normalize (a1);
|
struct TALER_Amount n1;
|
||||||
a2 = TALER_amount_normalize (a2);
|
struct TALER_Amount n2;
|
||||||
|
|
||||||
if (a1.value < a2.value)
|
if (GNUNET_YES !=
|
||||||
|
TALER_amount_cmp_currency (a1, a2))
|
||||||
{
|
{
|
||||||
a1.value = 0;
|
invalidate (diff);
|
||||||
a1.fraction = 0;
|
return GNUNET_SYSERR;
|
||||||
return a1;
|
|
||||||
}
|
}
|
||||||
|
n1 = *a1;
|
||||||
|
n2 = *a2;
|
||||||
|
TALER_amount_normalize (&n1);
|
||||||
|
TALER_amount_normalize (&n2);
|
||||||
|
|
||||||
if (a1.fraction < a2.fraction)
|
if (n1.fraction < n2.fraction)
|
||||||
{
|
{
|
||||||
if (0 == a1.value)
|
if (0 == n1.value)
|
||||||
{
|
{
|
||||||
a1.fraction = 0;
|
invalidate (diff);
|
||||||
return a1;
|
return GNUNET_SYSERR;
|
||||||
}
|
}
|
||||||
a1.fraction += AMOUNT_FRAC_BASE;
|
n1.fraction += TALER_AMOUNT_FRAC_BASE;
|
||||||
a1.value -= 1;
|
n1.value--;
|
||||||
}
|
}
|
||||||
|
if (n1.value < n2.value)
|
||||||
a1.fraction -= a2.fraction;
|
{
|
||||||
a1.value -= a2.value;
|
invalidate (diff);
|
||||||
|
return GNUNET_SYSERR;
|
||||||
return a1;
|
}
|
||||||
|
GNUNET_assert (GNUNET_OK ==
|
||||||
|
TALER_amount_get_zero (a1->currency,
|
||||||
|
diff));
|
||||||
|
GNUNET_assert (n1.fraction >= n2.fraction);
|
||||||
|
diff->fraction = n1.fraction - n2.fraction;
|
||||||
|
GNUNET_assert (n1.value >= n2.value);
|
||||||
|
diff->value = n1.value - n2.value;
|
||||||
|
if ( (0 == diff->fraction) &&
|
||||||
|
(0 == diff->value) )
|
||||||
|
return GNUNET_NO;
|
||||||
|
return GNUNET_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform saturating addition of amounts.
|
* Perform addition of amounts.
|
||||||
*
|
*
|
||||||
|
* @param sum where to store @a a1 + @a a2, set to "invalid" on overflow
|
||||||
* @param a1 first amount to add
|
* @param a1 first amount to add
|
||||||
* @param a2 second amount to add
|
* @param a2 second amount to add
|
||||||
* @return sum of a1 and a2
|
* @return #GNUNET_OK if the addition worked,
|
||||||
|
* #GNUNET_SYSERR on overflow
|
||||||
*/
|
*/
|
||||||
struct TALER_Amount
|
int
|
||||||
TALER_amount_add (struct TALER_Amount a1,
|
TALER_amount_add (struct TALER_Amount *sum,
|
||||||
struct TALER_Amount a2)
|
const struct TALER_Amount *a1,
|
||||||
|
const struct TALER_Amount *a2)
|
||||||
{
|
{
|
||||||
a1 = TALER_amount_normalize (a1);
|
struct TALER_Amount n1;
|
||||||
a2 = TALER_amount_normalize (a2);
|
struct TALER_Amount n2;
|
||||||
|
|
||||||
a1.value += a2.value;
|
if (GNUNET_YES !=
|
||||||
a1.fraction += a2.fraction;
|
TALER_amount_cmp_currency (a1, a2))
|
||||||
|
|
||||||
if (0 == a1.currency[0])
|
|
||||||
{
|
{
|
||||||
memcpy (a2.currency,
|
invalidate (sum);
|
||||||
a1.currency,
|
return GNUNET_SYSERR;
|
||||||
TALER_CURRENCY_LEN);
|
|
||||||
}
|
}
|
||||||
|
n1 = *a1;
|
||||||
|
n2 = *a2;
|
||||||
|
TALER_amount_normalize (&n1);
|
||||||
|
TALER_amount_normalize (&n2);
|
||||||
|
|
||||||
if (0 == a2.currency[0])
|
GNUNET_assert (GNUNET_OK ==
|
||||||
|
TALER_amount_get_zero (a1->currency,
|
||||||
|
sum));
|
||||||
|
sum->value = n1.value + n2.value;
|
||||||
|
if (sum->value < n1.value)
|
||||||
{
|
{
|
||||||
memcpy (a1.currency,
|
/* integer overflow */
|
||||||
a2.currency,
|
invalidate (sum);
|
||||||
TALER_CURRENCY_LEN);
|
return GNUNET_SYSERR;
|
||||||
}
|
}
|
||||||
|
sum->fraction = n1.fraction + n2.fraction;
|
||||||
if ( (0 != a1.currency[0]) &&
|
if (GNUNET_SYSERR ==
|
||||||
(0 != memcmp (a1.currency,
|
TALER_amount_normalize (sum))
|
||||||
a2.currency,
|
|
||||||
TALER_CURRENCY_LEN)) )
|
|
||||||
{
|
{
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
/* integer overflow via carry from fraction */
|
||||||
"adding mismatching currencies\n");
|
invalidate (sum);
|
||||||
|
return GNUNET_SYSERR;
|
||||||
}
|
}
|
||||||
|
return GNUNET_OK;
|
||||||
if (a1.value < a2.value)
|
|
||||||
{
|
|
||||||
a1.value = UINT32_MAX;
|
|
||||||
a2.value = UINT32_MAX;
|
|
||||||
return a1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return TALER_amount_normalize (a1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Normalize the given amount.
|
* Normalize the given amount.
|
||||||
*
|
*
|
||||||
* @param amout amount to normalize
|
* @param amount amount to normalize
|
||||||
* @return normalized amount
|
* @return #GNUNET_OK if normalization worked
|
||||||
|
* #GNUNET_NO if value was already normalized
|
||||||
|
* #GNUNET_SYSERR if value was invalid or could not be normalized
|
||||||
*/
|
*/
|
||||||
struct TALER_Amount
|
int
|
||||||
TALER_amount_normalize (struct TALER_Amount amount)
|
TALER_amount_normalize (struct TALER_Amount *amount)
|
||||||
{
|
{
|
||||||
while ( (amount.value != UINT32_MAX) &&
|
int ret;
|
||||||
(amount.fraction >= AMOUNT_FRAC_BASE) )
|
|
||||||
|
if (GNUNET_YES != test_valid (amount))
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
ret = GNUNET_NO;
|
||||||
|
while ( (amount->value != UINT64_MAX) &&
|
||||||
|
(amount->fraction >= TALER_AMOUNT_FRAC_BASE) )
|
||||||
{
|
{
|
||||||
amount.fraction -= AMOUNT_FRAC_BASE;
|
amount->fraction -= TALER_AMOUNT_FRAC_BASE;
|
||||||
amount.value += 1;
|
amount->value++;
|
||||||
|
ret = GNUNET_OK;
|
||||||
}
|
}
|
||||||
return amount;
|
if (amount->fraction >= TALER_AMOUNT_FRAC_BASE)
|
||||||
|
{
|
||||||
|
/* failed to normalize, adding up fractions caused
|
||||||
|
main value to overflow! */
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -327,40 +451,40 @@ TALER_amount_normalize (struct TALER_Amount amount)
|
|||||||
* @return freshly allocated string representation
|
* @return freshly allocated string representation
|
||||||
*/
|
*/
|
||||||
char *
|
char *
|
||||||
TALER_amount_to_string (struct TALER_Amount amount)
|
TALER_amount_to_string (const struct TALER_Amount *amount)
|
||||||
{
|
|
||||||
char tail[AMOUNT_FRAC_LEN + 1] = { 0 };
|
|
||||||
char curr[TALER_CURRENCY_LEN + 1] = { 0 };
|
|
||||||
char *result = NULL;
|
|
||||||
int len;
|
|
||||||
|
|
||||||
memcpy (curr, amount.currency, TALER_CURRENCY_LEN);
|
|
||||||
|
|
||||||
amount = TALER_amount_normalize (amount);
|
|
||||||
if (0 != amount.fraction)
|
|
||||||
{
|
{
|
||||||
|
char *result;
|
||||||
|
uint32_t n;
|
||||||
|
char tail[TALER_AMOUNT_FRAC_LEN + 1];
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
uint32_t n = amount.fraction;
|
struct TALER_Amount norm;
|
||||||
for (i = 0; (i < AMOUNT_FRAC_LEN) && (n != 0); i++)
|
|
||||||
|
if (GNUNET_YES != test_valid (amount))
|
||||||
|
return NULL;
|
||||||
|
norm = *amount;
|
||||||
|
GNUNET_break (GNUNET_SYSERR !=
|
||||||
|
TALER_amount_normalize (&norm));
|
||||||
|
if (0 != (n = norm.fraction))
|
||||||
{
|
{
|
||||||
tail[i] = '0' + (n / (AMOUNT_FRAC_BASE / 10));
|
for (i = 0; (i < TALER_AMOUNT_FRAC_LEN) && (0 != n); i++)
|
||||||
n = (n * 10) % (AMOUNT_FRAC_BASE);
|
{
|
||||||
|
tail[i] = '0' + (n / (TALER_AMOUNT_FRAC_BASE / 10));
|
||||||
|
n = (n * 10) % (TALER_AMOUNT_FRAC_BASE);
|
||||||
}
|
}
|
||||||
tail[i] = 0;
|
tail[i] = '\0';
|
||||||
len = GNUNET_asprintf (&result,
|
GNUNET_asprintf (&result,
|
||||||
"%s:%lu.%s",
|
"%s:%llu.%s",
|
||||||
curr,
|
norm.currency,
|
||||||
(unsigned long) amount.value,
|
(unsigned long long) norm.value,
|
||||||
tail);
|
tail);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
len = GNUNET_asprintf (&result,
|
GNUNET_asprintf (&result,
|
||||||
"%s:%lu",
|
"%s:%llu",
|
||||||
curr,
|
norm.currency,
|
||||||
(unsigned long) amount.value);
|
(unsigned long long) norm.value);
|
||||||
}
|
}
|
||||||
GNUNET_assert (len > 0);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,14 +48,25 @@
|
|||||||
* @return a json object describing the amount
|
* @return a json object describing the amount
|
||||||
*/
|
*/
|
||||||
json_t *
|
json_t *
|
||||||
TALER_JSON_from_amount (struct TALER_Amount amount)
|
TALER_JSON_from_amount (const struct TALER_Amount *amount)
|
||||||
{
|
{
|
||||||
json_t *j;
|
json_t *j;
|
||||||
|
|
||||||
|
if ( (amount->value != (uint64_t) ((json_int_t) amount->value)) ||
|
||||||
|
(0 > ((json_int_t) amount->value)) )
|
||||||
|
{
|
||||||
|
/* Theoretically, json_int_t can be a 32-bit "long", or we might
|
||||||
|
have a 64-bit value which converted to a 63-bit signed long
|
||||||
|
long causes problems here. So we check. Note that depending
|
||||||
|
on the platform, the compiler may be able to statically tell
|
||||||
|
that at least the first check is always false. */
|
||||||
|
GNUNET_break (0);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
j = json_pack ("{s:s, s:I, s:I}",
|
j = json_pack ("{s:s, s:I, s:I}",
|
||||||
"currency", amount.currency,
|
"currency", amount->currency,
|
||||||
"value", (json_int_t) amount.value,
|
"value", (json_int_t) amount->value,
|
||||||
"fraction", (json_int_t) amount.fraction);
|
"fraction", (json_int_t) amount->fraction);
|
||||||
GNUNET_assert (NULL != j);
|
GNUNET_assert (NULL != j);
|
||||||
return j;
|
return j;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user