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 (25670B)


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