more work on wire auditor and reporting (#4958)
This commit is contained in:
parent
45c443f348
commit
f8af22b882
4
.gitignore
vendored
4
.gitignore
vendored
@ -88,3 +88,7 @@ contrib/taler-exchange.tag
|
||||
doxygen-doc/
|
||||
src/exchange-lib/test_exchange_api_keys_cherry_picking
|
||||
src/auditor/taler-wire-auditor
|
||||
contrib/auditor-report.aux
|
||||
contrib/auditor-report.log
|
||||
contrib/auditor-report.tex
|
||||
contrib/auditor-report.pdf
|
||||
|
@ -311,11 +311,130 @@ public key for ``payback-master'' operations.
|
||||
|
||||
\subsection{Actual incoming wire transfers}
|
||||
|
||||
TBD. See bug 4958.
|
||||
This section highlights cases where the exchange's record about
|
||||
incoming wire transfers does not match with that of the bank.
|
||||
|
||||
{% if wire.reserve_in_amount_inconsistencies() == 0 %}
|
||||
{\bf All incoming wire transfer amounts and subjects matched up.}
|
||||
{% else %}
|
||||
\begin{longtable}{p{6.5cm}|rl|rl}
|
||||
{\bf Wire transfer identifier} & \multicolumn{2}{|c|}{ {\bf Wired}} & \multicolumn{2}{|c|}{ {\bf Expected}} \\
|
||||
{\bf Diagnostic} & \multicolumn{2}{|c|}{ {\bf Row}} & \multicolumn{2}{|c|}{ {\bf Timestamp}} \\
|
||||
\hline \hline
|
||||
\endfirsthead
|
||||
{\bf Wire transfer identifier} & \multicolumn{2}{|c|}{ {\bf Wired}} & \multicolumn{2}{|c|}{ {\bf Expected}} \\
|
||||
{\bf Diagnostic} & \multicolumn{2}{|c|}{ {\bf Row}} & \multicolumn{2}{|c|}{ {\bf Timestamp}} \\
|
||||
\hline \hline
|
||||
\endhead
|
||||
\hline \hline
|
||||
{\bf Wire transfer identifier} & \multicolumn{2}{|c|}{ {\bf Wired}} & \multicolumn{2}{|c|}{ {\bf Expected}} \\
|
||||
{\bf Diagnostic} & \multicolumn{2}{|c|}{ {\bf Row}} & \multicolumn{2}{|c|}{ {\bf Timestamp}} \\
|
||||
\endfoot
|
||||
\hline
|
||||
{\bf Total deltas} & &
|
||||
{{ wire.total_bad_amount_in_plus.value}}.{{ wire.total_bad_amount_in_plus.fraction}} & {{ wire.total_bad_amount_in_plus.currency}} &
|
||||
- {{ wire.total_bad_amount_in_minus.value}}.{{ wire.total_bad_amount_in_minus.fraction}} & {{ wire.total_bad_amount_in_minus.currency}} \\
|
||||
\caption{Incoming wire transfer amounts not matching up.}
|
||||
\label{table:wire_in:transfer_amount_inconsistencies}
|
||||
\endlastfoot
|
||||
{% for item in wire.reserve_in_amount_inconsistencies %}
|
||||
{\tt {{ item.wtid }} } &
|
||||
{{ item.amount_wired.value }}.{{ item.amount_wired.fraction }} &
|
||||
{{ item.amount_wired.currency }} &
|
||||
{{ item.amount_expected.value }}.{{ item.amount_expected.fraction }} &
|
||||
{{ item.amount_expected.currency }} \\ \hline
|
||||
\nopagebreak
|
||||
&
|
||||
{{ item.diagnostic }} &
|
||||
{{ item.row }} &
|
||||
{{ item.timestmap }} \\ \hline
|
||||
{% endfor %}
|
||||
\end{longtable}
|
||||
{% endif %}
|
||||
|
||||
|
||||
\subsection{Missattributed incoming wire transfers}
|
||||
|
||||
This section lists cases where the sender account record of an
|
||||
incoming wire transfer differs between the exchange and the bank.
|
||||
This will cause funds to be sent to the wrong account when the reserve
|
||||
is closed and the remaining balance is refunded to the original
|
||||
account.
|
||||
|
||||
|
||||
{% if wire.missattribution_in_inconsistencies() == 0 %}
|
||||
{\bf All incoming wire transfer sender accounts matched up.}
|
||||
{% else %}
|
||||
\begin{longtable}{p{6.5cm}|rl}
|
||||
{\bf Wire transfer identifier} & \multicolumn{2}{|c|}{ {\bf Amount}} \\
|
||||
\hline \hline
|
||||
\endfirsthead
|
||||
{\bf Wire transfer identifier} & \multicolumn{2}{|c|}{ {\bf Amount}} \\
|
||||
\hline \hline
|
||||
\endhead
|
||||
\hline \hline
|
||||
{\bf Wire transfer identifier} & \multicolumn{2}{|c|}{ {\bf Amount}} \\
|
||||
\endfoot
|
||||
\hline
|
||||
{\bf Total amount} &
|
||||
{{ wire.total_missattribution_in_plus.value}}.{{ wire.total_missattribution_in_plus.fraction}} & {{ wire.total_missattribution_in_plus.currency}} \\
|
||||
\caption{Incoming wire transfer sender accounts not matching up.}
|
||||
\label{table:wire_in:sender_account_inconsistencies}
|
||||
\endlastfoot
|
||||
{% for item in wire.missattribution_in_inconsistencies %}
|
||||
{\tt {{ item.wtid }} } &
|
||||
{{ item.amount.value }}.{{ item.amount.fraction }} &
|
||||
{{ item.amount.currency }} \\ hline
|
||||
{% endfor %}
|
||||
\end{longtable}
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
|
||||
\subsection{Actual outgoing wire transfers} \label{sec:wire_check_out}
|
||||
|
||||
TBD. See bug 4958.
|
||||
This section highlights cases where the exchange missbehaved
|
||||
with respect to outgoing wire transfers.
|
||||
|
||||
{% if wire.wire_out_amount_inconsistencies() == 0 %}
|
||||
{\bf All outgoing wire transfers matched up.}
|
||||
{% else %}
|
||||
\begin{longtable}{p{6.5cm}|rl|rl}
|
||||
{\bf Wire transfer identifier} & \multicolumn{2}{|c|}{ {\bf Wired}} & \multicolumn{2}{|c|}{ {\bf Justified}} \\
|
||||
{\bf Diagnostic} & \multicolumn{2}{|c|}{ {\bf Row}} & \multicolumn{2}{|c|}{ {\bf Timestamp}} \\
|
||||
\hline \hline
|
||||
\endfirsthead
|
||||
{\bf Wire transfer identifier} & \multicolumn{2}{|c|}{ {\bf Wired}} & \multicolumn{2}{|c|}{ {\bf Justified}} \\
|
||||
{\bf Diagnostic} & \multicolumn{2}{|c|}{ {\bf Row}} & \multicolumn{2}{|c|}{ {\bf Timestamp}} \\
|
||||
\hline \hline
|
||||
\endhead
|
||||
\hline \hline
|
||||
{\bf Wire transfer identifier} & \multicolumn{2}{|c|}{ {\bf Wired}} & \multicolumn{2}{|c|}{ {\bf Justified}} \\
|
||||
{\bf Diagnostic} & \multicolumn{2}{|c|}{ {\bf Row}} & \multicolumn{2}{|c|}{ {\bf Timestamp}} \\
|
||||
\endfoot
|
||||
\hline
|
||||
{\bf Total deltas} & &
|
||||
{{ wire.total_bad_amount_out_plus.value}}.{{ wire.total_bad_amount_out_plus.fraction}} & {{ wire.total_bad_amount_out_plus.currency}} &
|
||||
- {{ wire.total_bad_amount_out_minus.value}}.{{ wire.total_bad_amount_out_minus.fraction}} & {{ wire.total_bad_amount_out_minus.currency}} \\
|
||||
\caption{Outgoing wire transfer amounts not matching up.}
|
||||
\label{table:wire_out:transfer_amount_inconsistencies}
|
||||
\endlastfoot
|
||||
{% for item in wire.wire_out_amount_inconsistencies %}
|
||||
{\tt {{ item.wtid }} } &
|
||||
{{ item.amount_wired.value }}.{{ item.amount_wired.fraction }} &
|
||||
{{ item.amount_wired.currency }} &
|
||||
{{ item.amount_justified.value }}.{{ item.amount_justified.fraction }} &
|
||||
{{ item.amount_justified.currency }} \\ \hline
|
||||
\nopagebreak
|
||||
&
|
||||
{{ item.diagnostic }} &
|
||||
{{ item.row }} &
|
||||
{{ item.timestmap }} \\ \hline
|
||||
{% endfor %}
|
||||
\end{longtable}
|
||||
{% endif %}
|
||||
|
||||
|
||||
\section{Minor irregularities}
|
||||
|
||||
@ -358,6 +477,39 @@ translate into a financial loss (yet).
|
||||
{% endif %}
|
||||
|
||||
|
||||
\subsection{Wire table issues}
|
||||
|
||||
This section describes issues found by the wire auditor that do not
|
||||
have a clear financial impact.
|
||||
|
||||
{% if wire.row_inconsistencies|length() == 0 %}
|
||||
{\bf No wire row inconsistencies found.}
|
||||
{% else %}
|
||||
\begin{longtable}{p{1.5cm}|l|p{5.5}}
|
||||
{\bf Table} & {\bf Row} & {\bf Diagnostic} \\
|
||||
\hline \hline
|
||||
\endfirsthead
|
||||
{\bf Table} & {\bf Row} & {\bf Diagnostic} \\
|
||||
\hline \hline
|
||||
\endhead
|
||||
\hline \hline
|
||||
{\bf Table} & {\bf Row} & {\bf Diagnostic} \\
|
||||
\endfoot
|
||||
\hline
|
||||
{\bf Table} & {\bf Row} & {\bf Diagnostic} \\
|
||||
\caption{Other wire table issues found (by table and row).}
|
||||
\label{table:misc}
|
||||
\endlastfoot
|
||||
{% for item in data.row_inconsistencies %}
|
||||
{{ item.table }} &
|
||||
{{ item.row }} &
|
||||
{{ item.diagnostic }} \\
|
||||
\nopagebreak
|
||||
{{ item.wire_offset_hash }} \\ \hline
|
||||
{% endfor %}
|
||||
\end{longtable}
|
||||
{% endif %}
|
||||
|
||||
\subsection{Other issues}
|
||||
|
||||
This section describes issues found that do not have a clear financial
|
||||
@ -470,6 +622,34 @@ implications.
|
||||
{% endif %}
|
||||
|
||||
|
||||
\subsection{Wire transfer timestamp issues}
|
||||
|
||||
This section lists issues with wire transfers related to timestamps.
|
||||
|
||||
|
||||
{% if wire.row_minor_inconsistencies|length() == 0 %}
|
||||
{\bf No timestamp issues detected.}
|
||||
{% else %}
|
||||
\begin{longtable}{p{1.5cm}|r|p{5.5}}
|
||||
{\bf Table} & {\bf Table row} & {\bf Diagnostic}
|
||||
\\ \hline \hline
|
||||
\endfirsthead
|
||||
{\bf Table} & {\bf Table row} & {\bf Diagnostic}
|
||||
\\ \hline \hline
|
||||
\endhead
|
||||
\hline \hline
|
||||
{\bf Table} & {\bf Table row} & {\bf Diagnostic} \\
|
||||
\endfoot
|
||||
\hline \hline
|
||||
{\bf Table} & {\bf Table row} & {\bf Diagnostic} \\
|
||||
\caption{Execution times not matching in wire transfers.}
|
||||
\label{table:wire:bad_time}
|
||||
\endlastfoot
|
||||
{% for item in wire.row_minor_inconsistencies %}
|
||||
{\tt {{ item.table }} } & {{ item.row }} & {{ item.diagnostic }} \\ \hline
|
||||
{% endfor %}
|
||||
\end{longtable}
|
||||
{% endif %}
|
||||
|
||||
|
||||
\end{document}
|
||||
|
@ -1,14 +1,19 @@
|
||||
#!/usr/bin/python
|
||||
# This file is in the public domain.
|
||||
|
||||
"""
|
||||
Expand Jinja2 templates based on JSON input.
|
||||
"""Expand Jinja2 templates based on JSON input.
|
||||
|
||||
First command-line argument must be the JSON input.
|
||||
The tool reads the template from stdin and writes
|
||||
the expanded output to stdout.
|
||||
First command-line argument must be the JSON input from taler-auditor.
|
||||
Second command-line argument must be the JSON input from the
|
||||
taler-wire-auditor.
|
||||
|
||||
The tool then reads the template from stdin and writes the expanded
|
||||
output to stdout.
|
||||
|
||||
TODO: proper installation, man page, error handling, --help option.
|
||||
|
||||
@author Christian Grothoff
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
@ -25,8 +30,11 @@ class StdinLoader(BaseLoader):
|
||||
return source, self.path, lambda: false
|
||||
|
||||
|
||||
jsonFile = open (sys.argv[1], 'r')
|
||||
jsonData = json.load(jsonFile)
|
||||
jsonFile1 = open (sys.argv[1], 'r')
|
||||
jsonData1 = json.load(jsonFile)
|
||||
|
||||
jsonFile2 = open (sys.argv[2], 'r')
|
||||
jsonData2 = json.load(jsonFile)
|
||||
|
||||
jinjaEnv = jinja2.Environment(loader=StdinLoader(),
|
||||
lstrip_blocks=True,
|
||||
@ -35,4 +43,4 @@ jinjaEnv = jinja2.Environment(loader=StdinLoader(),
|
||||
autoescape=False)
|
||||
tmpl = jinjaEnv.get_template('stdin');
|
||||
|
||||
print(tmpl.render(data = jsonData))
|
||||
print(tmpl.render(data = jsonData1, wire = jsonData2))
|
||||
|
@ -39,6 +39,7 @@ taler_wire_auditor_LDADD = \
|
||||
$(top_builddir)/src/exchangedb/libtalerexchangedb.la \
|
||||
$(top_builddir)/src/auditordb/libtalerauditordb.la \
|
||||
-ljansson \
|
||||
-lgnunetjson \
|
||||
-lgnunetutil
|
||||
|
||||
taler_auditor_sign_SOURCES = \
|
||||
|
@ -130,7 +130,23 @@ static void *out_wire_off;
|
||||
static size_t wire_off_size;
|
||||
|
||||
/**
|
||||
* Array of reports about row inconsitencies.
|
||||
* Array of reports about row inconsitencies in wire_out table.
|
||||
*/
|
||||
static json_t *report_wire_out_inconsistencies;
|
||||
|
||||
/**
|
||||
* Array of reports about row inconsitencies in reserves_in table.
|
||||
*/
|
||||
static json_t *report_reserve_in_inconsistencies;
|
||||
|
||||
/**
|
||||
* Array of reports about wrong bank account being recorded for
|
||||
* incoming wire transfers.
|
||||
*/
|
||||
static json_t *report_missattribution_in_inconsistencies;
|
||||
|
||||
/**
|
||||
* Array of reports about row inconcistencies.
|
||||
*/
|
||||
static json_t *report_row_inconsistencies;
|
||||
|
||||
@ -139,6 +155,38 @@ static json_t *report_row_inconsistencies;
|
||||
*/
|
||||
static json_t *report_row_minor_inconsistencies;
|
||||
|
||||
/**
|
||||
* Total amount that was transferred too much from the exchange.
|
||||
*/
|
||||
static struct TALER_Amount total_bad_amount_out_plus;
|
||||
|
||||
/**
|
||||
* Total amount that was transferred too little from the exchange.
|
||||
*/
|
||||
static struct TALER_Amount total_bad_amount_out_minus;
|
||||
|
||||
/**
|
||||
* Total amount that was transferred too much to the exchange.
|
||||
*/
|
||||
static struct TALER_Amount total_bad_amount_in_plus;
|
||||
|
||||
/**
|
||||
* Total amount that was transferred too little to the exchange.
|
||||
*/
|
||||
static struct TALER_Amount total_bad_amount_in_minus;
|
||||
|
||||
/**
|
||||
* Total amount where the exchange has the wrong sender account
|
||||
* for incoming funds and may thus wire funds to the wrong
|
||||
* destination when closing the reserve.
|
||||
*/
|
||||
static struct TALER_Amount total_missattribution_in;
|
||||
|
||||
/**
|
||||
* Amount of zero in our currency.
|
||||
*/
|
||||
static struct TALER_Amount zero;
|
||||
|
||||
|
||||
/* ***************************** Shutdown **************************** */
|
||||
|
||||
@ -255,9 +303,30 @@ do_shutdown (void *cls)
|
||||
json_t *report;
|
||||
|
||||
GNUNET_assert (NULL != report_row_minor_inconsistencies);
|
||||
report = json_pack ("{s:o, s:o}",
|
||||
"row-inconsistencies", report_row_inconsistencies,
|
||||
"row-minor-inconsistencies", report_row_minor_inconsistencies);
|
||||
report = json_pack ("{s:o, s:o, s:o, s:o, s:o,"
|
||||
" s:o, s:o, s:o, s:o, s:o }",
|
||||
/* blocks of 5 */
|
||||
"wire_out_amount_inconsistencies",
|
||||
report_wire_out_inconsistencies,
|
||||
"total_wire_out_delta_plus",
|
||||
TALER_JSON_from_amount (&total_bad_amount_out_plus),
|
||||
"total_wire_out_delta_minus",
|
||||
TALER_JSON_from_amount (&total_bad_amount_out_minus),
|
||||
"reserve_in_amount_inconsistencies",
|
||||
report_reserve_in_inconsistencies,
|
||||
"total_wire_in_delta_minus",
|
||||
TALER_JSON_from_amount (&total_bad_amount_in_plus),
|
||||
/* block */
|
||||
"total_wire_in_delta_minus",
|
||||
TALER_JSON_from_amount (&total_bad_amount_in_minus),
|
||||
"missattribution_in_inconsistencies",
|
||||
report_missattribution_in_inconsistencies,
|
||||
"total_missattribution_in",
|
||||
TALER_JSON_from_amount (&total_missattribution_in),
|
||||
"row_inconsistencies",
|
||||
report_row_inconsistencies,
|
||||
"row_minor_inconsistencies",
|
||||
report_row_minor_inconsistencies);
|
||||
json_dumpf (report,
|
||||
stdout,
|
||||
JSON_INDENT (2));
|
||||
@ -325,47 +394,6 @@ report (json_t *array,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Report a (serious) inconsistency in the exchange's database.
|
||||
*
|
||||
* @param table affected table
|
||||
* @param rowid affected row, UINT64_MAX if row is missing
|
||||
* @param diagnostic message explaining the problem
|
||||
*/
|
||||
static void
|
||||
report_row_inconsistency (const char *table,
|
||||
uint64_t rowid,
|
||||
const char *diagnostic)
|
||||
{
|
||||
report (report_row_inconsistencies,
|
||||
json_pack ("{s:s, s:I, s:s}",
|
||||
"table", table,
|
||||
"row", (json_int_t) rowid,
|
||||
"diagnostic", diagnostic));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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));
|
||||
}
|
||||
|
||||
|
||||
/* *************************** General transaction logic ****************** */
|
||||
|
||||
/**
|
||||
@ -491,37 +519,108 @@ wire_out_cb (void *cls,
|
||||
&key);
|
||||
if (NULL == roi)
|
||||
{
|
||||
/* FIXME (#4963): do proper logging! */
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Failed to find wire transfer `%s' over %s at `%s' in exchange database!\n",
|
||||
TALER_B2S (wtid),
|
||||
TALER_amount2s (amount),
|
||||
GNUNET_STRINGS_absolute_time_to_string (date));
|
||||
/* Wire transfer was not made (yet) at all (but would have been
|
||||
justified), so the entire amount is missing / still to be done.
|
||||
This is moderately harmless, it might just be that the aggreator
|
||||
has not yet fully caught up with the transfers it should do. */
|
||||
report (report_wire_out_inconsistencies,
|
||||
json_pack ("{s:I, s:o, s:o, s:o, s:s, s:s}",
|
||||
"row", (json_int_t) rowid,
|
||||
"amount_wired", TALER_JSON_from_amount (&zero),
|
||||
"amount_justified", TALER_JSON_from_amount (amount),
|
||||
"wtid", GNUNET_JSON_from_data_auto (wtid),
|
||||
"timestamp", GNUNET_STRINGS_absolute_time_to_string (date),
|
||||
"diagnostic", "wire transfer not made (yet?)"));
|
||||
GNUNET_break (GNUNET_OK ==
|
||||
TALER_amount_add (&total_bad_amount_out_minus,
|
||||
&total_bad_amount_out_minus,
|
||||
amount));
|
||||
return GNUNET_OK;
|
||||
}
|
||||
if (0 != TALER_amount_cmp (&roi->details.amount,
|
||||
amount))
|
||||
{
|
||||
report_row_inconsistency ("reserves_out",
|
||||
rowid,
|
||||
"wire amount missmatch");
|
||||
return GNUNET_OK;
|
||||
}
|
||||
if (roi->details.execution_date.abs_value_us !=
|
||||
date.abs_value_us)
|
||||
{
|
||||
report_row_minor_inconsistency ("reserves_out",
|
||||
rowid,
|
||||
"execution date missmatch");
|
||||
}
|
||||
if (! json_equal ((json_t *) wire,
|
||||
roi->details.account_details))
|
||||
{
|
||||
report_row_inconsistency ("reserves_out",
|
||||
rowid,
|
||||
"receiver account missmatch");
|
||||
return GNUNET_OK;
|
||||
/* Destination bank account is wrong in actual wire transfer, so
|
||||
we should count the wire transfer as entirely spurious, and
|
||||
additionally consider the justified wire transfer as missing. */
|
||||
report (report_wire_out_inconsistencies,
|
||||
json_pack ("{s:I, s:o, s:o, s:o, s:s, s:s}",
|
||||
"row", (json_int_t) rowid,
|
||||
"amount_wired", TALER_JSON_from_amount (&roi->details.amount),
|
||||
"amount_justified", TALER_JSON_from_amount (&zero),
|
||||
"wtid", GNUNET_JSON_from_data_auto (wtid),
|
||||
"timestamp", GNUNET_STRINGS_absolute_time_to_string (date),
|
||||
"diagnostic", "recevier account missmatch"));
|
||||
GNUNET_break (GNUNET_OK ==
|
||||
TALER_amount_add (&total_bad_amount_out_plus,
|
||||
&total_bad_amount_out_plus,
|
||||
&roi->details.amount));
|
||||
report (report_wire_out_inconsistencies,
|
||||
json_pack ("{s:I, s:o, s:o, s:o, s:s, s:s}",
|
||||
"row", (json_int_t) rowid,
|
||||
"amount_wired", TALER_JSON_from_amount (&zero),
|
||||
"amount_justified", TALER_JSON_from_amount (amount),
|
||||
"wtid", GNUNET_JSON_from_data_auto (wtid),
|
||||
"timestamp", GNUNET_STRINGS_absolute_time_to_string (date),
|
||||
"diagnostic", "receiver account missmatch"));
|
||||
GNUNET_break (GNUNET_OK ==
|
||||
TALER_amount_add (&total_bad_amount_out_minus,
|
||||
&total_bad_amount_out_minus,
|
||||
amount));
|
||||
goto cleanup;
|
||||
}
|
||||
if (0 != TALER_amount_cmp (&roi->details.amount,
|
||||
amount))
|
||||
{
|
||||
report (report_wire_out_inconsistencies,
|
||||
json_pack ("{s:I, s:o, s:o, s:o, s:s, s:s}",
|
||||
"row", (json_int_t) rowid,
|
||||
"amount_justified", TALER_JSON_from_amount (amount),
|
||||
"amount_wired", TALER_JSON_from_amount (&roi->details.amount),
|
||||
"wtid", GNUNET_JSON_from_data_auto (wtid),
|
||||
"timestamp", GNUNET_STRINGS_absolute_time_to_string (date),
|
||||
"diagnostic", "wire amount does not match"));
|
||||
if (0 < TALER_amount_cmp (amount,
|
||||
&roi->details.amount))
|
||||
{
|
||||
/* amount > roi->details.amount: wire transfer was smaller than it should have been */
|
||||
struct TALER_Amount delta;
|
||||
|
||||
GNUNET_break (GNUNET_OK ==
|
||||
TALER_amount_subtract (&delta,
|
||||
amount,
|
||||
&roi->details.amount));
|
||||
GNUNET_break (GNUNET_OK ==
|
||||
TALER_amount_add (&total_bad_amount_out_minus,
|
||||
&total_bad_amount_out_minus,
|
||||
&delta));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* roi->details.amount < amount: wire transfer was larger than it should have been */
|
||||
struct TALER_Amount delta;
|
||||
|
||||
GNUNET_break (GNUNET_OK ==
|
||||
TALER_amount_subtract (&delta,
|
||||
&roi->details.amount,
|
||||
amount));
|
||||
GNUNET_break (GNUNET_OK ==
|
||||
TALER_amount_add (&total_bad_amount_out_plus,
|
||||
&total_bad_amount_out_plus,
|
||||
&delta));
|
||||
}
|
||||
goto cleanup;
|
||||
}
|
||||
if (roi->details.execution_date.abs_value_us !=
|
||||
date.abs_value_us)
|
||||
{
|
||||
report (report_row_minor_inconsistencies,
|
||||
json_pack ("{s:s, s:I, s:s}",
|
||||
"table", "wire_out",
|
||||
"row", (json_int_t) rowid,
|
||||
"diagnostic", "execution date missmatch"));
|
||||
}
|
||||
cleanup:
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
GNUNET_CONTAINER_multihashmap_remove (out_map,
|
||||
&key,
|
||||
@ -535,11 +634,12 @@ wire_out_cb (void *cls,
|
||||
|
||||
|
||||
/**
|
||||
* Complain that we failed to match an entry from #out_map.
|
||||
* Complain that we failed to match an entry from #out_map. This
|
||||
* means a wire transfer was made without proper justification.
|
||||
*
|
||||
* @param cls NULL
|
||||
* @param key unused key
|
||||
* @param value the `struct ReserveOutInfo` to free
|
||||
* @param value the `struct ReserveOutInfo` to report
|
||||
* @return #GNUNET_OK
|
||||
*/
|
||||
static int
|
||||
@ -549,12 +649,18 @@ complain_out_not_found (void *cls,
|
||||
{
|
||||
struct ReserveOutInfo *roi = value;
|
||||
|
||||
(void) roi;
|
||||
/* FIXME (#4963): log more precisely which wire transfer (and amount)
|
||||
is bogus. */
|
||||
report_row_inconsistency ("reserves_out",
|
||||
UINT64_MAX,
|
||||
"matching wire transfer not found");
|
||||
report (report_wire_out_inconsistencies,
|
||||
json_pack ("{s:I, s:o, s:o, s:o, s:s, s:s}",
|
||||
"row", (json_int_t) 0,
|
||||
"amount_wired", TALER_JSON_from_amount (&roi->details.amount),
|
||||
"amount_justified", TALER_JSON_from_amount (&zero),
|
||||
"wtid", GNUNET_JSON_from_data_auto (&roi->details.reserve_pub), /* #5077 missnomer */
|
||||
"timestamp", GNUNET_STRINGS_absolute_time_to_string (roi->details.execution_date),
|
||||
"diagnostic", "justification for wire transfer not found"));
|
||||
GNUNET_break (GNUNET_OK ==
|
||||
TALER_amount_add (&total_bad_amount_out_plus,
|
||||
&total_bad_amount_out_plus,
|
||||
&roi->details.amount));
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
@ -583,7 +689,7 @@ check_exchange_wire_out ()
|
||||
GNUNET_CONTAINER_multihashmap_iterate (out_map,
|
||||
&complain_out_not_found,
|
||||
NULL);
|
||||
/* clean up (technically redundant, but nicer) */
|
||||
/* clean up */
|
||||
GNUNET_CONTAINER_multihashmap_iterate (out_map,
|
||||
&free_roi,
|
||||
NULL);
|
||||
@ -640,9 +746,12 @@ history_debit_cb (void *cls,
|
||||
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
|
||||
{
|
||||
GNUNET_break_op (0); /* duplicate wire offset is not allowed! */
|
||||
report_row_inconsistency ("bank wire log",
|
||||
UINT64_MAX,
|
||||
"duplicate wire offset");
|
||||
report (report_row_inconsistencies,
|
||||
json_pack ("{s:s, s:I, s:o, s:s}",
|
||||
"table", "bank wire log",
|
||||
"row", (json_int_t) 0,
|
||||
"wire_offset_hash", GNUNET_JSON_from_data_auto (&roi->subject_hash),
|
||||
"diagnostic", "duplicate wire offset"));
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
return GNUNET_OK;
|
||||
@ -727,9 +836,12 @@ reserve_in_cb (void *cls,
|
||||
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
|
||||
{
|
||||
GNUNET_break_op (0); /* duplicate wire offset is not allowed! */
|
||||
report_row_inconsistency ("reserves_in",
|
||||
rowid,
|
||||
"duplicate wire offset");
|
||||
report (report_row_inconsistencies,
|
||||
json_pack ("{s:s, s:I, s:o, s:s}",
|
||||
"table", "reserves_in",
|
||||
"row", (json_int_t) rowid,
|
||||
"wire_offset_hash", GNUNET_JSON_from_data_auto (&rii->row_off_hash),
|
||||
"diagnostic", "duplicate wire offset"));
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
pp.last_reserve_in_serial_id = rowid + 1;
|
||||
@ -752,9 +864,18 @@ complain_in_not_found (void *cls,
|
||||
{
|
||||
struct ReserveInInfo *rii = value;
|
||||
|
||||
report_row_inconsistency ("reserves_in",
|
||||
rii->rowid,
|
||||
"matching wire transfer not found");
|
||||
report (report_reserve_in_inconsistencies,
|
||||
json_pack ("{s:I, s:o, s:o, s:o, s:s, s:s}",
|
||||
"row", (json_int_t) rii->rowid,
|
||||
"amount_expected", TALER_JSON_from_amount (&rii->details.amount),
|
||||
"amount_wired", TALER_JSON_from_amount (&zero),
|
||||
"wtid", GNUNET_JSON_from_data_auto (&rii->details.reserve_pub), /* also reserve_pub, but see #5077 missnomer */
|
||||
"timestamp", GNUNET_STRINGS_absolute_time_to_string (rii->details.execution_date),
|
||||
"diagnostic", "incoming wire transfer claimed by exchange not found"));
|
||||
GNUNET_break (GNUNET_OK ==
|
||||
TALER_amount_add (&total_bad_amount_in_minus,
|
||||
&total_bad_amount_in_minus,
|
||||
&rii->details.amount));
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
@ -831,42 +952,110 @@ history_credit_cb (void *cls,
|
||||
if (row_off_size != rii->row_off_size)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
report_row_inconsistency ("reserves_in",
|
||||
rii->rowid,
|
||||
"wire reference size missmatch");
|
||||
report (report_row_inconsistencies,
|
||||
json_pack ("{s:s, s:o, s:o, s:s}",
|
||||
"table", "reserves_in",
|
||||
"row", GNUNET_JSON_from_data (row_off, row_off_size),
|
||||
"wire_offset_hash", GNUNET_JSON_from_data_auto (&key),
|
||||
"diagnostic", "wire reference size missmatch"));
|
||||
return GNUNET_OK;
|
||||
}
|
||||
if (0 != TALER_amount_cmp (&rii->details.amount,
|
||||
&details->amount))
|
||||
{
|
||||
report_row_inconsistency ("reserves_in",
|
||||
rii->rowid,
|
||||
"wire amount missmatch");
|
||||
return GNUNET_OK;
|
||||
}
|
||||
if (details->execution_date.abs_value_us !=
|
||||
rii->details.execution_date.abs_value_us)
|
||||
{
|
||||
report_row_minor_inconsistency ("reserves_in",
|
||||
rii->rowid,
|
||||
"execution date missmatch");
|
||||
}
|
||||
if (0 != memcmp (&details->reserve_pub,
|
||||
&rii->details.reserve_pub,
|
||||
sizeof (struct TALER_ReservePublicKeyP)))
|
||||
{
|
||||
report_row_inconsistency ("reserves_in",
|
||||
rii->rowid,
|
||||
"reserve public key / wire subject missmatch");
|
||||
return GNUNET_OK;
|
||||
report (report_reserve_in_inconsistencies,
|
||||
json_pack ("{s:I, s:o, s:o, s:o, s:s, s:s}",
|
||||
"row", GNUNET_JSON_from_data (row_off, row_off_size),
|
||||
"amount_exchange_expected", TALER_JSON_from_amount (&rii->details.amount),
|
||||
"amount_wired", TALER_JSON_from_amount (&zero),
|
||||
"wtid", GNUNET_JSON_from_data_auto (&rii->details.reserve_pub), /* #5077 missnomer */
|
||||
"timestamp", GNUNET_STRINGS_absolute_time_to_string (rii->details.execution_date),
|
||||
"diagnostic", "wire subject does not match"));
|
||||
GNUNET_break (GNUNET_OK ==
|
||||
TALER_amount_add (&total_bad_amount_in_minus,
|
||||
&total_bad_amount_in_minus,
|
||||
&rii->details.amount));
|
||||
report (report_reserve_in_inconsistencies,
|
||||
json_pack ("{s:I, s:o, s:o, s:o, s:s, s:s}",
|
||||
"row", GNUNET_JSON_from_data (row_off, row_off_size),
|
||||
"amount_exchange_expected", TALER_JSON_from_amount (&zero),
|
||||
"amount_wired", TALER_JSON_from_amount (&details->amount),
|
||||
"wtid", GNUNET_JSON_from_data_auto (&details->reserve_pub), /* #5077 missnomer */
|
||||
"timestamp", GNUNET_STRINGS_absolute_time_to_string (details->execution_date),
|
||||
"diagnostic", "wire subject does not match"));
|
||||
|
||||
GNUNET_break (GNUNET_OK ==
|
||||
TALER_amount_add (&total_bad_amount_in_plus,
|
||||
&total_bad_amount_in_plus,
|
||||
&details->amount));
|
||||
goto cleanup;
|
||||
}
|
||||
if (0 != TALER_amount_cmp (&rii->details.amount,
|
||||
&details->amount))
|
||||
{
|
||||
report (report_reserve_in_inconsistencies,
|
||||
json_pack ("{s:I, s:o, s:o, s:o, s:s, s:s}",
|
||||
"row", GNUNET_JSON_from_data (row_off, row_off_size),
|
||||
"amount_exchange_expected", TALER_JSON_from_amount (&rii->details.amount),
|
||||
"amount_wired", TALER_JSON_from_amount (&details->amount),
|
||||
"wtid", GNUNET_JSON_from_data_auto (&details->reserve_pub), /* #5077 missnomer */
|
||||
"timestamp", GNUNET_STRINGS_absolute_time_to_string (details->execution_date),
|
||||
"diagnostic", "wire amount does not match"));
|
||||
if (0 < TALER_amount_cmp (&details->amount,
|
||||
&rii->details.amount))
|
||||
{
|
||||
/* details->amount > rii->details.amount: wire transfer was larger than it should have been */
|
||||
struct TALER_Amount delta;
|
||||
|
||||
GNUNET_break (GNUNET_OK ==
|
||||
TALER_amount_subtract (&delta,
|
||||
&details->amount,
|
||||
&rii->details.amount));
|
||||
GNUNET_break (GNUNET_OK ==
|
||||
TALER_amount_add (&total_bad_amount_in_plus,
|
||||
&total_bad_amount_in_plus,
|
||||
&delta));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* rii->details.amount < details->amount: wire transfer was smaller than it should have been */
|
||||
struct TALER_Amount delta;
|
||||
|
||||
GNUNET_break (GNUNET_OK ==
|
||||
TALER_amount_subtract (&delta,
|
||||
&rii->details.amount,
|
||||
&details->amount));
|
||||
GNUNET_break (GNUNET_OK ==
|
||||
TALER_amount_add (&total_bad_amount_in_minus,
|
||||
&total_bad_amount_in_minus,
|
||||
&delta));
|
||||
}
|
||||
goto cleanup;
|
||||
}
|
||||
if (! json_equal (details->account_details,
|
||||
rii->details.account_details))
|
||||
{
|
||||
report_row_minor_inconsistency ("reserves_in",
|
||||
rii->rowid,
|
||||
"sender account missmatch");
|
||||
report (report_missattribution_in_inconsistencies,
|
||||
json_pack ("{s:s, s:o, s:o}",
|
||||
"amount", TALER_JSON_from_amount (&rii->details.amount),
|
||||
"row", GNUNET_JSON_from_data (row_off, row_off_size),
|
||||
"wtid", GNUNET_JSON_from_data_auto (&rii->details.reserve_pub))); /* FIXME #5077 missnomer */
|
||||
GNUNET_break (GNUNET_OK ==
|
||||
TALER_amount_add (&total_missattribution_in,
|
||||
&total_missattribution_in,
|
||||
&rii->details.amount));
|
||||
}
|
||||
if (details->execution_date.abs_value_us !=
|
||||
rii->details.execution_date.abs_value_us)
|
||||
{
|
||||
report (report_row_minor_inconsistencies,
|
||||
json_pack ("{s:s, s:o, s:s}",
|
||||
"table", "reserves_in",
|
||||
"row", GNUNET_JSON_from_data (row_off, row_off_size),
|
||||
"diagnostic", "execution date missmatch"));
|
||||
}
|
||||
cleanup:
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
GNUNET_CONTAINER_multihashmap_remove (in_map,
|
||||
&key,
|
||||
@ -1002,9 +1191,32 @@ run (void *cls,
|
||||
return;
|
||||
}
|
||||
GNUNET_assert (NULL !=
|
||||
(report_row_inconsistencies = json_array ()));
|
||||
(report_wire_out_inconsistencies = json_array ()));
|
||||
GNUNET_assert (NULL !=
|
||||
(report_reserve_in_inconsistencies = json_array ()));
|
||||
GNUNET_assert (NULL !=
|
||||
(report_row_minor_inconsistencies = json_array ()));
|
||||
GNUNET_assert (NULL !=
|
||||
(report_row_inconsistencies = json_array ()));
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
TALER_amount_get_zero (currency,
|
||||
&total_bad_amount_out_plus));
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
TALER_amount_get_zero (currency,
|
||||
&total_bad_amount_out_minus));
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
TALER_amount_get_zero (currency,
|
||||
&total_bad_amount_in_plus));
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
TALER_amount_get_zero (currency,
|
||||
&total_bad_amount_in_minus));
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
TALER_amount_get_zero (currency,
|
||||
&total_missattribution_in));
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
TALER_amount_get_zero (currency,
|
||||
&zero));
|
||||
|
||||
qsx = adb->get_wire_auditor_progress (adb->cls,
|
||||
asession,
|
||||
&master_pub,
|
||||
|
Loading…
Reference in New Issue
Block a user