add check for #coins depoisted exceeding #coins issued (not just by amount), fixes #5446

This commit is contained in:
Christian Grothoff 2018-11-04 16:20:09 +01:00
parent 33441042a9
commit 332341cb7b
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2016, 2017 Taler Systems SA
Copyright (C) 2016, 2017, 2018 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU Affero Public License as published by the Free Software
@ -329,7 +329,7 @@ report (json_t *array,
* @param risk maximum risk that might have just become real (coins created by this @a dki)
*/
static void
report_emergency (const struct TALER_EXCHANGEDB_DenominationKeyInformationP *dki,
report_emergency_by_amount (const struct TALER_EXCHANGEDB_DenominationKeyInformationP *dki,
const struct TALER_Amount *risk)
{
report (report_emergencies,
@ -351,6 +351,49 @@ report_emergency (const struct TALER_EXCHANGEDB_DenominationKeyInformationP *dki
}
/**
* Called in case we detect an emergency situation where the exchange
* is paying out a larger NUMBER of coins of a denomination than we
* issued in that denomination. This means that the exchange's
* private keys might have gotten compromised, and that we need to
* trigger an emergency request to all wallets to deposit pending
* coins for the denomination (and as an exchange suffer a huge
* financial loss).
*
* @param dki denomination key where the loss was detected
* @param num_issued number of coins that were issued
* @param num_known number of coins that have been deposited
* @param risk amount that is at risk
*/
static void
report_emergency_by_count (const struct TALER_EXCHANGEDB_DenominationKeyInformationP *dki,
uint64_t num_issued,
uint64_t num_known,
const struct TALER_Amount *risk)
{
report (report_emergencies,
json_pack ("{s:o, s:I, s:I, s:o, s:s, s:s, s:o}",
"denompub_hash",
GNUNET_JSON_from_data_auto (&dki->properties.denom_hash),
"num_issued",
(json_int_t) num_issued,
"num_known",
(json_int_t) num_known,
"denom_risk",
TALER_JSON_from_amount (risk),
"start",
GNUNET_STRINGS_absolute_time_to_string (GNUNET_TIME_absolute_ntoh (dki->properties.start)),
"deposit_end",
GNUNET_STRINGS_absolute_time_to_string (GNUNET_TIME_absolute_ntoh (dki->properties.expire_deposit)),
"value",
TALER_JSON_from_amount_nbo (&dki->properties.value)));
GNUNET_assert (GNUNET_OK ==
TALER_amount_add (&reported_emergency_sum,
&reported_emergency_sum,
risk));
}
/**
* Report a (serious) inconsistency in the exchange's database with
* respect to calculations involving amounts.
@ -2962,10 +3005,32 @@ sync_denomination (void *cls,
}
else
{
long long cnt;
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Final balance for denomination `%s' is %s\n",
"Final balance for denomination `%s' is %s (%llu)\n",
GNUNET_h2s (denom_hash),
TALER_amount2s (&ds->denom_balance));
TALER_amount2s (&ds->denom_balance),
(unsigned long long) ds->num_issued);
cnt = edb->count_known_coins (edb->cls,
esession,
denom_hash);
if (0 > cnt)
{
/* Failed to obtain count? Bad database */
qs = (enum GNUNET_DB_QueryStatus) cnt;
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
cc->qs = qs;
}
else
{
if (ds->num_issued > (uint64_t) cnt)
{
report_emergency_by_count (dki,
cnt,
ds->num_issued,
&ds->denom_risk);
}
if (ds->in_db)
qs = adb->update_denomination_balance (adb->cls,
asession,
@ -2981,6 +3046,7 @@ sync_denomination (void *cls,
&ds->denom_risk,
ds->num_issued);
}
}
if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
{
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
@ -3272,7 +3338,6 @@ refresh_session_cb (void *cls,
amount_with_fee));
return GNUNET_OK;
}
// FIXME: free reveal_ctx.num_newcoins later!
{
const struct TALER_EXCHANGEDB_DenominationKeyInformationP *new_dkis[reveal_ctx.num_newcoins];
@ -3436,8 +3501,9 @@ refresh_session_cb (void *cls,
&dso->denom_balance,
amount_with_fee))
{
report_emergency (dki,
report_emergency_by_amount (dki,
&dso->denom_risk);
/* FIXME: we can't exactly just stop here! */
return GNUNET_SYSERR;
}
dso->denom_balance = tmp;
@ -3593,8 +3659,9 @@ deposit_cb (void *cls,
&ds->denom_balance,
amount_with_fee))
{
report_emergency (dki,
report_emergency_by_amount (dki,
&ds->denom_risk);
/* FIXME: we can't exactly just stop here like this! */
cc->qs = GNUNET_DB_STATUS_HARD_ERROR;
return GNUNET_SYSERR;
}