exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

report-lib.c (25243B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2016-2020 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/report-lib.c
     18  * @brief helper library to facilitate generation of audit reports
     19  * @author Christian Grothoff
     20  */
     21 #include "report-lib.h"
     22 #include "auditor-database/preflight.h"
     23 #include "auditor-database/start.h"
     24 #include "exchange-database/commit.h"
     25 #include "exchange-database/get_denomination_by_serial.h"
     26 #include "exchange-database/get_denomination_info.h"
     27 #include "exchange-database/iterate_denomination_info.h"
     28 #include "exchange-database/preflight.h"
     29 #include "exchange-database/rollback.h"
     30 #include "exchange-database/start.h"
     31 
     32 /**
     33  * Handle to access the exchange's database.
     34  */
     35 struct TALER_EXCHANGEDB_PostgresContext *TALER_ARL_edb;
     36 
     37 /**
     38  * Which currency are we doing the audit for?
     39  */
     40 char *TALER_ARL_currency;
     41 
     42 /**
     43  * How many fractional digits does the currency use?
     44  */
     45 struct TALER_Amount TALER_ARL_currency_round_unit;
     46 
     47 /**
     48  * Our configuration.
     49  */
     50 const struct GNUNET_CONFIGURATION_Handle *TALER_ARL_cfg;
     51 
     52 /**
     53  * Handle to access the auditor's database.
     54  */
     55 struct TALER_AUDITORDB_PostgresContext *TALER_ARL_adb;
     56 
     57 /**
     58  * Master public key of the exchange to audit.
     59  */
     60 struct TALER_MasterPublicKeyP TALER_ARL_master_pub;
     61 
     62 /**
     63  * Public key of the auditor.
     64  */
     65 struct TALER_AuditorPublicKeyP TALER_ARL_auditor_pub;
     66 
     67 /**
     68  * REST API endpoint of the auditor.
     69  */
     70 char *TALER_ARL_auditor_url;
     71 
     72 /**
     73  * REST API endpoint of the exchange.
     74  */
     75 char *TALER_ARL_exchange_url;
     76 
     77 /**
     78  * At what time did the auditor process start?
     79  */
     80 struct GNUNET_TIME_Absolute start_time;
     81 
     82 /**
     83  * Results about denominations, cached per-transaction, maps denomination pub hashes
     84  * to `const struct TALER_EXCHANGEDB_DenominationKeyInformation`.
     85  */
     86 static struct GNUNET_CONTAINER_MultiHashMap *denominations;
     87 
     88 /**
     89  * Results about denominations, cached per-transaction, maps row/serial ID's
     90  * to `const struct TALER_EXCHANGEDB_DenominationKeyInformation`.
     91  */
     92 static struct GNUNET_CONTAINER_MultiUuidmap *denominations_by_serial;
     93 
     94 /**
     95  * Helper to convert a serial/row id to a uuid for the lookup
     96  * in a uuid hash table.
     97  *
     98  * @param serial serial id of entry
     99  * @param[out] uuid uuid to write
    100  */
    101 static void
    102 serial_to_uuid (
    103   uint64_t serial,
    104   struct GNUNET_Uuid *uuid)
    105 {
    106   uuid->value[0] = serial;
    107   uuid->value[1] = serial >> 32;
    108   uuid->value[2] = 0;
    109   uuid->value[3] = 0;
    110 }
    111 
    112 
    113 /**
    114  * Function called with the results of iterate_denomination_info(),
    115  * or directly (!).  Used to check and add the respective denomination
    116  * to our hash table.
    117  *
    118  * @param cls closure, NULL
    119  * @param denom_serial table row of the denomaination
    120  * @param denom_pub public key, sometimes NULL (!)
    121  * @param issue issuing information with value, fees and other info about the denomination.
    122  */
    123 static void
    124 add_denomination (
    125   void *cls,
    126   uint64_t denom_serial,
    127   const struct TALER_DenominationPublicKey *denom_pub,
    128   const struct TALER_EXCHANGEDB_DenominationKeyInformation *issue)
    129 {
    130   (void) cls;
    131   (void) denom_pub;
    132   if (NULL !=
    133       GNUNET_CONTAINER_multihashmap_get (denominations,
    134                                          &issue->denom_hash.hash))
    135     return; /* value already known */
    136 #if GNUNET_EXTRA_LOGGING >= 1
    137   {
    138     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    139                 "Tracking denomination `%s' (%s)\n",
    140                 GNUNET_h2s (&issue->denom_hash.hash),
    141                 TALER_amount2s (&issue->value));
    142     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    143                 "Withdraw fee is %s\n",
    144                 TALER_amount2s (&issue->fees.withdraw));
    145     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    146                 "Start time is %s\n",
    147                 GNUNET_TIME_timestamp2s (issue->start));
    148     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    149                 "Expire deposit time is %s\n",
    150                 GNUNET_TIME_timestamp2s (issue->expire_deposit));
    151   }
    152 #endif
    153   {
    154     struct TALER_EXCHANGEDB_DenominationKeyInformation *i;
    155     struct GNUNET_Uuid uuid;
    156 
    157     i = GNUNET_new (struct TALER_EXCHANGEDB_DenominationKeyInformation);
    158     *i = *issue;
    159     GNUNET_assert (GNUNET_OK ==
    160                    GNUNET_CONTAINER_multihashmap_put (denominations,
    161                                                       &issue->denom_hash.hash,
    162                                                       i,
    163                                                       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
    164     serial_to_uuid (denom_serial, &uuid);
    165     GNUNET_assert (GNUNET_OK ==
    166                    GNUNET_CONTAINER_multiuuidmap_put (denominations_by_serial,
    167                                                       &uuid,
    168                                                       i,
    169                                                       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
    170   }
    171 }
    172 
    173 
    174 enum GNUNET_DB_QueryStatus
    175 TALER_ARL_get_denomination_info_by_hash (
    176   const struct TALER_DenominationHashP *dh,
    177   const struct TALER_EXCHANGEDB_DenominationKeyInformation **issuep)
    178 {
    179   enum GNUNET_DB_QueryStatus qs;
    180 
    181   if (NULL == denominations)
    182   {
    183     denominations = GNUNET_CONTAINER_multihashmap_create (256,
    184                                                           GNUNET_NO);
    185     if (NULL  == denominations_by_serial)
    186       denominations_by_serial = GNUNET_CONTAINER_multiuuidmap_create (256,
    187                                                                       GNUNET_NO)
    188       ;
    189 
    190     qs = TALER_EXCHANGEDB_iterate_denomination_info (TALER_ARL_edb,
    191                                                      &add_denomination,
    192                                                      NULL);
    193     if (0 > qs)
    194     {
    195       GNUNET_break (0);
    196       *issuep = NULL;
    197       return qs;
    198     }
    199   }
    200   {
    201     const struct TALER_EXCHANGEDB_DenominationKeyInformation *i;
    202 
    203     i = GNUNET_CONTAINER_multihashmap_get (denominations,
    204                                            &dh->hash);
    205     if (NULL != i)
    206     {
    207       /* cache hit */
    208       *issuep = i;
    209       return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
    210     }
    211   }
    212   /* maybe database changed since we last iterated, give it one more shot */
    213   {
    214     struct TALER_EXCHANGEDB_DenominationKeyInformation issue;
    215     uint64_t denom_serial;
    216 
    217     qs = TALER_EXCHANGEDB_get_denomination_info (TALER_ARL_edb,
    218                                                  dh,
    219                                                  &denom_serial,
    220                                                  &issue);
    221     if (qs <= 0)
    222     {
    223       GNUNET_break (qs >= 0);
    224       if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
    225         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    226                     "Denomination %s not found\n",
    227                     TALER_B2S (dh));
    228       return qs;
    229     }
    230 
    231     add_denomination (NULL,
    232                       denom_serial,
    233                       NULL,
    234                       &issue);
    235   }
    236   {
    237     const struct TALER_EXCHANGEDB_DenominationKeyInformation *i;
    238 
    239     i = GNUNET_CONTAINER_multihashmap_get (denominations,
    240                                            &dh->hash);
    241     if (NULL != i)
    242     {
    243       /* cache hit */
    244       *issuep = i;
    245       return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
    246     }
    247   }
    248   /* We found more keys, but not the denomination we are looking for :-( */
    249   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    250               "Denomination %s not found\n",
    251               TALER_B2S (dh));
    252   return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
    253 }
    254 
    255 
    256 enum GNUNET_DB_QueryStatus
    257 TALER_ARL_get_denomination_info_by_serial (
    258   uint64_t denom_serial,
    259   const struct TALER_EXCHANGEDB_DenominationKeyInformation **issuep)
    260 {
    261   enum GNUNET_DB_QueryStatus qs;
    262   struct GNUNET_Uuid uuid;
    263 
    264   serial_to_uuid (denom_serial,
    265                   &uuid);
    266   if (NULL == denominations_by_serial)
    267   {
    268     denominations_by_serial = GNUNET_CONTAINER_multiuuidmap_create (256,
    269                                                                     GNUNET_NO);
    270     if (NULL == denominations)
    271       denominations = GNUNET_CONTAINER_multihashmap_create (256,
    272                                                             GNUNET_NO);
    273 
    274     qs = TALER_EXCHANGEDB_iterate_denomination_info (TALER_ARL_edb,
    275                                                      &add_denomination,
    276                                                      NULL);
    277     if (0 > qs)
    278     {
    279       GNUNET_break (0);
    280       *issuep = NULL;
    281       return qs;
    282     }
    283   }
    284   {
    285     const struct TALER_EXCHANGEDB_DenominationKeyInformation *i;
    286 
    287     i = GNUNET_CONTAINER_multiuuidmap_get (denominations_by_serial,
    288                                            &uuid);
    289     if (NULL != i)
    290     {
    291       /* cache hit */
    292       *issuep = i;
    293       return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
    294     }
    295   }
    296   /* maybe database changed since we last iterated, give it one more shot */
    297   {
    298     struct TALER_EXCHANGEDB_DenominationKeyInformation issue;
    299 
    300     qs = TALER_EXCHANGEDB_get_denomination_by_serial (TALER_ARL_edb,
    301                                                       denom_serial,
    302                                                       &issue);
    303     if (qs <= 0)
    304     {
    305       GNUNET_break (qs >= 0);
    306       if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
    307         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    308                     "Denomination with serial %lu not found\n",
    309                     denom_serial);
    310       return qs;
    311     }
    312 
    313     add_denomination (NULL,
    314                       denom_serial,
    315                       NULL,
    316                       &issue);
    317   }
    318 
    319   {
    320     const struct TALER_EXCHANGEDB_DenominationKeyInformation *i;
    321 
    322     i = GNUNET_CONTAINER_multiuuidmap_get (denominations_by_serial,
    323                                            &uuid);
    324     if (NULL != i)
    325     {
    326       /* cache hit */
    327       *issuep = i;
    328       return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
    329     }
    330   }
    331   /* We found more keys, but not the denomination we are looking for :-( */
    332   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    333               "Denomination with serial %lu not found\n",
    334               denom_serial);
    335   return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
    336 }
    337 
    338 
    339 enum GNUNET_DB_QueryStatus
    340 TALER_ARL_get_denomination_info (
    341   const struct TALER_DenominationPublicKey *denom_pub,
    342   const struct TALER_EXCHANGEDB_DenominationKeyInformation **issue,
    343   struct TALER_DenominationHashP *dh)
    344 {
    345   struct TALER_DenominationHashP hc;
    346 
    347   if (NULL == dh)
    348     dh = &hc;
    349   TALER_denom_pub_hash (denom_pub,
    350                         dh);
    351   return TALER_ARL_get_denomination_info_by_hash (dh,
    352                                                   issue);
    353 }
    354 
    355 
    356 /**
    357  * Perform the given @a analysis within a transaction scope.
    358  * Commit on success.
    359  *
    360  * @param analysis analysis to run
    361  * @param analysis_cls closure for @a analysis
    362  * @return #GNUNET_OK if @a analysis successfully committed,
    363  *         #GNUNET_NO if we had an error on commit (retry may help)
    364  *         #GNUNET_SYSERR on hard errors
    365  */
    366 static enum GNUNET_GenericReturnValue
    367 transact (TALER_ARL_Analysis analysis,
    368           void *analysis_cls)
    369 {
    370   int ret;
    371   enum GNUNET_DB_QueryStatus qs;
    372 
    373   ret = TALER_AUDITORDB_start (TALER_ARL_adb,
    374                                "auditor-analysis");
    375   if (GNUNET_OK != ret)
    376   {
    377     GNUNET_break (0);
    378     return GNUNET_SYSERR;
    379   }
    380   if (GNUNET_OK !=
    381       TALER_EXCHANGEDB_preflight (TALER_ARL_edb))
    382   {
    383     GNUNET_break (0);
    384     return GNUNET_SYSERR;
    385   }
    386   ret = TALER_EXCHANGEDB_start (TALER_ARL_edb,
    387                                 "auditor");
    388   if (GNUNET_OK != ret)
    389   {
    390     GNUNET_break (0);
    391     TALER_EXCHANGEDB_rollback (TALER_ARL_edb);
    392     return GNUNET_SYSERR;
    393   }
    394   qs = analysis (analysis_cls);
    395   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
    396   {
    397     qs = TALER_EXCHANGEDB_commit (TALER_ARL_edb);
    398     if (0 > qs)
    399     {
    400       GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
    401       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    402                   "Exchange DB commit failed, rolling back transaction\n");
    403       TALER_AUDITORDB_rollback (TALER_ARL_adb);
    404     }
    405     else
    406     {
    407       qs = TALER_AUDITORDB_commit (TALER_ARL_adb);
    408       if (0 > qs)
    409       {
    410         GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
    411         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    412                     "Auditor DB commit failed!\n");
    413       }
    414     }
    415   }
    416   else
    417   {
    418     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    419                 "Processing failed; rolling back transaction\n");
    420     TALER_AUDITORDB_rollback (TALER_ARL_adb);
    421     TALER_EXCHANGEDB_rollback (TALER_ARL_edb);
    422   }
    423   switch (qs)
    424   {
    425   case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
    426     return GNUNET_OK;
    427   case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
    428     return GNUNET_OK;
    429   case GNUNET_DB_STATUS_SOFT_ERROR:
    430     return GNUNET_NO;
    431   case GNUNET_DB_STATUS_HARD_ERROR:
    432     return GNUNET_SYSERR;
    433   }
    434   return GNUNET_OK;
    435 }
    436 
    437 
    438 enum GNUNET_GenericReturnValue
    439 TALER_ARL_setup_sessions_and_run (TALER_ARL_Analysis ana,
    440                                   void *ana_cls)
    441 {
    442   enum GNUNET_DB_QueryStatus qs;
    443 
    444   if (GNUNET_SYSERR ==
    445       TALER_EXCHANGEDB_preflight (TALER_ARL_edb))
    446   {
    447     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    448                 "Failed to initialize exchange connection.\n");
    449     return GNUNET_SYSERR;
    450   }
    451   if (GNUNET_SYSERR ==
    452       TALER_AUDITORDB_preflight (TALER_ARL_adb))
    453   {
    454     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    455                 "Failed to initialize auditor session.\n");
    456     return GNUNET_SYSERR;
    457   }
    458 
    459   for (unsigned int retries=0; retries<3; retries++)
    460   {
    461     qs = transact (ana,
    462                    ana_cls);
    463     if (GNUNET_DB_STATUS_SOFT_ERROR != qs)
    464       break;
    465   }
    466   if (qs < 0)
    467     return GNUNET_SYSERR;
    468   return GNUNET_OK;
    469 }
    470 
    471 
    472 void
    473 TALER_ARL_amount_add_ (struct TALER_Amount *sum,
    474                        const struct TALER_Amount *a1,
    475                        const struct TALER_Amount *a2,
    476                        const char *filename,
    477                        const char *functionname,
    478                        unsigned int line)
    479 {
    480   enum TALER_AmountArithmeticResult aar;
    481   const char *msg;
    482   char *a2s;
    483 
    484   aar = TALER_amount_add (sum,
    485                           a1,
    486                           a2);
    487   if (aar >= 0)
    488     return;
    489   switch (aar)
    490   {
    491   case TALER_AAR_INVALID_RESULT_OVERFLOW:
    492     msg =
    493       "arithmetic overflow in amount addition (likely the database is corrupt, see manual)";
    494     break;
    495   case TALER_AAR_INVALID_NORMALIZATION_FAILED:
    496     msg =
    497       "normalization failed in amount addition (likely the database is corrupt, see manual)";
    498     break;
    499   case TALER_AAR_INVALID_CURRENCIES_INCOMPATIBLE:
    500     msg =
    501       "incompatible currencies in amount addition (likely bad configuration and auditor code missing a sanity check, see manual)";
    502     break;
    503   default:
    504     GNUNET_assert (0); /* should be impossible */
    505   }
    506   a2s = TALER_amount_to_string (a2);
    507   fprintf (stderr,
    508            "Aborting audit due to fatal error in function %s at %s:%d trying to add %s to %s: %s\n",
    509            functionname,
    510            filename,
    511            line,
    512            TALER_amount2s (a1),
    513            a2s,
    514            msg);
    515   GNUNET_free (a2s);
    516   exit (42);
    517 }
    518 
    519 
    520 void
    521 TALER_ARL_amount_subtract_ (struct TALER_Amount *diff,
    522                             const struct TALER_Amount *a1,
    523                             const struct TALER_Amount *a2,
    524                             const char *filename,
    525                             const char *functionname,
    526                             unsigned int line)
    527 {
    528   enum TALER_AmountArithmeticResult aar;
    529   const char *msg;
    530   char *a2s;
    531 
    532   aar = TALER_amount_subtract (diff,
    533                                a1,
    534                                a2);
    535   if (aar >= 0)
    536     return;
    537   switch (aar)
    538   {
    539   case TALER_AAR_INVALID_NEGATIVE_RESULT:
    540     msg =
    541       "negative result in amount subtraction (likely the database is corrupt, see manual)";
    542     break;
    543   case TALER_AAR_INVALID_NORMALIZATION_FAILED:
    544     msg =
    545       "normalization failed in amount subtraction (likely the database is corrupt, see manual)";
    546     break;
    547   case TALER_AAR_INVALID_CURRENCIES_INCOMPATIBLE:
    548     msg =
    549       "currencies incompatible in amount subtraction (likely bad configuration and auditor code missing a sanity check, see manual)";
    550     break;
    551   default:
    552     GNUNET_assert (0); /* should be impossible */
    553   }
    554   a2s = TALER_amount_to_string (a2);
    555   fprintf (stderr,
    556            "Aborting audit due to fatal error in function %s at %s:%d trying to subtract %s from %s: %s\n",
    557            functionname,
    558            filename,
    559            line,
    560            a2s,
    561            TALER_amount2s (a1),
    562            msg);
    563   GNUNET_free (a2s);
    564   exit (42);
    565 }
    566 
    567 
    568 enum TALER_ARL_SubtractionResult
    569 TALER_ARL_amount_subtract_neg_ (struct TALER_Amount *diff,
    570                                 const struct TALER_Amount *a1,
    571                                 const struct TALER_Amount *a2,
    572                                 const char *filename,
    573                                 const char *functionname,
    574                                 unsigned int line)
    575 {
    576   enum TALER_AmountArithmeticResult aar;
    577   const char *msg;
    578   char *a2s;
    579 
    580   aar = TALER_amount_subtract (diff,
    581                                a1,
    582                                a2);
    583   switch (aar)
    584   {
    585   case TALER_AAR_RESULT_POSITIVE:
    586     return TALER_ARL_SR_POSITIVE;
    587   case TALER_AAR_RESULT_ZERO:
    588     return TALER_ARL_SR_ZERO;
    589   case TALER_AAR_INVALID_NEGATIVE_RESULT:
    590     return TALER_ARL_SR_INVALID_NEGATIVE;
    591   case TALER_AAR_INVALID_NORMALIZATION_FAILED:
    592     msg =
    593       "normalization failed in amount subtraction (likely the database is corrupt, see manual)";
    594     break;
    595   case TALER_AAR_INVALID_CURRENCIES_INCOMPATIBLE:
    596     msg =
    597       "currencies incompatible in amount subtraction (likely bad configuration and auditor code missing a sanity check, see manual)";
    598     break;
    599   default:
    600     GNUNET_assert (0); /* should be impossible */
    601   }
    602   a2s = TALER_amount_to_string (a2);
    603   fprintf (stderr,
    604            "Aborting audit due to fatal error in function %s at %s:%d trying to subtract %s from %s: %s\n",
    605            functionname,
    606            filename,
    607            line,
    608            a2s,
    609            TALER_amount2s (a1),
    610            msg);
    611   GNUNET_free (a2s);
    612   exit (42);
    613 }
    614 
    615 
    616 enum GNUNET_GenericReturnValue
    617 TALER_ARL_init (const struct GNUNET_CONFIGURATION_Handle *c)
    618 {
    619   TALER_ARL_cfg = c;
    620   start_time = GNUNET_TIME_absolute_get ();
    621 
    622   if (GNUNET_OK !=
    623       GNUNET_CONFIGURATION_get_value_string (TALER_ARL_cfg,
    624                                              "auditor",
    625                                              "BASE_URL",
    626                                              &TALER_ARL_auditor_url))
    627   {
    628     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    629                                "auditor",
    630                                "BASE_URL");
    631     return GNUNET_SYSERR;
    632   }
    633   if (GNUNET_OK !=
    634       GNUNET_CONFIGURATION_get_value_string (TALER_ARL_cfg,
    635                                              "exchange",
    636                                              "BASE_URL",
    637                                              &TALER_ARL_exchange_url))
    638   {
    639     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    640                                "exchange",
    641                                "BASE_URL");
    642     return GNUNET_SYSERR;
    643   }
    644 
    645   if (GNUNET_is_zero (&TALER_ARL_master_pub))
    646   {
    647     /* -m option not given, try configuration */
    648     char *master_public_key_str;
    649 
    650     if (GNUNET_OK !=
    651         GNUNET_CONFIGURATION_get_value_string (TALER_ARL_cfg,
    652                                                "exchange",
    653                                                "MASTER_PUBLIC_KEY",
    654                                                &master_public_key_str))
    655     {
    656       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    657                   "Pass option -m or set MASTER_PUBLIC_KEY in the configuration!\n");
    658       GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    659                                  "exchange",
    660                                  "MASTER_PUBLIC_KEY");
    661       return GNUNET_SYSERR;
    662     }
    663     if (GNUNET_OK !=
    664         GNUNET_CRYPTO_eddsa_public_key_from_string (
    665           master_public_key_str,
    666           strlen (master_public_key_str),
    667           &TALER_ARL_master_pub.eddsa_pub))
    668     {
    669       GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
    670                                  "exchange",
    671                                  "MASTER_PUBLIC_KEY",
    672                                  "invalid key");
    673       GNUNET_free (master_public_key_str);
    674       return GNUNET_SYSERR;
    675     }
    676     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    677                 "Running auditor against exchange master public key `%s'\n",
    678                 master_public_key_str);
    679     GNUNET_free (master_public_key_str);
    680   } /* end of -m not given */
    681 
    682   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    683               "Taler auditor running for exchange master public key %s\n",
    684               TALER_B2S (&TALER_ARL_master_pub));
    685 
    686   if (GNUNET_is_zero (&TALER_ARL_auditor_pub))
    687   {
    688     char *auditor_public_key_str;
    689 
    690     if (GNUNET_OK ==
    691         GNUNET_CONFIGURATION_get_value_string (c,
    692                                                "auditor",
    693                                                "PUBLIC_KEY",
    694                                                &auditor_public_key_str))
    695     {
    696       if (GNUNET_OK !=
    697           GNUNET_CRYPTO_eddsa_public_key_from_string (
    698             auditor_public_key_str,
    699             strlen (auditor_public_key_str),
    700             &TALER_ARL_auditor_pub.eddsa_pub))
    701       {
    702         GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
    703                                    "auditor",
    704                                    "PUBLIC_KEY",
    705                                    "invalid key");
    706         GNUNET_free (auditor_public_key_str);
    707         return GNUNET_SYSERR;
    708       }
    709       GNUNET_free (auditor_public_key_str);
    710     }
    711   }
    712 
    713   if (GNUNET_is_zero (&TALER_ARL_auditor_pub))
    714   {
    715     /* public key not configured */
    716     /* try loading private key and deriving public key */
    717     char *fn;
    718 
    719     if (GNUNET_OK ==
    720         GNUNET_CONFIGURATION_get_value_filename (c,
    721                                                  "auditor",
    722                                                  "AUDITOR_PRIV_FILE",
    723                                                  &fn))
    724     {
    725       struct TALER_AuditorPrivateKeyP auditor_priv;
    726 
    727       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    728                   "Loading offline private key from `%s' to get auditor public key\n",
    729                   fn);
    730       if (GNUNET_OK ==
    731           GNUNET_CRYPTO_eddsa_key_from_file (fn,
    732                                              GNUNET_NO, /* do NOT create it! */
    733                                              &auditor_priv.eddsa_priv))
    734       {
    735         GNUNET_CRYPTO_eddsa_key_get_public (&auditor_priv.eddsa_priv,
    736                                             &TALER_ARL_auditor_pub.eddsa_pub);
    737       }
    738       GNUNET_free (fn);
    739     }
    740   }
    741 
    742   if (GNUNET_is_zero (&TALER_ARL_auditor_pub))
    743   {
    744     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    745                                "auditor",
    746                                "PUBLIC_KEY/AUDITOR_PRIV_FILE");
    747     return GNUNET_SYSERR;
    748   }
    749 
    750   if (GNUNET_OK !=
    751       TALER_config_get_currency (TALER_ARL_cfg,
    752                                  "exchange",
    753                                  &TALER_ARL_currency))
    754   {
    755     return GNUNET_SYSERR;
    756   }
    757   {
    758     if ( (GNUNET_OK !=
    759           TALER_config_get_amount (TALER_ARL_cfg,
    760                                    "exchange",
    761                                    "CURRENCY_ROUND_UNIT",
    762                                    &TALER_ARL_currency_round_unit)) ||
    763          ( (0 != TALER_ARL_currency_round_unit.fraction) &&
    764            (0 != TALER_ARL_currency_round_unit.value) ) )
    765     {
    766       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    767                   "Need non-zero value in section `exchange' under `CURRENCY_ROUND_UNIT'\n");
    768       return GNUNET_SYSERR;
    769     }
    770   }
    771   if (NULL ==
    772       (TALER_ARL_edb = TALER_EXCHANGEDB_connect (TALER_ARL_cfg)))
    773   {
    774     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    775                 "Failed to initialize exchange database plugin.\n");
    776     TALER_ARL_done ();
    777     return GNUNET_SYSERR;
    778   }
    779   if (NULL ==
    780       (TALER_ARL_adb = TALER_AUDITORDB_connect (TALER_ARL_cfg)))
    781   {
    782     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    783                 "Failed to initialize auditor database plugin.\n");
    784     TALER_ARL_done ();
    785     return GNUNET_SYSERR;
    786   }
    787   if (GNUNET_SYSERR ==
    788       TALER_AUDITORDB_preflight (TALER_ARL_adb))
    789   {
    790     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    791                 "Failed to start session with auditor database.\n");
    792     TALER_ARL_done ();
    793     return GNUNET_SYSERR;
    794   }
    795   return GNUNET_OK;
    796 }
    797 
    798 
    799 void
    800 TALER_ARL_done ()
    801 {
    802   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    803               "Audit complete\n");
    804   if (NULL != TALER_ARL_adb)
    805   {
    806     TALER_AUDITORDB_disconnect (TALER_ARL_adb);
    807     TALER_ARL_adb = NULL;
    808   }
    809   if (NULL != TALER_ARL_edb)
    810   {
    811     TALER_EXCHANGEDB_disconnect (TALER_ARL_edb);
    812     TALER_ARL_edb = NULL;
    813   }
    814   GNUNET_free (TALER_ARL_exchange_url);
    815   GNUNET_free (TALER_ARL_auditor_url);
    816 }
    817 
    818 
    819 /* end of report-lib.c */