diff --git a/contrib/auditor-report.tex.j2 b/contrib/auditor-report.tex.j2 index 921daabcd..ab5a16102 100644 --- a/contrib/auditor-report.tex.j2 +++ b/contrib/auditor-report.tex.j2 @@ -1,3 +1,24 @@ +% This file is part of TALER +% Copyright (C) 2016, 2017 Taler Systems SA +% +% TALER is free software; you can redistribute it and/or modify it under the +% terms of the GNU Affero General Public License as published by the Free Software +% Foundation; either version 3, or (at your option) any later version. +% +% TALER is distributed in the hope that it will be useful, but WITHOUT ANY +% WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +% A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. +% +% You should have received a copy of the GNU Affero General Public License along with +% TALER; see the file COPYING. If not, see +% +% +% With respect to this file, our interpretation of the license is +% that publishing an audit report (i.e. in TeX or PDF) requires +% publishing the corresponding j2 template sources under AGPL, and +% linking to them from the report. (This file _is_ source code, +% the generated PDF is the service under definition of the AGPL.) +% \documentclass{article} % {acmart} \usepackage{url} \usepackage[T1]{fontenc} @@ -7,7 +28,15 @@ \begin{document} -\title{Taler Auditor Report} +% If you update this template, complying with the license requires +% publishing the J2 source and linking to it from the generated PDF. +% So if you change this outside of the Taler Git repository, you must +% update this link (and the link must remain available to the receiver +% of the result from the generated TeX, PDF or other format). +\title{Taler Auditor Report\footnote{Template available at \url{https://git.taler.net/}}} + +% You must also credit the original author. +\author{Christian Grothoff} \maketitle \section{Operations} @@ -569,6 +598,80 @@ have a clear financial impact. \end{longtable} {% endif %} + +\subsection{Outgoing wire transfer subject issues} + +This section describes issues found by the wire auditor that +relate to outgoing wire transfers being malformed. +This happens if the exchange somehow creates wire transfers +with duplicate or malformed wire transfer subjects. + +{% if wire.wire_format_inconsistencies|length() == 0 %} + {\bf No wire format inconsistencies found.} +{% else %} + \begin{longtable}{p{4.5cm}|rl} + \multicolumn{3}{c}{ {\bf Row hash} } \\ + {\bf Diagnostic} & \multicolumn{2}{c|}{ {\bf Amount} } \\ + \hline \hline +\endfirsthead + \multicolumn{3}{c}{ {\bf Row hash} } \\ + {\bf Diagnostic} & \multicolumn{2}{c|}{ {\bf Amount} } \\ + \hline \hline +\endhead + \hline + \multicolumn{3}{c}{ {\bf Row hash} } \\ + {\bf Diagnostic} & \multicolumn{2}{c|}{ {\bf Amount} } \\ +\endfoot + \hline + \hline + {\bf Total} & + {{ wire.total_wire_format_amount.value }}.{{ wire.total_wire_format_amount.fraction }} & + {{ wire.total_wire_format_amount.currency }} \\ + \caption{Outgoing wire transfer subject issues found.} + \label{table:outgoing:wtid} +\endlastfoot +{% for item in wire.wire_format_inconsistencies %} + \multicolumn{3}{l}{ \verb! {{ item.wire_offset_hash }} ! } \\ +\nopagebreak + {{ item.diagnostic }} & + {{ item.amount.value }}.{{ item.amount.fraction }} & + {{ item.amount.currency }} \\ +{% endfor %} + \end{longtable} +{% endif %} + + +\subsection{Wire fee structure inconsistencies} + +This section lists cases where the exchange's database may be ambiguous +with respect to what wire fee it charges at what time. + +{% if data.wire_fee_time_inconsistencies|length() == 0 %} + {\bf No wire fee timing issues detected.} +{% else %} + \begin{longtable}{p{1.5cm}|r|p{5.5}} + {\bf Wire format} & {\bf Timestamp} & {\bf Diagnostic} + \\ \hline \hline +\endfirsthead + {\bf Wire format} & {\bf Timestamp} & {\bf Diagnostic} + \\ \hline \hline +\endhead + \hline \hline + {\bf Wire format} & {\bf Timestamp} & {\bf Diagnostic} \\ +\endfoot + \hline \hline + {\bf Wire format} & {\bf Timestamp} & {\bf Diagnostic} \\ + \caption{Wire fees with ambiguous timestamps.} + \label{table:wire_fee:ambiguity} +\endlastfoot +{% for item in data.wire_fee_time_inconsistencies %} + {\tt {{ item.type }} } & {{ item.time }} & {{ item.diagnostic }} \\ \hline +{% endfor %} + \end{longtable} +{% endif %} + + + \subsection{Other issues} This section describes issues found that do not have a clear financial diff --git a/src/auditor/taler-auditor.c b/src/auditor/taler-auditor.c index 7016dc701..cd1ee0d27 100644 --- a/src/auditor/taler-auditor.c +++ b/src/auditor/taler-auditor.c @@ -3,14 +3,14 @@ Copyright (C) 2016, 2017 Inria TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software + terms of the GNU Affero Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. TALER is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. + A PARTICULAR PURPOSE. See the GNU Affero Public License for more details. - You should have received a copy of the GNU General Public License along with + You should have received a copy of the GNU Affero Public License along with TALER; see the file COPYING. If not, see */ /** @@ -210,6 +210,11 @@ static json_t *report_aggregation_fee_balances; */ static json_t *report_amount_arithmetic_inconsistencies; +/** + * Array of reports about wire fees being ambiguous in terms of validity periods. + */ +static json_t *report_fee_time_inconsistencies; + /** * Profits the exchange made by bad amount calculations. */ @@ -2303,11 +2308,24 @@ get_wire_fee (struct AggregationContext *ac, pos->prev, wfi); /* Check non-overlaping fee invariant */ - /* TODO (#5177): report problems more nicely? */ - if (NULL != wfi->prev) - GNUNET_break (wfi->prev->end_date.abs_value_us <= wfi->start_date.abs_value_us); - if (NULL != wfi->next) - GNUNET_break (wfi->next->start_date.abs_value_us >= wfi->end_date.abs_value_us); + if ( (NULL != wfi->prev) && + (wfi->prev->end_date.abs_value_us > wfi->start_date.abs_value_us) ) + { + report (report_fee_time_inconsistencies, + json_pack ("{s:s, s:s, s:s}", + "type", type, + "diagnostic", "start date before previous end date", + "time", GNUNET_STRINGS_absolute_time_to_string (wfi->start_date))); + } + if ( (NULL != wfi->next) && + (wfi->next->start_date.abs_value_us >= wfi->end_date.abs_value_us) ) + { + report (report_fee_time_inconsistencies, + json_pack ("{s:s, s:s, s:s}", + "type", type, + "diagnostic", "end date date after next start date", + "time", GNUNET_STRINGS_absolute_time_to_string (wfi->end_date))); + } return &wfi->wire_fee; } @@ -4085,6 +4103,8 @@ run (void *cls, (report_amount_arithmetic_inconsistencies = json_array ())); GNUNET_assert (NULL != (report_bad_sig_losses = json_array ())); + GNUNET_assert (NULL != + (report_fee_time_inconsistencies = json_array ())); setup_sessions_and_run (); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Audit complete\n"); @@ -4108,7 +4128,8 @@ run (void *cls, " 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 */ /* block */ "reserve_balance_insufficient_inconsistencies", @@ -4175,9 +4196,10 @@ run (void *cls, "total_arithmetic_delta_minus", TALER_JSON_from_amount (&total_arithmetic_delta_minus), "total_aggregation_fee_income", - TALER_JSON_from_amount (&total_aggregation_fee_income) + TALER_JSON_from_amount (&total_aggregation_fee_income), /* block */ - ); + "wire_fee_time_inconsistencies", + report_fee_time_inconsistencies); GNUNET_break (NULL != report); json_dumpf (report, stdout, diff --git a/src/auditor/taler-wire-auditor.c b/src/auditor/taler-wire-auditor.c index a9a4e8c81..9f16794d2 100644 --- a/src/auditor/taler-wire-auditor.c +++ b/src/auditor/taler-wire-auditor.c @@ -159,6 +159,12 @@ static json_t *report_missattribution_in_inconsistencies; */ static json_t *report_row_inconsistencies; +/** + * Array of reports about inconcistencies in the database about + * the incoming wire transfers (exchange is not exactly to blame). + */ +static json_t *report_wire_format_inconsistencies; + /** * Array of reports about minor row inconcistencies. */ @@ -201,6 +207,11 @@ static struct TALER_Amount total_missattribution_in; */ static struct TALER_Amount total_amount_lag; +/** + * Total amount affected by wire format trouble.s + */ +static struct TALER_Amount total_wire_format_amount; + /** * Amount of zero in our currency. */ @@ -324,7 +335,7 @@ do_shutdown (void *cls) GNUNET_assert (NULL != 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," - " s:o, s:o }", + " s:o, s:o, s:o, s:o }", /* blocks of 5 */ "wire_out_amount_inconsistencies", report_wire_out_inconsistencies, @@ -348,6 +359,10 @@ do_shutdown (void *cls) "row_minor_inconsistencies", report_row_minor_inconsistencies, /* block */ + "total_wire_format_amount", + TALER_JSON_from_amount (&total_wire_format_amount), + "wire_format_inconsistencies", + report_wire_format_inconsistencies, "total_amount_lag", TALER_JSON_from_amount (&total_bad_amount_in_minus), "lag_details", @@ -363,6 +378,7 @@ do_shutdown (void *cls) report_row_minor_inconsistencies = NULL; report_missattribution_in_inconsistencies = NULL; report_lags = NULL; + report_wire_format_inconsistencies = NULL; } if (NULL != hh) { @@ -846,18 +862,17 @@ history_debit_cb (void *cls, row_off_size, &rowh); GNUNET_asprintf (&diagnostic, - "malformed wire transfer subject `%s'", + "malformed subject `%8s...'", details->wtid_s); - report (report_row_inconsistencies, - json_pack ("{s:s, s:I, s:o, s:o, s:s}", - "table", "bank wire log", - "row", (json_int_t) 0, + GNUNET_break (GNUNET_OK == + TALER_amount_add (&total_wire_format_amount, + &total_wire_format_amount, + &details->amount)); + report (report_wire_format_inconsistencies, + json_pack ("{s:o, s:o, s:s}", "amount", TALER_JSON_from_amount (&details->amount), "wire_offset_hash", GNUNET_JSON_from_data_auto (&rowh), "diagnostic", diagnostic)); - /* TODO (#5177): report generator currently ignores 'amount' for this - table, maybe use a different table to report this issue! */ - /* TODO: add 'amount' to some total amount that was badly wired! */ GNUNET_free (diagnostic); return GNUNET_SYSERR; } @@ -881,18 +896,17 @@ history_debit_cb (void *cls, row_off_size, &rowh); GNUNET_asprintf (&diagnostic, - "duplicate wire transfer subject `%s'", + "duplicate subject hash `%8s...'", TALER_B2S (&roi->subject_hash)); - report (report_row_inconsistencies, - json_pack ("{s:s, s:I, s:o, s:o, s:s}", - "table", "bank wire log", - "row", (json_int_t) 0, + GNUNET_break (GNUNET_OK == + TALER_amount_add (&total_wire_format_amount, + &total_wire_format_amount, + &details->amount)); + report (report_wire_format_inconsistencies, + json_pack ("{s:o, s:o, s:s}", "amount", TALER_JSON_from_amount (&details->amount), "wire_offset_hash", GNUNET_JSON_from_data_auto (&rowh), "diagnostic", diagnostic)); - /* TODO (#5177): report generator currently ignores 'amount' for this - table, maybe use a different table to report this issue! */ - /* TODO: add 'amount' to some total amount that was badly wired! */ GNUNET_free (diagnostic); return GNUNET_SYSERR; } @@ -1381,6 +1395,8 @@ run (void *cls, (report_reserve_in_inconsistencies = json_array ())); GNUNET_assert (NULL != (report_row_minor_inconsistencies = json_array ())); + GNUNET_assert (NULL != + (report_wire_format_inconsistencies = json_array ())); GNUNET_assert (NULL != (report_row_inconsistencies = json_array ())); GNUNET_assert (NULL != @@ -1405,6 +1421,9 @@ run (void *cls, GNUNET_assert (GNUNET_OK == TALER_amount_get_zero (currency, &total_amount_lag)); + GNUNET_assert (GNUNET_OK == + TALER_amount_get_zero (currency, + &total_wire_format_amount)); GNUNET_assert (GNUNET_OK == TALER_amount_get_zero (currency, &zero));