auditor-report.tex.j2 (50491B)
1 % This file is part of TALER 2 % Copyright (C) 2016--2023 Taler Systems SA 3 % 4 % TALER is free software; you can redistribute it and/or modify it under the 5 % terms of the GNU Affero General Public License as published by the Free Software 6 % Foundation; either version 3, or (at your option) any later version. 7 % 8 % TALER is distributed in the hope that it will be useful, but WITHOUT ANY 9 % WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 10 % A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. 11 % 12 % You should have received a copy of the GNU Affero General Public License along with 13 % TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> 14 % 15 % 16 % With respect to this file, our interpretation of the license is 17 % that publishing an audit report (i.e. in TeX or PDF) requires 18 % publishing the corresponding j2 template sources under AGPL, and 19 % linking to them from the report. (This file _is_ source code, 20 % the generated PDF is the service under definition of the AGPL.) 21 % 22 % 23 % NOTE WELL: 24 % 25 % When modifying this document, please verify that the output 26 % still looks good. For this, we have noted which testcases 27 % trigger the respective table being generated using comments 28 % of the form: 29 % 30 % "Table generation tested by testcase #XX in test-auditor.sh" 31 % 32 % Thus, whenever modifying such a table, please verify that the 33 % output still looks OK by manually inspecting the generated 34 % PDF from running 35 % 36 % $ test-auditor.sh XX 37 % 38 % in the src/auditor/ directory. 39 40 \documentclass{article} % {acmart} 41 \usepackage{url} 42 \usepackage[T1]{fontenc} 43 \usepackage[utf8]{inputenc} 44 \usepackage{multirow} 45 \usepackage{longtable} 46 \usepackage[breakall]{truncate} 47 48 \begin{document} 49 50 \title{Taler Auditor Report} 51 52 % You must also credit the original author. 53 \author{Christian Grothoff} 54 \maketitle 55 56 % If you update this template, complying with the license requires 57 % stating the license and publishing the J2 source and linking to it 58 % from the generated PDF. So if you change this outside of the Taler 59 % Git repository, you must update this link (and the link must remain 60 % available to the receiver of the result from the generated TeX, PDF 61 % or other format). 62 63 This report is based on a template licensed under the Affero General Public 64 License, either version 3, or (at your option) any later version. 65 The source code for the template is available at \url{https://git.taler.net/}. 66 67 The report was generated by the auditors at the following times: 68 69 \begin{table}[h!] 70 \begin{center} 71 \begin{tabular}{l|r|r} 72 Auditor & Start & End \\ \hline \hline 73 Aggregation & {{ aggregation.auditor_start_time }} & {{ aggregation.auditor_end_time }} \\ \hline 74 Coins & {{ coins.auditor_start_time }} & {{ coins.auditor_end_time }} \\ \hline 75 Deposits & {{ deposits.auditor_start_time }} & {{ deposits.auditor_end_time }} \\ \hline 76 Reserves & {{ reserves.auditor_start_time }} & {{ reserves.auditor_end_time }} \\ \hline 77 Wire & {{ wire.wire_auditor_start_time }} & {{ wire.wire_auditor_end_time }} \\ 78 \end{tabular} 79 \end{center} 80 \end{table} 81 82 In that time, the auditors processed the following table ranges: 83 \begin{table}[h!] 84 \begin{center} 85 \begin{tabular}{l|r|r} 86 Table & Start & End \\ \hline \hline 87 Reserves Incoming & {{ reserves.start_ppr_reserve_in_serial_id }} 88 & {{ reserves.end_ppr_reserve_in_serial_id }} \\ \hline 89 Reserves Out (withdraw) & {{ reserves.start_ppr_reserve_out_serial_id }} 90 & {{ reserves.end_ppr_reserve_out_serial_id }} \\ \hline 91 Reserves Recoup & {{ reserves.start_ppr_reserve_recoup_serial_id }} 92 & {{ reserves.end_ppr_reserve_recoup_serial_id }} \\ \hline 93 Reserves Close & {{ reserves.start_ppr_reserve_close_serial_id }} 94 & {{ reserves.end_ppr_reserve_close_serial_id }} \\ \hline 95 Aggregation & {{ aggregation.start_ppa_wire_out_serial_id }} 96 & {{ aggregation.end_ppa_wire_out_serial_id }} \\ \hline 97 Aggregation (wire) & {{ wire.start_pp_last_aggregation_serial_id }} 98 & {{ wire.end_pp_last_aggregation_serial_id }} \\ \hline 99 Deposits (wire) & {{ wire.start_pp_last_batch_deposit_id }} 100 & {{ wire.end_pp_last_batch_deposit_id }} \\ \hline 101 Reserves Close (wire) & {{ wire.start_pp_reserve_close_id }} 102 & {{ wire.end_pp_reserve_close_id }} \\ \hline 103 Coin withdraw & {{ coins.start_ppc_withdraw_serial_id }} 104 & {{ coins.end_ppc_withdraw_serial_id }} \\ \hline 105 Coin deposit & {{ coins.start_ppc_deposit_serial_id }} 106 & {{ coins.end_ppc_deposit_serial_id }} \\ \hline 107 Coin melt & {{ coins.start_ppc_melt_serial_id }} 108 & {{ coins.end_ppc_melt_serial_id }} \\ \hline 109 Coin refund & {{ coins.start_ppc_refund_serial_id }} 110 & {{ coins.end_ppc_refund_serial_id }} \\ \hline 111 Coin recoup & {{ coins.start_ppc_recoup_serial_id }} 112 & {{ coins.end_ppc_recoup_serial_id }} \\ \hline 113 Coin recoup refresh & {{ coins.start_ppc_recoup_refresh_serial_id }} 114 & {{ coins.end_ppc_recoup_refresh_serial_id }} \\ 115 \end{tabular} 116 \end{center} 117 \caption{Serial number ranges of the tables processed by the audit.} 118 \label{table:auditor_range} 119 \end{table} 120 121 {% if wire.account_progress|length() == 0 %} 122 In that time, the wire auditor processed NO accounts at all. 123 {% else %} 124 In that time, the wire auditor processed the following table ranges: 125 \begin{center} 126 \begin{longtable}{l|c|r|r} 127 Account & Table & Start & End \\ \hline 128 \endfirsthead 129 Account & Table & Start & End \\ \hline 130 \endhead 131 \endfoot 132 \caption{Range of account data processed by the wire auditor.} 133 \label{table:account_range} 134 \endlastfoot 135 {% for item in wire.account_progress %} 136 \hline 137 {{ item.account }} & 138 Reserves Incoming & {{ item.start_reserve_in }} 139 & {{ item.end_reserve_in }} \\ \hline 140 & 141 Outgoing wire transfers & {{ item.start_wire_out }} 142 & {{ item.end_wire_out }} \\ 143 {% endfor %} 144 \end{longtable} 145 {% endif %} 146 \end{center} 147 148 The total credits to the exchange processed in 149 this audit run was {\bf {{ wire.total_wire_in }}}. 150 The total debits initiated by the exchange processed in 151 this audit run was {\bf {{ wire.total_wire_out }}}. 152 153 \section{Operations} 154 155 The balance of the escrow account should 156 be {\bf {{ coins.total_escrow_balance }}} (coins) 157 plus {\bf {{ reserves.total_escrow_balance }}} (reserves). 158 159 \noindent 160 This should match the final balance computed from 161 ingoing and outgoing wire transfers, which is 162 {\bf {{ wire.final_balance}} }. 163 164 \noindent 165 A total of {\bf {{ wire.total_drained}} } in profits 166 were transferred (over the lifetime of the exchange) 167 to non-escrowed accounts. 168 169 \noindent 170 The active operational risk stands at 171 {\bf {{ coins.total_active_risk }}}. 172 173 \noindent 174 Loss (actualized risk from recoups) is 175 {\bf {{ coins.total_recoup_loss }}}. 176 177 \noindent 178 Losses from irregular reserve operations are at 179 {\bf {{ reserves.total_irregular_loss }}} (reserves). 180 181 \section{Income} 182 183 This section analyzes the income of the exchange operator from fees. 184 185 \begin{table}[h!] 186 \begin{center} 187 \caption{Fee revenue summary} 188 \label{table:revenue} 189 \begin{tabular}{l|r} 190 Category & Amount \\ \hline \hline 191 Withdraw fees & {{ reserves.total_withdraw_fee_income }} \\ 192 Deposit fees & {{ coins.total_deposit_fee_income }} \\ 193 Melt fees & {{ coins.total_melt_fee_income }} \\ 194 Refund fees & {{ coins.total_refund_fee_income }} \\ 195 Aggregation fees & {{ aggregation.total_aggregation_fee_income }} \\ 196 \end{tabular} 197 \end{center} 198 \end{table} 199 200 201 \section{Lag} 202 203 This section analyzes lag, which can be due to some component being behind in 204 executing transactions. This is usually either the exchange's aggregator, the 205 bank's wire transfer logic, or the synchronization of databases between 206 exchange and auditor. Significant lag may be indicative of fraud, while 207 moderate lag is indicative that the systems may be too slow to handle the 208 load. Small amounts of lag can occur in normal operation. 209 210 \subsection{Deposit lag} 211 212 The total amount the exchange currently lags behind in deposits is 213 {\bf {{ wire.total_amount_lag }}}. 214 215 Note that some lag is perfectly normal, as tiny amounts that are too small to 216 be wired are deferred beyond the due date, hoping that additional transfers 217 will push them above the tiny threshold. Below, we report {\em non-tiny} wire 218 transfers that are lagging behind. 219 220 % Table generation tested by testcase #1 in test-auditor.sh 221 222 {% if wire.lag_details|length() == 0 %} 223 {\bf No non-tiny wire transfers that are lagging behind detected.} 224 {% else %} 225 \begin{longtable}{l|r|r} 226 {\bf Deadline} & {\bf Amount} & {\bf Target account} \\ \hline \hline 227 \endfirsthead 228 {\bf Deadline} & {\bf Amount} & {\bf Target account} \\ \hline \hline 229 \endhead 230 \hline \hline 231 {\bf Deadline} & {\bf Amount} & {\bf Target account} \\ 232 \endfoot 233 \hline \hline 234 {\bf Deadline} & {\bf Amount} & {\bf Target account} \\ 235 \caption{Lagging non-tiny transactions.} 236 \label{table:lag} 237 \endlastfoot 238 {% for item in wire.lag_details %} 239 {{ item.deadline }} & 240 {{ item.total_amount }} & 241 {\tt 242 {% if 'account' in item %} 243 {{ item.account }} 244 {% endif %} 245 } \\ \hline 246 {% endfor %} 247 \end{longtable} 248 {% endif %} 249 250 251 252 {% if wire.lag_kyc_details|length() == 0 %} 253 {\bf No KYC-blocked non-tiny wire transfers that are lagging behind detected.} 254 {% else %} 255 \begin{longtable}{l|r|c|r} 256 {\bf Deadline} & {\bf Amount} & {\bf Requirement} & {\bf Target account} \\ \hline \hline 257 \endfirsthead 258 {\bf Deadline} & {\bf Amount} & {\bf Requirement} & {\bf Target account} \\ \hline \hline 259 \endhead 260 \hline \hline 261 {\bf Deadline} & {\bf Amount} & {\bf Requirement} & {\bf Target account} \\ 262 \endfoot 263 \hline \hline 264 {\bf Deadline} & {\bf Amount} & {\bf Requirement} & {\bf Target account} \\ 265 \caption{Lagging non-tiny transactions due to missing KYC data.} 266 \label{table:lag} 267 \endlastfoot 268 {% for item in wire.lag_kyc_details %} 269 {{ item.deadline }} & 270 {{ item.amount }} & 271 {{ item.kyc_pending }} & 272 {\tt 273 {% if 'account' in item %} 274 {{ item.account }} 275 {% endif %} 276 } \\ \hline 277 {% endfor %} 278 \end{longtable} 279 {% endif %} 280 281 282 {% if wire.lag_aml_details|length() == 0 %} 283 {\bf No non-tiny wire transfers that are lagging behind due to AML detected.} 284 {% else %} 285 \begin{longtable}{l|r|r} 286 {\bf Deadline} & {\bf Amount}/{\bf Limit} & {\bf AML status} \\ 287 \multicolumn{3}{l}{\bf Target account} \\ \hline \hline 288 \endfirsthead 289 {\bf Deadline} & {\bf Amount}/{\bf Limit} & {\bf AML status} \\ 290 \multicolumn{4}{l}{\bf Target account} \\ \hline \hline 291 \endhead 292 \hline \hline 293 {\bf Deadline} & {\bf Amount}/{\bf Limit} & {\bf AML status} \\ 294 \multicolumn{4}{l}{\bf Target account} \\ 295 \endfoot 296 \hline \hline 297 {\bf Deadline} & {\bf Amount}/{\bf Limit} & {\bf AML status} \\ 298 \multicolumn{4}{l}{\bf Target account} \\ 299 \caption{Lagging non-tiny transactions due to AML decisions.} 300 \label{table:lag} 301 \endlastfoot 302 {% for item in wire.lag_aml_details %} 303 {{ item.deadline }} & 304 {{ item.amount }}/{{ item.aml_limit }} & 305 {{ item.aml_status }} & 306 \nopagebreak 307 \multicolumn{4}{l}{ {\tt 308 {% if 'account' in item %} 309 {{ item.account }} 310 {% endif %} 311 } } \\ \hline 312 {% endfor %} 313 \end{longtable} 314 {% endif %} 315 316 317 \subsection{Reserve closure lag} 318 319 The total amount the exchange currently lags behind in reserve closures is 320 {\bf {{ wire.total_closure_amount_lag }}}. 321 322 Note that some minimal lag may be normal as transactions may be in-flight. 323 324 % Table generation tested by testcase #21 in test-auditor.sh 325 326 {% if wire.reserve_lag_details|length() == 0 %} 327 {\bf No closure transfers that are lagging behind detected.} 328 {% else %} 329 \begin{longtable}{l|r|r} 330 {\bf Deadline} & {\bf Amount} & {\bf Row} \\ 331 \multicolumn{3}{l}{\bf WTID} \\ 332 \multicolumn{3}{l}{\bf Target account} \\ \hline \hline 333 \endfirsthead 334 {\bf Deadline} & {\bf Amount} & {\bf Row} \\ 335 \multicolumn{3}{l}{\bf WTID} \\ 336 \multicolumn{3}{l}{\bf Target account} \\ \hline \hline 337 \endhead 338 \hline \hline 339 {\bf Deadline} & {\bf Amount} & {\bf Row} \\ 340 \multicolumn{3}{l}{\bf WTID} \\ 341 \multicolumn{3}{l}{\bf Target account} \\ 342 \endfoot 343 \hline \hline 344 {\bf Deadline} & {\bf Amount} & {\bf Row} \\ 345 \multicolumn{3}{l}{\bf WTID} \\ 346 \multicolumn{3}{l}{\bf Target account} \\ 347 \caption{Lagging reserve closure transactions.} 348 \label{table:lag} 349 \endlastfoot 350 {% for item in wire.reserve_lag_details %} 351 {{ item.deadline }} & 352 {{ item.amount }} & 353 {{ item.row }} \\ 354 \nopagebreak 355 \multicolumn{3}{l}{ {\tt \small {{ item.wtid }} } } \\ 356 \nopagebreak 357 \multicolumn{3}{l}{ {\tt 358 {% if 'payto_uri' in item.account %} 359 {{ item.account.payto_uri }} 360 {% endif %} 361 } } \\ \hline 362 {% endfor %} 363 \end{longtable} 364 {% endif %} 365 366 367 \subsection{Deposit confirmation lag} 368 369 This section analyzes the lag, which is by how much the exchange's 370 database reporting is behind in providing us with information about 371 deposit confirmations. Merchants probabilistically report deposit 372 confirmations to the auditor directly, so if the exchange is slow at 373 synchronizing its database with the auditor, some deposit 374 confirmations may be known at the auditor only directly. However, any 375 delta not accounted for by database synchronization delays is an 376 indicator of a malicious exchange (or online signing key compromise) 377 and should be answered by revoking the exchange's online signing keys. 378 % TODO: maybe reference PhD thesis on this? 379 380 The total amount the exchange currently lags behind is 381 {\bf {{ deposits.missing_deposit_confirmation_total }} } from a total number of 382 {\bf {{ deposits.missing_deposit_confirmation_count }} } deposit confirmations. 383 384 Note that some lag is perfectly normal. 385 Below, we report {\em all} deposit confirmations that are lagging behind. 386 387 % Table generation tested by testcase #24 in test-auditor.sh 388 389 {% if deposits.deposit_confirmation_inconsistencies|length() == 0 %} 390 {\bf No deposit confirmations that are lagging behind detected.} 391 {% else %} 392 \begin{longtable}{r|r|r} 393 {\bf Timestamp} & {\bf Amount} & {\bf Row} \\ 394 \multicolumn{3}{l}{\bf Target account} \\ \hline \hline 395 \endfirsthead 396 {\bf Timestamp} & {\bf Amount} & {\bf Row} \\ 397 \multicolumn{3}{l}{\bf Target account} \\ \hline \hline 398 \endhead 399 \hline \hline 400 {\bf Timestamp} & {\bf Amount} & {\bf Row} \\ 401 \multicolumn{3}{l}{\bf Target account} \\ 402 \endfoot 403 \hline \hline 404 {\bf Timestamp} & {\bf Amount} & {\bf Row} \\ 405 \multicolumn{3}{l}{\bf Target account} \\ 406 \caption{Missing deposit confirmations.} 407 \label{table:missing_dc} 408 \endlastfoot 409 {% for item in deposits.deposit_confirmation_inconsistencies %} 410 {{ item.timestamp }} & 411 {{ item.amount }} & 412 {{ item.rowid }} \\ 413 \nopagebreak 414 \multicolumn{3}{l}{ {\tt \truncate{0.95\textwidth}{ {{ item.account }} } } } \\ \hline 415 {% endfor %} 416 \end{longtable} 417 {% endif %} 418 419 420 \section{Major irregularities} 421 422 This section describes the possible major irregularities that the 423 auditor has checked, and lists all of the actual irregularities 424 encountered in detail. 425 426 \subsection{Emergencies} 427 428 Emergencies are errors where more coins were deposited than the 429 exchange remembers issuing. This usually means that the private keys 430 of the exchange were compromised (stolen or factored) and subsequently 431 used to sign coins off the books. If this happens, all coins of the 432 respective denomination that the exchange has redeemed so far may have 433 been created by the attacker, and the exchange would have to refund 434 all of the outstanding coins from ordinary users. Thus, the {\bf risk 435 exposure} is the amount of coins in circulation for a particular 436 denomination and the maximum loss for the exchange from this type of 437 compromise. 438 439 {% if (coins.emergencies|length() != 0) %} 440 The total risk from emergencies detected by amount is 441 {\bf {{ coins.emergencies_risk_by_amount }} }. 442 The total loss from emergencies detected by amount is 443 {\bf {{ coins.emergencies_loss }} }. 444 {% endif %} 445 446 {% if (coins.emergencies_by_count|length() != 0) %} 447 The total risk from emergencies detected by counting coins is 448 {\bf {{ coins.emergencies_risk_by_count }} } 449 The total loss from emergencies detected by counting coins could be up to 450 {\bf {{ coins.emergencies_loss_by_count }} }. 451 {% endif %} 452 453 454 \subsubsection{Emergencies by counting coins} 455 456 % Table generation tested by testcase #18 in test-auditor.sh 457 458 {% if coins.emergencies_by_count|length() == 0 %} 459 {\bf No emergencies detected by counting coins.} 460 {% else %} 461 \begin{longtable}{r|c|r|r} 462 \multicolumn{4}{c}{ {\bf Public key hash} } \\ 463 {\bf Denomination} & {\bf Lifetime} & {\bf \# Issued} & {\bf \# Deposited} \\ \hline \hline 464 \endfirsthead 465 \multicolumn{4}{|c|}{ {\bf Public key hash} } \\ 466 {\bf Denomination} & {\bf Lifetime} & {\bf \# Issued} & {\bf \# Deposited} \\ \hline \hline 467 \endhead 468 \hline \hline 469 \multicolumn{4}{|c|}{ {\bf Public key hash} } \\ 470 {\bf Denomination} & {\bf Lifetime} & {\bf \# Issued} & {\bf \# Deposited} \\ \hline \hline 471 \endfoot 472 \caption{Emergencies by counting coins.} 473 \label{table:emergencies_coin_counting} 474 \endlastfoot 475 {% for item in coins.emergencies_by_count %} 476 \multicolumn{4}{l}{ {\tt \truncate{0.95\textwidth}{ {{ item.denompub_hash }} } } } \\ 477 \nopagebreak 478 {{ item.value }} & 479 {\tiny \begin{tabular}{c} 480 {{ item.start }} \\ \hline 481 {{ item.deposit_end }} 482 \end{tabular} } & 483 {{ item.num_issued }} & 484 {{ item.num_known }} \\ \hline 485 {% endfor %} 486 \end{longtable} 487 {% endif %} 488 489 490 \subsubsection{Emergencies by value deposited} 491 492 Note that emergencies by value deposited can {\em also} arise if the exchange 493 fails to properly detect double spending (or simply fails to properly account 494 for the remaining balance of a coin). Thus, if issues are listed here {\bf in 495 combination with} arithmetic problems (Section~\ref{sec:arithmetic}) issues, 496 then they may not be a definitive indicator that the exchange's private 497 signing key was compromised. 498 499 % Table generation tested by testcases #18, #25 in test-auditor.sh 500 501 {% if coins.emergencies|length() == 0 %} 502 {\bf No emergencies by value detected.} 503 {% else %} 504 \begin{longtable}{r|c|r|r} 505 \multicolumn{4}{c}{ {\bf Public key hash} } \\ 506 {\bf Denomination} & {\bf Lifetime} & {\bf Risk exposure} & {\bf Loss} \\ \hline \hline 507 \endfirsthead 508 \multicolumn{4}{|c|}{ {\bf Public key hash} } \\ 509 {\bf Denomination} & {\bf Lifetime} & {\bf Risk exposure} & {\bf Loss} \\ \hline \hline 510 \endhead 511 \hline \hline 512 \multicolumn{4}{|c|}{ {\bf Public key hash} } \\ 513 {\bf Denomination} & {\bf Lifetime} & {\bf Risk exposure} & {\bf Loss} \\ 514 \endfoot 515 \caption{Emergencies by value deposited.} 516 \label{table:emergencies} 517 \endlastfoot 518 {% for item in coins.emergencies %} 519 \multicolumn{4}{l}{ {\tt \truncate{0.95\textwidth}{ {{ item.denompub_hash }} } } } \\ 520 \nopagebreak 521 {{ item.value }} & 522 {\tiny \begin{tabular}{c} 523 {{ item.start }} \\ \hline 524 {{ item.deposit_end }} 525 \end{tabular} } & 526 {{ item.denom_risk }} & 527 {{ item.denom_loss }} \\ \hline 528 {% endfor %} 529 \end{longtable} 530 {% endif %} 531 532 533 \subsection{Arithmetic problems} \label{sec:arithmetic} 534 535 This section lists cases where the arithmetic of the exchange 536 involving amounts disagrees with the arithmetic of the auditor. 537 Disagreements imply that either the exchange made a loss (sending out 538 too much money), or screwed a customer (and thus at least needs to fix 539 the financial damage done to the customer). 540 541 Note that the deltas only sum up the issues where $P \not= 0$ as only 542 then we can tell if the problem lead to a profit or loss. 543 544 The {\bf P} column is set to "1" if the arithmetic problem was be determined to be 545 profitable for the exchange, "-1" if the problem resulted in a net loss for 546 the exchange, and "0" if this is unclear or at least the gain/loss is not 547 easily determined from the amounts and thus not included in the totals. 548 549 \subsubsection{For aggregation} 550 551 % Table generation tested by testcase #XX in test-auditor.sh 552 553 {% if aggregation.amount_arithmetic_inconsistencies|length() == 0 %} 554 {\bf No arithmetic problems detected.} 555 {% else %} 556 \begin{longtable}{p{3.5cm}|r|r|r|c} 557 {\bf Operation} & {\bf Row} & {\bf Exchange} & {\bf Auditor} & {\bf P} \\ 558 \hline \hline 559 \endfirsthead 560 {\bf Operation} & {\bf Row} & {\bf Exchange} & {\bf Auditor} & {\bf P} \\ \hline \hline 561 \endhead 562 \hline \hline 563 {\bf Operation} & {\bf Row} & {\bf Exchange} & {\bf Auditor} & {\bf P} \\ 564 \endfoot 565 \hline \hline 566 \multicolumn{2}{l|}{ {\bf $\sum$ Deltas (Auditor-Exchange)} } & 567 + {{ aggregation.total_arithmetic_delta_plus }} & 568 - {{ aggregation.total_arithmetic_delta_minus }} & \\ 569 \caption{Arithmetic inconsistencies.} 570 \label{table:amount:arithmetic:inconsistencies:aggregation} 571 \endlastfoot 572 {% for item in aggregation.amount_arithmetic_inconsistencies %} 573 \truncate{3.3cm}{ {\tiny {{ item.operation }} } } & 574 {{ item.rowid }} & 575 {{ item.exchange }} & 576 {{ item.auditor }} & 577 {{ item.profitable }} \\ \hline 578 {% endfor %} 579 \end{longtable} 580 {% endif %} 581 582 \subsubsection{For coins} 583 584 % Table generation tested by testcase #18 in test-auditor.sh 585 % Table generation tested by testcase #3 in test-revocation.sh 586 587 {% if coins.amount_arithmetic_inconsistencies|length() == 0 %} 588 {\bf No arithmetic problems detected.} 589 {% else %} 590 \begin{longtable}{p{3.5cm}|r|r|r|c} 591 {\bf Operation} & {\bf Row} & {\bf Exchange} & {\bf Auditor} & {\bf P} \\ 592 \hline \hline 593 \endfirsthead 594 {\bf Operation} & {\bf Row} & {\bf Exchange} & {\bf Auditor} & {\bf P} \\ \hline \hline 595 \endhead 596 \hline \hline 597 {\bf Operation} & {\bf Row} & {\bf Exchange} & {\bf Auditor} & {\bf P} \\ 598 \endfoot 599 \hline \hline 600 \multicolumn{2}{l|}{ {\bf $\sum$ Deltas (Auditor-Exchange)} } & 601 + {{ coins.total_arithmetic_delta_plus }} & 602 - {{ coins.total_arithmetic_delta_minus }} & \\ 603 \caption{Arithmetic inconsistencies.} 604 \label{table:amount:arithmetic:inconsistencies:coins} 605 \endlastfoot 606 {% for item in coins.amount_arithmetic_inconsistencies %} 607 \truncate{3.3cm}{ {\tiny {{ item.operation }} } } & 608 {{ item.rowid }} & 609 {{ item.exchange }} & 610 {{ item.auditor }} & 611 {{ item.profitable }} \\ \hline 612 {% endfor %} 613 \end{longtable} 614 {% endif %} 615 616 \subsubsection{For reserves} 617 618 % Table generation tested by testcase #2 in test-auditor.sh 619 620 {% if reserves.amount_arithmetic_inconsistencies|length() == 0 %} 621 {\bf No arithmetic problems detected.} 622 {% else %} 623 \begin{longtable}{p{3.5cm}|r|r|r|c} 624 {\bf Operation} & {\bf Row} & {\bf Exchange} & {\bf Auditor} & {\bf P} \\ 625 \hline \hline 626 \endfirsthead 627 {\bf Operation} & {\bf Row} & {\bf Exchange} & {\bf Auditor} & {\bf P} \\ \hline \hline 628 \endhead 629 \hline \hline 630 {\bf Operation} & {\bf Row} & {\bf Exchange} & {\bf Auditor} & {\bf P} \\ 631 \endfoot 632 \hline \hline 633 \multicolumn{2}{l|}{ {\bf $\sum$ Deltas (Auditor-Exchange)} } & 634 + {{ reserves.total_arithmetic_delta_plus }} & 635 - {{ reserves.total_arithmetic_delta_minus }} & \\ 636 \caption{Arithmetic inconsistencies.} 637 \label{table:amount:arithmetic:inconsistencies:reserves} 638 \endlastfoot 639 {% for item in reserves.amount_arithmetic_inconsistencies %} 640 \truncate{3.3cm}{ {\tiny {{ item.operation }} } } & 641 {{ item.rowid }} & 642 {{ item.exchange }} & 643 {{ item.auditor }} & 644 {{ item.profitable }} \\ \hline 645 {% endfor %} 646 \end{longtable} 647 {% endif %} 648 649 650 \subsection{Reserve withdrawals exceeding balance} 651 652 This section highlights cases where more coins were withdrawn from a 653 reserve than the reserve contained funding for. This is a serious 654 compromise resulting in proportional financial losses to the exchange. 655 656 % Table generation tested by testcase #2 in test-auditor.sh 657 658 {% if reserves.reserve_balance_insufficient_inconsistencies|length() == 0 %} 659 {\bf All withdrawals were covered by sufficient reserve funding.} 660 {% else %} 661 \begin{longtable}{p{8.5cm}|r} 662 {\bf Reserve} & {\bf Loss} \\ \hline \hline 663 \endfirsthead 664 {\bf Reserve} & {\bf Loss} \\ \hline \hline 665 \endhead 666 \hline \hline 667 {\bf Reserve} & {\bf Loss} 668 \endfoot 669 \hline 670 {\bf Total loss} & 671 {{ reserves.total_irregular_loss }} \\ 672 \caption{Reserves with withdrawals higher than reserve funding.} 673 \label{table:reserve:balance_insufficient} 674 \endlastfoot 675 {% for item in reserves.reserve_balance_insufficient_inconsistencies %} 676 {\tt \small {{ item.reserve_pub }} } 677 & 678 {{ item.loss }} \\ \hline 679 {% endfor %} 680 \end{longtable} 681 {% endif %} 682 683 684 \subsection{Claimed outgoing wire transfer inconsistencies} 685 686 This section is about the exchange's database containing a 687 justification to make an outgoing wire transfer for an aggregated 688 amount for various deposits. It is reported as an inconsistency if the 689 amount claimed for the wire transfer does not match up the deposits 690 aggregated. This is about a {\em claimed} outgoing wire transfer as 691 violations do not imply that the wire transfer was actually made (as 692 that is a separate check). Note that not making the wire transfer 693 would be reported separately in Section~\ref{sec:wire_check_out}. 694 695 % Table generation tested by testcase #23 in test-auditor.sh 696 697 {% if aggregation.wire_out_inconsistencies|length() == 0 %} 698 {\bf All aggregations matched up.} 699 {% else %} 700 \begin{longtable}{r|r|r} 701 \multicolumn{3}{c}{ {\bf Destination account} } \\ 702 {\bf Row} & {\bf Expected} & {\bf Claimed} \\ \hline \hline 703 \endfirsthead 704 \multicolumn{3}{c}{ {\bf Destination account} } \\ 705 {\bf Row} & {\bf Expected} & {\bf Claimed} \\ \hline \hline 706 \endhead 707 \hline \hline 708 \multicolumn{3}{c}{ {\bf Destination account} } \\ 709 {\bf Row} & {\bf Expected} & {\bf Claimed} \\ 710 \endfoot 711 \hline 712 {\bf Total deltas} & 713 {{ aggregation.total_wire_out_delta_plus}} & 714 - {{ aggregation.total_wire_out_delta_minus}} \\ 715 \caption{Claimed wire out aggregate totals not matching up.} 716 \label{table:reserve:wire_out_balance_inconsistencies} 717 \endlastfoot 718 {% for item in aggregation.wire_out_inconsistencies %} 719 \multicolumn{3}{l}{ {\tt \truncate{0.95\textwidth}{ 720 {% if 'payto_uri' in item.destination_account %} 721 {{ item.destination_account.payto_uri }} 722 {% endif %} 723 } } } \\ 724 \nopagebreak 725 {{ item.rowid }} & 726 {{ item.expected }} & 727 {{ item.claimed }} \\ \hline 728 {% endfor %} 729 \end{longtable} 730 {% endif %} 731 732 733 \subsection{Coin history inconsistencies} 734 735 This section lists cases where the exchange made arithmetic errors found when 736 looking at the transaction history of a coin. The totals sum up the differences 737 in amounts that matter for profit/loss calculations of the exchange. When an 738 exchange merely shifted money from customers to merchants (or vice versa) without 739 any effects on its own balance, those entries are excluded from the total. 740 741 % Table generation tested by testcase #25 in test-auditor.sh 742 743 {% if aggregation.coin_inconsistencies|length() == 0 %} 744 {\bf All coin histories were unproblematic.} 745 {% else %} 746 \begin{longtable}{p{1.8cm}|r|r} 747 {\bf Operation} & \multicolumn{2}{|c}{\bf Coin public key} \\ 748 & {\bf Exchange } & {\bf Auditor} \\ 749 \hline \hline 750 \endfirsthead 751 {\bf Operation} & \multicolumn{2}{|r}{\bf Coin public key} \\ 752 & {\bf Exchange } & {\bf Auditor} \\ 753 \hline \hline 754 \endhead 755 \hline \hline 756 {\bf Operation} & \multicolumn{2}{|r}{\bf Coin public key} \\ 757 & {\bf Exchange } & {\bf Auditor} \\ 758 \endfoot 759 \hline 760 $\sum$ {\bf Delta (Auditor-Exchange)} & 761 {{ aggregation.total_coin_delta_plus }} & 762 - {{ aggregation.total_coin_delta_minus }} \\ 763 \caption{Arithmetic inconsistencies of amount calculations involving a coin.} 764 \label{table:amount:arithmetic:coin:inconsistencies} 765 \endlastfoot 766 {% for item in aggregation.coin_inconsistencies %} 767 {{ item.operation }} & 768 \multicolumn{2}{l}{ {\tt \small {{ item.coin_pub }} } } \\ 769 \nopagebreak & 770 {{ item.exchange }} & 771 {{ item.auditor }} \\ \hline 772 {% endfor %} 773 \end{longtable} 774 {% endif %} 775 776 777 \subsection{Operations with bad signatures} 778 779 This section lists operations that the exchange performed, but for 780 which the signatures provided are invalid. Hence the operations were 781 invalid and the amount involved should be considered lost. 782 783 \subsubsection{For aggregation} 784 785 % Table generation tested by testcase #32 in test-auditor.sh 786 787 {% if aggregation.bad_sig_losses|length() == 0 %} 788 {\bf All signatures were valid.} 789 {% else %} 790 \begin{longtable}{l|r|r} 791 \multicolumn{3}{l}{ {\bf Coin public key} }\\ 792 {\bf Operation type} & Database row & {\bf Loss amount} \\ 793 \hline \hline 794 \endfirsthead 795 \multicolumn{3}{l}{ {\bf Coin public key} }\\ 796 {\bf Operation type} & Database row & {\bf Loss amount} \\ \hline \hline 797 \endhead 798 \hline \hline 799 \multicolumn{3}{l}{ {\bf Coin public key} }\\ 800 {\bf Operation type} & Database row & {\bf Loss amount} \\ 801 \endfoot 802 \hline 803 \multicolumn{2}{l}{ {\bf Total losses} } & 804 {\bf {{ aggregation.total_bad_sig_loss}} } \\ 805 \caption{Losses from operations performed on coins without proper signatures.} 806 \label{table:bad_signature_losses} 807 \endlastfoot 808 {% for item in aggregation.bad_sig_losses %} 809 \multicolumn{3}{l}{ {\tt \small \truncate{0.9\textwidth}{ {{ item.coin_pub }} } } } \\ 810 \nopagebreak 811 {{ item.operation }} & 812 {{ item.row }} & 813 {{ item.loss }} \\ \hline 814 {% endfor %} 815 \end{longtable} 816 {% endif %} 817 818 \subsubsection{For coins} 819 820 % Table generation tested by testcase #4/#5/#6/#13 in test-auditor.sh 821 % Table generation tested by testcase #4 in test-revocation.sh 822 823 {% if coins.bad_sig_losses|length() == 0 %} 824 {\bf All signatures were valid.} 825 {% else %} 826 \begin{longtable}{l|r|r} 827 \multicolumn{3}{l}{ {\bf Coin public key} }\\ 828 {\bf Operation type} & Database row & {\bf Loss amount} \\ 829 \hline \hline 830 \endfirsthead 831 \multicolumn{3}{l}{ {\bf Coin public key} }\\ 832 {\bf Operation type} & Database row & {\bf Loss amount} \\ \hline \hline 833 \endhead 834 \hline \hline 835 \multicolumn{3}{l}{ {\bf Coin public key} }\\ 836 {\bf Operation type} & Database row & {\bf Loss amount} \\ 837 \endfoot 838 \hline 839 \multicolumn{2}{l}{ {\bf Total losses} } & 840 {\bf {{ coins.irregular_loss}} } \\ 841 \caption{Losses from operations performed on coins without proper signatures.} 842 \label{table:bad_signature_losses} 843 \endlastfoot 844 {% for item in coins.bad_sig_losses %} 845 \multicolumn{3}{l}{ {\tt \small \truncate{0.9\textwidth}{ {{ item.coin_pub }} } } } \\ 846 \nopagebreak 847 {{ item.operation }} & 848 {{ item.row }} & 849 {{ item.loss }} \\ \hline 850 {% endfor %} 851 \end{longtable} 852 {% endif %} 853 854 \subsubsection{For reserves} 855 856 % Table generation tested by testcase #7 in test-auditor.sh 857 858 The key given is always the key for which the signature verification step 859 failed. This is the reserve public key for ``withdraw'' operations, the coin 860 public key for ``recoup'' operations, and the master public key for 861 ``recoup-master'' operations (where the master's signature on the revocation 862 is invalid). 863 864 865 {% if reserves.bad_sig_losses|length() == 0 %} 866 {\bf All signatures were valid.} 867 {% else %} 868 \begin{longtable}{l|r|r} 869 \multicolumn{3}{l}{ {\bf Public key} }\\ 870 {\bf Operation type} & Database row & {\bf Loss amount} \\ 871 \hline \hline 872 \endfirsthead 873 \multicolumn{3}{l}{ {\bf Public key} }\\ 874 {\bf Operation type} & Database row & {\bf Loss amount} \\ \hline \hline 875 \endhead 876 \hline \hline 877 \multicolumn{3}{l}{ {\bf Public key} }\\ 878 {\bf Operation type} & Database row & {\bf Loss amount} \\ 879 \endfoot 880 \hline 881 \multicolumn{2}{l}{ {\bf Total losses} } & 882 {\bf {{ reserves.total_bad_sig_loss}} } \\ 883 \caption{Losses from operations performed on coins without proper signatures.} 884 \label{table:bad_signature_losses} 885 \endlastfoot 886 {% for item in reserves.bad_sig_losses %} 887 \multicolumn{3}{l}{ {\tt \small \truncate{0.9\textwidth}{ {{ item.key_pub }} } } } \\ 888 \nopagebreak 889 {{ item.operation }} & 890 {{ item.row }} & 891 {{ item.loss }} \\ \hline 892 {% endfor %} 893 \end{longtable} 894 {% endif %} 895 896 897 898 \subsection{Actual incoming wire transfers} \label{sec:wire_in} 899 900 This section highlights cases where the exchange's record about 901 incoming wire transfers does not match with that of the bank. 902 903 % Table generation tested by testcase #3 and #8 in test-auditor.sh 904 905 {% if wire.reserve_in_amount_inconsistencies|length() == 0 %} 906 {\bf All incoming wire transfer amounts and subjects matched up.} 907 {% else %} 908 \begin{longtable}{p{5.5cm}|r|r} 909 \multicolumn{2}{l}{ {\bf Reserve Public Key} ({\bf Row}) } \\ 910 \multicolumn{3}{l}{ {\bf Diagnostic} } \\ 911 {\bf When} & {\bf Wired} & {\bf Expected} \\ 912 \hline \hline 913 \endfirsthead 914 \multicolumn{2}{l}{ {\bf Reserve Public Key} ({\bf Row}) } \\ 915 \multicolumn{3}{l}{ {\bf Diagnostic} } \\ 916 {\bf When} & {\bf Wired} & {\bf Expected} \\ 917 \hline \hline 918 \endhead 919 \hline \hline 920 \multicolumn{2}{l}{ {\bf Reserve Public Key} ({\bf Row}) } \\ 921 \multicolumn{3}{l}{ {\bf Diagnostic} } \\ 922 {\bf When} & {\bf Wired} & {\bf Expected} \\ 923 \endfoot 924 \hline \hline 925 {\bf Total deltas} & 926 {{ wire.total_wire_in_delta_plus }} & 927 - {{ wire.total_wire_in_delta_minus}} \\ 928 \caption{Incoming wire transfer amounts not matching up.} 929 \label{table:wire_in:transfer_amount_inconsistencies} 930 \endlastfoot 931 {% for item in wire.reserve_in_amount_inconsistencies %} 932 \multicolumn{3}{l}{ {\tt \small {{ item.reserve_pub }} } ({{ item.row }}) } \\ 933 \nopagebreak 934 \multicolumn{3}{l}{ {{ item.diagnostic }} } \\ 935 \nopagebreak 936 {{ item.timestamp }} & 937 {{ item.amount_wired }} & 938 {{ item.amount_exchange_expected }} \\ 939 \hline 940 {% endfor %} 941 \end{longtable} 942 {% endif %} 943 944 945 {% if wire.reserve_in_amount_inconsistencies|length() != 0 %} 946 This means that there are inconsistencies in the exchange's 947 claims about incoming wire transfers, amounting to: 948 \begin{itemize} 949 \item The exchange believing it received 950 {\bf {{ wire.total_wire_in_delta_plus }} } {\em less} than it 951 actually received in some reserves. 952 \item The exchange believing that it received 953 {\bf {{ wire.total_wire_in_delta_minus}} } {\em more} than it 954 actually received in some reserves. 955 \end{itemize} 956 {% endif %} 957 958 959 \subsection{Misattributed incoming wire transfers} 960 961 This section lists cases where the sender account record of an 962 incoming wire transfer differs between the exchange and the bank. 963 This will cause funds to be sent to the wrong account when the reserve 964 is closed and the remaining balance is refunded to the original 965 account. 966 967 % Table generation tested by testcase #9 in test-auditor.sh 968 969 {% if wire.misattribution_in_inconsistencies|length() == 0 %} 970 {\bf All incoming wire transfer sender accounts matched up.} 971 {% else %} 972 \begin{longtable}{p{8.5cm}|r} 973 {\bf Reserve Public Key} & {\bf Amount} \\ 974 \hline \hline 975 \endfirsthead 976 {\bf Reserve Public Key} & {\bf Amount} \\ 977 \hline \hline 978 \endhead 979 \hline \hline 980 {\bf Reserve Public Key} & {\bf Amount} \\ 981 \endfoot 982 \hline 983 {\bf Total amount} & 984 {{ wire.total_misattribution_in}} \\ 985 \caption{Incoming wire transfer sender accounts not matching up.} 986 \label{table:wire_in:sender_account_inconsistencies} 987 \endlastfoot 988 {% for item in wire.misattribution_in_inconsistencies %} 989 {\tt \small \truncate{8.3cm}{ {{ item.reserve_pub }} } } & 990 {{ item.amount }} \\ \hline 991 {% endfor %} 992 \end{longtable} 993 {% endif %} 994 995 996 997 998 \subsection{Actual outgoing wire transfers} \label{sec:wire_check_out} 999 1000 This section highlights cases where the exchange misbehaved 1001 with respect to outgoing wire transfers. 1002 1003 % Table generation tested by testcase #11 in test-auditor.sh 1004 1005 {% if wire.wire_out_amount_inconsistencies|length() == 0 %} 1006 {\bf All outgoing wire transfers matched up.} 1007 {% else %} 1008 \begin{longtable}{p{5.5cm}|r|r} 1009 {\bf Wire transfer identifier} & {\bf Wired} & {\bf Justified} \\ 1010 {\bf Account} & {\bf Row} & {\bf Timestamp} \\ 1011 \hline \hline 1012 \endfirsthead 1013 {\bf Wire transfer identifier} & {\bf Wired} & {\bf Justified} \\ 1014 {\bf Account} & {\bf Row} & {\bf Timestamp} \\ 1015 \hline \hline 1016 \endhead 1017 \hline \hline 1018 {\bf Wire transfer identifier} & {\bf Wired} & {\bf Justified} \\ 1019 {\bf Account} & {\bf Row} & {\bf Timestamp} \\ 1020 \endfoot 1021 \hline 1022 {\bf Total deltas} & 1023 {{ wire.total_wire_out_delta_plus }} & 1024 - {{ wire.total_wire_out_delta_minus }} \\ 1025 \caption{Outgoing wire transfer amounts not matching up.} 1026 \label{table:wire_out:transfer_amount_inconsistencies} 1027 \endlastfoot 1028 {% for item in wire.wire_out_amount_inconsistencies %} 1029 {\tt \small \truncate{5.2cm}{ {{ item.wtid }} } } & 1030 {{ item.amount_wired }} & 1031 {{ item.amount_justified }} \\ 1032 \nopagebreak 1033 {{ item.account_section }} & 1034 {{ item.row }} & 1035 {\tiny {{ item.timestamp }} } \\ \hline 1036 {% endfor %} 1037 \end{longtable} 1038 {% endif %} 1039 1040 1041 \section{Minor irregularities} 1042 1043 \subsection{Denominations without auditor signature} 1044 1045 This section highlights denomination keys that lack a proper 1046 signature from the {\tt taler-auditor-offline} tool. This may be 1047 legitimate, say in case where the auditor's involvement in the 1048 exchange business is ending and a new auditor is responsible for 1049 future denominations. So this must be read with a keen eye on the 1050 business situation. 1051 1052 1053 {% if coins.unsigned_denominations|length() == 0 %} 1054 {\bf All denominations officially audited by this auditor.} 1055 {% else %} 1056 \begin{longtable}{p{6cm}|r|r|r} 1057 {\bf Denomination} & {\bf Value} & {\bf Start} & {\bf End} \\ \hline \hline 1058 \endfirsthead 1059 {\bf Denomination} & {\bf Value} & {\bf Start} & {\bf End} \\ \hline \hline 1060 \endhead 1061 \hline \hline 1062 {\bf Denomination} & {\bf Value} & {\bf Start} & {\bf End} \\ \hline \hline 1063 \endfoot 1064 \caption{Denominations not officially audited by this auditor.} 1065 \label{table:denominations:denoms_without_signatures} 1066 \endlastfoot 1067 {% for item in coins.unsigned_denominations %} 1068 {\tt \tiny {{ item.denomination }} } & 1069 {{ item.value }} & 1070 {{ item.start_time }} & 1071 {{ item.end_time }} \\ \hline 1072 {% endfor %} 1073 \end{longtable} 1074 {% endif %} 1075 1076 \subsection{Incorrect reserve balance summary in database} 1077 1078 This section highlights cases where the reserve balance summary 1079 in the database does not match the calculations made by the auditor. 1080 Deltas may indicate a corrupt database, but do not necessarily 1081 translate into a financial loss (yet). 1082 1083 % Table generation tested by testcase #3 in test-auditor.sh 1084 % Table generation tested by testcase #4 in test-revocation.sh 1085 1086 {% if reserves.reserve_balance_summary_wrong_inconsistencies|length() == 0 %} 1087 {\bf All balances matched up.} 1088 {% else %} 1089 \begin{longtable}{p{6cm}|r|r} 1090 {\bf Reserve} & {\bf Auditor} & {\bf Exchange} \\ \hline \hline 1091 \endfirsthead 1092 {\bf Reserve} & {\bf Auditor} & {\bf Exchange} \\ \hline \hline 1093 \endhead 1094 \hline \hline 1095 {\bf Reserve} & {\bf Auditor} & {\bf Exchange} 1096 \endfoot 1097 \hline 1098 \hline 1099 {\bf Total deltas} & 1100 {{ reserves.total_balance_summary_delta_plus}} & 1101 - {{ reserves.total_balance_summary_delta_minus}} \\ 1102 \caption{Reserves balances not matching up.} 1103 \label{table:reserve:balance_inconsistencies} 1104 \endlastfoot 1105 {% for item in reserves.reserve_balance_summary_wrong_inconsistencies %} 1106 {\tt \tiny {{ item.reserve_pub }} } & 1107 {{ item.auditor }} & 1108 {{ item.exchange }} \\ \hline 1109 {% endfor %} 1110 \end{longtable} 1111 {% endif %} 1112 1113 {% if reserves.reserve_balance_summary_wrong_inconsistencies|length() != 0 %} 1114 This means that there are inconsistencies in the exchange's 1115 summary data about reserve balances. 1116 \begin{itemize} 1117 \item The exchange believes some reserves contain (in total) 1118 {\bf {{ reserves.total_balance_summary_delta_plus}} } {\em less} than they 1119 actually contain. A non-zero value here means the exchange may deny legitimate withdrawal 1120 requests, denying customers access to their funds. 1121 \item The exchange believes some reserves contain (in total) 1122 {\bf {{ reserves.total_balance_summary_delta_minus}} } {\em more} than they 1123 actually contain. A non-zero value here means the exchange may allow coins to be withdrawn 1124 for which it never received any income, at a loss (for the exchange). 1125 \end{itemize} 1126 1127 {% if wire.reserve_in_amount_inconsistencies|length() != 0 %} 1128 Note that inconsistencies detected in Section~\ref{sec:wire_in} may 1129 have created follow-up errors in this table. 1130 {% endif %} 1131 1132 {% endif %} 1133 1134 1135 \subsection{Wire table issues} 1136 1137 This section describes issues found by the wire auditor that do not 1138 have a clear financial impact. 1139 1140 % Table generation tested by testcase #17 in test-auditor.sh 1141 1142 {% if wire.row_inconsistencies|length() == 0 %} 1143 {\bf No wire row inconsistencies found.} 1144 {% else %} 1145 \begin{longtable}{p{5.5cm}|l|p{4.5cm}} 1146 {\bf Table} & {\bf Row} & {\bf Diagnostic} \\ 1147 \hline \hline 1148 \endfirsthead 1149 {\bf Table} & {\bf Row} & {\bf Diagnostic} \\ 1150 \hline \hline 1151 \endhead 1152 \hline 1153 {\bf Table} & {\bf Row} & {\bf Diagnostic} \\ 1154 \endfoot 1155 \hline 1156 {\bf Table} & {\bf Row} & {\bf Diagnostic} \\ 1157 \caption{Other wire table issues found (by table and row).} 1158 \label{table:wire:misc} 1159 \endlastfoot 1160 {% for item in wire.row_inconsistencies %} 1161 \verb! {{ item.table }} ! & 1162 {{ item.row }} & 1163 {{ item.diagnostic }} \\ 1164 \nopagebreak 1165 \multicolumn{3}{l}{ {\tiny {\tt \truncate{\textwidth}{ {{ item.id }} } } } } \\ \hline 1166 {% endfor %} 1167 \end{longtable} 1168 {% endif %} 1169 1170 1171 \subsection{Outgoing wire transfer subject issues} 1172 1173 This section describes issues found by the wire auditor that 1174 relate to outgoing wire transfers subjects being duplicated. 1175 1176 % Table generation tested by testcase #27 in test-auditor.sh 1177 1178 {% if wire.wire_format_inconsistencies|length() == 0 %} 1179 {\bf No wire format inconsistencies found.} 1180 {% else %} 1181 \begin{longtable}{p{6.5cm}|r} 1182 \multicolumn{2}{c}{ {\bf Diagnostic} } \\ 1183 {\bf Row (base32)} & {\bf Amount} \\ 1184 \hline \hline 1185 \endfirsthead 1186 \multicolumn{2}{c}{ {\bf Diagnostic} } \\ 1187 {\bf Row (base32)} & {\bf Amount} \\ 1188 \hline \hline 1189 \endhead 1190 \hline 1191 \multicolumn{2}{c}{ {\bf Diagnostic} } \\ 1192 {\bf Row (base32)} & {\bf Amount} \\ 1193 \endfoot 1194 \hline 1195 \hline 1196 {\bf Total} & 1197 {{ wire.total_wire_format_amount }} \\ 1198 \caption{Outgoing wire transfer subject issues found.} 1199 \label{table:outgoing:wtid} 1200 \endlastfoot 1201 {% for item in wire.wire_format_inconsistencies %} 1202 \multicolumn{2}{l}{ \small \truncate{0.95\textwidth}{ {{ item.diagnostic }} } } \\ 1203 \nopagebreak 1204 { \tt \small \truncate{0.95\textwidth}{ {{ item.wire_offset }} } } & {{ item.amount }} \\ \hline 1205 {% endfor %} 1206 \end{longtable} 1207 {% endif %} 1208 1209 1210 \subsection{Wire fee structure inconsistencies} 1211 1212 This section lists cases where the exchange's database may be ambiguous 1213 with respect to what wire fee it charges at what time. 1214 1215 % Table generation tested by testcase #14 in test-auditor.sh 1216 1217 {% if aggregation.wire_fee_time_inconsistencies|length() == 0 %} 1218 {\bf No wire fee timing issues detected.} 1219 {% else %} 1220 \begin{longtable}{p{1.5cm}|r|p{6}} 1221 {\bf Wire format} & {\bf Timestamp} & {\bf Diagnostic} 1222 \\ \hline \hline 1223 \endfirsthead 1224 {\bf Wire format} & {\bf Timestamp} & {\bf Diagnostic} 1225 \\ \hline \hline 1226 \endhead 1227 \hline \hline 1228 {\bf Wire format} & {\bf Timestamp} & {\bf Diagnostic} \\ 1229 \endfoot 1230 \hline \hline 1231 {\bf Wire format} & {\bf Timestamp} & {\bf Diagnostic} \\ 1232 \caption{Wire fees with ambiguous timestamps.} 1233 \label{table:wire_fee:ambiguity} 1234 \endlastfoot 1235 {% for item in aggregation.wire_fee_time_inconsistencies %} 1236 {\tt {{ item.type }} } & {{ item.time }} & {{ item.diagnostic }} \\ \hline 1237 {% endfor %} 1238 \end{longtable} 1239 {% endif %} 1240 1241 1242 1243 \subsection{Other issues} 1244 1245 This section describes issues found that do not have a clear financial 1246 impact. 1247 1248 \subsubsection{For aggregation} 1249 1250 % Table generation tested by testcase #15/#25 in test-auditor.sh 1251 1252 {% if aggregation.row_inconsistencies|length() == 0 %} 1253 {\bf No row inconsistencies found.} 1254 {% else %} 1255 \begin{longtable}{p{2.5cm}|l|p{5cm}} 1256 {\bf Table} & {\bf Row} & {\bf Diagnostic} \\ 1257 \hline \hline 1258 \endfirsthead 1259 {\bf Table} & {\bf Row} & {\bf Diagnostic} \\ 1260 \hline \hline 1261 \endhead 1262 \hline \hline 1263 {\bf Table} & {\bf Row} & {\bf Diagnostic} \\ 1264 \endfoot 1265 \hline \hline 1266 {\bf Table} & {\bf Row} & {\bf Diagnostic} \\ 1267 \caption{Other issues found (by table and row).} 1268 \label{table:misc:aggregation} 1269 \endlastfoot 1270 {% for item in aggregation.row_inconsistencies %} 1271 \verb! {{ item.table }} ! & 1272 {{ item.row }} & 1273 {{ item.diagnostic }} \\ \hline 1274 {% endfor %} 1275 \end{longtable} 1276 {% endif %} 1277 1278 \subsubsection{For coins} 1279 1280 % Table generation tested by testcase #13 in test-auditor.sh 1281 1282 {% if coins.row_inconsistencies|length() == 0 %} 1283 {\bf No row inconsistencies found.} 1284 {% else %} 1285 \begin{longtable}{p{2.5cm}|l|p{5cm}} 1286 {\bf Table} & {\bf Row} & {\bf Diagnostic} \\ 1287 \hline \hline 1288 \endfirsthead 1289 {\bf Table} & {\bf Row} & {\bf Diagnostic} \\ 1290 \hline \hline 1291 \endhead 1292 \hline \hline 1293 {\bf Table} & {\bf Row} & {\bf Diagnostic} \\ 1294 \endfoot 1295 \hline \hline 1296 {\bf Table} & {\bf Row} & {\bf Diagnostic} \\ 1297 \caption{Other issues found (by table and row).} 1298 \label{table:misc:coins} 1299 \endlastfoot 1300 {% for item in coins.row_inconsistencies %} 1301 \verb! {{ item.table }} ! & 1302 {{ item.row }} & 1303 {{ item.diagnostic }} \\ \hline 1304 {% endfor %} 1305 \end{longtable} 1306 {% endif %} 1307 1308 \subsubsection{For reserves} 1309 1310 % Table generation tested by testcase #4 in test-revocation.sh 1311 1312 {% if reserves.row_inconsistencies|length() == 0 %} 1313 {\bf No row inconsistencies found.} 1314 {% else %} 1315 \begin{longtable}{p{2.5cm}|l|p{5cm}} 1316 {\bf Table} & {\bf Row} & {\bf Diagnostic} \\ 1317 \hline \hline 1318 \endfirsthead 1319 {\bf Table} & {\bf Row} & {\bf Diagnostic} \\ 1320 \hline \hline 1321 \endhead 1322 \hline \hline 1323 {\bf Table} & {\bf Row} & {\bf Diagnostic} \\ 1324 \endfoot 1325 \hline \hline 1326 {\bf Table} & {\bf Row} & {\bf Diagnostic} \\ 1327 \caption{Other issues found (by table and row).} 1328 \label{table:misc:reserves} 1329 \endlastfoot 1330 {% for item in reserves.row_inconsistencies %} 1331 \verb! {{ item.table }} ! & 1332 {{ item.row }} & 1333 {{ item.diagnostic }} \\ \hline 1334 {% endfor %} 1335 \end{longtable} 1336 {% endif %} 1337 1338 1339 \section{Delays and timing} 1340 1341 This section describes issues that are likely caused simply by 1342 some job process of the exchange not running properly or not having 1343 caught up with the work load yet. 1344 1345 \subsection{Delayed closure of reserves} 1346 1347 This section describes cases where the exchange did not 1348 close a reserve and wire back the remaining funds when the 1349 reserve expired. 1350 1351 % Table generation tested by testcase #20 in test-auditor.sh 1352 1353 {% if reserves.reserve_not_closed_inconsistencies|length() == 0 %} 1354 {\bf All expired reserves were closed.} 1355 {% else %} 1356 \begin{longtable}{p{4.5cm}|c|r} 1357 {\bf Reserve} & {\bf Expired} & {\bf Balance} \\ \hline \hline 1358 \endfirsthead 1359 {\bf Reserve} & {\bf Expired} & {\bf Balance} \\ \hline \hline 1360 \endhead 1361 \hline \hline 1362 {\bf Reserve} & {\bf Expired} & {\bf Balance} 1363 \endfoot 1364 \hline 1365 {\bf Sum} & & 1366 {{ reserves.total_balance_reserve_not_closed}} \\ 1367 \caption{Reserves not closed on time.} 1368 \label{table:reserve:not_closed} 1369 \endlastfoot 1370 {% for item in reserves.reserve_not_closed_inconsistencies %} 1371 {\tt \tiny \truncate{4.3cm}{ {{ item.reserve_pub }} } } & 1372 {\tiny {{ item.expiration_time }} } & 1373 {{ item.balance }} \\ \hline 1374 {% endfor %} 1375 \end{longtable} 1376 {% endif %} 1377 1378 1379 \subsection{Hanging refresh operations} 1380 1381 This section describes cases where the exchange booked a 1382 coin as spent from {\tt /refresh/melt} but where the 1383 wallet did not yet complete {\tt /refresh/reveal}. This 1384 may happen even if the exchange is correct. 1385 1386 % Table generation tested by testcase #12 in test-auditor.sh 1387 1388 {% if coins.refresh_hanging|length() == 0 %} 1389 {\bf All melted coins were refreshed.} 1390 {% else %} 1391 \begin{longtable}{p{6.5cm}|c|r} 1392 {\bf Key} & {\bf row} & {\bf Amount} \\ 1393 \hline \hline 1394 \endfirsthead 1395 {\bf Key} & {\bf row} & {\bf Amount} \\ 1396 \hline \hline 1397 \endhead 1398 \hline \hline 1399 {\bf Key} & {\bf row} & {\bf Amount} \\ 1400 \endfoot 1401 \hline 1402 {\bf Sum} & & 1403 {{ coins.total_refresh_hanging}} \\ 1404 \caption{Refresh operations hanging.} 1405 \label{table:refresh:hanging} 1406 \endlastfoot 1407 {% for item in coins.refresh_hanging %} 1408 \truncate{6.2cm}{ {\tt \small {{ item.coin_pub }} } } & 1409 {{ item.row }} & 1410 {{ item.amount }} \\ \hline 1411 {% endfor %} 1412 \end{longtable} 1413 {% endif %} 1414 1415 1416 \subsection{Denomination key invalid at time of withdrawal} 1417 1418 This section lists cases where a denomination key was not valid for 1419 withdrawal at the time when the exchange claims to have signed a coin 1420 with it. This would be irregular, but has no obvious financial 1421 implications. 1422 1423 % Table generation tested by testcase #22 in test-auditor.sh 1424 1425 {% if reserves.denomination_key_validity_withdraw_inconsistencies|length() == 0 %} 1426 {\bf All denomination keys were valid at the time of withdrawals.} 1427 {% else %} 1428 \begin{longtable}{p{7.5cm}|r} 1429 {\bf Reserve} & {\bf Table row} \\ 1430 {\bf Denomination key hash} & {\bf Execution time} \\ \hline \hline 1431 \endfirsthead 1432 {\bf Reserve} & {\bf Table row} \\ 1433 {\bf Denomination key hash} & {\bf Execution time} \\ \hline \hline 1434 \endhead 1435 \hline \hline 1436 {\bf Reserve} & {\bf Table row} \\ 1437 {\bf Denomination key hash} & {\bf Execution time} \\ 1438 \endfoot 1439 \hline 1440 {\bf Reserve} & {\bf Table row} \\ 1441 {\bf Denomination key hash} & {\bf Execution time} \\ 1442 \caption{Execution times not matching denomination key validity period.} 1443 \label{table:withdraw:bad_time} 1444 \endlastfoot 1445 {% for item in reserves.denomination_key_validity_withdraw_inconsistencies %} 1446 {\tt \small \truncate{0.6\textwidth}{ {{ item.reserve_pub }} } } & {{ item.row }} \\ 1447 \nopagebreak 1448 {\tt \small \truncate{0.6\textwidth}{ {{ item.denompub_h }} } } & {{ item.execution_date }} \\ \hline 1449 {% endfor %} 1450 \end{longtable} 1451 {% endif %} 1452 1453 1454 \subsection{Wire transfer timestamp issues} 1455 1456 This section lists issues with wire transfers related to timestamps. 1457 1458 % Table generation tested by testcase #10/#17 in test-auditor.sh 1459 1460 {% if wire.row_minor_inconsistencies|length() == 0 %} 1461 {\bf No timestamp issues detected.} 1462 {% else %} 1463 \begin{longtable}{p{3cm}|r|p{5cm}} 1464 {\bf Table} & {\bf Row} & {\bf Diagnostic} 1465 \\ \hline \hline 1466 \endfirsthead 1467 {\bf Table} & {\bf Row} & {\bf Diagnostic} 1468 \\ \hline \hline 1469 \endhead 1470 \hline \hline 1471 {\bf Table} & {\bf Row} & {\bf Diagnostic} \\ 1472 \endfoot 1473 \hline \hline 1474 {\bf Table} & {\bf Row} & {\bf Diagnostic} \\ 1475 \caption{Execution times not matching in wire transfers.} 1476 \label{table:wire:bad_time} 1477 \endlastfoot 1478 {% for item in wire.row_minor_inconsistencies %} 1479 \verb! {{ item.table }} ! & {{ item.row }} & {{ item.diagnostic }} \\ \hline 1480 {% endfor %} 1481 \end{longtable} 1482 {% endif %} 1483 1484 1485 \end{document}