From cc09fbbb29d3e24bdc668cfc65848b05ea63e4e5 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Mon, 6 Nov 2017 14:54:52 +0100 Subject: [PATCH] working on #4962 --- contrib/auditor-report.tex.j2 | 227 +++++++++++++++++++- src/auditor/taler-auditor.c | 391 +++++++++++++++++++++------------- 2 files changed, 459 insertions(+), 159 deletions(-) diff --git a/contrib/auditor-report.tex.j2 b/contrib/auditor-report.tex.j2 index ff31e7b05..9f454ffe6 100644 --- a/contrib/auditor-report.tex.j2 +++ b/contrib/auditor-report.tex.j2 @@ -58,11 +58,11 @@ This section analyzes the income of the exchange operator from fees. \end{table} -\section{Irregularities} +\section{Major irregularities} -This section describes the possible irregularities that the auditor -has checked, and lists all of the actual irregularities encountered -in detail. +This section describes the possible major irregularities that the +auditor has checked, and lists all of the actual irregularities +encountered in detail. \subsection{Emergencies} @@ -108,11 +108,8 @@ compromise. {% endif %} -\subsection{Reserve inconsistencies} -{% if data.reserve_inconsistencies|length() == 0 %} - {\bf No reserve inconsistencies detected.} -{% else %} + \begin{longtable}{p{1.5cm}|rl|rl|p{4cm}} {\bf Reserve} & \multicolumn{2}{|c|}{ {\bf Expected}} & \multicolumn{2}{|c|}{ {\bf Observed}} & {\bf Diagnostic} \\ \hline \hline \endfirsthead @@ -138,6 +135,220 @@ compromise. {{ item.diagnostic }} \\ \hline {% endfor %} \end{longtable} + + +\subsection{Reserve withdrawals exceeding balance} + +This section highlights cases where more coins were withdrawn from a +reserve than the reserve contained funding for. This is a serious +compromise resulting in proportional financial losses to the exchange. + + +{% if data.reserve_balance_insufficient_inconsistencies|length() == 0 %} + {\bf All withdrawals were covered by sufficient reserve funding.} +{% else %} + \begin{longtable}{p{4.5cm}|rl} + {\bf Reserve} & \multicolumn{2}{|c|}{ {\bf Loss}} \\ \hline \hline +\endfirsthead + {\bf Reserve} & \multicolumn{2}{|c|}{ {\bf Loss}} \\ \hline \hline +\endhead + \hline \hline + {\bf Reserve} & \multicolumn{2}{|c|}{ {\bf Loss}} +\endfoot + \hline + {\bf Total loss} & & + {{ data.total_loss_balance_insufficient.value}}.{{ data.total_loss_balance_insufficient.fraction}} & {{ data.total_loss_balance_insufficient.currency}} \\ + \caption{Reserves with withdrawals higher than reserve funding.} + \label{table:reserve:balance_insufficient} +\endlastfoot +{% for item in data.reserve_balance_insufficient_inconsistencies %} + \multicolumn{3}{l}{ {\tt {{ item.reserve_pub }} } } \\ +\nopagebreak + & + {{ item.loss.value }}.{{ item.loss.fraction }} & + {{ item.loss.currency }} \\ \hline +{% endfor %} + \end{longtable} {% endif %} + +\subsection{Claimed outgoing wire transfers} + +This section is about the exchange's database containing a +justification to make an outgoing wire transfer for an aggregated +amount for various deposits. It is reported as an inconsistency if the +amount claimed for the wire transfer does not match up the deposits +aggregated. This is about a {\em claimed} outgoing wire transfer as +violations do not imply that the wire transfer was actually made (as +that is a separate check). Note that not making the wire transfer +would be reported separately in Section~\ref{sec:wire_check_out}. + + +{% if data.reserve_wire_out_inconsistencies|length() == 0 %} + {\bf All aggregations matched up.} +{% else %} + \begin{longtable}{p{1.5cm}|l|rl|rl} + {\bf Destination account} & {\bf Database row} & \multicolumn{2}{|c|}{ {\bf Expected}} & \multicolumn{2}{|c|}{ {\bf Claimed}} \\ \hline \hline +\endfirsthead + {\bf Destination account} & {\bf Database row} & \multicolumn{2}{|c|}{ {\bf Expected}} & \multicolumn{2}{|c|}{ {\bf Claimed}} \\ \hline \hline +\endhead + \hline \hline + {\bf Destination account} & {\bf Database row} & \multicolumn{2}{|c|}{ {\bf Expected}} & \multicolumn{2}{|c|}{ {\bf Claimed}} \\ +\endfoot + \hline + {\bf Total deltas} & & + {{ data.total_wire_out_delta_plus.value}}.{{ data.total_wire_out_delta_plus.fraction}} & {{ data.total_wire_out_delta_plus.currency}} & + - {{ data.total_wire_out_delta_minus.value}}.{{ data.total_wire_out_delta_minus.fraction}} & {{ data.total_wire_out_delta_minus.currency}} \\ + \caption{Claimed wire out aggregate totals not matching up.} + \label{table:reserve:wire_out_balance_inconsistencies} +\endlastfoot +{% for item in data.wire_out_inconsistencies %} + \multicolumn{6}{l}{ {\tt {{ item.destination_account }} } } \\ +\nopagebreak + & {{ item.rowid }} & + {{ item.expected.value }}.{{ item.expected.fraction }} & + {{ item.expected.currency }} & + {{ item.claimed.value }}.{{ item.claimed.fraction }} & + {{ item.claimed.currency }} \\ \hline +{% endfor %} + \end{longtable} +{% endif %} + + +\subsection{Coin history inconsistencies} + +TODO. + + +\subsection{Actual incoming wire transfers} + +TBD. See bug 4958. + +\subsection{Actual outgoing wire transfers} \label{sec:wire_check_out} + +TBD. See bug 4958. + +\section{Minor irregularities} + +\subsection{Incorrect reserve balance summary in database} + +This section highlights cases where the reserve balance summary +in the database does not match the calculations made by the auditor. +Deltas may indicate a corrupt database, but do not necessarily +translate into a financial loss (yet). + + +{% if data.reserve_balance_summary_wrong_inconsistencies|length() == 0 %} + {\bf All balances matched up.} +{% else %} + \begin{longtable}{p{1.5cm}|rl|rl} + {\bf Reserve} & \multicolumn{2}{|c|}{ {\bf Auditor}} & \multicolumn{2}{|c|}{ {\bf Exchange}} \\ \hline \hline +\endfirsthead + {\bf Reserve} & \multicolumn{2}{|c|}{ {\bf Auditor}} & \multicolumn{2}{|c|}{ {\bf Exchange}} \\ \hline \hline +\endhead + \hline \hline + {\bf Reserve} & \multicolumn{2}{|c|}{ {\bf Auditor}} & \multicolumn{2}{|c|}{ {\bf Exchange}} +\endfoot + \hline + {\bf Total deltas} & & + {{ data.total_balance_summary_delta_plus.value}}.{{ data.total_balance_summary_delta_plus.fraction}} & {{ data.total_balance_summary_delta_plus.currency}} & + - {{ data.total_balance_summary_delta_minus.value}}.{{ data.total_balance_summary_delta_minus.fraction}} & {{ data.total_balance_summary_delta_minus.currency}} \\ + \caption{Reserves balances not matching up.} + \label{table:reserve:balance_inconsistencies} +\endlastfoot +{% for item in data.reserve_balance_summary_wrong_inconsistencies %} + \multicolumn{5}{l}{ {\tt {{ item.reserve_pub }} } } \\ +\nopagebreak + & + {{ item.auditor.value }}.{{ item.auditor.fraction }} & + {{ item.auditor.currency }} & + {{ item.exchange.value }}.{{ item.exchange.fraction }} & + {{ item.exchange.currency }} \\ \hline +{% endfor %} + \end{longtable} +{% endif %} + + +\section{Delays and timing} + +This section describes issues that are likely caused simply by +some job process of the exchange not running properly or not having +caught up with the work load yet. + +\subsection{Delayed closure of reserves} + +This section describes cases where the exchange did not +close a reserve and wire back the remaining funds when the +reserve expired. + + +{% if data.reserve_not_closed_inconsistencies|length() == 0 %} + {\bf All expired reserves were closed.} +{% else %} + \begin{longtable}{p{1.5cm}|c|rl} + {\bf Reserve} & {\bf Expired} & \multicolumn{2}{|c|}{ {\bf Balance}} \\ \hline \hline +\endfirsthead + {\bf Reserve} & {\bf Expired} & \multicolumn{2}{|c|}{ {\bf Balance}} \\ \hline \hline +\endhead + \hline \hline + {\bf Reserve} & {\bf Expired} & \multicolumn{2}{|c|}{ {\bf Balance}} +\endfoot + \hline + {\bf Sum} & & + {{ data.total_balance_reserve_not_closed.value}}.{{ data.total_balance_reserve_not_closed.fraction}} & {{ data.total_balance_reserve_not_closed.currency}} \\ + \caption{Reserves not closed on time.} + \label{table:reserve:not_closed} +\endlastfoot +{% for item in data.reserve_not_closed_inconsistencies %} + \multicolumn{4}{l}{ {\tt {{ item.reserve_pub }} } } \\ +\nopagebreak + & + {{ item.expiration_time }} & + {{ item.balance.value }}.{{ item.balance.fraction }} & + {{ item.balance.currency }} \\ \hline +{% endfor %} + \end{longtable} +{% endif %} + + +\subsection{Denomination key invalid at time of withdrawal} + +This section lists cases where a denomination key was not valid for +withdrawal at the time when the exchange claims to have signed a coin +with it. This would be irregular, but has no obvious financial +implications. + + +{% if data.denomination_key_validity_withdraw_inconsistencies|length() == 0 %} + {\bf All denomination keys were valid at the time of withdrawals.} +{% else %} + \begin{longtable}{p{7.5cm}|c} + {\bf Reserve} & {\bf Table row} \\ + {\bf Denomination key hash} & {\bf Execution time} \\ \hline \hline +\endfirsthead + {\bf Reserve} & {\bf Table row} \\ + {\bf Denomination key hash} & {\bf Execution time} \\ \hline \hline +\endhead + \hline \hline + {\bf Reserve} & {\bf Table row} \\ + {\bf Denomination key hash} & {\bf Execution time} \\ +\endfoot + \hline + {\bf Reserve} & {\bf Table row} \\ + {\bf Denomination key hash} & {\bf Execution time} \\ + \caption{Execution times not matching denomination key validity period.} + \label{table:withdraw:bad_time} +\endlastfoot +{% for item in data.denomination_key_validity_withdraw_inconsistencies %} + {\tt {{ item.reserve_pub }} } & {{ item.row }} \\ +\nopagebreak + & + {\tt {{ item.denompub_h }} } & {{ item.execution_date }} \\ \hline +{% endfor %} + \end{longtable} +{% endif %} + + + + \end{document} diff --git a/src/auditor/taler-auditor.c b/src/auditor/taler-auditor.c index 4dbcaea89..1190e5c34 100644 --- a/src/auditor/taler-auditor.c +++ b/src/auditor/taler-auditor.c @@ -125,20 +125,65 @@ static json_t *report_emergencies; static json_t *report_row_inconsistencies; /** - * Array of reports about minor row inconcistencies. + * Array of reports about the denomination key not being + * valid at the time of withdrawal. */ -static json_t *report_row_minor_inconsistencies; +static json_t *denomination_key_validity_withdraw_inconsistencies; /** - * Array of reports about reserve inconsitencies. + * Array of reports about reserve balance insufficient inconsitencies. */ -static json_t *report_reserve_inconsistencies; +static json_t *report_reserve_balance_insufficient_inconsistencies; + +/** + * Total amount reserves were charged beyond their balance. + */ +static struct TALER_Amount total_balance_insufficient_loss; + +/** + * Array of reports about reserve balance summary wrong in database. + */ +static json_t *report_reserve_balance_summary_wrong_inconsistencies; + +/** + * Total delta between expected and stored reserve balance summaries, + * for positive deltas. + */ +static struct TALER_Amount total_balance_summary_delta_plus; + +/** + * Total delta between expected and stored reserve balance summaries, + * for negative deltas. + */ +static struct TALER_Amount total_balance_summary_delta_minus; + +/** + * Array of reports about reserve's not being closed inconsitencies. + */ +static json_t *report_reserve_not_closed_inconsistencies; + +/** + * Total amount affected by reserves not having been closed on time. + */ +static struct TALER_Amount total_balance_reserve_not_closed; /** * Array of reports about irregular wire out entries. */ static json_t *report_wire_out_inconsistencies; +/** + * Total delta between calculated and stored wire out transfers, + * for positive deltas. + */ +static struct TALER_Amount total_wire_out_delta_plus; + +/** + * Total delta between calculated and stored wire out transfers + * for negative deltas. + */ +static struct TALER_Amount total_wire_out_delta_minus; + /** * Array of reports about inconsistencies about coins. */ @@ -265,85 +310,6 @@ report_row_inconsistency (const char *table, } -/** - * Report a minor inconsistency in the exchange's database (i.e. something - * relating to timestamps that should have no financial implications). - * - * @param table affected table - * @param rowid affected row, UINT64_MAX if row is missing - * @param diagnostic message explaining the problem - */ -static void -report_row_minor_inconsistency (const char *table, - uint64_t rowid, - const char *diagnostic) -{ - report (report_row_minor_inconsistencies, - json_pack ("{s:s, s:I, s:s}", - "table", table, - "row", (json_int_t) rowid, - "diagnostic", diagnostic)); -} - - -/** - * Report a global inconsistency with respect to a reserve. - * - * @param reserve_pub the affected reserve - * @param expected expected amount - * @param observed observed amount - * @param diagnostic message explaining what @a expected and @a observed refer to - */ -static void -report_reserve_inconsistency (const struct TALER_ReservePublicKeyP *reserve_pub, - const struct TALER_Amount *expected, - const struct TALER_Amount *observed, - const char *diagnostic) -{ - report (report_reserve_inconsistencies, - json_pack ("{s:o, s:o, s:o, s:s}", - "reserve_pub", - GNUNET_JSON_from_data_auto (reserve_pub), - "expected", - TALER_JSON_from_amount (expected), - "observed", - TALER_JSON_from_amount (observed), - "diagnostic", - diagnostic)); -} - - -/** - * Report a global inconsistency with respect to a wire transfer. - * - * @param destination wire transfer target account - * @param rowid which row is the inconsitency in - * @param expected expected amount - * @param observed observed amount - * @param diagnostic message explaining what @a expected and @a observed refer to - */ -static void -report_wire_out_inconsistency (const json_t *destination, - uint64_t rowid, - const struct TALER_Amount *expected, - const struct TALER_Amount *observed, - const char *diagnostic) -{ - report (report_wire_out_inconsistencies, - json_pack ("{s:O, s:I, s:o, s:o, s:s}", - "destination_account", - destination, - "rowid", - (json_int_t) rowid, - "expected", - TALER_JSON_from_amount (expected), - "observed", - TALER_JSON_from_amount (observed), - "diagnostic", - diagnostic)); -} - - /** * Report a global inconsistency with respect to a coin's history. * @@ -594,10 +560,6 @@ load_auditor_reserve_summary (struct ReserveSummary *rs) TALER_amount_cmp_currency (&rs->total_in, &rs->a_balance)) ) { - report_row_inconsistency ("auditor-reserve-info", - rowid, - "currencies for reserve differ"); - /* TODO: find a sane way to continue... */ GNUNET_break (0); return GNUNET_DB_STATUS_HARD_ERROR; } @@ -781,9 +743,12 @@ handle_reserve_out (void *cls, if ( (valid_start.abs_value_us > execution_date.abs_value_us) || (expire_withdraw.abs_value_us < execution_date.abs_value_us) ) { - report_row_minor_inconsistency ("withdraw", - rowid, - "denomination key not valid at time of withdrawal"); + report (denomination_key_validity_withdraw_inconsistencies, + json_pack ("{s:I, s:s, s:o, s:o}", + "row", (json_int_t) rowid, + "execution_date", GNUNET_STRINGS_absolute_time_to_string (execution_date), + "reserve_pub", GNUNET_JSON_from_data_auto (reserve_pub), + "denompub_h", GNUNET_JSON_from_data_auto (&wsrd.h_denomination_pub))); } /* check reserve_sig */ @@ -1155,10 +1120,7 @@ verify_reserve_balance (void *cls, &rs->total_in, &rs->a_balance)) { - report_reserve_inconsistency (&rs->reserve_pub, - &rs->total_in, - &rs->a_balance, - "could not add old balance to new balance"); + GNUNET_break (0); goto cleanup; } @@ -1167,19 +1129,62 @@ verify_reserve_balance (void *cls, &balance, &rs->total_out)) { - report_reserve_inconsistency (&rs->reserve_pub, - &rs->total_in, - &rs->total_out, - "available balance insufficient to cover transfers"); + struct TALER_Amount loss; + + GNUNET_break (GNUNET_SYSERR != + TALER_amount_subtract (&loss, + &rs->total_out, + &balance)); + GNUNET_break (GNUNET_OK == + TALER_amount_add (&total_balance_insufficient_loss, + &total_balance_insufficient_loss, + &loss)); + report (report_reserve_balance_insufficient_inconsistencies, + json_pack ("{s:o, s:o, s:o, s:s}", + "reserve_pub", + GNUNET_JSON_from_data_auto (&rs->reserve_pub), + "loss", + TALER_JSON_from_amount (&loss))); goto cleanup; } if (0 != TALER_amount_cmp (&balance, &reserve.balance)) { - report_reserve_inconsistency (&rs->reserve_pub, - &balance, - &reserve.balance, - "computed balance does not match stored balance"); + struct TALER_Amount delta; + + if (0 < TALER_amount_cmp (&balance, + &reserve.balance)) + { + /* balance > reserve.balance */ + GNUNET_assert (GNUNET_OK == + TALER_amount_subtract (&delta, + &balance, + &reserve.balance)); + GNUNET_assert (GNUNET_OK == + TALER_amount_add (&total_balance_summary_delta_plus, + &total_balance_summary_delta_plus, + &delta)); + } + else + { + /* balance < reserve.balance */ + GNUNET_assert (GNUNET_OK == + TALER_amount_subtract (&delta, + &reserve.balance, + &balance)); + GNUNET_assert (GNUNET_OK == + TALER_amount_add (&total_balance_summary_delta_minus, + &total_balance_summary_delta_minus, + &delta)); + } + report (report_reserve_balance_summary_wrong_inconsistencies, + json_pack ("{s:o, s:o, s:o}", + "reserve_pub", + GNUNET_JSON_from_data_auto (&rs->reserve_pub), + "exchange", + TALER_JSON_from_amount (&reserve.balance), + "auditor", + TALER_JSON_from_amount (&balance))); goto cleanup; } @@ -1189,16 +1194,18 @@ verify_reserve_balance (void *cls, ( (0 != balance.value) || (0 != balance.fraction) ) ) { - struct TALER_Amount zero; - GNUNET_assert (GNUNET_OK == - TALER_amount_get_zero (balance.currency, - &zero)); - - report_reserve_inconsistency (&rs->reserve_pub, - &balance, - &zero, - "expired reserve needs to be closed"); + TALER_amount_add (&total_balance_reserve_not_closed, + &total_balance_reserve_not_closed, + &balance)); + report (report_reserve_not_closed_inconsistencies, + json_pack ("{s:o, s:o, s:s}", + "reserve_pub", + GNUNET_JSON_from_data_auto (&rs->reserve_pub), + "balance", + TALER_JSON_from_amount (&balance), + "expiration_time", + GNUNET_STRINGS_absolute_time_to_string (rs->a_expiration_date))); } /* Add withdraw fees we encountered to totals */ @@ -2206,10 +2213,8 @@ check_wire_out_cb (void *cls, TALER_JSON_hash (wire, &wcc.h_wire)) { - report_row_inconsistency ("wire_out", - rowid, - "could not hash wire address"); - return GNUNET_OK; + GNUNET_break (0); + return GNUNET_SYSERR; } qs = edb->lookup_wire_transfer (edb->cls, esession, @@ -2256,20 +2261,13 @@ check_wire_out_cb (void *cls, wcc.method); if (NULL == plugin) { - report_row_inconsistency ("wire_out", - rowid, - "could not load required wire plugin to validate"); - return GNUNET_OK; + GNUNET_break (0); + return GNUNET_SYSERR; } - if (GNUNET_SYSERR == - plugin->amount_round (plugin->cls, - &final_amount)) - { - report_row_minor_inconsistency ("wire_out", - rowid, - "wire plugin failed to round given amount"); - } + GNUNET_break (GNUNET_SYSERR != + plugin->amount_round (plugin->cls, + &final_amount)); /* Calculate the exchange's gain as the fees plus rounding differences! */ if (GNUNET_OK != @@ -2297,11 +2295,44 @@ check_wire_out_cb (void *cls, if (0 != TALER_amount_cmp (amount, &final_amount)) { - report_wire_out_inconsistency (wire, - rowid, - &final_amount, - amount, - "computed amount inconsistent with wire amount"); + struct TALER_Amount delta; + + if (0 < TALER_amount_cmp (amount, + &final_amount)) + { + /* amount > final_amount */ + GNUNET_assert (GNUNET_OK == + TALER_amount_subtract (&delta, + amount, + &final_amount)); + GNUNET_assert (GNUNET_OK == + TALER_amount_add (&total_wire_out_delta_plus, + &total_wire_out_delta_plus, + &delta)); + } + else + { + /* amount < final_amount */ + GNUNET_assert (GNUNET_OK == + TALER_amount_subtract (&delta, + &final_amount, + amount)); + GNUNET_assert (GNUNET_OK == + TALER_amount_add (&total_wire_out_delta_minus, + &total_wire_out_delta_minus, + &delta)); + } + + report (report_wire_out_inconsistencies, + json_pack ("{s:O, s:I, s:o, s:o}", + "destination_account", + wire, + "rowid", + (json_int_t) rowid, + "expected", + TALER_JSON_from_amount (&final_amount), + "claimed", + TALER_JSON_from_amount (amount))); return GNUNET_OK; } GNUNET_log (GNUNET_ERROR_TYPE_INFO, @@ -3777,14 +3808,36 @@ run (void *cls, GNUNET_assert (GNUNET_OK == TALER_amount_get_zero (currency, &total_aggregation_fee_income)); + GNUNET_assert (GNUNET_OK == + TALER_amount_get_zero (currency, + &total_balance_insufficient_loss)); + GNUNET_assert (GNUNET_OK == + TALER_amount_get_zero (currency, + &total_balance_summary_delta_plus)); + GNUNET_assert (GNUNET_OK == + TALER_amount_get_zero (currency, + &total_balance_summary_delta_minus)); + GNUNET_assert (GNUNET_OK == + TALER_amount_get_zero (currency, + &total_wire_out_delta_plus)); + GNUNET_assert (GNUNET_OK == + TALER_amount_get_zero (currency, + &total_wire_out_delta_minus)); + GNUNET_assert (GNUNET_OK == + TALER_amount_get_zero (currency, + &total_balance_reserve_not_closed)); GNUNET_assert (NULL != (report_emergencies = json_array ())); GNUNET_assert (NULL != (report_row_inconsistencies = json_array ())); GNUNET_assert (NULL != - (report_row_minor_inconsistencies = json_array ())); + (denomination_key_validity_withdraw_inconsistencies = json_array ())); GNUNET_assert (NULL != - (report_reserve_inconsistencies = json_array ())); + (report_reserve_balance_summary_wrong_inconsistencies = json_array ())); + GNUNET_assert (NULL != + (report_reserve_balance_insufficient_inconsistencies = json_array ())); + GNUNET_assert (NULL != + (report_reserve_not_closed_inconsistencies = json_array ())); GNUNET_assert (NULL != (report_wire_out_inconsistencies = json_array ())); GNUNET_assert (NULL != @@ -3810,26 +3863,62 @@ run (void *cls, &income_fee_total, &total_aggregation_fee_income)); report = json_pack ("{s:o, s:o, s:o, s:o, s:o," - " s:o, s:o, s:o, s:o, s:o" - " s:o, s:o, s:o, s:o, s:o}", + " s:o, s:o, s:o, s:o, s:o," + " s:o, s:o, s:o, s:o, s:o," + " s:o, s:o, s:o, s:o, s:o," + " s:o, s:o, s:o }", /* blocks of 5 for easier counting/matching to format string */ - "emergencies", report_emergencies, - "emergencies_risk_total", TALER_JSON_from_amount (&reported_emergency_sum), - "row_inconsistencies", report_row_inconsistencies, - "row_minor_inconsistencies", report_row_minor_inconsistencies, - "reserve_inconsistencies", report_reserve_inconsistencies, /* block */ - "wire_out_inconsistencies", report_wire_out_inconsistencies, - "coin_inconsistencies", report_coin_inconsistencies, - "total_aggregation_fee_income", TALER_JSON_from_amount (&total_aggregation_fee_income), - "total_escrow_balance", TALER_JSON_from_amount (&total_escrow_balance), - "total_active_risk", TALER_JSON_from_amount (&total_risk), + "reserve_balance_insufficient_inconsistencies", + report_reserve_balance_insufficient_inconsistencies, + "total_loss_balance_insufficient", + TALER_JSON_from_amount (&total_balance_insufficient_loss), + "reserve_balance_summary_wrong_inconsistencies", + report_reserve_balance_summary_wrong_inconsistencies, + "total_balance_summary_delta_plus", + TALER_JSON_from_amount (&total_balance_summary_delta_plus), + "total_balance_summary_delta_minus", + TALER_JSON_from_amount (&total_balance_summary_delta_minus), /* block */ - "total_withdraw_fee_income", TALER_JSON_from_amount (&total_withdraw_fee_income), - "total_deposit_fee_income", TALER_JSON_from_amount (&total_deposit_fee_income), - "total_melt_fee_income", TALER_JSON_from_amount (&total_melt_fee_income), - "total_refund_fee_income", TALER_JSON_from_amount (&total_refund_fee_income), - "income_fee_total", TALER_JSON_from_amount (&income_fee_total) + "total_escrow_balance", + TALER_JSON_from_amount (&total_escrow_balance), + "total_active_risk", + TALER_JSON_from_amount (&total_risk), + "total_withdraw_fee_income", + TALER_JSON_from_amount (&total_withdraw_fee_income), + "total_deposit_fee_income", + TALER_JSON_from_amount (&total_deposit_fee_income), + "total_melt_fee_income", + /* block */ + TALER_JSON_from_amount (&total_melt_fee_income), + "total_refund_fee_income", + TALER_JSON_from_amount (&total_refund_fee_income), + "income_fee_total", + TALER_JSON_from_amount (&income_fee_total), + "emergencies", + report_emergencies, + "emergencies_risk_total", + TALER_JSON_from_amount (&reported_emergency_sum), + /* block */ + "reserve_not_closed_inconsistencies", + report_reserve_not_closed_inconsistencies, + "total_balance_reserve_not_closed", + TALER_JSON_from_amount (&total_balance_reserve_not_closed), + "wire_out_inconsistencies", + report_wire_out_inconsistencies, + "total_wire_out_delta_plus", + TALER_JSON_from_amount (&total_wire_out_delta_plus), + "total_wire_out_delta_minus", + TALER_JSON_from_amount (&total_wire_out_delta_minus), + /* block */ + "row_inconsistencies", + report_row_inconsistencies, + "denomination_key_validity_withdraw_inconsistencies", + denomination_key_validity_withdraw_inconsistencies, + "coin_inconsistencies", + report_coin_inconsistencies, + "total_aggregation_fee_income", + TALER_JSON_from_amount (&total_aggregation_fee_income) ); json_dumpf (report, stdout,