LCOV - code coverage report
Current view: top level - auditor - taler-helper-auditor-coins.c (source / functions) Hit Total Coverage
Test: GNU Taler exchange coverage report Lines: 496 686 72.3 %
Date: 2021-08-30 06:43:37 Functions: 23 24 95.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2016-2021 Taler Systems SA
       4             : 
       5             :   TALER is free software; you can redistribute it and/or modify it under the
       6             :   terms of the GNU Affero Public License as published by the Free Software
       7             :   Foundation; either version 3, or (at your option) any later version.
       8             : 
       9             :   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
      10             :   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
      11             :   A PARTICULAR PURPOSE.  See the GNU Affero Public License for more details.
      12             : 
      13             :   You should have received a copy of the GNU Affero Public License along with
      14             :   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
      15             : */
      16             : /**
      17             :  * @file auditor/taler-helper-auditor-coins.c
      18             :  * @brief audits coins in an exchange database.
      19             :  * @author Christian Grothoff
      20             :  *
      21             :  * UNDECIDED:
      22             :  * - do we care about checking the 'done' flag in deposit_cb?
      23             :  */
      24             : #include "platform.h"
      25             : #include <gnunet/gnunet_util_lib.h>
      26             : #include "taler_auditordb_plugin.h"
      27             : #include "taler_exchangedb_lib.h"
      28             : #include "taler_json_lib.h"
      29             : #include "taler_bank_service.h"
      30             : #include "taler_signatures.h"
      31             : #include "report-lib.h"
      32             : 
      33             : /**
      34             :  * How many coin histories do we keep in RAM at any given point in time?
      35             :  * Expect a few kB per coin history to be used. Used bound memory consumption
      36             :  * of the auditor. Larger values reduce database accesses.
      37             :  */
      38             : #define MAX_COIN_HISTORIES (16 * 1024 * 1024)
      39             : 
      40             : /**
      41             :  * Use a 1 day grace period to deal with clocks not being perfectly synchronized.
      42             :  */
      43             : #define DEPOSIT_GRACE_PERIOD GNUNET_TIME_UNIT_DAYS
      44             : 
      45             : /**
      46             :  * Return value from main().
      47             :  */
      48             : static int global_ret;
      49             : 
      50             : /**
      51             :  * Checkpointing our progress for coins.
      52             :  */
      53             : static struct TALER_AUDITORDB_ProgressPointCoin ppc;
      54             : 
      55             : /**
      56             :  * Checkpointing our progress for coins.
      57             :  */
      58             : static struct TALER_AUDITORDB_ProgressPointCoin ppc_start;
      59             : 
      60             : /**
      61             :  * Array of reports about denomination keys with an
      62             :  * emergency (more value deposited than withdrawn)
      63             :  */
      64             : static json_t *report_emergencies;
      65             : 
      66             : /**
      67             :  * Array of reports about denomination keys with an
      68             :  * emergency (more coins deposited than withdrawn)
      69             :  */
      70             : static json_t *report_emergencies_by_count;
      71             : 
      72             : /**
      73             :  * Array of reports about row inconsitencies.
      74             :  */
      75             : static json_t *report_row_inconsistencies;
      76             : 
      77             : /**
      78             :  * Array of reports about denominations not counter-signed by the auditor.
      79             :  */
      80             : static json_t *report_denominations_without_sigs;
      81             : 
      82             : /**
      83             :  * Report about amount calculation differences (causing profit
      84             :  * or loss at the exchange).
      85             :  */
      86             : static json_t *report_amount_arithmetic_inconsistencies;
      87             : 
      88             : /**
      89             :  * Profits the exchange made by bad amount calculations.
      90             :  */
      91             : static struct TALER_Amount total_arithmetic_delta_plus;
      92             : 
      93             : /**
      94             :  * Losses the exchange made by bad amount calculations.
      95             :  */
      96             : static struct TALER_Amount total_arithmetic_delta_minus;
      97             : 
      98             : /**
      99             :  * Total amount reported in all calls to #report_emergency_by_count().
     100             :  */
     101             : static struct TALER_Amount reported_emergency_risk_by_count;
     102             : 
     103             : /**
     104             :  * Total amount reported in all calls to #report_emergency_by_amount().
     105             :  */
     106             : static struct TALER_Amount reported_emergency_risk_by_amount;
     107             : 
     108             : /**
     109             :  * Total amount in losses reported in all calls to #report_emergency_by_amount().
     110             :  */
     111             : static struct TALER_Amount reported_emergency_loss;
     112             : 
     113             : /**
     114             :  * Total amount in losses reported in all calls to #report_emergency_by_count().
     115             :  */
     116             : static struct TALER_Amount reported_emergency_loss_by_count;
     117             : 
     118             : /**
     119             :  * Expected balance in the escrow account.
     120             :  */
     121             : static struct TALER_Amount total_escrow_balance;
     122             : 
     123             : /**
     124             :  * Active risk exposure.
     125             :  */
     126             : static struct TALER_Amount total_risk;
     127             : 
     128             : /**
     129             :  * Actualized risk (= loss) from recoups.
     130             :  */
     131             : static struct TALER_Amount total_recoup_loss;
     132             : 
     133             : /**
     134             :  * Recoups we made on denominations that were not revoked (!?).
     135             :  */
     136             : static struct TALER_Amount total_irregular_recoups;
     137             : 
     138             : /**
     139             :  * Total deposit fees earned.
     140             :  */
     141             : static struct TALER_Amount total_deposit_fee_income;
     142             : 
     143             : /**
     144             :  * Total melt fees earned.
     145             :  */
     146             : static struct TALER_Amount total_melt_fee_income;
     147             : 
     148             : /**
     149             :  * Total refund fees earned.
     150             :  */
     151             : static struct TALER_Amount total_refund_fee_income;
     152             : 
     153             : /**
     154             :  * Array of reports about coin operations with bad signatures.
     155             :  */
     156             : static json_t *report_bad_sig_losses;
     157             : 
     158             : /**
     159             :  * Total amount lost by operations for which signatures were invalid.
     160             :  */
     161             : static struct TALER_Amount total_bad_sig_loss;
     162             : 
     163             : /**
     164             :  * Array of refresh transactions where the /refresh/reveal has not yet
     165             :  * happened (and may of course never happen).
     166             :  */
     167             : static json_t *report_refreshs_hanging;
     168             : 
     169             : /**
     170             :  * Total amount lost by operations for which signatures were invalid.
     171             :  */
     172             : static struct TALER_Amount total_refresh_hanging;
     173             : 
     174             : /**
     175             :  * Coin and associated transaction history.
     176             :  */
     177             : struct CoinHistory
     178             : {
     179             :   /**
     180             :    * Public key of the coin.
     181             :    */
     182             :   struct TALER_CoinSpendPublicKeyP coin_pub;
     183             : 
     184             :   /**
     185             :    * The transaction list for the @a coin_pub.
     186             :    */
     187             :   struct TALER_EXCHANGEDB_TransactionList *tl;
     188             : };
     189             : 
     190             : /**
     191             :  * Array of transaction histories for coins.  The index is based on the coin's
     192             :  * public key.  Entries are replaced whenever we have a collision.
     193             :  */
     194             : static struct CoinHistory coin_histories[MAX_COIN_HISTORIES];
     195             : 
     196             : /**
     197             :  * Should we run checks that only work for exchange-internal audits?
     198             :  */
     199             : static int internal_checks;
     200             : 
     201             : 
     202             : /**
     203             :  * Return the index we should use for @a coin_pub in #coin_histories.
     204             :  *
     205             :  * @param coin_pub a coin's public key
     206             :  * @return index for caching this coin's history in #coin_histories
     207             :  */
     208             : static unsigned int
     209         499 : coin_history_index (const struct TALER_CoinSpendPublicKeyP *coin_pub)
     210             : {
     211             :   uint32_t i;
     212             : 
     213         499 :   memcpy (&i,
     214             :           coin_pub,
     215             :           sizeof (i));
     216         499 :   return i % MAX_COIN_HISTORIES;
     217             : }
     218             : 
     219             : 
     220             : /**
     221             :  * Add a coin history to our in-memory cache.
     222             :  *
     223             :  * @param coin_pub public key of the coin to cache
     224             :  * @param tl history to store
     225             :  */
     226             : static void
     227         177 : cache_history (const struct TALER_CoinSpendPublicKeyP *coin_pub,
     228             :                struct TALER_EXCHANGEDB_TransactionList *tl)
     229             : {
     230         177 :   unsigned int i = coin_history_index (coin_pub);
     231             : 
     232         177 :   if (NULL != coin_histories[i].tl)
     233           0 :     TALER_ARL_edb->free_coin_transaction_list (TALER_ARL_edb->cls,
     234             :                                                coin_histories[i].tl);
     235         177 :   coin_histories[i].coin_pub = *coin_pub;
     236         177 :   coin_histories[i].tl = tl;
     237         177 : }
     238             : 
     239             : 
     240             : /**
     241             :  * Obtain a coin's history from our in-memory cache.
     242             :  *
     243             :  * @param coin_pub public key of the coin to cache
     244             :  * @return NULL if @a coin_pub is not in the cache
     245             :  */
     246             : static struct TALER_EXCHANGEDB_TransactionList *
     247         322 : get_cached_history (const struct TALER_CoinSpendPublicKeyP *coin_pub)
     248             : {
     249         322 :   unsigned int i = coin_history_index (coin_pub);
     250             : 
     251         322 :   if (0 == GNUNET_memcmp (coin_pub,
     252             :                           &coin_histories[i].coin_pub))
     253             :   {
     254         145 :     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     255             :                 "Found verification of %s in cache\n",
     256             :                 TALER_B2S (coin_pub));
     257         145 :     return coin_histories[i].tl;
     258             :   }
     259         177 :   return NULL;
     260             : }
     261             : 
     262             : 
     263             : /* ***************************** Report logic **************************** */
     264             : 
     265             : /**
     266             :  * Called in case we detect an emergency situation where the exchange
     267             :  * is paying out a larger amount on a denomination than we issued in
     268             :  * that denomination.  This means that the exchange's private keys
     269             :  * might have gotten compromised, and that we need to trigger an
     270             :  * emergency request to all wallets to deposit pending coins for the
     271             :  * denomination (and as an exchange suffer a huge financial loss).
     272             :  *
     273             :  * @param issue denomination key where the loss was detected
     274             :  * @param risk maximum risk that might have just become real (coins created by this @a issue)
     275             :  * @param loss actual losses already (actualized before denomination was revoked)
     276             :  */
     277             : static void
     278           3 : report_emergency_by_amount (
     279             :   const struct TALER_DenominationKeyValidityPS *issue,
     280             :   const struct TALER_Amount *risk,
     281             :   const struct TALER_Amount *loss)
     282             : {
     283           3 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     284             :               "Reporting emergency on denomination `%s' over loss of %s\n",
     285             :               GNUNET_h2s (&issue->denom_hash),
     286             :               TALER_amount2s (loss));
     287           3 :   TALER_ARL_report (report_emergencies,
     288           3 :                     GNUNET_JSON_PACK (
     289             :                       GNUNET_JSON_pack_data_auto ("denompub_hash",
     290             :                                                   &issue->denom_hash),
     291             :                       TALER_JSON_pack_amount ("denom_risk",
     292             :                                               risk),
     293             :                       TALER_JSON_pack_amount ("denom_loss",
     294             :                                               loss),
     295             :                       TALER_JSON_pack_time_abs_nbo_human ("start",
     296             :                                                           issue->start),
     297             :                       TALER_JSON_pack_time_abs_nbo_human ("deposit_end",
     298             :                                                           issue->expire_deposit),
     299             :                       TALER_JSON_pack_amount_nbo ("value",
     300             :                                                   &issue->value)));
     301           3 :   TALER_ARL_amount_add (&reported_emergency_risk_by_amount,
     302             :                         &reported_emergency_risk_by_amount,
     303             :                         risk);
     304           3 :   TALER_ARL_amount_add (&reported_emergency_loss,
     305             :                         &reported_emergency_loss,
     306             :                         loss);
     307           3 : }
     308             : 
     309             : 
     310             : /**
     311             :  * Called in case we detect an emergency situation where the exchange
     312             :  * is paying out a larger NUMBER of coins of a denomination than we
     313             :  * issued in that denomination.  This means that the exchange's
     314             :  * private keys might have gotten compromised, and that we need to
     315             :  * trigger an emergency request to all wallets to deposit pending
     316             :  * coins for the denomination (and as an exchange suffer a huge
     317             :  * financial loss).
     318             :  *
     319             :  * @param issue denomination key where the loss was detected
     320             :  * @param num_issued number of coins that were issued
     321             :  * @param num_known number of coins that have been deposited
     322             :  * @param risk amount that is at risk
     323             :  */
     324             : static void
     325           2 : report_emergency_by_count (
     326             :   const struct TALER_DenominationKeyValidityPS *issue,
     327             :   uint64_t num_issued,
     328             :   uint64_t num_known,
     329             :   const struct TALER_Amount *risk)
     330             : {
     331             :   struct TALER_Amount denom_value;
     332             : 
     333           2 :   TALER_ARL_report (report_emergencies_by_count,
     334           2 :                     GNUNET_JSON_PACK (
     335             :                       GNUNET_JSON_pack_data_auto ("denompub_hash",
     336             :                                                   &issue->denom_hash),
     337             :                       GNUNET_JSON_pack_uint64 ("num_issued",
     338             :                                                num_issued),
     339             :                       GNUNET_JSON_pack_uint64 ("num_known",
     340             :                                                num_known),
     341             :                       TALER_JSON_pack_amount ("denom_risk",
     342             :                                               risk),
     343             :                       TALER_JSON_pack_time_abs_nbo_human ("start",
     344             :                                                           issue->start),
     345             :                       TALER_JSON_pack_time_abs_nbo_human ("deposit_end",
     346             :                                                           issue->expire_deposit),
     347             :                       TALER_JSON_pack_amount_nbo ("value",
     348             :                                                   &issue->value)));
     349           2 :   TALER_ARL_amount_add (&reported_emergency_risk_by_count,
     350             :                         &reported_emergency_risk_by_count,
     351             :                         risk);
     352           2 :   TALER_amount_ntoh (&denom_value,
     353             :                      &issue->value);
     354           4 :   for (uint64_t i = num_issued; i<num_known; i++)
     355           2 :     TALER_ARL_amount_add (&reported_emergency_loss_by_count,
     356             :                           &reported_emergency_loss_by_count,
     357             :                           &denom_value);
     358             : 
     359           2 : }
     360             : 
     361             : 
     362             : /**
     363             :  * Report a (serious) inconsistency in the exchange's database with
     364             :  * respect to calculations involving amounts.
     365             :  *
     366             :  * @param operation what operation had the inconsistency
     367             :  * @param rowid affected row, 0 if row is missing
     368             :  * @param exchange amount calculated by exchange
     369             :  * @param auditor amount calculated by auditor
     370             :  * @param profitable 1 if @a exchange being larger than @a auditor is
     371             :  *           profitable for the exchange for this operation
     372             :  *           (and thus @a exchange being smaller than @ auditor
     373             :  *            representing a loss for the exchange);
     374             :  *           -1 if @a exchange being smaller than @a auditor is
     375             :  *           profitable for the exchange; and 0 if it is unclear
     376             :  */
     377             : static void
     378          13 : report_amount_arithmetic_inconsistency (
     379             :   const char *operation,
     380             :   uint64_t rowid,
     381             :   const struct TALER_Amount *exchange,
     382             :   const struct TALER_Amount *auditor,
     383             :   int profitable)
     384             : {
     385             :   struct TALER_Amount delta;
     386             :   struct TALER_Amount *target;
     387             : 
     388          13 :   if (0 < TALER_amount_cmp (exchange,
     389             :                             auditor))
     390             :   {
     391             :     /* exchange > auditor */
     392           3 :     TALER_ARL_amount_subtract (&delta,
     393             :                                exchange,
     394             :                                auditor);
     395             :   }
     396             :   else
     397             :   {
     398             :     /* auditor < exchange */
     399          10 :     profitable = -profitable;
     400          10 :     TALER_ARL_amount_subtract (&delta,
     401             :                                auditor,
     402             :                                exchange);
     403             :   }
     404          13 :   TALER_ARL_report (report_amount_arithmetic_inconsistencies,
     405          13 :                     GNUNET_JSON_PACK (
     406             :                       GNUNET_JSON_pack_string ("operation",
     407             :                                                operation),
     408             :                       GNUNET_JSON_pack_uint64 ("rowid",
     409             :                                                rowid),
     410             :                       TALER_JSON_pack_amount ("exchange",
     411             :                                               exchange),
     412             :                       TALER_JSON_pack_amount ("auditor",
     413             :                                               auditor),
     414             :                       GNUNET_JSON_pack_int64 ("profitable",
     415             :                                               profitable)));
     416          13 :   if (0 != profitable)
     417             :   {
     418          11 :     target = (1 == profitable)
     419             :              ? &total_arithmetic_delta_plus
     420          11 :              : &total_arithmetic_delta_minus;
     421          11 :     TALER_ARL_amount_add (target,
     422             :                           target,
     423             :                           &delta);
     424             :   }
     425          13 : }
     426             : 
     427             : 
     428             : /**
     429             :  * Report a (serious) inconsistency in the exchange's database.
     430             :  *
     431             :  * @param table affected table
     432             :  * @param rowid affected row, 0 if row is missing
     433             :  * @param diagnostic message explaining the problem
     434             :  */
     435             : static void
     436           0 : report_row_inconsistency (const char *table,
     437             :                           uint64_t rowid,
     438             :                           const char *diagnostic)
     439             : {
     440           0 :   TALER_ARL_report (report_row_inconsistencies,
     441           0 :                     GNUNET_JSON_PACK (
     442             :                       GNUNET_JSON_pack_string ("table",
     443             :                                                table),
     444             :                       GNUNET_JSON_pack_uint64 ("row",
     445             :                                                rowid),
     446             :                       GNUNET_JSON_pack_string ("diagnostic",
     447             :                                                diagnostic)));
     448           0 : }
     449             : 
     450             : 
     451             : /* ************* Analyze history of a coin ******************** */
     452             : 
     453             : 
     454             : /**
     455             :  * Obtain @a coin_pub's history, verify it, report inconsistencies
     456             :  * and store the result in our cache.
     457             :  *
     458             :  * @param coin_pub public key of the coin to check the history of
     459             :  * @param rowid a row identifying the transaction
     460             :  * @param operation operation matching @a rowid
     461             :  * @param value value of the respective coin's denomination
     462             :  * @return database status code, negative on failures
     463             :  */
     464             : static enum GNUNET_DB_QueryStatus
     465         177 : check_coin_history (const struct TALER_CoinSpendPublicKeyP *coin_pub,
     466             :                     uint64_t rowid,
     467             :                     const char *operation,
     468             :                     const struct TALER_Amount *value)
     469             : {
     470             :   struct TALER_EXCHANGEDB_TransactionList *tl;
     471             :   enum GNUNET_DB_QueryStatus qs;
     472             :   struct TALER_Amount total;
     473             :   struct TALER_Amount spent;
     474             :   struct TALER_Amount refunded;
     475             :   struct TALER_Amount deposit_fee;
     476             :   int have_refund;
     477             : 
     478         177 :   qs = TALER_ARL_edb->get_coin_transactions (TALER_ARL_edb->cls,
     479             :                                              coin_pub,
     480             :                                              GNUNET_YES,
     481             :                                              &tl);
     482         177 :   if (0 >= qs)
     483           0 :     return qs;
     484             : 
     485         177 :   GNUNET_assert (GNUNET_OK ==
     486             :                  TALER_amount_set_zero (value->currency,
     487             :                                         &refunded));
     488         177 :   GNUNET_assert (GNUNET_OK ==
     489             :                  TALER_amount_set_zero (value->currency,
     490             :                                         &spent));
     491         177 :   GNUNET_assert (GNUNET_OK ==
     492             :                  TALER_amount_set_zero (value->currency,
     493             :                                         &deposit_fee));
     494         177 :   have_refund = GNUNET_NO;
     495         573 :   for (struct TALER_EXCHANGEDB_TransactionList *pos = tl;
     496             :        NULL != pos;
     497         396 :        pos = pos->next)
     498             :   {
     499         396 :     switch (pos->type)
     500             :     {
     501         124 :     case TALER_EXCHANGEDB_TT_DEPOSIT:
     502             :       /* spent += pos->amount_with_fee */
     503         124 :       TALER_ARL_amount_add (&spent,
     504             :                             &spent,
     505             :                             &pos->details.deposit->amount_with_fee);
     506         124 :       deposit_fee = pos->details.deposit->deposit_fee;
     507         124 :       break;
     508         151 :     case TALER_EXCHANGEDB_TT_MELT:
     509             :       /* spent += pos->amount_with_fee */
     510         151 :       TALER_ARL_amount_add (&spent,
     511             :                             &spent,
     512             :                             &pos->details.melt->amount_with_fee);
     513         151 :       break;
     514          34 :     case TALER_EXCHANGEDB_TT_REFUND:
     515             :       /* refunded += pos->refund_amount - pos->refund_fee */
     516          34 :       TALER_ARL_amount_add (&refunded,
     517             :                             &refunded,
     518             :                             &pos->details.refund->refund_amount);
     519          34 :       TALER_ARL_amount_add (&spent,
     520             :                             &spent,
     521             :                             &pos->details.refund->refund_fee);
     522          34 :       have_refund = GNUNET_YES;
     523          34 :       break;
     524          40 :     case TALER_EXCHANGEDB_TT_OLD_COIN_RECOUP:
     525             :       /* refunded += pos->value */
     526          40 :       TALER_ARL_amount_add (&refunded,
     527             :                             &refunded,
     528             :                             &pos->details.old_coin_recoup->value);
     529          40 :       break;
     530           7 :     case TALER_EXCHANGEDB_TT_RECOUP:
     531             :       /* spent += pos->value */
     532           7 :       TALER_ARL_amount_add (&spent,
     533             :                             &spent,
     534             :                             &pos->details.recoup->value);
     535           7 :       break;
     536          40 :     case TALER_EXCHANGEDB_TT_RECOUP_REFRESH:
     537             :       /* spent += pos->value */
     538          40 :       TALER_ARL_amount_add (&spent,
     539             :                             &spent,
     540             :                             &pos->details.recoup_refresh->value);
     541          40 :       break;
     542             :     }
     543         396 :   }
     544             : 
     545         177 :   if (have_refund)
     546             :   {
     547             :     /* If we gave any refund, also discount ONE deposit fee */
     548          34 :     TALER_ARL_amount_add (&refunded,
     549             :                           &refunded,
     550             :                           &deposit_fee);
     551             :   }
     552             :   /* total coin value = original value plus refunds */
     553         177 :   TALER_ARL_amount_add (&total,
     554             :                         &refunded,
     555             :                         value);
     556         177 :   if (1 ==
     557         177 :       TALER_amount_cmp (&spent,
     558             :                         &total))
     559             :   {
     560             :     /* spent > total: bad */
     561             :     struct TALER_Amount loss;
     562             : 
     563           3 :     TALER_ARL_amount_subtract (&loss,
     564             :                                &spent,
     565             :                                &total);
     566           3 :     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     567             :                 "Loss detected for coin %s - %s\n",
     568             :                 TALER_B2S (coin_pub),
     569             :                 TALER_amount2s (&loss));
     570           3 :     report_amount_arithmetic_inconsistency (operation,
     571             :                                             rowid,
     572             :                                             &spent,
     573             :                                             &total,
     574             :                                             -1);
     575             :   }
     576         177 :   cache_history (coin_pub,
     577             :                  tl);
     578         177 :   return qs;
     579             : }
     580             : 
     581             : 
     582             : /* ************************* Analyze coins ******************** */
     583             : /* This logic checks that the exchange did the right thing for each
     584             :    coin, checking deposits, refunds, refresh* and known_coins
     585             :    tables */
     586             : 
     587             : 
     588             : /**
     589             :  * Summary data we keep per denomination.
     590             :  */
     591             : struct DenominationSummary
     592             : {
     593             :   /**
     594             :    * Total value of outstanding (not deposited) coins issued with this
     595             :    * denomination key.
     596             :    */
     597             :   struct TALER_Amount denom_balance;
     598             : 
     599             :   /**
     600             :    * Total losses made (once coins deposited exceed
     601             :    * coins withdrawn and thus the @e denom_balance is
     602             :    * effectively negative).
     603             :    */
     604             :   struct TALER_Amount denom_loss;
     605             : 
     606             :   /**
     607             :    * Total value of coins issued with this denomination key.
     608             :    */
     609             :   struct TALER_Amount denom_risk;
     610             : 
     611             :   /**
     612             :    * Total value of coins subjected to recoup with this denomination key.
     613             :    */
     614             :   struct TALER_Amount denom_recoup;
     615             : 
     616             :   /**
     617             :    * How many coins (not their amount!) of this denomination
     618             :    * did the exchange issue overall?
     619             :    */
     620             :   uint64_t num_issued;
     621             : 
     622             :   /**
     623             :    * Denomination key information for this denomination.
     624             :    */
     625             :   const struct TALER_DenominationKeyValidityPS *issue;
     626             : 
     627             :   /**
     628             :    * #GNUNET_YES if this record already existed in the DB.
     629             :    * Used to decide between insert/update in
     630             :    * #sync_denomination().
     631             :    */
     632             :   int in_db;
     633             : 
     634             :   /**
     635             :    * Should we report an emergency for this denomination, causing it to be
     636             :    * revoked (because more coins were deposited than issued)?
     637             :    */
     638             :   int report_emergency;
     639             : 
     640             :   /**
     641             :    * #GNUNET_YES if this denomination was revoked.
     642             :    */
     643             :   int was_revoked;
     644             : };
     645             : 
     646             : 
     647             : /**
     648             :  * Closure for callbacks during #analyze_coins().
     649             :  */
     650             : struct CoinContext
     651             : {
     652             : 
     653             :   /**
     654             :    * Map for tracking information about denominations.
     655             :    */
     656             :   struct GNUNET_CONTAINER_MultiHashMap *denom_summaries;
     657             : 
     658             :   /**
     659             :    * Transaction status code.
     660             :    */
     661             :   enum GNUNET_DB_QueryStatus qs;
     662             : 
     663             : };
     664             : 
     665             : 
     666             : /**
     667             :  * Initialize information about denomination from the database.
     668             :  *
     669             :  * @param denom_hash hash of the public key of the denomination
     670             :  * @param[out] ds summary to initialize
     671             :  * @return transaction status code
     672             :  */
     673             : static enum GNUNET_DB_QueryStatus
     674         289 : init_denomination (const struct GNUNET_HashCode *denom_hash,
     675             :                    struct DenominationSummary *ds)
     676             : {
     677             :   enum GNUNET_DB_QueryStatus qs;
     678             :   struct TALER_MasterSignatureP msig;
     679             :   uint64_t rowid;
     680             : 
     681         289 :   qs = TALER_ARL_adb->get_denomination_balance (TALER_ARL_adb->cls,
     682             :                                                 denom_hash,
     683             :                                                 &ds->denom_balance,
     684             :                                                 &ds->denom_loss,
     685             :                                                 &ds->denom_risk,
     686             :                                                 &ds->denom_recoup,
     687             :                                                 &ds->num_issued);
     688         289 :   if (0 > qs)
     689             :   {
     690           0 :     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
     691           0 :     return qs;
     692             :   }
     693         289 :   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
     694             :   {
     695           1 :     ds->in_db = GNUNET_YES;
     696             :   }
     697             :   else
     698             :   {
     699         288 :     GNUNET_assert (GNUNET_OK ==
     700             :                    TALER_amount_set_zero (TALER_ARL_currency,
     701             :                                           &ds->denom_balance));
     702         288 :     GNUNET_assert (GNUNET_OK ==
     703             :                    TALER_amount_set_zero (TALER_ARL_currency,
     704             :                                           &ds->denom_loss));
     705         288 :     GNUNET_assert (GNUNET_OK ==
     706             :                    TALER_amount_set_zero (TALER_ARL_currency,
     707             :                                           &ds->denom_risk));
     708         288 :     GNUNET_assert (GNUNET_OK ==
     709             :                    TALER_amount_set_zero (TALER_ARL_currency,
     710             :                                           &ds->denom_recoup));
     711             :   }
     712         289 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     713             :               "Starting balance for denomination `%s' is %s (%llu)\n",
     714             :               GNUNET_h2s (denom_hash),
     715             :               TALER_amount2s (&ds->denom_balance),
     716             :               (unsigned long long) ds->num_issued);
     717         289 :   qs = TALER_ARL_edb->get_denomination_revocation (TALER_ARL_edb->cls,
     718             :                                                    denom_hash,
     719             :                                                    &msig,
     720             :                                                    &rowid);
     721         289 :   if (0 > qs)
     722             :   {
     723           0 :     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
     724           0 :     return qs;
     725             :   }
     726         289 :   if (0 < qs)
     727             :   {
     728             :     /* check revocation signature */
     729          10 :     if (GNUNET_OK !=
     730          10 :         TALER_exchange_offline_denomination_revoke_verify (
     731             :           denom_hash,
     732             :           &TALER_ARL_master_pub,
     733             :           &msig))
     734             :     {
     735           0 :       report_row_inconsistency ("denomination revocations",
     736             :                                 rowid,
     737             :                                 "revocation signature invalid");
     738             :     }
     739             :     else
     740             :     {
     741          10 :       ds->was_revoked = GNUNET_YES;
     742             :     }
     743             :   }
     744         289 :   return (GNUNET_YES == ds->in_db)
     745             :          ? GNUNET_DB_STATUS_SUCCESS_ONE_RESULT
     746         289 :          : GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
     747             : }
     748             : 
     749             : 
     750             : /**
     751             :  * Obtain the denomination summary for the given @a dh
     752             :  *
     753             :  * @param cc our execution context
     754             :  * @param issue denomination key information for @a dh
     755             :  * @param dh the denomination hash to use for the lookup
     756             :  * @return NULL on error
     757             :  */
     758             : static struct DenominationSummary *
     759        3316 : get_denomination_summary (struct CoinContext *cc,
     760             :                           const struct TALER_DenominationKeyValidityPS *issue,
     761             :                           const struct GNUNET_HashCode *dh)
     762             : {
     763             :   struct DenominationSummary *ds;
     764             : 
     765        3316 :   ds = GNUNET_CONTAINER_multihashmap_get (cc->denom_summaries,
     766             :                                           dh);
     767        3316 :   if (NULL != ds)
     768        3027 :     return ds;
     769         289 :   ds = GNUNET_new (struct DenominationSummary);
     770         289 :   ds->issue = issue;
     771         289 :   if (0 > (cc->qs = init_denomination (dh,
     772             :                                        ds)))
     773             :   {
     774           0 :     GNUNET_break (0);
     775           0 :     GNUNET_free (ds);
     776           0 :     return NULL;
     777             :   }
     778         289 :   GNUNET_assert (GNUNET_OK ==
     779             :                  GNUNET_CONTAINER_multihashmap_put (cc->denom_summaries,
     780             :                                                     dh,
     781             :                                                     ds,
     782             :                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
     783         289 :   return ds;
     784             : }
     785             : 
     786             : 
     787             : /**
     788             :  * Write information about the current knowledge about a denomination key
     789             :  * back to the database and update our global reporting data about the
     790             :  * denomination.  Also remove and free the memory of @a value.
     791             :  *
     792             :  * @param cls the `struct CoinContext`
     793             :  * @param denom_hash the hash of the denomination key
     794             :  * @param value a `struct DenominationSummary`
     795             :  * @return #GNUNET_OK (continue to iterate)
     796             :  */
     797             : static int
     798         289 : sync_denomination (void *cls,
     799             :                    const struct GNUNET_HashCode *denom_hash,
     800             :                    void *value)
     801             : {
     802         289 :   struct CoinContext *cc = cls;
     803         289 :   struct DenominationSummary *ds = value;
     804         289 :   const struct TALER_DenominationKeyValidityPS *issue = ds->issue;
     805             :   struct GNUNET_TIME_Absolute now;
     806             :   struct GNUNET_TIME_Absolute expire_deposit;
     807             :   struct GNUNET_TIME_Absolute expire_deposit_grace;
     808             :   enum GNUNET_DB_QueryStatus qs;
     809             : 
     810         289 :   now = GNUNET_TIME_absolute_get ();
     811         289 :   expire_deposit = GNUNET_TIME_absolute_ntoh (issue->expire_deposit);
     812             :   /* add day grace period to deal with clocks not being perfectly synchronized */
     813         289 :   expire_deposit_grace = GNUNET_TIME_absolute_add (expire_deposit,
     814             :                                                    DEPOSIT_GRACE_PERIOD);
     815         289 :   if (now.abs_value_us > expire_deposit_grace.abs_value_us)
     816             :   {
     817             :     /* Denomination key has expired, book remaining balance of
     818             :        outstanding coins as revenue; and reduce cc->risk exposure. */
     819           0 :     if (ds->in_db)
     820           0 :       qs = TALER_ARL_adb->del_denomination_balance (TALER_ARL_adb->cls,
     821             :                                                     denom_hash);
     822             :     else
     823           0 :       qs = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
     824           0 :     if ( (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs) &&
     825           0 :          ( (0 != ds->denom_risk.value) ||
     826           0 :            (0 != ds->denom_risk.fraction) ) )
     827             :     {
     828             :       /* The denomination expired and carried a balance; we can now
     829             :          book the remaining balance as profit, and reduce our risk
     830             :          exposure by the accumulated risk of the denomination. */
     831           0 :       TALER_ARL_amount_subtract (&total_risk,
     832             :                                  &total_risk,
     833             :                                  &ds->denom_risk);
     834             :       /* If the above fails, our risk assessment is inconsistent!
     835             :          This is really, really bad (auditor-internal invariant
     836             :          would be violated). Hence we can "safely" assert.  If
     837             :          this assertion fails, well, good luck: there is a bug
     838             :          in the auditor _or_ the auditor's database is corrupt. *///
     839             :     }
     840           0 :     if ( (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs) &&
     841           0 :          ( (0 != ds->denom_balance.value) ||
     842           0 :            (0 != ds->denom_balance.fraction) ) )
     843             :     {
     844             :       /* book denom_balance coin expiration profits! */
     845           0 :       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     846             :                   "Denomination `%s' expired, booking %s in expiration profits\n",
     847             :                   GNUNET_h2s (denom_hash),
     848             :                   TALER_amount2s (&ds->denom_balance));
     849           0 :       if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     850           0 :           (qs = TALER_ARL_adb->insert_historic_denom_revenue (
     851           0 :              TALER_ARL_adb->cls,
     852             :              &TALER_ARL_master_pub,
     853             :              denom_hash,
     854             :              expire_deposit,
     855           0 :              &ds->denom_balance,
     856           0 :              &ds->denom_recoup)))
     857             :       {
     858             :         /* Failed to store profits? Bad database */
     859           0 :         GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
     860           0 :         cc->qs = qs;
     861             :       }
     862             :     }
     863             :   }
     864             :   else
     865             :   {
     866             :     /* Not expired, just store current denomination summary
     867             :        to auditor database for next iteration */
     868             :     long long cnt;
     869             : 
     870         289 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     871             :                 "Final balance for denomination `%s' is %s (%llu)\n",
     872             :                 GNUNET_h2s (denom_hash),
     873             :                 TALER_amount2s (&ds->denom_balance),
     874             :                 (unsigned long long) ds->num_issued);
     875         289 :     cnt = TALER_ARL_edb->count_known_coins (TALER_ARL_edb->cls,
     876             :                                             denom_hash);
     877         289 :     if (0 > cnt)
     878             :     {
     879             :       /* Failed to obtain count? Bad database */
     880           0 :       qs = (enum GNUNET_DB_QueryStatus) cnt;
     881           0 :       GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
     882           0 :       cc->qs = qs;
     883             :     }
     884             :     else
     885             :     {
     886         289 :       if (ds->num_issued < (uint64_t) cnt)
     887             :       {
     888             :         /* more coins deposited than issued! very bad */
     889           2 :         report_emergency_by_count (issue,
     890             :                                    ds->num_issued,
     891             :                                    cnt,
     892           2 :                                    &ds->denom_risk);
     893             :       }
     894         289 :       if (GNUNET_YES == ds->report_emergency)
     895             :       {
     896             :         /* Value of coins deposited exceed value of coins
     897             :            issued! Also very bad! */
     898           3 :         report_emergency_by_amount (issue,
     899           3 :                                     &ds->denom_risk,
     900           3 :                                     &ds->denom_loss);
     901             : 
     902             :       }
     903         289 :       if (ds->in_db)
     904           1 :         qs = TALER_ARL_adb->update_denomination_balance (TALER_ARL_adb->cls,
     905             :                                                          denom_hash,
     906           1 :                                                          &ds->denom_balance,
     907           1 :                                                          &ds->denom_loss,
     908           1 :                                                          &ds->denom_risk,
     909           1 :                                                          &ds->denom_recoup,
     910             :                                                          ds->num_issued);
     911             :       else
     912         288 :         qs = TALER_ARL_adb->insert_denomination_balance (TALER_ARL_adb->cls,
     913             :                                                          denom_hash,
     914         288 :                                                          &ds->denom_balance,
     915         288 :                                                          &ds->denom_loss,
     916         288 :                                                          &ds->denom_risk,
     917         288 :                                                          &ds->denom_recoup,
     918             :                                                          ds->num_issued);
     919             :     }
     920             :   }
     921         289 :   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
     922             :   {
     923           0 :     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
     924           0 :     cc->qs = qs;
     925             :   }
     926         289 :   GNUNET_assert (GNUNET_YES ==
     927             :                  GNUNET_CONTAINER_multihashmap_remove (cc->denom_summaries,
     928             :                                                        denom_hash,
     929             :                                                        ds));
     930         289 :   GNUNET_free (ds);
     931         289 :   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != cc->qs)
     932           0 :     return GNUNET_SYSERR;
     933         289 :   return GNUNET_OK;
     934             : }
     935             : 
     936             : 
     937             : /**
     938             :  * Function called with details about all withdraw operations.
     939             :  * Updates the denomination balance and the overall balance as
     940             :  * we now have additional coins that have been issued.
     941             :  *
     942             :  * Note that the signature was already checked in
     943             :  * taler-helper-auditor-reserves.c::#handle_reserve_out(), so we do not check
     944             :  * it again here.
     945             :  *
     946             :  * @param cls our `struct CoinContext`
     947             :  * @param rowid unique serial ID for the refresh session in our DB
     948             :  * @param h_blind_ev blinded hash of the coin's public key
     949             :  * @param denom_pub public denomination key of the deposited coin
     950             :  * @param reserve_pub public key of the reserve
     951             :  * @param reserve_sig signature over the withdraw operation (verified elsewhere)
     952             :  * @param execution_date when did the wallet withdraw the coin
     953             :  * @param amount_with_fee amount that was withdrawn
     954             :  * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
     955             :  */
     956             : static int
     957        1042 : withdraw_cb (void *cls,
     958             :              uint64_t rowid,
     959             :              const struct GNUNET_HashCode *h_blind_ev,
     960             :              const struct TALER_DenominationPublicKey *denom_pub,
     961             :              const struct TALER_ReservePublicKeyP *reserve_pub,
     962             :              const struct TALER_ReserveSignatureP *reserve_sig,
     963             :              struct GNUNET_TIME_Absolute execution_date,
     964             :              const struct TALER_Amount *amount_with_fee)
     965             : {
     966        1042 :   struct CoinContext *cc = cls;
     967             :   struct DenominationSummary *ds;
     968             :   struct GNUNET_HashCode dh;
     969             :   const struct TALER_DenominationKeyValidityPS *issue;
     970             :   struct TALER_Amount value;
     971             :   enum GNUNET_DB_QueryStatus qs;
     972             : 
     973             :   /* Note: some optimization potential here: lots of fields we
     974             :      could avoid fetching from the database with a custom function. */
     975             :   (void) h_blind_ev;
     976             :   (void) reserve_pub;
     977             :   (void) reserve_sig;
     978             :   (void) execution_date;
     979             :   (void) amount_with_fee;
     980             : 
     981        1042 :   GNUNET_assert (rowid >= ppc.last_withdraw_serial_id); /* should be monotonically increasing */
     982        1042 :   ppc.last_withdraw_serial_id = rowid + 1;
     983             : 
     984        1042 :   qs = TALER_ARL_get_denomination_info (denom_pub,
     985             :                                         &issue,
     986             :                                         &dh);
     987        1042 :   if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
     988             :   {
     989           0 :     report_row_inconsistency ("withdraw",
     990             :                               rowid,
     991             :                               "denomination key not found");
     992           0 :     if (TALER_ARL_do_abort ())
     993           0 :       return GNUNET_SYSERR;
     994           0 :     return GNUNET_OK;
     995             :   }
     996        1042 :   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
     997             :   {
     998             :     /* This really ought to be a transient DB error. */
     999           0 :     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
    1000           0 :     cc->qs = qs;
    1001           0 :     return GNUNET_SYSERR;
    1002             :   }
    1003        1042 :   ds = get_denomination_summary (cc,
    1004             :                                  issue,
    1005             :                                  &dh);
    1006        1042 :   if (NULL == ds)
    1007             :   {
    1008             :     /* cc->qs is set by #get_denomination_summary() */
    1009           0 :     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == cc->qs);
    1010           0 :     return GNUNET_SYSERR;
    1011             :   }
    1012        1042 :   TALER_amount_ntoh (&value,
    1013        1042 :                      &issue->value);
    1014        1042 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    1015             :               "Issued coin in denomination `%s' of total value %s\n",
    1016             :               GNUNET_h2s (&dh),
    1017             :               TALER_amount2s (&value));
    1018        1042 :   ds->num_issued++;
    1019        1042 :   TALER_ARL_amount_add (&ds->denom_balance,
    1020             :                         &ds->denom_balance,
    1021             :                         &value);
    1022        1042 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    1023             :               "New balance of denomination `%s' is %s\n",
    1024             :               GNUNET_h2s (&dh),
    1025             :               TALER_amount2s (&ds->denom_balance));
    1026        1042 :   TALER_ARL_amount_add (&total_escrow_balance,
    1027             :                         &total_escrow_balance,
    1028             :                         &value);
    1029        1042 :   TALER_ARL_amount_add (&total_risk,
    1030             :                         &total_risk,
    1031             :                         &value);
    1032        1042 :   TALER_ARL_amount_add (&ds->denom_risk,
    1033             :                         &ds->denom_risk,
    1034             :                         &value);
    1035        1042 :   if (TALER_ARL_do_abort ())
    1036           0 :     return GNUNET_SYSERR;
    1037        1042 :   return GNUNET_OK;
    1038             : }
    1039             : 
    1040             : 
    1041             : /**
    1042             :  * Closure for #reveal_data_cb().
    1043             :  */
    1044             : struct RevealContext
    1045             : {
    1046             : 
    1047             :   /**
    1048             :    * Denomination public data of the new coins.
    1049             :    */
    1050             :   const struct TALER_DenominationKeyValidityPS **new_issues;
    1051             : 
    1052             :   /**
    1053             :    * Set to the size of the @a new_issues array.
    1054             :    */
    1055             :   unsigned int num_freshcoins;
    1056             : 
    1057             :   /**
    1058             :    * Which coin row are we currently processing (for report generation).
    1059             :    */
    1060             :   uint64_t rowid;
    1061             : 
    1062             :   /**
    1063             :    * Error status. #GNUNET_OK if all is OK.
    1064             :    * #GNUNET_NO if a denomination key was not found
    1065             :    * #GNUNET_SYSERR if we had a database error.
    1066             :    */
    1067             :   int err;
    1068             : 
    1069             :   /**
    1070             :    * Database error, if @e err is #GNUNET_SYSERR.
    1071             :    */
    1072             :   enum GNUNET_DB_QueryStatus qs;
    1073             : };
    1074             : 
    1075             : 
    1076             : /**
    1077             :  * Function called with information about a refresh order.
    1078             :  *
    1079             :  * @param cls closure with a `struct RevealContext *` in it
    1080             :  * @param num_freshcoins size of the @a rrcs array
    1081             :  * @param rrcs array of @a num_freshcoins information about coins to be created
    1082             :  * @param num_tprivs number of entries in @a tprivs, should be #TALER_CNC_KAPPA - 1
    1083             :  * @param tprivs array of @e num_tprivs transfer private keys
    1084             :  * @param tp transfer public key information
    1085             :  */
    1086             : static void
    1087         147 : reveal_data_cb (void *cls,
    1088             :                 uint32_t num_freshcoins,
    1089             :                 const struct TALER_EXCHANGEDB_RefreshRevealedCoin *rrcs,
    1090             :                 unsigned int num_tprivs,
    1091             :                 const struct TALER_TransferPrivateKeyP *tprivs,
    1092             :                 const struct TALER_TransferPublicKeyP *tp)
    1093             : {
    1094         147 :   struct RevealContext *rctx = cls;
    1095             : 
    1096             :   /* Note: optimization using custom database accessor API could avoid
    1097             :      fetching these fields -- and we */
    1098             :   (void) num_tprivs;
    1099             :   (void) tprivs;
    1100             :   (void) tp;
    1101             : 
    1102         147 :   rctx->num_freshcoins = num_freshcoins;
    1103         147 :   rctx->new_issues = GNUNET_new_array (
    1104             :     num_freshcoins,
    1105             :     const struct TALER_DenominationKeyValidityPS *);
    1106             : 
    1107             :   /* Update outstanding amounts for all new coin's denominations */
    1108        2033 :   for (unsigned int i = 0; i<num_freshcoins; i++)
    1109             :   {
    1110             :     enum GNUNET_DB_QueryStatus qs;
    1111             : 
    1112             :     /* lookup new coin denomination key */
    1113        1886 :     qs = TALER_ARL_get_denomination_info (&rrcs[i].denom_pub,
    1114        1886 :                                           &rctx->new_issues[i],
    1115             :                                           NULL);
    1116        1886 :     if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
    1117             :     {
    1118           0 :       report_row_inconsistency ("refresh_reveal",
    1119             :                                 rctx->rowid,
    1120             :                                 "denomination key not found");
    1121           0 :       rctx->err = GNUNET_NO; /* terminate here, but return "OK" to commit transaction */
    1122             :     }
    1123        1886 :     else if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
    1124             :     {
    1125           0 :       GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
    1126           0 :       rctx->qs = qs;
    1127           0 :       rctx->err = GNUNET_SYSERR; /* terminate, return #GNUNET_SYSERR: abort transaction */
    1128             :     }
    1129             :   }
    1130         147 : }
    1131             : 
    1132             : 
    1133             : /**
    1134             :  * Check that the @a coin_pub is a known coin with a proper
    1135             :  * signature for denominatinon @a denom_pub. If not, report
    1136             :  * a loss of @a loss_potential.
    1137             :  *
    1138             :  * @param operation which operation is this about
    1139             :  * @param issue denomination key information about the coin
    1140             :  * @param rowid which row is this operation in
    1141             :  * @param coin_pub public key of a coin
    1142             :  * @param denom_pub expected denomination of the coin
    1143             :  * @param loss_potential how big could the loss be if the coin is
    1144             :  *        not properly signed
    1145             :  * @return database transaction status, on success
    1146             :  *  #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT
    1147             :  */
    1148             : static enum GNUNET_DB_QueryStatus
    1149         322 : check_known_coin (const char *operation,
    1150             :                   const struct TALER_DenominationKeyValidityPS *issue,
    1151             :                   uint64_t rowid,
    1152             :                   const struct TALER_CoinSpendPublicKeyP *coin_pub,
    1153             :                   const struct TALER_DenominationPublicKey *denom_pub,
    1154             :                   const struct TALER_Amount *loss_potential)
    1155             : {
    1156             :   struct TALER_CoinPublicInfo ci;
    1157             :   enum GNUNET_DB_QueryStatus qs;
    1158             : 
    1159         322 :   if (NULL == get_cached_history (coin_pub))
    1160             :   {
    1161             :     struct TALER_Amount value;
    1162             : 
    1163         177 :     TALER_amount_ntoh (&value,
    1164             :                        &issue->value);
    1165         177 :     qs = check_coin_history (coin_pub,
    1166             :                              rowid,
    1167             :                              operation,
    1168             :                              &value);
    1169         177 :     if (0 > qs)
    1170             :     {
    1171           0 :       GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
    1172           0 :       return qs;
    1173             :     }
    1174         177 :     GNUNET_break (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs);
    1175             :   }
    1176             : 
    1177             : 
    1178         322 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    1179             :               "Checking denomination signature on %s\n",
    1180             :               TALER_B2S (coin_pub));
    1181         322 :   qs = TALER_ARL_edb->get_known_coin (TALER_ARL_edb->cls,
    1182             :                                       coin_pub,
    1183             :                                       &ci);
    1184         322 :   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
    1185             :   {
    1186           0 :     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
    1187           0 :     return qs;
    1188             :   }
    1189         322 :   if (GNUNET_YES !=
    1190         322 :       TALER_test_coin_valid (&ci,
    1191             :                              denom_pub))
    1192             :   {
    1193           6 :     TALER_ARL_report (report_bad_sig_losses,
    1194           6 :                       GNUNET_JSON_PACK (
    1195             :                         GNUNET_JSON_pack_string ("operation",
    1196             :                                                  operation),
    1197             :                         GNUNET_JSON_pack_uint64 ("row",
    1198             :                                                  rowid),
    1199             :                         TALER_JSON_pack_amount ("loss",
    1200             :                                                 loss_potential),
    1201             :                         GNUNET_JSON_pack_data_auto ("coin_pub",
    1202             :                                                     coin_pub)));
    1203           6 :     TALER_ARL_amount_add (&total_bad_sig_loss,
    1204             :                           &total_bad_sig_loss,
    1205             :                           loss_potential);
    1206             :   }
    1207         322 :   GNUNET_CRYPTO_rsa_signature_free (ci.denom_sig.rsa_signature);
    1208         322 :   return qs;
    1209             : }
    1210             : 
    1211             : 
    1212             : /**
    1213             :  * Function called with details about coins that were melted, with the
    1214             :  * goal of auditing the refresh's execution.  Verifies the signature
    1215             :  * and updates our information about coins outstanding (the old coin's
    1216             :  * denomination has less, the fresh coins increased outstanding
    1217             :  * balances).
    1218             :  *
    1219             :  * @param cls closure
    1220             :  * @param rowid unique serial ID for the refresh session in our DB
    1221             :  * @param denom_pub denomination public key of @a coin_pub
    1222             :  * @param coin_pub public key of the coin
    1223             :  * @param coin_sig signature from the coin
    1224             :  * @param amount_with_fee amount that was deposited including fee
    1225             :  * @param noreveal_index which index was picked by the exchange in cut-and-choose
    1226             :  * @param rc what is the refresh commitment
    1227             :  * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
    1228             :  */
    1229             : static int
    1230         151 : refresh_session_cb (void *cls,
    1231             :                     uint64_t rowid,
    1232             :                     const struct TALER_DenominationPublicKey *denom_pub,
    1233             :                     const struct TALER_CoinSpendPublicKeyP *coin_pub,
    1234             :                     const struct TALER_CoinSpendSignatureP *coin_sig,
    1235             :                     const struct TALER_Amount *amount_with_fee,
    1236             :                     uint32_t noreveal_index,
    1237             :                     const struct TALER_RefreshCommitmentP *rc)
    1238             : {
    1239         151 :   struct CoinContext *cc = cls;
    1240             :   const struct TALER_DenominationKeyValidityPS *issue;
    1241             :   struct DenominationSummary *dso;
    1242             :   struct TALER_Amount amount_without_fee;
    1243             :   struct TALER_Amount tmp;
    1244             :   enum GNUNET_DB_QueryStatus qs;
    1245             : 
    1246             :   (void) noreveal_index;
    1247         151 :   GNUNET_assert (rowid >= ppc.last_melt_serial_id); /* should be monotonically increasing */
    1248         151 :   ppc.last_melt_serial_id = rowid + 1;
    1249             : 
    1250         151 :   qs = TALER_ARL_get_denomination_info (denom_pub,
    1251             :                                         &issue,
    1252             :                                         NULL);
    1253         151 :   if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
    1254             :   {
    1255           0 :     report_row_inconsistency ("melt",
    1256             :                               rowid,
    1257             :                               "denomination key not found");
    1258           0 :     if (TALER_ARL_do_abort ())
    1259           0 :       return GNUNET_SYSERR;
    1260           0 :     return GNUNET_OK;
    1261             :   }
    1262         151 :   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
    1263             :   {
    1264           0 :     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
    1265           0 :     cc->qs = qs;
    1266           0 :     return GNUNET_SYSERR;
    1267             :   }
    1268         151 :   qs = check_known_coin ("melt",
    1269             :                          issue,
    1270             :                          rowid,
    1271             :                          coin_pub,
    1272             :                          denom_pub,
    1273             :                          amount_with_fee);
    1274         151 :   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
    1275             :   {
    1276           0 :     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
    1277           0 :     cc->qs = qs;
    1278           0 :     return GNUNET_SYSERR;
    1279             :   }
    1280             : 
    1281             :   /* verify melt signature */
    1282             :   {
    1283         151 :     struct TALER_RefreshMeltCoinAffirmationPS rmc = {
    1284         151 :       .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_MELT),
    1285         151 :       .purpose.size = htonl (sizeof (rmc)),
    1286             :       .rc = *rc,
    1287         151 :       .melt_fee = issue->fee_refresh,
    1288             :       .coin_pub = *coin_pub
    1289             :     };
    1290             : 
    1291         151 :     GNUNET_CRYPTO_rsa_public_key_hash (denom_pub->rsa_public_key,
    1292             :                                        &rmc.h_denom_pub);
    1293         151 :     TALER_amount_hton (&rmc.amount_with_fee,
    1294             :                        amount_with_fee);
    1295         151 :     if (GNUNET_OK !=
    1296         151 :         GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_MELT,
    1297             :                                     &rmc,
    1298             :                                     &coin_sig->eddsa_signature,
    1299             :                                     &coin_pub->eddsa_pub))
    1300             :     {
    1301           7 :       TALER_ARL_report (report_bad_sig_losses,
    1302           7 :                         GNUNET_JSON_PACK (
    1303             :                           GNUNET_JSON_pack_string ("operation",
    1304             :                                                    "melt"),
    1305             :                           GNUNET_JSON_pack_uint64 ("row",
    1306             :                                                    rowid),
    1307             :                           TALER_JSON_pack_amount ("loss",
    1308             :                                                   amount_with_fee),
    1309             :                           GNUNET_JSON_pack_data_auto ("coin_pub",
    1310             :                                                       coin_pub)));
    1311           7 :       TALER_ARL_amount_add (&total_bad_sig_loss,
    1312             :                             &total_bad_sig_loss,
    1313             :                             amount_with_fee);
    1314             :     }
    1315             :   }
    1316         151 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    1317             :               "Melting coin %s in denomination `%s' of value %s\n",
    1318             :               TALER_B2S (coin_pub),
    1319             :               GNUNET_h2s (&issue->denom_hash),
    1320             :               TALER_amount2s (amount_with_fee));
    1321             : 
    1322             :   {
    1323             :     struct TALER_Amount refresh_cost;
    1324         151 :     struct RevealContext reveal_ctx = {
    1325             :       .rowid = rowid,
    1326             :       .err = GNUNET_OK
    1327             :     };
    1328             : 
    1329         151 :     qs = TALER_ARL_edb->get_refresh_reveal (TALER_ARL_edb->cls,
    1330             :                                             rc,
    1331             :                                             &reveal_data_cb,
    1332             :                                             &reveal_ctx);
    1333         151 :     if (0 > qs)
    1334             :     {
    1335           0 :       GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
    1336           0 :       cc->qs = GNUNET_DB_STATUS_HARD_ERROR;
    1337           4 :       return GNUNET_SYSERR;
    1338             :     }
    1339         151 :     if ( (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) ||
    1340         147 :          (0 == reveal_ctx.num_freshcoins) )
    1341             :     {
    1342             :       /* This can legitimately happen if reveal was not yet called or only
    1343             :          with invalid data, even if the exchange is correctly operating. We
    1344             :          still report it. */
    1345           4 :       TALER_ARL_report (report_refreshs_hanging,
    1346           4 :                         GNUNET_JSON_PACK (
    1347             :                           GNUNET_JSON_pack_uint64 ("row",
    1348             :                                                    rowid),
    1349             :                           TALER_JSON_pack_amount ("amount",
    1350             :                                                   amount_with_fee),
    1351             :                           GNUNET_JSON_pack_data_auto ("coin_pub",
    1352             :                                                       coin_pub)));
    1353           4 :       TALER_ARL_amount_add (&total_refresh_hanging,
    1354             :                             &total_refresh_hanging,
    1355             :                             amount_with_fee);
    1356           4 :       if (TALER_ARL_do_abort ())
    1357           0 :         return GNUNET_SYSERR;
    1358           4 :       return GNUNET_OK;
    1359             :     }
    1360         147 :     if (GNUNET_SYSERR == reveal_ctx.err)
    1361           0 :       cc->qs = reveal_ctx.qs;
    1362             : 
    1363         147 :     if (GNUNET_OK != reveal_ctx.err)
    1364             :     {
    1365           0 :       GNUNET_free (reveal_ctx.new_issues);
    1366           0 :       if (GNUNET_SYSERR == reveal_ctx.err)
    1367           0 :         return GNUNET_SYSERR;
    1368           0 :       if (TALER_ARL_do_abort ())
    1369           0 :         return GNUNET_SYSERR;
    1370           0 :       return GNUNET_OK;
    1371             :     }
    1372             : 
    1373             :     /* Check that the resulting amounts are consistent with the value being
    1374             :      refreshed by calculating the total refresh cost */
    1375         147 :     GNUNET_assert (GNUNET_OK ==
    1376             :                    TALER_amount_set_zero (amount_with_fee->currency,
    1377             :                                           &refresh_cost));
    1378        2033 :     for (unsigned int i = 0; i<reveal_ctx.num_freshcoins; i++)
    1379             :     {
    1380             :       /* update cost of refresh */
    1381             :       struct TALER_Amount fee;
    1382             :       struct TALER_Amount value;
    1383             : 
    1384        1886 :       TALER_amount_ntoh (&fee,
    1385        1886 :                          &reveal_ctx.new_issues[i]->fee_withdraw);
    1386        1886 :       TALER_amount_ntoh (&value,
    1387        1886 :                          &reveal_ctx.new_issues[i]->value);
    1388        1886 :       TALER_ARL_amount_add (&refresh_cost,
    1389             :                             &refresh_cost,
    1390             :                             &fee);
    1391        1886 :       TALER_ARL_amount_add (&refresh_cost,
    1392             :                             &refresh_cost,
    1393             :                             &value);
    1394             :     }
    1395             : 
    1396             :     /* compute contribution of old coin */
    1397             :     {
    1398             :       struct TALER_Amount melt_fee;
    1399             : 
    1400         147 :       TALER_amount_ntoh (&melt_fee,
    1401         147 :                          &issue->fee_refresh);
    1402         147 :       if (TALER_ARL_SR_POSITIVE !=
    1403         147 :           TALER_ARL_amount_subtract_neg (&amount_without_fee,
    1404             :                                          amount_with_fee,
    1405             :                                          &melt_fee))
    1406             :       {
    1407             :         /* Melt fee higher than contribution of melted coin; this makes
    1408             :            no sense (exchange should never have accepted the operation) */
    1409           0 :         report_amount_arithmetic_inconsistency ("melt contribution vs. fee",
    1410             :                                                 rowid,
    1411             :                                                 amount_with_fee,
    1412             :                                                 &melt_fee,
    1413             :                                                 -1);
    1414             :         /* To continue, best assumption is the melted coin contributed
    1415             :            nothing (=> all withdrawal amounts will be counted as losses) */
    1416           0 :         GNUNET_assert (GNUNET_OK ==
    1417             :                        TALER_amount_set_zero (TALER_ARL_currency,
    1418             :                                               &amount_without_fee));
    1419             :       }
    1420             :     }
    1421             : 
    1422             :     /* check old coin covers complete expenses (of withdraw operations) */
    1423         147 :     if (1 == TALER_amount_cmp (&refresh_cost,
    1424             :                                &amount_without_fee))
    1425             :     {
    1426             :       /* refresh_cost > amount_without_fee, which is bad (exchange lost) */
    1427           8 :       report_amount_arithmetic_inconsistency ("melt (cost)",
    1428             :                                               rowid,
    1429             :                                               &amount_without_fee, /* 'exchange' */
    1430             :                                               &refresh_cost, /* 'auditor' */
    1431             :                                               1);
    1432             :     }
    1433             : 
    1434             :     /* update outstanding denomination amounts for fresh coins withdrawn */
    1435        2033 :     for (unsigned int i = 0; i<reveal_ctx.num_freshcoins; i++)
    1436             :     {
    1437             :       struct DenominationSummary *dsi;
    1438             :       struct TALER_Amount value;
    1439             : 
    1440        1886 :       dsi = get_denomination_summary (cc,
    1441        1886 :                                       reveal_ctx.new_issues[i],
    1442        1886 :                                       &reveal_ctx.new_issues[i]->denom_hash);
    1443        1886 :       if (NULL == dsi)
    1444             :       {
    1445           0 :         report_row_inconsistency ("refresh_reveal",
    1446             :                                   rowid,
    1447             :                                   "denomination key for fresh coin unknown to auditor");
    1448             :       }
    1449             :       else
    1450             :       {
    1451        1886 :         TALER_amount_ntoh (&value,
    1452        1886 :                            &reveal_ctx.new_issues[i]->value);
    1453        1886 :         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    1454             :                     "Created fresh coin in denomination `%s' of value %s\n",
    1455             :                     GNUNET_h2s (&reveal_ctx.new_issues[i]->denom_hash),
    1456             :                     TALER_amount2s (&value));
    1457        1886 :         dsi->num_issued++;
    1458        1886 :         TALER_ARL_amount_add (&dsi->denom_balance,
    1459             :                               &dsi->denom_balance,
    1460             :                               &value);
    1461        1886 :         TALER_ARL_amount_add (&dsi->denom_risk,
    1462             :                               &dsi->denom_risk,
    1463             :                               &value);
    1464        1886 :         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    1465             :                     "New balance of denomination `%s' is %s\n",
    1466             :                     GNUNET_h2s (&reveal_ctx.new_issues[i]->denom_hash),
    1467             :                     TALER_amount2s (&dsi->denom_balance));
    1468        1886 :         TALER_ARL_amount_add (&total_escrow_balance,
    1469             :                               &total_escrow_balance,
    1470             :                               &value);
    1471        1886 :         TALER_ARL_amount_add (&total_risk,
    1472             :                               &total_risk,
    1473             :                               &value);
    1474             :       }
    1475             :     }
    1476         147 :     GNUNET_free (reveal_ctx.new_issues);
    1477             :   }
    1478             : 
    1479             :   /* update old coin's denomination balance */
    1480         147 :   dso = get_denomination_summary (cc,
    1481             :                                   issue,
    1482         147 :                                   &issue->denom_hash);
    1483         147 :   if (NULL == dso)
    1484             :   {
    1485           0 :     report_row_inconsistency ("refresh_reveal",
    1486             :                               rowid,
    1487             :                               "denomination key for dirty coin unknown to auditor");
    1488             :   }
    1489             :   else
    1490             :   {
    1491         147 :     if (TALER_ARL_SR_INVALID_NEGATIVE ==
    1492         147 :         TALER_ARL_amount_subtract_neg (&tmp,
    1493             :                                        &dso->denom_balance,
    1494             :                                        amount_with_fee))
    1495             :     {
    1496           2 :       TALER_ARL_amount_add (&dso->denom_loss,
    1497             :                             &dso->denom_loss,
    1498             :                             amount_with_fee);
    1499           2 :       dso->report_emergency = GNUNET_YES;
    1500             :     }
    1501             :     else
    1502             :     {
    1503         145 :       dso->denom_balance = tmp;
    1504             :     }
    1505         147 :     if (-1 == TALER_amount_cmp (&total_escrow_balance,
    1506             :                                 amount_with_fee))
    1507             :     {
    1508             :       /* This can theoretically happen if for example the exchange
    1509             :          never issued any coins (i.e. escrow balance is zero), but
    1510             :          accepted a forged coin (i.e. emergency situation after
    1511             :          private key compromise). In that case, we cannot even
    1512             :          subtract the profit we make from the fee from the escrow
    1513             :          balance. Tested as part of test-auditor.sh, case #18 *///
    1514           0 :       report_amount_arithmetic_inconsistency (
    1515             :         "subtracting refresh fee from escrow balance",
    1516             :         rowid,
    1517             :         &total_escrow_balance,
    1518             :         amount_with_fee,
    1519             :         0);
    1520             :     }
    1521             :     else
    1522             :     {
    1523         147 :       TALER_ARL_amount_subtract (&total_escrow_balance,
    1524             :                                  &total_escrow_balance,
    1525             :                                  amount_with_fee);
    1526             :     }
    1527         147 :     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    1528             :                 "New balance of denomination `%s' after melt is %s\n",
    1529             :                 GNUNET_h2s (&issue->denom_hash),
    1530             :                 TALER_amount2s (&dso->denom_balance));
    1531             :   }
    1532             : 
    1533             :   /* update global melt fees */
    1534             :   {
    1535             :     struct TALER_Amount rfee;
    1536             : 
    1537         147 :     TALER_amount_ntoh (&rfee,
    1538         147 :                        &issue->fee_refresh);
    1539         147 :     TALER_ARL_amount_add (&total_melt_fee_income,
    1540             :                           &total_melt_fee_income,
    1541             :                           &rfee);
    1542             :   }
    1543         147 :   if (TALER_ARL_do_abort ())
    1544           0 :     return GNUNET_SYSERR;
    1545         147 :   return GNUNET_OK;
    1546             : }
    1547             : 
    1548             : 
    1549             : /**
    1550             :  * Function called with details about deposits that have been made,
    1551             :  * with the goal of auditing the deposit's execution.
    1552             :  *
    1553             :  * @param cls closure
    1554             :  * @param rowid unique serial ID for the deposit in our DB
    1555             :  * @param exchange_timestamp when did the exchange get the deposit
    1556             :  * @param wallet_timestamp when did the contract signing happen
    1557             :  * @param merchant_pub public key of the merchant
    1558             :  * @param denom_pub denomination public key of @a coin_pub
    1559             :  * @param coin_pub public key of the coin
    1560             :  * @param coin_sig signature from the coin
    1561             :  * @param amount_with_fee amount that was deposited including fee
    1562             :  * @param h_contract_terms hash of the proposal data known to merchant and customer
    1563             :  * @param refund_deadline by which the merchant advised that he might want
    1564             :  *        to get a refund
    1565             :  * @param wire_deadline by which the merchant advised that he would like the
    1566             :  *        wire transfer to be executed
    1567             :  * @param receiver_wire_account wire details for the merchant, NULL from iterate_matching_deposits()
    1568             :  * @param done flag set if the deposit was already executed (or not)
    1569             :  * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
    1570             :  */
    1571             : static int
    1572         124 : deposit_cb (void *cls,
    1573             :             uint64_t rowid,
    1574             :             struct GNUNET_TIME_Absolute exchange_timestamp,
    1575             :             struct GNUNET_TIME_Absolute wallet_timestamp,
    1576             :             const struct TALER_MerchantPublicKeyP *merchant_pub,
    1577             :             const struct TALER_DenominationPublicKey *denom_pub,
    1578             :             const struct TALER_CoinSpendPublicKeyP *coin_pub,
    1579             :             const struct TALER_CoinSpendSignatureP *coin_sig,
    1580             :             const struct TALER_Amount *amount_with_fee,
    1581             :             const struct GNUNET_HashCode *h_contract_terms,
    1582             :             struct GNUNET_TIME_Absolute refund_deadline,
    1583             :             struct GNUNET_TIME_Absolute wire_deadline,
    1584             :             const json_t *receiver_wire_account,
    1585             :             int done)
    1586             : {
    1587         124 :   struct CoinContext *cc = cls;
    1588             :   const struct TALER_DenominationKeyValidityPS *issue;
    1589             :   struct DenominationSummary *ds;
    1590             :   enum GNUNET_DB_QueryStatus qs;
    1591             : 
    1592             :   (void) done;
    1593         124 :   GNUNET_assert (rowid >= ppc.last_deposit_serial_id); /* should be monotonically increasing */
    1594         124 :   ppc.last_deposit_serial_id = rowid + 1;
    1595             : 
    1596         124 :   qs = TALER_ARL_get_denomination_info (denom_pub,
    1597             :                                         &issue,
    1598             :                                         NULL);
    1599         124 :   if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
    1600             :   {
    1601           0 :     report_row_inconsistency ("deposits",
    1602             :                               rowid,
    1603             :                               "denomination key not found");
    1604           0 :     if (TALER_ARL_do_abort ())
    1605           0 :       return GNUNET_SYSERR;
    1606           0 :     return GNUNET_OK;
    1607             :   }
    1608         124 :   if (refund_deadline.abs_value_us >
    1609         124 :       wire_deadline.abs_value_us)
    1610             :   {
    1611           0 :     report_row_inconsistency ("deposits",
    1612             :                               rowid,
    1613             :                               "refund deadline past wire deadline");
    1614             :   }
    1615             : 
    1616         124 :   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
    1617             :   {
    1618           0 :     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
    1619           0 :     cc->qs = qs;
    1620           0 :     return GNUNET_SYSERR;
    1621             :   }
    1622         124 :   qs = check_known_coin ("deposit",
    1623             :                          issue,
    1624             :                          rowid,
    1625             :                          coin_pub,
    1626             :                          denom_pub,
    1627             :                          amount_with_fee);
    1628         124 :   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
    1629             :   {
    1630           0 :     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
    1631           0 :     cc->qs = qs;
    1632           0 :     return GNUNET_SYSERR;
    1633             :   }
    1634             : 
    1635             :   /* Verify deposit signature */
    1636             :   {
    1637         248 :     struct TALER_DepositRequestPS dr = {
    1638         124 :       .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT),
    1639         124 :       .purpose.size = htonl (sizeof (dr)),
    1640             :       .h_contract_terms = *h_contract_terms,
    1641         124 :       .wallet_timestamp = GNUNET_TIME_absolute_hton (wallet_timestamp),
    1642         124 :       .refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline),
    1643         124 :       .deposit_fee = issue->fee_deposit,
    1644             :       .merchant = *merchant_pub,
    1645             :       .coin_pub = *coin_pub
    1646             :     };
    1647             : 
    1648         124 :     GNUNET_CRYPTO_rsa_public_key_hash (denom_pub->rsa_public_key,
    1649             :                                        &dr.h_denom_pub);
    1650         124 :     if (GNUNET_OK !=
    1651         124 :         TALER_JSON_merchant_wire_signature_hash (receiver_wire_account,
    1652             :                                                  &dr.h_wire))
    1653             :     {
    1654           1 :       TALER_ARL_report (report_bad_sig_losses,
    1655           1 :                         GNUNET_JSON_PACK (
    1656             :                           GNUNET_JSON_pack_string ("operation",
    1657             :                                                    "deposit"),
    1658             :                           GNUNET_JSON_pack_uint64 ("row",
    1659             :                                                    rowid),
    1660             :                           TALER_JSON_pack_amount ("loss",
    1661             :                                                   amount_with_fee),
    1662             :                           GNUNET_JSON_pack_data_auto ("coin_pub",
    1663             :                                                       coin_pub)));
    1664           1 :       TALER_ARL_amount_add (&total_bad_sig_loss,
    1665             :                             &total_bad_sig_loss,
    1666             :                             amount_with_fee);
    1667           1 :       if (TALER_ARL_do_abort ())
    1668           0 :         return GNUNET_SYSERR;
    1669           1 :       return GNUNET_OK;
    1670             :     }
    1671         123 :     TALER_amount_hton (&dr.amount_with_fee,
    1672             :                        amount_with_fee);
    1673             :     /* NOTE: This is one of the operations we might eventually
    1674             :        want to do in parallel in the background to improve
    1675             :        auditor performance! */
    1676         123 :     if (GNUNET_OK !=
    1677         123 :         GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_DEPOSIT,
    1678             :                                     &dr,
    1679             :                                     &coin_sig->eddsa_signature,
    1680             :                                     &coin_pub->eddsa_pub))
    1681             :     {
    1682           3 :       TALER_ARL_report (report_bad_sig_losses,
    1683           3 :                         GNUNET_JSON_PACK (
    1684             :                           GNUNET_JSON_pack_string ("operation",
    1685             :                                                    "deposit"),
    1686             :                           GNUNET_JSON_pack_uint64 ("row",
    1687             :                                                    rowid),
    1688             :                           TALER_JSON_pack_amount ("loss",
    1689             :                                                   amount_with_fee),
    1690             :                           GNUNET_JSON_pack_data_auto ("coin_pub",
    1691             :                                                       coin_pub)));
    1692           3 :       TALER_ARL_amount_add (&total_bad_sig_loss,
    1693             :                             &total_bad_sig_loss,
    1694             :                             amount_with_fee);
    1695           3 :       if (TALER_ARL_do_abort ())
    1696           0 :         return GNUNET_SYSERR;
    1697           3 :       return GNUNET_OK;
    1698             :     }
    1699             :   }
    1700         120 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    1701             :               "Deposited coin %s in denomination `%s' of value %s\n",
    1702             :               TALER_B2S (coin_pub),
    1703             :               GNUNET_h2s (&issue->denom_hash),
    1704             :               TALER_amount2s (amount_with_fee));
    1705             : 
    1706             :   /* update old coin's denomination balance */
    1707         120 :   ds = get_denomination_summary (cc,
    1708             :                                  issue,
    1709         120 :                                  &issue->denom_hash);
    1710         120 :   if (NULL == ds)
    1711             :   {
    1712           0 :     report_row_inconsistency ("deposit",
    1713             :                               rowid,
    1714             :                               "denomination key for deposited coin unknown to auditor");
    1715             :   }
    1716             :   else
    1717             :   {
    1718             :     struct TALER_Amount tmp;
    1719             : 
    1720         120 :     if (TALER_ARL_SR_INVALID_NEGATIVE ==
    1721         120 :         TALER_ARL_amount_subtract_neg (&tmp,
    1722             :                                        &ds->denom_balance,
    1723             :                                        amount_with_fee))
    1724             :     {
    1725           3 :       TALER_ARL_amount_add (&ds->denom_loss,
    1726             :                             &ds->denom_loss,
    1727             :                             amount_with_fee);
    1728           3 :       ds->report_emergency = GNUNET_YES;
    1729             :     }
    1730             :     else
    1731             :     {
    1732         117 :       ds->denom_balance = tmp;
    1733             :     }
    1734             : 
    1735         120 :     if (-1 == TALER_amount_cmp (&total_escrow_balance,
    1736             :                                 amount_with_fee))
    1737             :     {
    1738             :       /* This can theoretically happen if for example the exchange
    1739             :          never issued any coins (i.e. escrow balance is zero), but
    1740             :          accepted a forged coin (i.e. emergency situation after
    1741             :          private key compromise). In that case, we cannot even
    1742             :          subtract the profit we make from the fee from the escrow
    1743             :          balance. Tested as part of test-auditor.sh, case #18 *///
    1744           2 :       report_amount_arithmetic_inconsistency (
    1745             :         "subtracting deposit fee from escrow balance",
    1746             :         rowid,
    1747             :         &total_escrow_balance,
    1748             :         amount_with_fee,
    1749             :         0);
    1750             :     }
    1751             :     else
    1752             :     {
    1753         118 :       TALER_ARL_amount_subtract (&total_escrow_balance,
    1754             :                                  &total_escrow_balance,
    1755             :                                  amount_with_fee);
    1756             :     }
    1757             : 
    1758         120 :     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    1759             :                 "New balance of denomination `%s' after deposit is %s\n",
    1760             :                 GNUNET_h2s (&issue->denom_hash),
    1761             :                 TALER_amount2s (&ds->denom_balance));
    1762             :   }
    1763             : 
    1764             :   /* update global deposit fees */
    1765             :   {
    1766             :     struct TALER_Amount dfee;
    1767             : 
    1768         120 :     TALER_amount_ntoh (&dfee,
    1769         120 :                        &issue->fee_deposit);
    1770         120 :     TALER_ARL_amount_add (&total_deposit_fee_income,
    1771             :                           &total_deposit_fee_income,
    1772             :                           &dfee);
    1773             :   }
    1774         120 :   if (TALER_ARL_do_abort ())
    1775           0 :     return GNUNET_SYSERR;
    1776         120 :   return GNUNET_OK;
    1777             : }
    1778             : 
    1779             : 
    1780             : /**
    1781             :  * Function called with details about coins that were refunding,
    1782             :  * with the goal of auditing the refund's execution.  Adds the
    1783             :  * refunded amount back to the outstanding balance of the respective
    1784             :  * denomination.
    1785             :  *
    1786             :  * @param cls closure
    1787             :  * @param rowid unique serial ID for the refund in our DB
    1788             :  * @param denom_pub denomination public key of @a coin_pub
    1789             :  * @param coin_pub public key of the coin
    1790             :  * @param merchant_pub public key of the merchant
    1791             :  * @param merchant_sig signature of the merchant
    1792             :  * @param h_contract_terms hash of the proposal data known to merchant and customer
    1793             :  * @param rtransaction_id refund transaction ID chosen by the merchant
    1794             :  * @param amount_with_fee amount that was deposited including fee
    1795             :  * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
    1796             :  */
    1797             : static int
    1798          34 : refund_cb (void *cls,
    1799             :            uint64_t rowid,
    1800             :            const struct TALER_DenominationPublicKey *denom_pub,
    1801             :            const struct TALER_CoinSpendPublicKeyP *coin_pub,
    1802             :            const struct TALER_MerchantPublicKeyP *merchant_pub,
    1803             :            const struct TALER_MerchantSignatureP *merchant_sig,
    1804             :            const struct GNUNET_HashCode *h_contract_terms,
    1805             :            uint64_t rtransaction_id,
    1806             :            const struct TALER_Amount *amount_with_fee)
    1807             : {
    1808          34 :   struct CoinContext *cc = cls;
    1809             :   const struct TALER_DenominationKeyValidityPS *issue;
    1810             :   struct DenominationSummary *ds;
    1811             :   struct TALER_Amount amount_without_fee;
    1812             :   struct TALER_Amount refund_fee;
    1813             :   enum GNUNET_DB_QueryStatus qs;
    1814             : 
    1815          34 :   GNUNET_assert (rowid >= ppc.last_refund_serial_id); /* should be monotonically increasing */
    1816          34 :   ppc.last_refund_serial_id = rowid + 1;
    1817             : 
    1818          34 :   qs = TALER_ARL_get_denomination_info (denom_pub,
    1819             :                                         &issue,
    1820             :                                         NULL);
    1821          34 :   if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
    1822             :   {
    1823           0 :     report_row_inconsistency ("refunds",
    1824             :                               rowid,
    1825             :                               "denomination key not found");
    1826           0 :     if (TALER_ARL_do_abort ())
    1827           0 :       return GNUNET_SYSERR;
    1828           0 :     return GNUNET_OK;
    1829             :   }
    1830          34 :   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
    1831             :   {
    1832           0 :     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
    1833           0 :     return GNUNET_SYSERR;
    1834             :   }
    1835             : 
    1836             :   /* verify refund signature */
    1837             :   {
    1838          68 :     struct TALER_RefundRequestPS rr = {
    1839          34 :       .purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_REFUND),
    1840          34 :       .purpose.size = htonl (sizeof (rr)),
    1841             :       .h_contract_terms = *h_contract_terms,
    1842             :       .coin_pub = *coin_pub,
    1843             :       .merchant = *merchant_pub,
    1844          34 :       .rtransaction_id = GNUNET_htonll (rtransaction_id),
    1845             :     };
    1846             : 
    1847          34 :     TALER_amount_hton (&rr.refund_amount,
    1848             :                        amount_with_fee);
    1849          34 :     if (GNUNET_OK !=
    1850          34 :         GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MERCHANT_REFUND,
    1851             :                                     &rr,
    1852             :                                     &merchant_sig->eddsa_sig,
    1853             :                                     &merchant_pub->eddsa_pub))
    1854             :     {
    1855           0 :       TALER_ARL_report (report_bad_sig_losses,
    1856           0 :                         GNUNET_JSON_PACK (
    1857             :                           GNUNET_JSON_pack_string ("operation",
    1858             :                                                    "refund"),
    1859             :                           GNUNET_JSON_pack_uint64 ("row",
    1860             :                                                    rowid),
    1861             :                           TALER_JSON_pack_amount ("loss",
    1862             :                                                   amount_with_fee),
    1863             :                           GNUNET_JSON_pack_data_auto ("coin_pub",
    1864             :                                                       coin_pub)));
    1865           0 :       TALER_ARL_amount_add (&total_bad_sig_loss,
    1866             :                             &total_bad_sig_loss,
    1867             :                             amount_with_fee);
    1868           0 :       if (TALER_ARL_do_abort ())
    1869           0 :         return GNUNET_SYSERR;
    1870           0 :       return GNUNET_OK;
    1871             :     }
    1872             :   }
    1873             : 
    1874          34 :   TALER_amount_ntoh (&refund_fee,
    1875          34 :                      &issue->fee_refund);
    1876          34 :   if (TALER_ARL_SR_INVALID_NEGATIVE ==
    1877          34 :       TALER_ARL_amount_subtract_neg (&amount_without_fee,
    1878             :                                      amount_with_fee,
    1879             :                                      &refund_fee))
    1880             :   {
    1881           0 :     report_amount_arithmetic_inconsistency ("refund (fee)",
    1882             :                                             rowid,
    1883             :                                             &amount_without_fee,
    1884             :                                             &refund_fee,
    1885             :                                             -1);
    1886           0 :     if (TALER_ARL_do_abort ())
    1887           0 :       return GNUNET_SYSERR;
    1888           0 :     return GNUNET_OK;
    1889             :   }
    1890             : 
    1891          34 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    1892             :               "Refunding coin %s in denomination `%s' value %s\n",
    1893             :               TALER_B2S (coin_pub),
    1894             :               GNUNET_h2s (&issue->denom_hash),
    1895             :               TALER_amount2s (amount_with_fee));
    1896             : 
    1897             :   /* update coin's denomination balance */
    1898          34 :   ds = get_denomination_summary (cc,
    1899             :                                  issue,
    1900          34 :                                  &issue->denom_hash);
    1901          34 :   if (NULL == ds)
    1902             :   {
    1903           0 :     report_row_inconsistency ("refund",
    1904             :                               rowid,
    1905             :                               "denomination key for refunded coin unknown to auditor");
    1906             :   }
    1907             :   else
    1908             :   {
    1909          34 :     TALER_ARL_amount_add (&ds->denom_balance,
    1910             :                           &ds->denom_balance,
    1911             :                           &amount_without_fee);
    1912          34 :     TALER_ARL_amount_add (&ds->denom_risk,
    1913             :                           &ds->denom_risk,
    1914             :                           &amount_without_fee);
    1915          34 :     TALER_ARL_amount_add (&total_escrow_balance,
    1916             :                           &total_escrow_balance,
    1917             :                           &amount_without_fee);
    1918          34 :     TALER_ARL_amount_add (&total_risk,
    1919             :                           &total_risk,
    1920             :                           &amount_without_fee);
    1921          34 :     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    1922             :                 "New balance of denomination `%s' after refund is %s\n",
    1923             :                 GNUNET_h2s (&issue->denom_hash),
    1924             :                 TALER_amount2s (&ds->denom_balance));
    1925             :   }
    1926             :   /* update total refund fee balance */
    1927          34 :   TALER_ARL_amount_add (&total_refund_fee_income,
    1928             :                         &total_refund_fee_income,
    1929             :                         &refund_fee);
    1930          34 :   if (TALER_ARL_do_abort ())
    1931           0 :     return GNUNET_SYSERR;
    1932          34 :   return GNUNET_OK;
    1933             : }
    1934             : 
    1935             : 
    1936             : /**
    1937             :  * Check that the recoup operation was properly initiated by a coin
    1938             :  * and update the denomination's losses accordingly.
    1939             :  *
    1940             :  * @param cc the context with details about the coin
    1941             :  * @param operation name of the operation matching @a rowid
    1942             :  * @param rowid row identifier used to uniquely identify the recoup operation
    1943             :  * @param amount how much should be added back to the reserve
    1944             :  * @param coin public information about the coin
    1945             :  * @param denom_pub public key of the denomionation of @a coin
    1946             :  * @param coin_sig signature with @e coin_pub of type #TALER_SIGNATURE_WALLET_COIN_RECOUP
    1947             :  * @param coin_blind blinding factor used to blind the coin
    1948             :  * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
    1949             :  */
    1950             : static int
    1951          47 : check_recoup (struct CoinContext *cc,
    1952             :               const char *operation,
    1953             :               uint64_t rowid,
    1954             :               const struct TALER_Amount *amount,
    1955             :               const struct TALER_CoinPublicInfo *coin,
    1956             :               const struct TALER_DenominationPublicKey *denom_pub,
    1957             :               const struct TALER_CoinSpendSignatureP *coin_sig,
    1958             :               const struct TALER_DenominationBlindingKeyP *coin_blind)
    1959             : {
    1960             :   struct DenominationSummary *ds;
    1961             :   enum GNUNET_DB_QueryStatus qs;
    1962             :   const struct TALER_DenominationKeyValidityPS *issue;
    1963             : 
    1964          47 :   if (GNUNET_OK !=
    1965          47 :       TALER_test_coin_valid (coin,
    1966             :                              denom_pub))
    1967             :   {
    1968           0 :     TALER_ARL_report (report_bad_sig_losses,
    1969           0 :                       GNUNET_JSON_PACK (
    1970             :                         GNUNET_JSON_pack_string ("operation",
    1971             :                                                  operation),
    1972             :                         GNUNET_JSON_pack_uint64 ("row",
    1973             :                                                  rowid),
    1974             :                         TALER_JSON_pack_amount ("loss",
    1975             :                                                 amount),
    1976             :                         GNUNET_JSON_pack_data_auto ("coin_pub",
    1977             :                                                     &coin->denom_pub_hash)));
    1978           0 :     TALER_ARL_amount_add (&total_bad_sig_loss,
    1979             :                           &total_bad_sig_loss,
    1980             :                           amount);
    1981             :   }
    1982          47 :   qs = TALER_ARL_get_denomination_info_by_hash (&coin->denom_pub_hash,
    1983             :                                                 &issue);
    1984          47 :   if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
    1985             :   {
    1986           0 :     report_row_inconsistency (operation,
    1987             :                               rowid,
    1988             :                               "denomination key not found");
    1989           0 :     if (TALER_ARL_do_abort ())
    1990           0 :       return GNUNET_SYSERR;
    1991           0 :     return GNUNET_OK;
    1992             :   }
    1993          47 :   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
    1994             :   {
    1995             :     /* The key not existing should be prevented by foreign key constraints,
    1996             :        so must be a transient DB error. */
    1997           0 :     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
    1998           0 :     cc->qs = qs;
    1999           0 :     return GNUNET_SYSERR;
    2000             :   }
    2001          47 :   qs = check_known_coin (operation,
    2002             :                          issue,
    2003             :                          rowid,
    2004             :                          &coin->coin_pub,
    2005             :                          denom_pub,
    2006             :                          amount);
    2007          47 :   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
    2008             :   {
    2009           0 :     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
    2010           0 :     cc->qs = qs;
    2011           0 :     return GNUNET_SYSERR;
    2012             :   }
    2013             :   {
    2014          47 :     struct TALER_RecoupRequestPS pr = {
    2015          47 :       .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_RECOUP),
    2016          47 :       .purpose.size = htonl (sizeof (pr)),
    2017             :       .coin_pub = coin->coin_pub,
    2018             :       .coin_blind = *coin_blind,
    2019             :       .h_denom_pub = coin->denom_pub_hash
    2020             :     };
    2021             : 
    2022          47 :     if (GNUNET_OK !=
    2023          47 :         GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_RECOUP,
    2024             :                                     &pr,
    2025             :                                     &coin_sig->eddsa_signature,
    2026             :                                     &coin->coin_pub.eddsa_pub))
    2027             :     {
    2028           0 :       TALER_ARL_report (report_bad_sig_losses,
    2029           0 :                         GNUNET_JSON_PACK (
    2030             :                           GNUNET_JSON_pack_string ("operation",
    2031             :                                                    operation),
    2032             :                           GNUNET_JSON_pack_uint64 ("row",
    2033             :                                                    rowid),
    2034             :                           TALER_JSON_pack_amount ("loss",
    2035             :                                                   amount),
    2036             :                           GNUNET_JSON_pack_data_auto ("coin_pub",
    2037             :                                                       &coin->coin_pub)));
    2038           0 :       TALER_ARL_amount_add (&total_bad_sig_loss,
    2039             :                             &total_bad_sig_loss,
    2040             :                             amount);
    2041           0 :       if (TALER_ARL_do_abort ())
    2042           0 :         return GNUNET_SYSERR;
    2043           0 :       return GNUNET_OK;
    2044             :     }
    2045             :   }
    2046          47 :   ds = get_denomination_summary (cc,
    2047             :                                  issue,
    2048          47 :                                  &issue->denom_hash);
    2049          47 :   if (NULL == ds)
    2050             :   {
    2051           0 :     report_row_inconsistency ("recoup",
    2052             :                               rowid,
    2053             :                               "denomination key for recouped coin unknown to auditor");
    2054             :   }
    2055             :   else
    2056             :   {
    2057          47 :     if (GNUNET_NO == ds->was_revoked)
    2058             :     {
    2059             :       /* Woopsie, we allowed recoup on non-revoked denomination!? */
    2060           9 :       TALER_ARL_report (report_bad_sig_losses,
    2061           9 :                         GNUNET_JSON_PACK (
    2062             :                           GNUNET_JSON_pack_string ("operation",
    2063             :                                                    operation),
    2064             :                           GNUNET_JSON_pack_string ("hint",
    2065             :                                                    "denomination not revoked"),
    2066             :                           GNUNET_JSON_pack_uint64 ("row",
    2067             :                                                    rowid),
    2068             :                           TALER_JSON_pack_amount ("loss",
    2069             :                                                   amount),
    2070             :                           GNUNET_JSON_pack_data_auto ("coin_pub",
    2071             :                                                       &coin->coin_pub)));
    2072           9 :       TALER_ARL_amount_add (&total_bad_sig_loss,
    2073             :                             &total_bad_sig_loss,
    2074             :                             amount);
    2075             :     }
    2076          47 :     TALER_ARL_amount_add (&ds->denom_recoup,
    2077             :                           &ds->denom_recoup,
    2078             :                           amount);
    2079          47 :     TALER_ARL_amount_add (&total_recoup_loss,
    2080             :                           &total_recoup_loss,
    2081             :                           amount);
    2082             :   }
    2083          47 :   if (TALER_ARL_do_abort ())
    2084           0 :     return GNUNET_SYSERR;
    2085          47 :   return GNUNET_OK;
    2086             : }
    2087             : 
    2088             : 
    2089             : /**
    2090             :  * Function called about recoups the exchange has to perform.
    2091             :  *
    2092             :  * @param cls a `struct CoinContext *`
    2093             :  * @param rowid row identifier used to uniquely identify the recoup operation
    2094             :  * @param timestamp when did we receive the recoup request
    2095             :  * @param amount how much should be added back to the reserve
    2096             :  * @param reserve_pub public key of the reserve
    2097             :  * @param coin public information about the coin
    2098             :  * @param denom_pub denomination public key of @a coin
    2099             :  * @param coin_sig signature with @e coin_pub of type #TALER_SIGNATURE_WALLET_COIN_RECOUP
    2100             :  * @param coin_blind blinding factor used to blind the coin
    2101             :  * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
    2102             :  */
    2103             : static int
    2104           7 : recoup_cb (void *cls,
    2105             :            uint64_t rowid,
    2106             :            struct GNUNET_TIME_Absolute timestamp,
    2107             :            const struct TALER_Amount *amount,
    2108             :            const struct TALER_ReservePublicKeyP *reserve_pub,
    2109             :            const struct TALER_CoinPublicInfo *coin,
    2110             :            const struct TALER_DenominationPublicKey *denom_pub,
    2111             :            const struct TALER_CoinSpendSignatureP *coin_sig,
    2112             :            const struct TALER_DenominationBlindingKeyP *coin_blind)
    2113             : {
    2114           7 :   struct CoinContext *cc = cls;
    2115             : 
    2116           7 :   GNUNET_assert (rowid >= ppc.last_recoup_serial_id); /* should be monotonically increasing */
    2117           7 :   ppc.last_recoup_serial_id = rowid + 1;
    2118             :   (void) timestamp;
    2119             :   (void) reserve_pub;
    2120           7 :   return check_recoup (cc,
    2121             :                        "recoup",
    2122             :                        rowid,
    2123             :                        amount,
    2124             :                        coin,
    2125             :                        denom_pub,
    2126             :                        coin_sig,
    2127             :                        coin_blind);
    2128             : }
    2129             : 
    2130             : 
    2131             : /**
    2132             :  * Function called about recoups on refreshed coins the exchange has to
    2133             :  * perform.
    2134             :  *
    2135             :  * @param cls a `struct CoinContext *`
    2136             :  * @param rowid row identifier used to uniquely identify the recoup operation
    2137             :  * @param timestamp when did we receive the recoup request
    2138             :  * @param amount how much should be added back to the reserve
    2139             :  * @param old_coin_pub original coin that was refreshed to create @a coin
    2140             :  * @param old_denom_pub_hash hash of the public key of @a old_coin_pub
    2141             :  * @param coin public information about the coin
    2142             :  * @param denom_pub denomination public key of @a coin
    2143             :  * @param coin_sig signature with @e coin_pub of type #TALER_SIGNATURE_WALLET_COIN_RECOUP
    2144             :  * @param coin_blind blinding factor used to blind the coin
    2145             :  * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
    2146             :  */
    2147             : static int
    2148          40 : recoup_refresh_cb (void *cls,
    2149             :                    uint64_t rowid,
    2150             :                    struct GNUNET_TIME_Absolute timestamp,
    2151             :                    const struct TALER_Amount *amount,
    2152             :                    const struct TALER_CoinSpendPublicKeyP *old_coin_pub,
    2153             :                    const struct GNUNET_HashCode *old_denom_pub_hash,
    2154             :                    const struct TALER_CoinPublicInfo *coin,
    2155             :                    const struct TALER_DenominationPublicKey *denom_pub,
    2156             :                    const struct TALER_CoinSpendSignatureP *coin_sig,
    2157             :                    const struct TALER_DenominationBlindingKeyP *coin_blind)
    2158             : {
    2159          40 :   struct CoinContext *cc = cls;
    2160             :   const struct TALER_DenominationKeyValidityPS *issue;
    2161             :   enum GNUNET_DB_QueryStatus qs;
    2162             : 
    2163             :   (void) timestamp;
    2164             :   (void) old_coin_pub;
    2165          40 :   GNUNET_assert (rowid >= ppc.last_recoup_refresh_serial_id); /* should be monotonically increasing */
    2166          40 :   ppc.last_recoup_refresh_serial_id = rowid + 1;
    2167          40 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    2168             :               "Recoup-refresh amount is %s\n",
    2169             :               TALER_amount2s (amount));
    2170             : 
    2171             :   /* Update old coin's denomination balance summary */
    2172          40 :   qs = TALER_ARL_get_denomination_info_by_hash (old_denom_pub_hash,
    2173             :                                                 &issue);
    2174          40 :   if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS >= qs)
    2175             :   {
    2176           0 :     if (qs < 0)
    2177             :     {
    2178           0 :       GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
    2179           0 :       cc->qs = qs;
    2180           0 :       return GNUNET_SYSERR;
    2181             :     }
    2182           0 :     report_row_inconsistency ("refresh-recoup",
    2183             :                               rowid,
    2184             :                               "denomination key of old coin not found");
    2185             :   }
    2186             :   else
    2187             :   {
    2188             :     struct DenominationSummary *dso;
    2189             : 
    2190          40 :     dso = get_denomination_summary (cc,
    2191             :                                     issue,
    2192             :                                     old_denom_pub_hash);
    2193          40 :     if (NULL == dso)
    2194             :     {
    2195           0 :       report_row_inconsistency ("refresh_reveal",
    2196             :                                 rowid,
    2197             :                                 "denomination key for old coin unknown to auditor");
    2198             :     }
    2199             :     else
    2200             :     {
    2201          40 :       TALER_ARL_amount_add (&dso->denom_balance,
    2202             :                             &dso->denom_balance,
    2203             :                             amount);
    2204          40 :       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    2205             :                   "New balance of denomination `%s' after refresh-recoup is %s\n",
    2206             :                   GNUNET_h2s (&issue->denom_hash),
    2207             :                   TALER_amount2s (&dso->denom_balance));
    2208             :     }
    2209             :   }
    2210             : 
    2211          40 :   return check_recoup (cc,
    2212             :                        "recoup-refresh",
    2213             :                        rowid,
    2214             :                        amount,
    2215             :                        coin,
    2216             :                        denom_pub,
    2217             :                        coin_sig,
    2218             :                        coin_blind);
    2219             : }
    2220             : 
    2221             : 
    2222             : /**
    2223             :  * Function called with the results of iterate_denomination_info(),
    2224             :  * or directly (!).  Used to check that we correctly signed the
    2225             :  * denomination and to warn if there are denominations not approved
    2226             :  * by this auditor.
    2227             :  *
    2228             :  * @param cls closure, NULL
    2229             :  * @param denom_pub public key, sometimes NULL (!)
    2230             :  * @param validity issuing information with value, fees and other info about the denomination.
    2231             :  */
    2232             : static void
    2233       33980 : check_denomination (
    2234             :   void *cls,
    2235             :   const struct TALER_DenominationPublicKey *denom_pub,
    2236             :   const struct TALER_EXCHANGEDB_DenominationKeyInformationP *validity)
    2237             : {
    2238       33980 :   const struct TALER_DenominationKeyValidityPS *issue = &validity->properties;
    2239             :   enum GNUNET_DB_QueryStatus qs;
    2240             :   struct TALER_AuditorSignatureP auditor_sig;
    2241             : 
    2242       33980 :   qs = TALER_ARL_edb->select_auditor_denom_sig (TALER_ARL_edb->cls,
    2243             :                                                 &issue->denom_hash,
    2244             :                                                 &TALER_ARL_auditor_pub,
    2245             :                                                 &auditor_sig);
    2246       33980 :   if (0 >= qs)
    2247             :   {
    2248       33980 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    2249             :                 "Encountered denomination `%s' that this auditor is not auditing!\n",
    2250             :                 GNUNET_h2s (&issue->denom_hash));
    2251       33980 :     return; /* skip! */
    2252             :   }
    2253             :   {
    2254             :     struct TALER_Amount coin_value;
    2255             :     struct TALER_Amount fee_withdraw;
    2256             :     struct TALER_Amount fee_deposit;
    2257             :     struct TALER_Amount fee_refresh;
    2258             :     struct TALER_Amount fee_refund;
    2259             : 
    2260           0 :     TALER_amount_ntoh (&coin_value,
    2261             :                        &issue->value);
    2262           0 :     TALER_amount_ntoh (&fee_withdraw,
    2263             :                        &issue->fee_withdraw);
    2264           0 :     TALER_amount_ntoh (&fee_deposit,
    2265             :                        &issue->fee_deposit);
    2266           0 :     TALER_amount_ntoh (&fee_refresh,
    2267             :                        &issue->fee_refresh);
    2268           0 :     TALER_amount_ntoh (&fee_refund,
    2269             :                        &issue->fee_refund);
    2270           0 :     if (GNUNET_OK !=
    2271           0 :         TALER_auditor_denom_validity_verify (
    2272             :           TALER_ARL_auditor_url,
    2273             :           &issue->denom_hash,
    2274             :           &TALER_ARL_master_pub,
    2275             :           GNUNET_TIME_absolute_ntoh (issue->start),
    2276             :           GNUNET_TIME_absolute_ntoh (issue->expire_withdraw),
    2277             :           GNUNET_TIME_absolute_ntoh (issue->expire_deposit),
    2278             :           GNUNET_TIME_absolute_ntoh (issue->expire_legal),
    2279             :           &coin_value,
    2280             :           &fee_withdraw,
    2281             :           &fee_deposit,
    2282             :           &fee_refresh,
    2283             :           &fee_refund,
    2284             :           &TALER_ARL_auditor_pub,
    2285             :           &auditor_sig))
    2286             :     {
    2287           0 :       TALER_ARL_report (report_denominations_without_sigs,
    2288           0 :                         GNUNET_JSON_PACK (
    2289             :                           GNUNET_JSON_pack_data_auto ("denomination",
    2290             :                                                       &issue->denom_hash),
    2291             :                           TALER_JSON_pack_amount ("value",
    2292             :                                                   &coin_value),
    2293             :                           TALER_JSON_pack_time_abs_nbo_human ("start_time",
    2294             :                                                               issue->start),
    2295             :                           TALER_JSON_pack_time_abs_nbo_human ("end_time",
    2296             :                                                               issue->
    2297             :                                                               expire_legal)));
    2298             :     }
    2299             :   }
    2300             : }
    2301             : 
    2302             : 
    2303             : /**
    2304             :  * Analyze the exchange's processing of coins.
    2305             :  *
    2306             :  * @param cls closure
    2307             :  * @return transaction status code
    2308             :  */
    2309             : static enum GNUNET_DB_QueryStatus
    2310          83 : analyze_coins (void *cls)
    2311             : {
    2312             :   struct CoinContext cc;
    2313             :   enum GNUNET_DB_QueryStatus qs;
    2314             :   enum GNUNET_DB_QueryStatus qsx;
    2315             :   enum GNUNET_DB_QueryStatus qsp;
    2316             : 
    2317             :   (void) cls;
    2318          83 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    2319             :               "Checking denominations...\n");
    2320          83 :   qs = TALER_ARL_edb->iterate_denomination_info (TALER_ARL_edb->cls,
    2321             :                                                  &check_denomination,
    2322             :                                                  NULL);
    2323          83 :   if (0 > qs)
    2324             :   {
    2325           0 :     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
    2326           0 :     return qs;
    2327             :   }
    2328          83 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    2329             :               "Analyzing coins\n");
    2330          83 :   qsp = TALER_ARL_adb->get_auditor_progress_coin (TALER_ARL_adb->cls,
    2331             :                                                   &TALER_ARL_master_pub,
    2332             :                                                   &ppc);
    2333          83 :   if (0 > qsp)
    2334             :   {
    2335           0 :     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qsp);
    2336           0 :     return qsp;
    2337             :   }
    2338          83 :   if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qsp)
    2339             :   {
    2340          41 :     GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
    2341             :                 "First analysis using this auditor, starting from scratch\n");
    2342             :   }
    2343             :   else
    2344             :   {
    2345          42 :     ppc_start = ppc;
    2346          42 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    2347             :                 "Resuming coin audit at %llu/%llu/%llu/%llu/%llu\n",
    2348             :                 (unsigned long long) ppc.last_deposit_serial_id,
    2349             :                 (unsigned long long) ppc.last_melt_serial_id,
    2350             :                 (unsigned long long) ppc.last_refund_serial_id,
    2351             :                 (unsigned long long) ppc.last_withdraw_serial_id,
    2352             :                 (unsigned long long) ppc.last_recoup_refresh_serial_id);
    2353             :   }
    2354             : 
    2355             :   /* setup 'cc' */
    2356          83 :   cc.qs = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
    2357          83 :   cc.denom_summaries = GNUNET_CONTAINER_multihashmap_create (256,
    2358             :                                                              GNUNET_NO);
    2359          83 :   qsx = TALER_ARL_adb->get_balance_summary (TALER_ARL_adb->cls,
    2360             :                                             &TALER_ARL_master_pub,
    2361             :                                             &total_escrow_balance,
    2362             :                                             &total_deposit_fee_income,
    2363             :                                             &total_melt_fee_income,
    2364             :                                             &total_refund_fee_income,
    2365             :                                             &total_risk,
    2366             :                                             &total_recoup_loss,
    2367             :                                             &total_irregular_recoups);
    2368          83 :   if (0 > qsx)
    2369             :   {
    2370           0 :     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qsx);
    2371           0 :     return qsx;
    2372             :   }
    2373             : 
    2374             :   /* process withdrawals */
    2375          83 :   if (0 >
    2376          83 :       (qs = TALER_ARL_edb->select_withdrawals_above_serial_id (
    2377          83 :          TALER_ARL_edb->cls,
    2378             :          ppc.last_withdraw_serial_id,
    2379             :          &withdraw_cb,
    2380             :          &cc)) )
    2381             :   {
    2382           0 :     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
    2383           0 :     return qs;
    2384             :   }
    2385          83 :   if (0 > cc.qs)
    2386           0 :     return cc.qs;
    2387             : 
    2388             :   /* process refunds */
    2389          83 :   if (0 >
    2390          83 :       (qs = TALER_ARL_edb->select_refunds_above_serial_id (
    2391          83 :          TALER_ARL_edb->cls,
    2392             :          ppc.last_refund_serial_id,
    2393             :          &refund_cb,
    2394             :          &cc)))
    2395             :   {
    2396           0 :     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
    2397           0 :     return qs;
    2398             :   }
    2399          83 :   if (0 > cc.qs)
    2400           0 :     return cc.qs;
    2401             : 
    2402             :   /* process recoups */
    2403          83 :   if (0 >
    2404          83 :       (qs = TALER_ARL_edb->select_recoup_refresh_above_serial_id (
    2405          83 :          TALER_ARL_edb->cls,
    2406             :          ppc.last_recoup_refresh_serial_id,
    2407             :          &recoup_refresh_cb,
    2408             :          &cc)))
    2409             :   {
    2410           0 :     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
    2411           0 :     return qs;
    2412             :   }
    2413          83 :   if (0 > cc.qs)
    2414           0 :     return cc.qs;
    2415          83 :   if (0 >
    2416          83 :       (qs = TALER_ARL_edb->select_recoup_above_serial_id (
    2417          83 :          TALER_ARL_edb->cls,
    2418             :          ppc.last_recoup_serial_id,
    2419             :          &recoup_cb,
    2420             :          &cc)))
    2421             :   {
    2422           0 :     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
    2423           0 :     return qs;
    2424             :   }
    2425          83 :   if (0 > cc.qs)
    2426           0 :     return cc.qs;
    2427             : 
    2428             :   /* process refreshs */
    2429          83 :   if (0 >
    2430          83 :       (qs = TALER_ARL_edb->select_refreshes_above_serial_id (
    2431          83 :          TALER_ARL_edb->cls,
    2432             :          ppc.last_melt_serial_id,
    2433             :          &refresh_session_cb,
    2434             :          &cc)))
    2435             :   {
    2436           0 :     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
    2437           0 :     return qs;
    2438             :   }
    2439          83 :   if (0 > cc.qs)
    2440           0 :     return cc.qs;
    2441             : 
    2442             :   /* process deposits */
    2443          83 :   if (0 >
    2444          83 :       (qs = TALER_ARL_edb->select_deposits_above_serial_id (
    2445          83 :          TALER_ARL_edb->cls,
    2446             :          ppc.last_deposit_serial_id,
    2447             :          &deposit_cb,
    2448             :          &cc)))
    2449             :   {
    2450           0 :     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
    2451           0 :     return qs;
    2452             :   }
    2453          83 :   if (0 > cc.qs)
    2454           0 :     return cc.qs;
    2455             : 
    2456             :   /* sync 'cc' back to disk */
    2457          83 :   cc.qs = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
    2458          83 :   GNUNET_CONTAINER_multihashmap_iterate (cc.denom_summaries,
    2459             :                                          &sync_denomination,
    2460             :                                          &cc);
    2461          83 :   GNUNET_CONTAINER_multihashmap_destroy (cc.denom_summaries);
    2462          83 :   if (0 > cc.qs)
    2463             :   {
    2464           0 :     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == cc.qs);
    2465           0 :     return cc.qs;
    2466             :   }
    2467          83 :   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qsx)
    2468          42 :     qs = TALER_ARL_adb->update_balance_summary (TALER_ARL_adb->cls,
    2469             :                                                 &TALER_ARL_master_pub,
    2470             :                                                 &total_escrow_balance,
    2471             :                                                 &total_deposit_fee_income,
    2472             :                                                 &total_melt_fee_income,
    2473             :                                                 &total_refund_fee_income,
    2474             :                                                 &total_risk,
    2475             :                                                 &total_recoup_loss,
    2476             :                                                 &total_irregular_recoups);
    2477             :   else
    2478          41 :     qs = TALER_ARL_adb->insert_balance_summary (TALER_ARL_adb->cls,
    2479             :                                                 &TALER_ARL_master_pub,
    2480             :                                                 &total_escrow_balance,
    2481             :                                                 &total_deposit_fee_income,
    2482             :                                                 &total_melt_fee_income,
    2483             :                                                 &total_refund_fee_income,
    2484             :                                                 &total_risk,
    2485             :                                                 &total_recoup_loss,
    2486             :                                                 &total_irregular_recoups);
    2487          83 :   if (0 >= qs)
    2488             :   {
    2489           0 :     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
    2490           0 :     return qs;
    2491             :   }
    2492             : 
    2493          83 :   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qsp)
    2494          42 :     qs = TALER_ARL_adb->update_auditor_progress_coin (TALER_ARL_adb->cls,
    2495             :                                                       &TALER_ARL_master_pub,
    2496             :                                                       &ppc);
    2497             :   else
    2498          41 :     qs = TALER_ARL_adb->insert_auditor_progress_coin (TALER_ARL_adb->cls,
    2499             :                                                       &TALER_ARL_master_pub,
    2500             :                                                       &ppc);
    2501          83 :   if (0 >= qs)
    2502             :   {
    2503           0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    2504             :                 "Failed to update auditor DB, not recording progress\n");
    2505           0 :     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
    2506           0 :     return qs;
    2507             :   }
    2508          83 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    2509             :               "Concluded coin audit step at %llu/%llu/%llu/%llu/%llu\n",
    2510             :               (unsigned long long) ppc.last_deposit_serial_id,
    2511             :               (unsigned long long) ppc.last_melt_serial_id,
    2512             :               (unsigned long long) ppc.last_refund_serial_id,
    2513             :               (unsigned long long) ppc.last_withdraw_serial_id,
    2514             :               (unsigned long long) ppc.last_recoup_refresh_serial_id);
    2515          83 :   return qs;
    2516             : }
    2517             : 
    2518             : 
    2519             : /**
    2520             :  * Main function that will be run.
    2521             :  *
    2522             :  * @param cls closure
    2523             :  * @param args remaining command-line arguments
    2524             :  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
    2525             :  * @param c configuration
    2526             :  */
    2527             : static void
    2528          83 : run (void *cls,
    2529             :      char *const *args,
    2530             :      const char *cfgfile,
    2531             :      const struct GNUNET_CONFIGURATION_Handle *c)
    2532             : {
    2533             :   (void) cls;
    2534             :   (void) args;
    2535             :   (void) cfgfile;
    2536          83 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    2537             :               "Launching auditor\n");
    2538          83 :   if (GNUNET_OK !=
    2539          83 :       TALER_ARL_init (c))
    2540             :   {
    2541           0 :     global_ret = EXIT_FAILURE;
    2542           0 :     return;
    2543             :   }
    2544          83 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    2545             :               "Starting audit\n");
    2546          83 :   GNUNET_assert (GNUNET_OK ==
    2547             :                  TALER_amount_set_zero (TALER_ARL_currency,
    2548             :                                         &reported_emergency_loss));
    2549          83 :   GNUNET_assert (GNUNET_OK ==
    2550             :                  TALER_amount_set_zero (TALER_ARL_currency,
    2551             :                                         &reported_emergency_risk_by_amount));
    2552          83 :   GNUNET_assert (GNUNET_OK ==
    2553             :                  TALER_amount_set_zero (TALER_ARL_currency,
    2554             :                                         &reported_emergency_risk_by_count));
    2555          83 :   GNUNET_assert (GNUNET_OK ==
    2556             :                  TALER_amount_set_zero (TALER_ARL_currency,
    2557             :                                         &reported_emergency_loss_by_count));
    2558          83 :   GNUNET_assert (GNUNET_OK ==
    2559             :                  TALER_amount_set_zero (TALER_ARL_currency,
    2560             :                                         &total_escrow_balance));
    2561          83 :   GNUNET_assert (GNUNET_OK ==
    2562             :                  TALER_amount_set_zero (TALER_ARL_currency,
    2563             :                                         &total_risk));
    2564          83 :   GNUNET_assert (GNUNET_OK ==
    2565             :                  TALER_amount_set_zero (TALER_ARL_currency,
    2566             :                                         &total_recoup_loss));
    2567          83 :   GNUNET_assert (GNUNET_OK ==
    2568             :                  TALER_amount_set_zero (TALER_ARL_currency,
    2569             :                                         &total_irregular_recoups));
    2570          83 :   GNUNET_assert (GNUNET_OK ==
    2571             :                  TALER_amount_set_zero (TALER_ARL_currency,
    2572             :                                         &total_deposit_fee_income));
    2573          83 :   GNUNET_assert (GNUNET_OK ==
    2574             :                  TALER_amount_set_zero (TALER_ARL_currency,
    2575             :                                         &total_melt_fee_income));
    2576          83 :   GNUNET_assert (GNUNET_OK ==
    2577             :                  TALER_amount_set_zero (TALER_ARL_currency,
    2578             :                                         &total_refund_fee_income));
    2579          83 :   GNUNET_assert (GNUNET_OK ==
    2580             :                  TALER_amount_set_zero (TALER_ARL_currency,
    2581             :                                         &total_arithmetic_delta_plus));
    2582          83 :   GNUNET_assert (GNUNET_OK ==
    2583             :                  TALER_amount_set_zero (TALER_ARL_currency,
    2584             :                                         &total_arithmetic_delta_minus));
    2585          83 :   GNUNET_assert (GNUNET_OK ==
    2586             :                  TALER_amount_set_zero (TALER_ARL_currency,
    2587             :                                         &total_bad_sig_loss));
    2588          83 :   GNUNET_assert (GNUNET_OK ==
    2589             :                  TALER_amount_set_zero (TALER_ARL_currency,
    2590             :                                         &total_refresh_hanging));
    2591          83 :   GNUNET_assert (NULL !=
    2592             :                  (report_emergencies = json_array ()));
    2593          83 :   GNUNET_assert (NULL !=
    2594             :                  (report_emergencies_by_count = json_array ()));
    2595          83 :   GNUNET_assert (NULL !=
    2596             :                  (report_row_inconsistencies = json_array ()));
    2597          83 :   GNUNET_assert (NULL !=
    2598             :                  (report_denominations_without_sigs = json_array ()));
    2599          83 :   GNUNET_assert (NULL !=
    2600             :                  (report_amount_arithmetic_inconsistencies =
    2601             :                     json_array ()));
    2602          83 :   GNUNET_assert (NULL !=
    2603             :                  (report_bad_sig_losses = json_array ()));
    2604          83 :   GNUNET_assert (NULL !=
    2605             :                  (report_refreshs_hanging = json_array ()));
    2606          83 :   if (GNUNET_OK !=
    2607          83 :       TALER_ARL_setup_sessions_and_run (&analyze_coins,
    2608             :                                         NULL))
    2609             :   {
    2610           0 :     global_ret = 1;
    2611           0 :     return;
    2612             :   }
    2613          83 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    2614             :               "Audit complete\n");
    2615          83 :   TALER_ARL_done (
    2616          83 :     GNUNET_JSON_PACK (
    2617             :       TALER_JSON_pack_amount ("total_escrow_balance",
    2618             :                               &total_escrow_balance),
    2619             :       TALER_JSON_pack_amount ("total_active_risk",
    2620             :                               &total_risk),
    2621             :       TALER_JSON_pack_amount ("total_deposit_fee_income",
    2622             :                               &total_deposit_fee_income),
    2623             :       TALER_JSON_pack_amount ("total_melt_fee_income",
    2624             :                               &total_melt_fee_income),
    2625             :       TALER_JSON_pack_amount ("total_refund_fee_income",
    2626             :                               &total_refund_fee_income),
    2627             :       /* Tested in test-auditor.sh #18 */
    2628             :       GNUNET_JSON_pack_array_steal ("emergencies",
    2629             :                                     report_emergencies),
    2630             :       /* Tested in test-auditor.sh #18 */
    2631             :       TALER_JSON_pack_amount ("emergencies_risk_by_amount",
    2632             :                               &reported_emergency_risk_by_amount),
    2633             :       /* Tested in test-auditor.sh #4/#5/#6/#13/#26 */
    2634             :       GNUNET_JSON_pack_array_steal ("bad_sig_losses",
    2635             :                                     report_bad_sig_losses),
    2636             :       /* Tested in test-auditor.sh #4/#5/#6/#13/#26 */
    2637             :       TALER_JSON_pack_amount ("total_bad_sig_loss",
    2638             :                               &total_bad_sig_loss),
    2639             :       /* Tested in test-auditor.sh #31 */
    2640             :       GNUNET_JSON_pack_array_steal ("row_inconsistencies",
    2641             :                                     report_row_inconsistencies),
    2642             :       /* Tested in test-auditor.sh #18 */
    2643             :       GNUNET_JSON_pack_array_steal ("amount_arithmetic_inconsistencies",
    2644             :                                     report_amount_arithmetic_inconsistencies),
    2645             :       TALER_JSON_pack_amount ("total_arithmetic_delta_plus",
    2646             :                               &total_arithmetic_delta_plus),
    2647             :       TALER_JSON_pack_amount ("total_arithmetic_delta_minus",
    2648             :                               &total_arithmetic_delta_minus),
    2649             :       TALER_JSON_pack_amount ("total_refresh_hanging",
    2650             :                               &total_refresh_hanging),
    2651             :       /* Tested in test-auditor.sh #12 */
    2652             :       GNUNET_JSON_pack_array_steal ("refresh_hanging",
    2653             :                                     report_refreshs_hanging),
    2654             :       TALER_JSON_pack_amount ("total_recoup_loss",
    2655             :                               &total_recoup_loss),
    2656             :       /* Tested in test-auditor.sh #18 */
    2657             :       GNUNET_JSON_pack_array_steal ("emergencies_by_count",
    2658             :                                     report_emergencies_by_count),
    2659             :       /* Tested in test-auditor.sh #18 */
    2660             :       TALER_JSON_pack_amount ("emergencies_risk_by_count",
    2661             :                               &reported_emergency_risk_by_count),
    2662             :       /* Tested in test-auditor.sh #18 */
    2663             :       TALER_JSON_pack_amount ("emergencies_loss",
    2664             :                               &reported_emergency_loss),
    2665             :       /* Tested in test-auditor.sh #18 */
    2666             :       TALER_JSON_pack_amount ("emergencies_loss_by_count",
    2667             :                               &reported_emergency_loss_by_count),
    2668             :       GNUNET_JSON_pack_uint64 ("start_ppc_withdraw_serial_id",
    2669             :                                ppc_start.last_withdraw_serial_id),
    2670             :       GNUNET_JSON_pack_uint64 ("start_ppc_deposit_serial_id",
    2671             :                                ppc_start.last_deposit_serial_id),
    2672             :       GNUNET_JSON_pack_uint64 ("start_ppc_melt_serial_id",
    2673             :                                ppc_start.last_melt_serial_id),
    2674             :       GNUNET_JSON_pack_uint64 ("start_ppc_refund_serial_id",
    2675             :                                ppc_start.last_refund_serial_id),
    2676             :       GNUNET_JSON_pack_uint64 ("start_ppc_recoup_serial_id",
    2677             :                                ppc_start.last_recoup_serial_id),
    2678             :       GNUNET_JSON_pack_uint64 ("start_ppc_recoup_refresh_serial_id",
    2679             :                                ppc_start.
    2680             :                                last_recoup_refresh_serial_id),
    2681             :       GNUNET_JSON_pack_uint64 ("end_ppc_withdraw_serial_id",
    2682             :                                ppc.last_withdraw_serial_id),
    2683             :       GNUNET_JSON_pack_uint64 ("end_ppc_deposit_serial_id",
    2684             :                                ppc.last_deposit_serial_id),
    2685             :       GNUNET_JSON_pack_uint64 ("end_ppc_melt_serial_id",
    2686             :                                ppc.last_melt_serial_id),
    2687             :       GNUNET_JSON_pack_uint64 ("end_ppc_refund_serial_id",
    2688             :                                ppc.last_refund_serial_id),
    2689             :       GNUNET_JSON_pack_uint64 ("end_ppc_recoup_serial_id",
    2690             :                                ppc.last_recoup_serial_id),
    2691             :       GNUNET_JSON_pack_uint64 ("end_ppc_recoup_refresh_serial_id",
    2692             :                                ppc.last_recoup_refresh_serial_id),
    2693             :       TALER_JSON_pack_time_abs_human ("auditor_start_time",
    2694             :                                       start_time),
    2695             :       TALER_JSON_pack_time_abs_human ("auditor_end_time",
    2696             :                                       GNUNET_TIME_absolute_get ()),
    2697             :       TALER_JSON_pack_amount ("total_irregular_recoups",
    2698             :                               &total_irregular_recoups),
    2699             :       GNUNET_JSON_pack_array_steal ("unsigned_denominations",
    2700             :                                     report_denominations_without_sigs)));
    2701             : }
    2702             : 
    2703             : 
    2704             : /**
    2705             :  * The main function to audit operations on coins.
    2706             :  *
    2707             :  * @param argc number of arguments from the command line
    2708             :  * @param argv command line arguments
    2709             :  * @return 0 ok, 1 on error
    2710             :  */
    2711             : int
    2712          83 : main (int argc,
    2713             :       char *const *argv)
    2714             : {
    2715          83 :   const struct GNUNET_GETOPT_CommandLineOption options[] = {
    2716          83 :     GNUNET_GETOPT_option_flag ('i',
    2717             :                                "internal",
    2718             :                                "perform checks only applicable for exchange-internal audits",
    2719             :                                &internal_checks),
    2720          83 :     GNUNET_GETOPT_option_base32_auto ('m',
    2721             :                                       "exchange-key",
    2722             :                                       "KEY",
    2723             :                                       "public key of the exchange (Crockford base32 encoded)",
    2724             :                                       &TALER_ARL_master_pub),
    2725          83 :     GNUNET_GETOPT_option_timetravel ('T',
    2726             :                                      "timetravel"),
    2727             :     GNUNET_GETOPT_OPTION_END
    2728             :   };
    2729             :   enum GNUNET_GenericReturnValue ret;
    2730             : 
    2731             :   /* force linker to link against libtalerutil; if we do
    2732             :      not do this, the linker may "optimize" libtalerutil
    2733             :      away and skip #TALER_OS_init(), which we do need */
    2734          83 :   (void) TALER_project_data_default ();
    2735          83 :   if (GNUNET_OK !=
    2736          83 :       GNUNET_STRINGS_get_utf8_args (argc, argv,
    2737             :                                     &argc, &argv))
    2738           0 :     return EXIT_INVALIDARGUMENT;
    2739          83 :   ret = GNUNET_PROGRAM_run (
    2740             :     argc,
    2741             :     argv,
    2742             :     "taler-helper-auditor-coins",
    2743             :     gettext_noop ("Audit Taler coin processing"),
    2744             :     options,
    2745             :     &run,
    2746             :     NULL);
    2747          83 :   GNUNET_free_nz ((void *) argv);
    2748          83 :   if (GNUNET_SYSERR == ret)
    2749           0 :     return EXIT_INVALIDARGUMENT;
    2750          83 :   if (GNUNET_NO == ret)
    2751           0 :     return EXIT_SUCCESS;
    2752          83 :   return global_ret;
    2753             : }
    2754             : 
    2755             : 
    2756             : /* end of taler-helper-auditor-coins.c */

Generated by: LCOV version 1.14