1378 lines
46 KiB
Django/Jinja
1378 lines
46 KiB
Django/Jinja
% This file is part of TALER
|
|
% Copyright (C) 2016--2019 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 <http://www.gnu.org/licenses/>
|
|
%
|
|
%
|
|
% 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.)
|
|
%
|
|
%
|
|
% NOTE WELL:
|
|
%
|
|
% When modifying this document, please verify that the output
|
|
% still looks good. For this, we have noted which testcases
|
|
% trigger the respective table being generated using comments
|
|
% of the form:
|
|
%
|
|
% "Table generation tested by testcase #XX in test-auditor.sh"
|
|
%
|
|
% Thus, whenever modifying such a table, please verify that the
|
|
% output still looks OK by manually inspecting the generated
|
|
% PDF from running
|
|
%
|
|
% $ test-auditor.sh XX
|
|
%
|
|
% in the src/auditor/ directory.
|
|
|
|
\documentclass{article} % {acmart}
|
|
\usepackage{url}
|
|
\usepackage[T1]{fontenc}
|
|
\usepackage[utf8]{inputenc}
|
|
\usepackage{multirow}
|
|
\usepackage{longtable}
|
|
\usepackage[breakall]{truncate}
|
|
|
|
\begin{document}
|
|
|
|
\title{Taler Auditor Report}
|
|
|
|
% You must also credit the original author.
|
|
\author{Christian Grothoff}
|
|
\maketitle
|
|
|
|
% If you update this template, complying with the license requires
|
|
% stating the license and 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).
|
|
|
|
This report is based on a template licensed under the Affero General Public
|
|
License, either version 3, or (at your option) any later version.
|
|
The source code for the template is available at \url{https://git.taler.net/}.
|
|
|
|
The report was generated by the auditors at the following times:
|
|
|
|
\begin{table}[h!]
|
|
\begin{center}
|
|
\begin{tabular}{l|r|r}
|
|
Auditor & Start & End \\ \hline \hline
|
|
Aggregation & {{ aggregation.auditor_start_time }} & {{ aggregation.auditor_end_time }} \\ \hline
|
|
Coins & {{ coins.auditor_start_time }} & {{ coins.auditor_end_time }} \\ \hline
|
|
Deposits & {{ deposits.auditor_start_time }} & {{ deposits.auditor_end_time }} \\ \hline
|
|
Reserves & {{ reserves.auditor_start_time }} & {{ reserves.auditor_end_time }} \\ \hline
|
|
Wire & {{ wire.wire_auditor_start_time }} & {{ wire.wire_auditor_end_time }} \\
|
|
\end{tabular}
|
|
\end{center}
|
|
\end{table}
|
|
|
|
In that time, the auditors processed the following table ranges:
|
|
\begin{table}[h!]
|
|
\begin{center}
|
|
\begin{tabular}{l|r|r}
|
|
Table & Start & End \\ \hline \hline
|
|
Reserves Incoming & {{ reserves.start_ppr_reserve_in_serial_id }}
|
|
& {{ reserves.end_ppr_reserve_in_serial_id }} \\ \hline
|
|
Reserves Out (withdraw) & {{ reserves.start_ppr_reserve_out_serial_id }}
|
|
& {{ reserves.end_ppr_reserve_out_serial_id }} \\ \hline
|
|
Reserves Recoup & {{ reserves.start_ppr_reserve_recoup_serial_id }}
|
|
& {{ reserves.end_ppr_reserve_recoup_serial_id }} \\ \hline
|
|
Reserves Close & {{ reserves.start_ppr_reserve_close_serial_id }}
|
|
& {{ reserves.end_ppr_reserve_close_serial_id }} \\ \hline
|
|
Aggregation & {{ aggregation.start_ppa_wire_out_serial_id }}
|
|
& {{ aggregation.end_ppa_wire_out_serial_id }} \\ \hline
|
|
Coin withdraw & {{ coins.start_ppc_withdraw_serial_id }}
|
|
& {{ coins.end_ppc_withdraw_serial_id }} \\ \hline
|
|
Coin deposit & {{ coins.start_ppc_deposit_serial_id }}
|
|
& {{ coins.end_ppc_deposit_serial_id }} \\ \hline
|
|
Coin melt & {{ coins.start_ppc_melt_serial_id }}
|
|
& {{ coins.end_ppc_melt_serial_id }} \\ \hline
|
|
Coin refund & {{ coins.start_ppc_refund_serial_id }}
|
|
& {{ coins.end_ppc_refund_serial_id }} \\ \hline
|
|
Coin recoup & {{ coins.start_ppc_recoup_serial_id }}
|
|
& {{ coins.end_ppc_recoup_serial_id }} \\ \hline
|
|
Coin recoup refresh & {{ coins.start_ppc_recoup_refresh_serial_id }}
|
|
& {{ coins.end_ppc_recoup_refresh_serial_id }} \\
|
|
\end{tabular}
|
|
\end{center}
|
|
\caption{Serial number ranges of the tables processed by the audit.}
|
|
\label{table:auditor_range}
|
|
\end{table}
|
|
|
|
{% if wire.account_progress|length() == 0 %}
|
|
In that time, the wire auditor processed NO accounts at all.
|
|
{% else %}
|
|
In that time, the wire auditor processed the following table ranges:
|
|
\begin{center}
|
|
\begin{longtable}{l|c|r|r}
|
|
Account & Table & Start & End \\ \hline
|
|
\endfirsthead
|
|
Account & Table & Start & End \\ \hline
|
|
\endhead
|
|
\endfoot
|
|
\caption{Range of account data processed by the wire auditor.}
|
|
\label{table:account_range}
|
|
\endlastfoot
|
|
{% for item in wire.account_progress %}
|
|
\hline
|
|
{{ item.account }} &
|
|
Reserves Incoming & {{ item.start_reserve_in }}
|
|
& {{ item.end_reserve_in }} \\ \hline
|
|
&
|
|
Outgoing wire transfers & {{ item.start_wire_out }}
|
|
& {{ item.end_wire_out }} \\
|
|
{% endfor %}
|
|
\end{longtable}
|
|
{% endif %}
|
|
\end{center}
|
|
|
|
|
|
\section{Operations}
|
|
|
|
The balance of the escrow account should
|
|
be {\bf {{ coins.total_escrow_balance }}} (coins)
|
|
plus {\bf {{ reserves.total_escrow_balance }}} (reserves).
|
|
|
|
\noindent
|
|
The active operational risk stands at
|
|
{\bf {{ coins.total_active_risk }}}.
|
|
|
|
\noindent
|
|
Loss (actualized risk from recoups) is
|
|
{\bf {{ coins.total_recoup_loss }}}.
|
|
|
|
\noindent
|
|
Recoups of non-revoked coins are at
|
|
{\bf {{ coins.total_irregular_recoups }}} (coins)
|
|
plus {\bf {{ reserves.total_irregular_recoups }}} (reserves).
|
|
|
|
\section{Income}
|
|
|
|
This section analyzes the income of the exchange operator from fees.
|
|
|
|
\begin{table}[h!]
|
|
\begin{center}
|
|
\caption{Fee revenue summary}
|
|
\label{table:revenue}
|
|
\begin{tabular}{l|r}
|
|
Category & Amount \\ \hline \hline
|
|
Withdraw fees & {{ reserves.total_withdraw_fee_income }} \\
|
|
Deposit fees & {{ coins.total_deposit_fee_income }} \\
|
|
Melt fees & {{ coins.total_melt_fee_income }} \\
|
|
Refund fees & {{ coins.total_refund_fee_income }} \\
|
|
Aggregation fees & {{ aggregation.total_aggregation_fee_income }} \\
|
|
\end{tabular}
|
|
\end{center}
|
|
\end{table}
|
|
|
|
|
|
\section{Lag}
|
|
|
|
This section analyzes lag, which can be due to some component being behind in
|
|
executing transactions. This is usually either the exchange's aggregator, the
|
|
bank's wire transfer logic, or the synchronization of databases between
|
|
exchange and auditor. Significant lag may be indicative of fraud, while
|
|
moderate lag is indicative that the systems may be too slow to handle the
|
|
load. Small amounts of lag can occur in normal operation.
|
|
|
|
\subsection{Deposit lag}
|
|
|
|
The total amount the exchange currently lags behind in deposits is
|
|
{\bf {{ wire.total_amount_lag }}}.
|
|
|
|
Note that some lag is perfectly normal, as tiny amounts that are too small to be wired
|
|
are deferred beyond the due date, hoping that additional transfers will push them above
|
|
the tiny threshold. Below, we report {\em non-tiny} wire transfers that are lagging behind.
|
|
|
|
% Table generation tested by testcase #1 in test-auditor.sh
|
|
|
|
{% if wire.lag_details|length() == 0 %}
|
|
{\bf No non-tiny wire transfers that are lagging behind detected.}
|
|
{% else %}
|
|
\begin{longtable}{l|r|r|c}
|
|
{\bf Deadline} & {\bf Amount} & {\bf Row} & {\bf Claimed done} \\
|
|
\multicolumn{4}{l}{\bf Coin} \\
|
|
\multicolumn{4}{l}{\bf Target account} \\ \hline \hline
|
|
\endfirsthead
|
|
{\bf Deadline} & {\bf Amount} & {\bf Row} & {\bf Claimed done} \\
|
|
\multicolumn{4}{l}{\bf Coin} \\
|
|
\multicolumn{4}{l}{\bf Target account} \\ \hline \hline
|
|
\endhead
|
|
\hline \hline
|
|
{\bf Deadline} & {\bf Amount} & {\bf Row} & {\bf Claimed done} \\
|
|
\multicolumn{4}{l}{\bf Coin} \\
|
|
\multicolumn{4}{l}{\bf Target account} \\
|
|
\endfoot
|
|
\hline \hline
|
|
{\bf Deadline} & {\bf Amount} & {\bf Row} & {\bf Claimed done} \\
|
|
\multicolumn{4}{l}{\bf Coin} \\
|
|
\multicolumn{4}{l}{\bf Target account} \\
|
|
\caption{Lagging non-tiny transactions.}
|
|
\label{table:lag}
|
|
\endlastfoot
|
|
{% for item in wire.lag_details %}
|
|
{{ item.deadline }} &
|
|
{{ item.amount }} &
|
|
{{ item.row }} &
|
|
{{ item.claimed_done }} \\
|
|
\nopagebreak
|
|
\multicolumn{4}{l}{ {\tt \small {{ item.coin_pub }} } } \\
|
|
\nopagebreak
|
|
\multicolumn{4}{l}{ {\tt
|
|
{% if 'payto_uri' in item.account %}
|
|
{{ item.account.payto_uri }}
|
|
{% endif %}
|
|
} } \\ \hline
|
|
{% endfor %}
|
|
\end{longtable}
|
|
{% endif %}
|
|
|
|
|
|
\subsection{Reserve closure lag}
|
|
|
|
The total amount the exchange currently lags behind in reserve closures is
|
|
{\bf {{ wire.total_closure_amount_lag }}}.
|
|
|
|
Note that some minimal lag may be normal as transactions may be in-flight.
|
|
|
|
% Table generation tested by testcase #21 in test-auditor.sh
|
|
|
|
{% if wire.reserve_lag_details|length() == 0 %}
|
|
{\bf No closure transfers that are lagging behind detected.}
|
|
{% else %}
|
|
\begin{longtable}{l|r|r}
|
|
{\bf Deadline} & {\bf Amount} & {\bf Row} \\
|
|
\multicolumn{3}{l}{\bf WTID} \\
|
|
\multicolumn{3}{l}{\bf Target account} \\ \hline \hline
|
|
\endfirsthead
|
|
{\bf Deadline} & {\bf Amount} & {\bf Row} \\
|
|
\multicolumn{3}{l}{\bf WTID} \\
|
|
\multicolumn{3}{l}{\bf Target account} \\ \hline \hline
|
|
\endhead
|
|
\hline \hline
|
|
{\bf Deadline} & {\bf Amount} & {\bf Row} \\
|
|
\multicolumn{3}{l}{\bf WTID} \\
|
|
\multicolumn{3}{l}{\bf Target account} \\
|
|
\endfoot
|
|
\hline \hline
|
|
{\bf Deadline} & {\bf Amount} & {\bf Row} \\
|
|
\multicolumn{3}{l}{\bf WTID} \\
|
|
\multicolumn{3}{l}{\bf Target account} \\
|
|
\caption{Lagging reserve closure transactions.}
|
|
\label{table:lag}
|
|
\endlastfoot
|
|
{% for item in wire.reserve_lag_details %}
|
|
{{ item.deadline }} &
|
|
{{ item.amount }} &
|
|
{{ item.row }} \\
|
|
\nopagebreak
|
|
\multicolumn{3}{l}{ {\tt \small {{ item.wtid }} } } \\
|
|
\nopagebreak
|
|
\multicolumn{3}{l}{ {\tt
|
|
{% if 'payto_uri' in item.account %}
|
|
{{ item.account.payto_uri }}
|
|
{% endif %}
|
|
} } \\ \hline
|
|
{% endfor %}
|
|
\end{longtable}
|
|
{% endif %}
|
|
|
|
|
|
\subsection{Deposit confirmation lag}
|
|
|
|
This section analyzes the lag, which is by how much the exchange's
|
|
database reporting is behind in providing us with information about
|
|
deposit confirmations. Merchants probabilistically report deposit
|
|
confirmations to the auditor directly, so if the exchange is slow at
|
|
synchronizing its database with the auditor, some deposit
|
|
confirmations may be known at the auditor only directly. However, any
|
|
delta not accounted for by database synchronization delays is an
|
|
indicator of a malicious exchange (or online singing key compromise)
|
|
and should be answered by revoking the exchange's online siging keys.
|
|
% TODO: maybe reference PhD thesis on this?
|
|
|
|
The total amount the exchange currently lags behind is
|
|
{\bf {{ deposits.missing_deposit_confirmation_total }} } from a total number of
|
|
{\bf {{ deposits.missing_deposit_confirmation_count }} } deposit confirmations.
|
|
|
|
Note that some lag is perfectly normal.
|
|
Below, we report {\em all} deposit confirmations that are lagging behind.
|
|
|
|
% Table generation tested by testcase #24 in test-auditor.sh
|
|
|
|
{% if deposits.deposit_confirmation_inconsistencies|length() == 0 %}
|
|
{\bf No deposit confirmations that are lagging behind detected.}
|
|
{% else %}
|
|
\begin{longtable}{r|r|r}
|
|
{\bf Timestamp} & {\bf Amount} & {\bf Row} \\
|
|
\multicolumn{3}{l}{\bf Target account} \\ \hline \hline
|
|
\endfirsthead
|
|
{\bf Timestamp} & {\bf Amount} & {\bf Row} \\
|
|
\multicolumn{3}{l}{\bf Target account} \\ \hline \hline
|
|
\endhead
|
|
\hline \hline
|
|
{\bf Timestamp} & {\bf Amount} & {\bf Row} \\
|
|
\multicolumn{3}{l}{\bf Target account} \\
|
|
\endfoot
|
|
\hline \hline
|
|
{\bf Timestamp} & {\bf Amount} & {\bf Row} \\
|
|
\multicolumn{3}{l}{\bf Target account} \\
|
|
\caption{Missing deposit confirmations.}
|
|
\label{table:missing_dc}
|
|
\endlastfoot
|
|
{% for item in deposits.deposit_confirmation_inconsistencies %}
|
|
{{ item.timestamp }} &
|
|
{{ item.amount }} &
|
|
{{ item.rowid }} \\
|
|
\nopagebreak
|
|
\multicolumn{3}{l}{ {\tt \truncate{0.95\textwidth}{ {{ item.account }} } } } \\ \hline
|
|
{% endfor %}
|
|
\end{longtable}
|
|
{% endif %}
|
|
|
|
|
|
\section{Major irregularities}
|
|
|
|
This section describes the possible major irregularities that the
|
|
auditor has checked, and lists all of the actual irregularities
|
|
encountered in detail.
|
|
|
|
\subsection{Emergencies}
|
|
|
|
Emergencies are errors where more coins were deposited than the
|
|
exchange remembers issuing. This usually means that the private keys
|
|
of the exchange were compromised (stolen or factored) and subsequently
|
|
used to sign coins off the books. If this happens, all coins of the
|
|
respective denomination that the exchange has redeemed so far may have
|
|
been created by the attacker, and the exchange would have to refund
|
|
all of the outstanding coins from ordinary users. Thus, the {\bf risk
|
|
exposure} is the amount of coins in circulation for a particular
|
|
denomination and the maximum loss for the exchange from this type of
|
|
compromise.
|
|
|
|
{% if (coins.emergencies|length() != 0) %}
|
|
The total risk from emergencies detected by amount is
|
|
{\bf {{ coins.emergencies_risk_by_amount }} }.
|
|
The total loss from emergencies detected by amount is
|
|
{\bf {{ coins.emergencies_loss }} }.
|
|
{% endif %}
|
|
|
|
{% if (coins.emergencies_by_count|length() != 0) %}
|
|
The total risk from emergencies detected by counting coins is
|
|
{\bf {{ coins.emergencies_risk_by_count }} }
|
|
The total loss from emergencies detected by counting coins could be up to
|
|
{\bf {{ coins.emergencies_loss_by_count }} }.
|
|
{% endif %}
|
|
|
|
|
|
\subsubsection{Emergencies by counting coins}
|
|
|
|
% Table generation tested by testcase #18 in test-auditor.sh
|
|
|
|
{% if coins.emergencies_by_count|length() == 0 %}
|
|
{\bf No emergencies detected by counting coins.}
|
|
{% else %}
|
|
\begin{longtable}{r|c|r|r}
|
|
\multicolumn{4}{c}{ {\bf Public key hash} } \\
|
|
{\bf Denomination} & {\bf Lifetime} & {\bf \# Issued} & {\bf \# Deposited} \\ \hline \hline
|
|
\endfirsthead
|
|
\multicolumn{4}{|c|}{ {\bf Public key hash} } \\
|
|
{\bf Denomination} & {\bf Lifetime} & {\bf \# Issued} & {\bf \# Deposited} \\ \hline \hline
|
|
\endhead
|
|
\hline \hline
|
|
\multicolumn{4}{|c|}{ {\bf Public key hash} } \\
|
|
{\bf Denomination} & {\bf Lifetime} & {\bf \# Issued} & {\bf \# Deposited} \\ \hline \hline
|
|
\endfoot
|
|
\caption{Emergencies by counting coins.}
|
|
\label{table:emergencies_coin_counting}
|
|
\endlastfoot
|
|
{% for item in coins.emergencies_by_count %}
|
|
\multicolumn{4}{l}{ {\tt \truncate{0.95\textwidth}{ {{ item.denompub_hash }} } } } \\
|
|
\nopagebreak
|
|
{{ item.value }} &
|
|
{\tiny \begin{tabular}{c}
|
|
{{ item.start }} \\ \hline
|
|
{{ item.deposit_end }}
|
|
\end{tabular} } &
|
|
{{ item.num_issued }} &
|
|
{{ item.num_known }} \\ \hline
|
|
{% endfor %}
|
|
\end{longtable}
|
|
{% endif %}
|
|
|
|
|
|
\subsubsection{Emergencies by value deposited}
|
|
|
|
Note that emergencies by value deposited can {\em also} arise if the exchange
|
|
fails to properly detect double spending (or simply fails to properly account
|
|
for the remaining balance of a coin). So in combintation with arithmetic
|
|
problems (Section~\ref{sec:arithmetic}) issues in this section are not a clear
|
|
indicator that the exchange's private signing key was compromised.
|
|
|
|
% Table generation tested by testcases #18, #25 in test-auditor.sh
|
|
|
|
{% if coins.emergencies|length() == 0 %}
|
|
{\bf No emergencies by value detected.}
|
|
{% else %}
|
|
\begin{longtable}{r|c|r|r}
|
|
\multicolumn{4}{c}{ {\bf Public key hash} } \\
|
|
{\bf Denomination} & {\bf Lifetime} & {\bf Risk exposure} & {\bf Loss} \\ \hline \hline
|
|
\endfirsthead
|
|
\multicolumn{4}{|c|}{ {\bf Public key hash} } \\
|
|
{\bf Denomination} & {\bf Lifetime} & {\bf Risk exposure} & {\bf Loss} \\ \hline \hline
|
|
\endhead
|
|
\hline \hline
|
|
\multicolumn{4}{|c|}{ {\bf Public key hash} } \\
|
|
{\bf Denomination} & {\bf Lifetime} & {\bf Risk exposure} & {\bf Loss} \\
|
|
\endfoot
|
|
\caption{Emergencies by value deposited.}
|
|
\label{table:emergencies}
|
|
\endlastfoot
|
|
{% for item in coins.emergencies %}
|
|
\multicolumn{4}{l}{ {\tt \truncate{0.95\textwidth}{ {{ item.denompub_hash }} } } } \\
|
|
\nopagebreak
|
|
{{ item.value }} &
|
|
{\tiny \begin{tabular}{c}
|
|
{{ item.start }} \\ \hline
|
|
{{ item.deposit_end }}
|
|
\end{tabular} } &
|
|
{{ item.denom_risk }} &
|
|
{{ item.denom_loss }} \\ \hline
|
|
{% endfor %}
|
|
\end{longtable}
|
|
{% endif %}
|
|
|
|
|
|
\subsection{Arithmetic problems} \label{sec:arithmetic}
|
|
|
|
This section lists cases where the arithmetic of the exchange
|
|
involving amounts disagrees with the arithmetic of the auditor.
|
|
Disagreements imply that either the exchange made a loss (sending out
|
|
too much money), or screwed a customer (and thus at least needs to fix
|
|
the financial damage done to the customer).
|
|
|
|
Note that the deltas only sum up the issues where $P \not= 0$ as only
|
|
then we can tell if the problem lead to a profit or loss.
|
|
|
|
The {\bf P} colum is set to "1" if the arithmetic problem was be determined to be
|
|
profitable for the exchange, "-1" if the problem resulted in a net loss for
|
|
the exchange, and "0" if this is unclear or at least the gain/loss is not
|
|
easily determined from the amounts and thus not included in the totals.
|
|
|
|
\subsubsection{For aggregation}
|
|
|
|
% Table generation tested by testcase #XX in test-auditor.sh
|
|
|
|
{% if aggregation.amount_arithmetic_inconsistencies|length() == 0 %}
|
|
{\bf No arithmetic problems detected.}
|
|
{% else %}
|
|
\begin{longtable}{p{3.5cm}|r|r|r|c}
|
|
{\bf Operation} & {\bf Row} & {\bf Exchange} & {\bf Auditor} & {\bf P} \\
|
|
\hline \hline
|
|
\endfirsthead
|
|
{\bf Operation} & {\bf Row} & {\bf Exchange} & {\bf Auditor} & {\bf P} \\ \hline \hline
|
|
\endhead
|
|
\hline \hline
|
|
{\bf Operation} & {\bf Row} & {\bf Exchange} & {\bf Auditor} & {\bf P} \\
|
|
\endfoot
|
|
\hline \hline
|
|
\multicolumn{2}{l|}{ {\bf $\sum$ Deltas (Auditor-Exchange)} } &
|
|
+ {{ aggregation.total_arithmetic_delta_plus }} &
|
|
- {{ aggregation.total_arithmetic_delta_minus }} & \\
|
|
\caption{Arithmetic inconsistencies.}
|
|
\label{table:amount:arithmetic:inconsistencies:aggregation}
|
|
\endlastfoot
|
|
{% for item in aggregation.amount_arithmetic_inconsistencies %}
|
|
\truncate{3.3cm}{ {\tiny {{ item.operation }} } } &
|
|
{{ item.rowid }} &
|
|
{{ item.exchange }} &
|
|
{{ item.auditor }} &
|
|
{{ item.profitable }} \\ \hline
|
|
{% endfor %}
|
|
\end{longtable}
|
|
{% endif %}
|
|
|
|
\subsubsection{For coins}
|
|
|
|
% Table generation tested by testcase #18 in test-auditor.sh
|
|
|
|
{% if coins.amount_arithmetic_inconsistencies|length() == 0 %}
|
|
{\bf No arithmetic problems detected.}
|
|
{% else %}
|
|
\begin{longtable}{p{3.5cm}|r|r|r|c}
|
|
{\bf Operation} & {\bf Row} & {\bf Exchange} & {\bf Auditor} & {\bf P} \\
|
|
\hline \hline
|
|
\endfirsthead
|
|
{\bf Operation} & {\bf Row} & {\bf Exchange} & {\bf Auditor} & {\bf P} \\ \hline \hline
|
|
\endhead
|
|
\hline \hline
|
|
{\bf Operation} & {\bf Row} & {\bf Exchange} & {\bf Auditor} & {\bf P} \\
|
|
\endfoot
|
|
\hline \hline
|
|
\multicolumn{2}{l|}{ {\bf $\sum$ Deltas (Auditor-Exchange)} } &
|
|
+ {{ coins.total_arithmetic_delta_plus }} &
|
|
- {{ coins.total_arithmetic_delta_minus }} & \\
|
|
\caption{Arithmetic inconsistencies.}
|
|
\label{table:amount:arithmetic:inconsistencies:coins}
|
|
\endlastfoot
|
|
{% for item in coins.amount_arithmetic_inconsistencies %}
|
|
\truncate{3.3cm}{ {\tiny {{ item.operation }} } } &
|
|
{{ item.rowid }} &
|
|
{{ item.exchange }} &
|
|
{{ item.auditor }} &
|
|
{{ item.profitable }} \\ \hline
|
|
{% endfor %}
|
|
\end{longtable}
|
|
{% endif %}
|
|
|
|
\subsubsection{For reserves}
|
|
|
|
% Table generation tested by testcase #XX in test-auditor.sh
|
|
|
|
{% if reserves.amount_arithmetic_inconsistencies|length() == 0 %}
|
|
{\bf No arithmetic problems detected.}
|
|
{% else %}
|
|
\begin{longtable}{p{3.5cm}|r|r|r|c}
|
|
{\bf Operation} & {\bf Row} & {\bf Exchange} & {\bf Auditor} & {\bf P} \\
|
|
\hline \hline
|
|
\endfirsthead
|
|
{\bf Operation} & {\bf Row} & {\bf Exchange} & {\bf Auditor} & {\bf P} \\ \hline \hline
|
|
\endhead
|
|
\hline \hline
|
|
{\bf Operation} & {\bf Row} & {\bf Exchange} & {\bf Auditor} & {\bf P} \\
|
|
\endfoot
|
|
\hline \hline
|
|
\multicolumn{2}{l|}{ {\bf $\sum$ Deltas (Auditor-Exchange)} } &
|
|
+ {{ reserves.total_arithmetic_delta_plus }} &
|
|
- {{ reserves.total_arithmetic_delta_minus }} & \\
|
|
\caption{Arithmetic inconsistencies.}
|
|
\label{table:amount:arithmetic:inconsistencies:reserves}
|
|
\endlastfoot
|
|
{% for item in reserves.amount_arithmetic_inconsistencies %}
|
|
\truncate{3.3cm}{ {\tiny {{ item.operation }} } } &
|
|
{{ item.rowid }} &
|
|
{{ item.exchange }} &
|
|
{{ item.auditor }} &
|
|
{{ item.profitable }} \\ \hline
|
|
{% endfor %}
|
|
\end{longtable}
|
|
{% endif %}
|
|
|
|
|
|
\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.
|
|
|
|
% Table generation tested by testcase #2 in test-auditor.sh
|
|
|
|
{% if reserves.reserve_balance_insufficient_inconsistencies|length() == 0 %}
|
|
{\bf All withdrawals were covered by sufficient reserve funding.}
|
|
{% else %}
|
|
\begin{longtable}{p{8.5cm}|r}
|
|
{\bf Reserve} & {\bf Loss} \\ \hline \hline
|
|
\endfirsthead
|
|
{\bf Reserve} & {\bf Loss} \\ \hline \hline
|
|
\endhead
|
|
\hline \hline
|
|
{\bf Reserve} & {\bf Loss}
|
|
\endfoot
|
|
\hline
|
|
{\bf Total loss} &
|
|
{{ reserves.total_loss_balance_insufficient }} \\
|
|
\caption{Reserves with withdrawals higher than reserve funding.}
|
|
\label{table:reserve:balance_insufficient}
|
|
\endlastfoot
|
|
{% for item in reserves.reserve_balance_insufficient_inconsistencies %}
|
|
{\tt \small {{ item.reserve_pub }} }
|
|
&
|
|
{{ item.loss }} \\ \hline
|
|
{% endfor %}
|
|
\end{longtable}
|
|
{% endif %}
|
|
|
|
|
|
\subsection{Claimed outgoing wire transfer inconsistencies}
|
|
|
|
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}.
|
|
|
|
% Table generation tested by testcase #23 in test-auditor.sh
|
|
|
|
{% if aggregation.wire_out_inconsistencies|length() == 0 %}
|
|
{\bf All aggregations matched up.}
|
|
{% else %}
|
|
\begin{longtable}{r|r|r}
|
|
\multicolumn{3}{c}{ {\bf Destination account} } \\
|
|
{\bf Row} & {\bf Expected} & {\bf Claimed} \\ \hline \hline
|
|
\endfirsthead
|
|
\multicolumn{3}{c}{ {\bf Destination account} } \\
|
|
{\bf Row} & {\bf Expected} & {\bf Claimed} \\ \hline \hline
|
|
\endhead
|
|
\hline \hline
|
|
\multicolumn{3}{c}{ {\bf Destination account} } \\
|
|
{\bf Row} & {\bf Expected} & {\bf Claimed} \\
|
|
\endfoot
|
|
\hline
|
|
{\bf Total deltas} &
|
|
{{ aggregation.total_wire_out_delta_plus}} &
|
|
- {{ aggregation.total_wire_out_delta_minus}} \\
|
|
\caption{Claimed wire out aggregate totals not matching up.}
|
|
\label{table:reserve:wire_out_balance_inconsistencies}
|
|
\endlastfoot
|
|
{% for item in aggregation.wire_out_inconsistencies %}
|
|
\multicolumn{3}{l}{ {\tt \truncate{0.95\textwidth}{
|
|
{% if 'payto_uri' in item.destination_account %}
|
|
{{ item.destination_account.payto_uri }}
|
|
{% endif %}
|
|
} } } \\
|
|
\nopagebreak
|
|
{{ item.rowid }} &
|
|
{{ item.expected }} &
|
|
{{ item.claimed }} \\ \hline
|
|
{% endfor %}
|
|
\end{longtable}
|
|
{% endif %}
|
|
|
|
|
|
\subsection{Coin history inconsistencies}
|
|
|
|
This section lists cases where the exchange made arithmetic errors found when
|
|
looking at the transaction history of a coin. The totals sum up the differences
|
|
in amounts that matter for profit/loss calculations of the exchange. When an
|
|
exchange merely shifted money from customers to merchants (or vice versa) without
|
|
any effects on its own balance, those entries are excluded from the total.
|
|
|
|
% Table generation tested by testcase #25 in test-auditor.sh
|
|
|
|
{% if aggregation.coin_inconsistencies|length() == 0 %}
|
|
{\bf All coin histories were unproblematic.}
|
|
{% else %}
|
|
\begin{longtable}{p{1.8cm}|r|r}
|
|
{\bf Operation} & \multicolumn{2}{|c}{\bf Coin public key} \\
|
|
& {\bf Exchange } & {\bf Auditor} \\
|
|
\hline \hline
|
|
\endfirsthead
|
|
{\bf Operation} & \multicolumn{2}{|r}{\bf Coin public key} \\
|
|
& {\bf Exchange } & {\bf Auditor} \\
|
|
\hline \hline
|
|
\endhead
|
|
\hline \hline
|
|
{\bf Operation} & \multicolumn{2}{|r}{\bf Coin public key} \\
|
|
& {\bf Exchange } & {\bf Auditor} \\
|
|
\endfoot
|
|
\hline
|
|
$\sum$ {\bf Delta (Auditor-Exchange)} &
|
|
{{ aggregation.total_coin_delta_plus }} &
|
|
- {{ aggregation.total_coin_delta_minus }} \\
|
|
\caption{Arithmetic inconsistencies of amount calculations involving a coin.}
|
|
\label{table:amount:arithmetic:coin:inconsistencies}
|
|
\endlastfoot
|
|
{% for item in aggregation.coin_inconsistencies %}
|
|
{{ item.operation }} &
|
|
\multicolumn{2}{l}{ {\tt \small {{ item.coin_pub }} } } \\
|
|
\nopagebreak &
|
|
{{ item.exchange }} &
|
|
{{ item.auditor }} \\ \hline
|
|
{% endfor %}
|
|
\end{longtable}
|
|
{% endif %}
|
|
|
|
|
|
\subsection{Operations with bad signatures}
|
|
|
|
This section lists operations that the exchange performed, but for
|
|
which the signatures provided are invalid. Hence the operations were
|
|
invalid and the amount involved should be considered lost.
|
|
|
|
The key given is always the key for which the signature verification
|
|
step failed. This is the reserve public key for ``withdraw''
|
|
operations, the coin public key for ``deposit'' and ``melt''
|
|
operations, the merchant's public key for ``melt'' operations,
|
|
the (hash of the) denomination public key for
|
|
``recoup-verify'' and ``deposit-verify'' operations, and the master
|
|
public key for ``recoup-master'' operations.
|
|
|
|
\subsubsection{For aggregations}
|
|
|
|
% Table generation tested by testcase #XX in test-auditor.sh
|
|
|
|
{% if aggregation.bad_sig_losses|length() == 0 %}
|
|
{\bf All signatures were valid.}
|
|
{% else %}
|
|
\begin{longtable}{l|r|r}
|
|
\multicolumn{3}{l}{ {\bf Public key} }\\
|
|
{\bf Operation type} & Database row & {\bf Loss amount} \\
|
|
\hline \hline
|
|
\endfirsthead
|
|
\multicolumn{3}{l}{ {\bf Public key} }\\
|
|
{\bf Operation type} & Database row & {\bf Loss amount} \\ \hline \hline
|
|
\endhead
|
|
\hline \hline
|
|
\multicolumn{3}{l}{ {\bf Public key} }\\
|
|
{\bf Operation type} & Database row & {\bf Loss amount} \\
|
|
\endfoot
|
|
\hline
|
|
\multicolumn{2}{l}{ {\bf Total losses} } &
|
|
{\bf {{ aggregation.total_bad_sig_loss}} } \\
|
|
\caption{Losses from operations performed on coins without proper signatures.}
|
|
\label{table:bad_signature_losses}
|
|
\endlastfoot
|
|
{% for item in aggregation.bad_sig_losses %}
|
|
\multicolumn{3}{l}{ {\tt \small \truncate{0.9\textwidth}{ {{ item.key_pub }} } } } \\
|
|
\nopagebreak
|
|
{{ item.operation }} &
|
|
{{ item.row }} &
|
|
{{ item.loss }} \\ \hline
|
|
{% endfor %}
|
|
\end{longtable}
|
|
{% endif %}
|
|
|
|
\subsubsection{For coins}
|
|
|
|
% Table generation tested by testcase #4/#5/#6/#13 in test-auditor.sh
|
|
|
|
{% if coins.bad_sig_losses|length() == 0 %}
|
|
{\bf All signatures were valid.}
|
|
{% else %}
|
|
\begin{longtable}{l|r|r}
|
|
\multicolumn{3}{l}{ {\bf Public key} }\\
|
|
{\bf Operation type} & Database row & {\bf Loss amount} \\
|
|
\hline \hline
|
|
\endfirsthead
|
|
\multicolumn{3}{l}{ {\bf Public key} }\\
|
|
{\bf Operation type} & Database row & {\bf Loss amount} \\ \hline \hline
|
|
\endhead
|
|
\hline \hline
|
|
\multicolumn{3}{l}{ {\bf Public key} }\\
|
|
{\bf Operation type} & Database row & {\bf Loss amount} \\
|
|
\endfoot
|
|
\hline
|
|
\multicolumn{2}{l}{ {\bf Total losses} } &
|
|
{\bf {{ coins.total_bad_sig_loss}} } \\
|
|
\caption{Losses from operations performed on coins without proper signatures.}
|
|
\label{table:bad_signature_losses}
|
|
\endlastfoot
|
|
{% for item in coins.bad_sig_losses %}
|
|
\multicolumn{3}{l}{ {\tt \small \truncate{0.9\textwidth}{ {{ item.key_pub }} } } } \\
|
|
\nopagebreak
|
|
{{ item.operation }} &
|
|
{{ item.row }} &
|
|
{{ item.loss }} \\ \hline
|
|
{% endfor %}
|
|
\end{longtable}
|
|
{% endif %}
|
|
|
|
\subsubsection{For reserves}
|
|
|
|
% Table generation tested by testcase #7 in test-auditor.sh
|
|
|
|
{% if reserves.bad_sig_losses|length() == 0 %}
|
|
{\bf All signatures were valid.}
|
|
{% else %}
|
|
\begin{longtable}{l|r|r}
|
|
\multicolumn{3}{l}{ {\bf Public key} }\\
|
|
{\bf Operation type} & Database row & {\bf Loss amount} \\
|
|
\hline \hline
|
|
\endfirsthead
|
|
\multicolumn{3}{l}{ {\bf Public key} }\\
|
|
{\bf Operation type} & Database row & {\bf Loss amount} \\ \hline \hline
|
|
\endhead
|
|
\hline \hline
|
|
\multicolumn{3}{l}{ {\bf Public key} }\\
|
|
{\bf Operation type} & Database row & {\bf Loss amount} \\
|
|
\endfoot
|
|
\hline
|
|
\multicolumn{2}{l}{ {\bf Total losses} } &
|
|
{\bf {{ reserves.total_bad_sig_loss}} } \\
|
|
\caption{Losses from operations performed on coins without proper signatures.}
|
|
\label{table:bad_signature_losses}
|
|
\endlastfoot
|
|
{% for item in reserves.bad_sig_losses %}
|
|
\multicolumn{3}{l}{ {\tt \small \truncate{0.9\textwidth}{ {{ item.key_pub }} } } } \\
|
|
\nopagebreak
|
|
{{ item.operation }} &
|
|
{{ item.row }} &
|
|
{{ item.loss }} \\ \hline
|
|
{% endfor %}
|
|
\end{longtable}
|
|
{% endif %}
|
|
|
|
|
|
|
|
\subsection{Actual incoming wire transfers} \label{sec:wire_in}
|
|
|
|
This section highlights cases where the exchange's record about
|
|
incoming wire transfers does not match with that of the bank.
|
|
|
|
% Table generation tested by testcase #3 and #8 in test-auditor.sh
|
|
|
|
{% if wire.reserve_in_amount_inconsistencies|length() == 0 %}
|
|
{\bf All incoming wire transfer amounts and subjects matched up.}
|
|
{% else %}
|
|
\begin{longtable}{p{5.5cm}|r|r}
|
|
\multicolumn{2}{l}{ {\bf Reserve Public Key} ({\bf Row}) } \\
|
|
\multicolumn{3}{l}{ {\bf Diagnostic} } \\
|
|
{\bf When} & {\bf Wired} & {\bf Expected} \\
|
|
\hline \hline
|
|
\endfirsthead
|
|
\multicolumn{2}{l}{ {\bf Reserve Public Key} ({\bf Row}) } \\
|
|
\multicolumn{3}{l}{ {\bf Diagnostic} } \\
|
|
{\bf When} & {\bf Wired} & {\bf Expected} \\
|
|
\hline \hline
|
|
\endhead
|
|
\hline \hline
|
|
\multicolumn{2}{l}{ {\bf Reserve Public Key} ({\bf Row}) } \\
|
|
\multicolumn{3}{l}{ {\bf Diagnostic} } \\
|
|
{\bf When} & {\bf Wired} & {\bf Expected} \\
|
|
\endfoot
|
|
\hline \hline
|
|
{\bf Total deltas} &
|
|
{{ wire.total_wire_in_delta_plus }} &
|
|
- {{ wire.total_wire_in_delta_minus}} \\
|
|
\caption{Incoming wire transfer amounts not matching up.}
|
|
\label{table:wire_in:transfer_amount_inconsistencies}
|
|
\endlastfoot
|
|
{% for item in wire.reserve_in_amount_inconsistencies %}
|
|
\multicolumn{3}{l}{ {\tt \small {{ item.reserve_pub }} } ({{ item.row }}) } \\
|
|
\nopagebreak
|
|
\multicolumn{3}{l}{ {{ item.diagnostic }} } \\
|
|
\nopagebreak
|
|
{{ item.timestamp }} &
|
|
{{ item.amount_wired }} &
|
|
{{ item.amount_exchange_expected }} \\
|
|
\hline
|
|
{% endfor %}
|
|
\end{longtable}
|
|
{% endif %}
|
|
|
|
|
|
{% if wire.reserve_in_amount_inconsistencies|length() != 0 %}
|
|
This means that there are inconsistencies in the exchange's
|
|
claims about incoming wire transfers, amounting to:
|
|
\begin{itemize}
|
|
\item The exchange believing it received
|
|
{\bf {{ wire.total_wire_in_delta_plus }} } {\em less} than it
|
|
actually received in some reserves.
|
|
\item The exchange believing that it received
|
|
{\bf {{ wire.total_wire_in_delta_minus}} } {\em more} than it
|
|
actually received in some reserves.
|
|
\end{itemize}
|
|
{% 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.
|
|
|
|
% Table generation tested by testcase #9 in test-auditor.sh
|
|
|
|
{% if wire.missattribution_in_inconsistencies|length() == 0 %}
|
|
{\bf All incoming wire transfer sender accounts matched up.}
|
|
{% else %}
|
|
\begin{longtable}{p{8.5cm}|r}
|
|
{\bf Reserve Public Key} & {\bf Amount} \\
|
|
\hline \hline
|
|
\endfirsthead
|
|
{\bf Reserve Public Key} & {\bf Amount} \\
|
|
\hline \hline
|
|
\endhead
|
|
\hline \hline
|
|
{\bf Reserve Public Key} & {\bf Amount} \\
|
|
\endfoot
|
|
\hline
|
|
{\bf Total amount} &
|
|
{{ wire.total_missattribution_in}} \\
|
|
\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 \small \truncate{8.3cm}{ {{ item.reserve_pub }} } } &
|
|
{{ item.amount }} \\ \hline
|
|
{% endfor %}
|
|
\end{longtable}
|
|
{% endif %}
|
|
|
|
|
|
|
|
|
|
\subsection{Actual outgoing wire transfers} \label{sec:wire_check_out}
|
|
|
|
This section highlights cases where the exchange missbehaved
|
|
with respect to outgoing wire transfers.
|
|
|
|
% Table generation tested by testcase #11 in test-auditor.sh
|
|
|
|
{% if wire.wire_out_amount_inconsistencies|length() == 0 %}
|
|
{\bf All outgoing wire transfers matched up.}
|
|
{% else %}
|
|
\begin{longtable}{p{5.5cm}|r|r}
|
|
{\bf Wire transfer identifier} & {\bf Wired} & {\bf Justified} \\
|
|
{\bf Account} & {\bf Row} & {\bf Timestamp} \\
|
|
\hline \hline
|
|
\endfirsthead
|
|
{\bf Wire transfer identifier} & {\bf Wired} & {\bf Justified} \\
|
|
{\bf Account} & {\bf Row} & {\bf Timestamp} \\
|
|
\hline \hline
|
|
\endhead
|
|
\hline \hline
|
|
{\bf Wire transfer identifier} & {\bf Wired} & {\bf Justified} \\
|
|
{\bf Account} & {\bf Row} & {\bf Timestamp} \\
|
|
\endfoot
|
|
\hline
|
|
{\bf Total deltas} &
|
|
{{ wire.total_wire_out_delta_plus }} &
|
|
- {{ wire.total_wire_out_delta_minus }} \\
|
|
\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 \small \truncate{5.2cm}{ {{ item.wtid }} } } &
|
|
{{ item.amount_wired }} &
|
|
{{ item.amount_justified }} \\
|
|
\nopagebreak
|
|
{{ item.account_section }} &
|
|
{{ item.row }} &
|
|
{\tiny {{ item.timestamp }} } \\ \hline
|
|
{% endfor %}
|
|
\end{longtable}
|
|
{% endif %}
|
|
|
|
|
|
\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).
|
|
|
|
% Table generation tested by testcase #3 in test-auditor.sh
|
|
|
|
{% if reserves.reserve_balance_summary_wrong_inconsistencies|length() == 0 %}
|
|
{\bf All balances matched up.}
|
|
{% else %}
|
|
\begin{longtable}{p{6cm}|r|r}
|
|
{\bf Reserve} & {\bf Auditor} & {\bf Exchange} \\ \hline \hline
|
|
\endfirsthead
|
|
{\bf Reserve} & {\bf Auditor} & {\bf Exchange} \\ \hline \hline
|
|
\endhead
|
|
\hline \hline
|
|
{\bf Reserve} & {\bf Auditor} & {\bf Exchange}
|
|
\endfoot
|
|
\hline
|
|
\hline
|
|
{\bf Total deltas} &
|
|
{{ reserves.total_balance_summary_delta_plus}} &
|
|
- {{ reserves.total_balance_summary_delta_minus}} \\
|
|
\caption{Reserves balances not matching up.}
|
|
\label{table:reserve:balance_inconsistencies}
|
|
\endlastfoot
|
|
{% for item in reserves.reserve_balance_summary_wrong_inconsistencies %}
|
|
{\tt \tiny {{ item.reserve_pub }} } &
|
|
{{ item.auditor }} &
|
|
{{ item.exchange }} \\ \hline
|
|
{% endfor %}
|
|
\end{longtable}
|
|
{% endif %}
|
|
|
|
{% if reserves.reserve_balance_summary_wrong_inconsistencies|length() != 0 %}
|
|
This means that there are inconsistencies in the exchange's
|
|
summary data about reserve balances.
|
|
\begin{itemize}
|
|
\item The exchange believes some reserves contain (in total)
|
|
{\bf {{ reserves.total_balance_summary_delta_plus}} } {\em less} than they
|
|
actually contain. A non-zero value here means the exchange may deny legitimate withdrawal
|
|
requests, denying customers access to their funds.
|
|
\item The exchange believes some reserves contain (in total)
|
|
{\bf {{ reserves.total_balance_summary_delta_minus}} } {\em more} than they
|
|
actually contain. A non-zero value here means the exchange may allow coins to be withdrawn
|
|
for which it never received any income, at a loss (for the exchange).
|
|
\end{itemize}
|
|
|
|
{% if wire.reserve_in_amount_inconsistencies|length() != 0 %}
|
|
Note that inconsistencies detected in Section~\ref{sec:wire_in} may
|
|
have created follow-up errors in this table.
|
|
{% endif %}
|
|
|
|
{% endif %}
|
|
|
|
|
|
\subsection{Wire table issues}
|
|
|
|
This section describes issues found by the wire auditor that do not
|
|
have a clear financial impact.
|
|
|
|
% Table generation tested by testcase #17 in test-auditor.sh
|
|
|
|
{% if wire.row_inconsistencies|length() == 0 %}
|
|
{\bf No wire row inconsistencies found.}
|
|
{% else %}
|
|
\begin{longtable}{p{5.5cm}|l|p{4.5cm}}
|
|
{\bf Table} & {\bf Row} & {\bf Diagnostic} \\
|
|
\hline \hline
|
|
\endfirsthead
|
|
{\bf Table} & {\bf Row} & {\bf Diagnostic} \\
|
|
\hline \hline
|
|
\endhead
|
|
\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:wire:misc}
|
|
\endlastfoot
|
|
{% for item in wire.row_inconsistencies %}
|
|
\verb! {{ item.table }} ! &
|
|
{{ item.row }} &
|
|
{{ item.diagnostic }} \\
|
|
\nopagebreak
|
|
\multicolumn{3}{l}{ {\tiny {\tt \truncate{\textwidth}{ {{ item.wire_offset_hash }} } } } } \\ \hline
|
|
{% endfor %}
|
|
\end{longtable}
|
|
{% endif %}
|
|
|
|
|
|
\subsection{Outgoing wire transfer subject issues}
|
|
|
|
This section describes issues found by the wire auditor that
|
|
relate to outgoing wire transfers subjects being duplicated.
|
|
|
|
% Table generation tested by testcase #XX in test-auditor.sh
|
|
% TODO: test this! #6054
|
|
|
|
{% if wire.wire_format_inconsistencies|length() == 0 %}
|
|
{\bf No wire format inconsistencies found.}
|
|
{% else %}
|
|
\begin{longtable}{p{6.5cm}|r}
|
|
\multicolumn{2}{c}{ {\bf Diagnostic} } \\
|
|
{\bf Row (base32)} & {\bf Amount} \\
|
|
\hline \hline
|
|
\endfirsthead
|
|
\multicolumn{2}{c}{ {\bf Diagnostic} } \\
|
|
{\bf Row (base32)} & {\bf Amount} \\
|
|
\hline \hline
|
|
\endhead
|
|
\hline
|
|
\multicolumn{2}{c}{ {\bf Row (base32)} } \\
|
|
{\bf Row (base32)} & {\bf Amount} \\
|
|
\endfoot
|
|
\hline
|
|
\hline
|
|
{\bf Total} &
|
|
{{ wire.total_wire_format_amount }} \\
|
|
\caption{Outgoing wire transfer subject issues found.}
|
|
\label{table:outgoing:wtid}
|
|
\endlastfoot
|
|
{% for item in wire.wire_format_inconsistencies %}
|
|
\multicolumn{2}{l}{ \small \truncate{0.95\textwidth}{ {{ item.diagnostic }} } } \\
|
|
\nopagebreak
|
|
{ \tt \small \truncate{0.95\textwidth}{ {{ item.wire_offset }} } } & {{ item.amount }} \\ \hline
|
|
{% 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.
|
|
|
|
% Table generation tested by testcase #14 in test-auditor.sh
|
|
|
|
{% if aggregation.wire_fee_time_inconsistencies|length() == 0 %}
|
|
{\bf No wire fee timing issues detected.}
|
|
{% else %}
|
|
\begin{longtable}{p{1.5cm}|r|p{6}}
|
|
{\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 aggregation.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
|
|
impact.
|
|
|
|
\subsubsection{For aggregations}
|
|
|
|
% Table generation tested by testcase #15/#25 in test-auditor.sh
|
|
|
|
{% if aggregation.row_inconsistencies|length() == 0 %}
|
|
{\bf No row inconsistencies found.}
|
|
{% else %}
|
|
\begin{longtable}{p{2.5cm}|l|p{5cm}}
|
|
{\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 \hline
|
|
{\bf Table} & {\bf Row} & {\bf Diagnostic} \\
|
|
\caption{Other issues found (by table and row).}
|
|
\label{table:misc:aggregation}
|
|
\endlastfoot
|
|
{% for item in aggregation.row_inconsistencies %}
|
|
\verb! {{ item.table }} ! &
|
|
{{ item.row }} &
|
|
{{ item.diagnostic }} \\ \hline
|
|
{% endfor %}
|
|
\end{longtable}
|
|
{% endif %}
|
|
|
|
\subsubsection{For coins}
|
|
|
|
% Table generation tested by testcase #13 in test-auditor.sh
|
|
|
|
{% if coins.row_inconsistencies|length() == 0 %}
|
|
{\bf No row inconsistencies found.}
|
|
{% else %}
|
|
\begin{longtable}{p{2.5cm}|l|p{5cm}}
|
|
{\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 \hline
|
|
{\bf Table} & {\bf Row} & {\bf Diagnostic} \\
|
|
\caption{Other issues found (by table and row).}
|
|
\label{table:misc:coins}
|
|
\endlastfoot
|
|
{% for item in coins.row_inconsistencies %}
|
|
\verb! {{ item.table }} ! &
|
|
{{ item.row }} &
|
|
{{ item.diagnostic }} \\ \hline
|
|
{% endfor %}
|
|
\end{longtable}
|
|
{% endif %}
|
|
|
|
\subsubsection{For reserves}
|
|
|
|
% Table generation tested by testcase #XX in test-auditor.sh
|
|
|
|
{% if reserves.row_inconsistencies|length() == 0 %}
|
|
{\bf No row inconsistencies found.}
|
|
{% else %}
|
|
\begin{longtable}{p{2.5cm}|l|p{5cm}}
|
|
{\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 \hline
|
|
{\bf Table} & {\bf Row} & {\bf Diagnostic} \\
|
|
\caption{Other issues found (by table and row).}
|
|
\label{table:misc:reserves}
|
|
\endlastfoot
|
|
{% for item in reserves.row_inconsistencies %}
|
|
\verb! {{ item.table }} ! &
|
|
{{ item.row }} &
|
|
{{ item.diagnostic }} \\ \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.
|
|
|
|
% Table generation tested by testcase #20 in test-auditor.sh
|
|
|
|
{% if reserves.reserve_not_closed_inconsistencies|length() == 0 %}
|
|
{\bf All expired reserves were closed.}
|
|
{% else %}
|
|
\begin{longtable}{p{4.5cm}|c|r}
|
|
{\bf Reserve} & {\bf Expired} & {\bf Balance} \\ \hline \hline
|
|
\endfirsthead
|
|
{\bf Reserve} & {\bf Expired} & {\bf Balance} \\ \hline \hline
|
|
\endhead
|
|
\hline \hline
|
|
{\bf Reserve} & {\bf Expired} & {\bf Balance}
|
|
\endfoot
|
|
\hline
|
|
{\bf Sum} & &
|
|
{{ reserves.total_balance_reserve_not_closed}} \\
|
|
\caption{Reserves not closed on time.}
|
|
\label{table:reserve:not_closed}
|
|
\endlastfoot
|
|
{% for item in reserves.reserve_not_closed_inconsistencies %}
|
|
{\tt \tiny \truncate{4.3cm}{ {{ item.reserve_pub }} } } &
|
|
{\tiny {{ item.expiration_time }} } &
|
|
{{ item.balance }} \\ \hline
|
|
{% endfor %}
|
|
\end{longtable}
|
|
{% endif %}
|
|
|
|
|
|
\subsection{Hanging refresh operations}
|
|
|
|
This section describes cases where the exchange booked a
|
|
coin as spent from {\tt /refresh/melt} but where the
|
|
wallet did not yet complete {\tt /refresh/reveal}. This
|
|
may happen even if the exchange is correct.
|
|
|
|
% Table generation tested by testcase #12 in test-auditor.sh
|
|
|
|
{% if coins.refresh_hanging|length() == 0 %}
|
|
{\bf All melted coins were refreshed.}
|
|
{% else %}
|
|
\begin{longtable}{p{6.5cm}|c|r}
|
|
{\bf Key} & {\bf row} & {\bf Amount} \\
|
|
\hline \hline
|
|
\endfirsthead
|
|
{\bf Key} & {\bf row} & {\bf Amount} \\
|
|
\hline \hline
|
|
\endhead
|
|
\hline \hline
|
|
{\bf Key} & {\bf row} & {\bf Amount} \\
|
|
\endfoot
|
|
\hline
|
|
{\bf Sum} & &
|
|
{{ coins.total_refresh_hanging}} \\
|
|
\caption{Refresh operations hanging.}
|
|
\label{table:refresh:hanging}
|
|
\endlastfoot
|
|
{% for item in coins.refresh_hanging %}
|
|
\truncate{6.2cm}{ {\tt \small {{ item.coin_pub }} } } &
|
|
{{ item.row }} &
|
|
{{ item.amount }} \\ \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.
|
|
|
|
% Table generation tested by testcase #22 in test-auditor.sh
|
|
|
|
{% if reserves.denomination_key_validity_withdraw_inconsistencies|length() == 0 %}
|
|
{\bf All denomination keys were valid at the time of withdrawals.}
|
|
{% else %}
|
|
\begin{longtable}{p{7.5cm}|r}
|
|
{\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 reserves.denomination_key_validity_withdraw_inconsistencies %}
|
|
{\tt \small \truncate{0.6\textwidth}{ {{ item.reserve_pub }} } } & {{ item.row }} \\
|
|
\nopagebreak
|
|
{\tt \small \truncate{0.6\textwidth}{ {{ item.denompub_h }} } } & {{ item.execution_date }} \\ \hline
|
|
{% endfor %}
|
|
\end{longtable}
|
|
{% endif %}
|
|
|
|
|
|
\subsection{Wire transfer timestamp issues}
|
|
|
|
This section lists issues with wire transfers related to timestamps.
|
|
|
|
% Table generation tested by testcase #10/#17 in test-auditor.sh
|
|
|
|
{% if wire.row_minor_inconsistencies|length() == 0 %}
|
|
{\bf No timestamp issues detected.}
|
|
{% else %}
|
|
\begin{longtable}{p{3cm}|r|p{5cm}}
|
|
{\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 \hline
|
|
{\bf Table} & {\bf Row} & {\bf Diagnostic} \\
|
|
\caption{Execution times not matching in wire transfers.}
|
|
\label{table:wire:bad_time}
|
|
\endlastfoot
|
|
{% for item in wire.row_minor_inconsistencies %}
|
|
\verb! {{ item.table }} ! & {{ item.row }} & {{ item.diagnostic }} \\ \hline
|
|
{% endfor %}
|
|
\end{longtable}
|
|
{% endif %}
|
|
|
|
|
|
\end{document}
|