This commit is contained in:
Christian Grothoff 2017-11-06 14:54:52 +01:00
parent c5f9c0ca88
commit cc09fbbb29
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
2 changed files with 459 additions and 159 deletions

View File

@ -58,11 +58,11 @@ This section analyzes the income of the exchange operator from fees.
\end{table} \end{table}
\section{Irregularities} \section{Major irregularities}
This section describes the possible irregularities that the auditor This section describes the possible major irregularities that the
has checked, and lists all of the actual irregularities encountered auditor has checked, and lists all of the actual irregularities
in detail. encountered in detail.
\subsection{Emergencies} \subsection{Emergencies}
@ -108,11 +108,8 @@ compromise.
{% endif %} {% 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}} \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 {\bf Reserve} & \multicolumn{2}{|c|}{ {\bf Expected}} & \multicolumn{2}{|c|}{ {\bf Observed}} & {\bf Diagnostic} \\ \hline \hline
\endfirsthead \endfirsthead
@ -138,6 +135,220 @@ compromise.
{{ item.diagnostic }} \\ \hline {{ item.diagnostic }} \\ \hline
{% endfor %} {% endfor %}
\end{longtable} \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 %} {% 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} \end{document}

View File

@ -125,20 +125,65 @@ static json_t *report_emergencies;
static json_t *report_row_inconsistencies; 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. * Array of reports about irregular wire out entries.
*/ */
static json_t *report_wire_out_inconsistencies; 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. * 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. * 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, TALER_amount_cmp_currency (&rs->total_in,
&rs->a_balance)) ) &rs->a_balance)) )
{ {
report_row_inconsistency ("auditor-reserve-info",
rowid,
"currencies for reserve differ");
/* TODO: find a sane way to continue... */
GNUNET_break (0); GNUNET_break (0);
return GNUNET_DB_STATUS_HARD_ERROR; 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) || if ( (valid_start.abs_value_us > execution_date.abs_value_us) ||
(expire_withdraw.abs_value_us < execution_date.abs_value_us) ) (expire_withdraw.abs_value_us < execution_date.abs_value_us) )
{ {
report_row_minor_inconsistency ("withdraw", report (denomination_key_validity_withdraw_inconsistencies,
rowid, json_pack ("{s:I, s:s, s:o, s:o}",
"denomination key not valid at time of withdrawal"); "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 */ /* check reserve_sig */
@ -1155,10 +1120,7 @@ verify_reserve_balance (void *cls,
&rs->total_in, &rs->total_in,
&rs->a_balance)) &rs->a_balance))
{ {
report_reserve_inconsistency (&rs->reserve_pub, GNUNET_break (0);
&rs->total_in,
&rs->a_balance,
"could not add old balance to new balance");
goto cleanup; goto cleanup;
} }
@ -1167,19 +1129,62 @@ verify_reserve_balance (void *cls,
&balance, &balance,
&rs->total_out)) &rs->total_out))
{ {
report_reserve_inconsistency (&rs->reserve_pub, struct TALER_Amount loss;
&rs->total_in,
&rs->total_out, GNUNET_break (GNUNET_SYSERR !=
"available balance insufficient to cover transfers"); 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; goto cleanup;
} }
if (0 != TALER_amount_cmp (&balance, if (0 != TALER_amount_cmp (&balance,
&reserve.balance)) &reserve.balance))
{ {
report_reserve_inconsistency (&rs->reserve_pub, struct TALER_Amount delta;
&balance,
&reserve.balance, if (0 < TALER_amount_cmp (&balance,
"computed balance does not match stored 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; goto cleanup;
} }
@ -1189,16 +1194,18 @@ verify_reserve_balance (void *cls,
( (0 != balance.value) || ( (0 != balance.value) ||
(0 != balance.fraction) ) ) (0 != balance.fraction) ) )
{ {
struct TALER_Amount zero;
GNUNET_assert (GNUNET_OK == GNUNET_assert (GNUNET_OK ==
TALER_amount_get_zero (balance.currency, TALER_amount_add (&total_balance_reserve_not_closed,
&zero)); &total_balance_reserve_not_closed,
&balance));
report_reserve_inconsistency (&rs->reserve_pub, report (report_reserve_not_closed_inconsistencies,
&balance, json_pack ("{s:o, s:o, s:s}",
&zero, "reserve_pub",
"expired reserve needs to be closed"); 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 */ /* Add withdraw fees we encountered to totals */
@ -2206,10 +2213,8 @@ check_wire_out_cb (void *cls,
TALER_JSON_hash (wire, TALER_JSON_hash (wire,
&wcc.h_wire)) &wcc.h_wire))
{ {
report_row_inconsistency ("wire_out", GNUNET_break (0);
rowid, return GNUNET_SYSERR;
"could not hash wire address");
return GNUNET_OK;
} }
qs = edb->lookup_wire_transfer (edb->cls, qs = edb->lookup_wire_transfer (edb->cls,
esession, esession,
@ -2256,20 +2261,13 @@ check_wire_out_cb (void *cls,
wcc.method); wcc.method);
if (NULL == plugin) if (NULL == plugin)
{ {
report_row_inconsistency ("wire_out", GNUNET_break (0);
rowid, return GNUNET_SYSERR;
"could not load required wire plugin to validate");
return GNUNET_OK;
} }
if (GNUNET_SYSERR == GNUNET_break (GNUNET_SYSERR !=
plugin->amount_round (plugin->cls, plugin->amount_round (plugin->cls,
&final_amount)) &final_amount));
{
report_row_minor_inconsistency ("wire_out",
rowid,
"wire plugin failed to round given amount");
}
/* Calculate the exchange's gain as the fees plus rounding differences! */ /* Calculate the exchange's gain as the fees plus rounding differences! */
if (GNUNET_OK != if (GNUNET_OK !=
@ -2297,11 +2295,44 @@ check_wire_out_cb (void *cls,
if (0 != TALER_amount_cmp (amount, if (0 != TALER_amount_cmp (amount,
&final_amount)) &final_amount))
{ {
report_wire_out_inconsistency (wire, struct TALER_Amount delta;
rowid,
&final_amount, if (0 < TALER_amount_cmp (amount,
amount, &final_amount))
"computed amount inconsistent with wire 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; return GNUNET_OK;
} }
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log (GNUNET_ERROR_TYPE_INFO,
@ -3777,14 +3808,36 @@ run (void *cls,
GNUNET_assert (GNUNET_OK == GNUNET_assert (GNUNET_OK ==
TALER_amount_get_zero (currency, TALER_amount_get_zero (currency,
&total_aggregation_fee_income)); &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 != GNUNET_assert (NULL !=
(report_emergencies = json_array ())); (report_emergencies = json_array ()));
GNUNET_assert (NULL != GNUNET_assert (NULL !=
(report_row_inconsistencies = json_array ())); (report_row_inconsistencies = json_array ()));
GNUNET_assert (NULL != GNUNET_assert (NULL !=
(report_row_minor_inconsistencies = json_array ())); (denomination_key_validity_withdraw_inconsistencies = json_array ()));
GNUNET_assert (NULL != 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 != GNUNET_assert (NULL !=
(report_wire_out_inconsistencies = json_array ())); (report_wire_out_inconsistencies = json_array ()));
GNUNET_assert (NULL != GNUNET_assert (NULL !=
@ -3810,26 +3863,62 @@ run (void *cls,
&income_fee_total, &income_fee_total,
&total_aggregation_fee_income)); &total_aggregation_fee_income));
report = json_pack ("{s:o, s:o, s:o, s:o, s:o," 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 */ /* 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 */ /* block */
"wire_out_inconsistencies", report_wire_out_inconsistencies, "reserve_balance_insufficient_inconsistencies",
"coin_inconsistencies", report_coin_inconsistencies, report_reserve_balance_insufficient_inconsistencies,
"total_aggregation_fee_income", TALER_JSON_from_amount (&total_aggregation_fee_income), "total_loss_balance_insufficient",
"total_escrow_balance", TALER_JSON_from_amount (&total_escrow_balance), TALER_JSON_from_amount (&total_balance_insufficient_loss),
"total_active_risk", TALER_JSON_from_amount (&total_risk), "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 */ /* block */
"total_withdraw_fee_income", TALER_JSON_from_amount (&total_withdraw_fee_income), "total_escrow_balance",
"total_deposit_fee_income", TALER_JSON_from_amount (&total_deposit_fee_income), TALER_JSON_from_amount (&total_escrow_balance),
"total_melt_fee_income", TALER_JSON_from_amount (&total_melt_fee_income), "total_active_risk",
"total_refund_fee_income", TALER_JSON_from_amount (&total_refund_fee_income), TALER_JSON_from_amount (&total_risk),
"income_fee_total", TALER_JSON_from_amount (&income_fee_total) "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, json_dumpf (report,
stdout, stdout,