exchange

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

test_exchangedb.c (94093B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2014-2025 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify it under the
      6   terms of the GNU General 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 General Public License for more details.
     12 
     13   You should have received a copy of the GNU General Public License along with
     14   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
     15 */
     16 /**
     17  * @file exchangedb/test_exchangedb.c
     18  * @brief test cases for DB interaction functions
     19  * @author Sree Harsha Totakura
     20  * @author Christian Grothoff
     21  * @author Marcello Stanisci
     22  * @author Özgür Kesim
     23  */
     24 #include "exchangedb_lib.h"
     25 #include "taler/taler_json_lib.h"
     26 #include "exchangedb_lib.h"
     27 
     28 
     29 /**
     30  * @brief Information we keep for a withdrawn coin to reproduce
     31  * the /batch-withdraw operation if needed, and to have proof
     32  * that a reserve was drained by this amount.
     33  */
     34 struct TALER_EXCHANGEDB_CollectableBlindcoin
     35 {
     36 
     37   /**
     38    * Our (blinded) signature over the (blinded) coin.
     39    */
     40   struct TALER_BlindedDenominationSignature sig;
     41 
     42   /**
     43    * Hash of the denomination key (which coin was generated).
     44    */
     45   struct TALER_DenominationHashP denom_pub_hash;
     46 
     47   /**
     48    * Value of the coin being exchangeed (matching the denomination key)
     49    * plus the transaction fee.  We include this in what is being
     50    * signed so that we can verify a reserve's remaining total balance
     51    * without needing to access the respective denomination key
     52    * information each time.
     53    */
     54   struct TALER_Amount amount_with_fee;
     55 
     56   /**
     57    * Withdrawal fee charged by the exchange.  This must match the Exchange's
     58    * denomination key's withdrawal fee.  If the client puts in an
     59    * invalid withdrawal fee (too high or too low) that does not match
     60    * the Exchange's denomination key, the withdraw operation is invalid
     61    * and will be rejected by the exchange.  The @e amount_with_fee minus
     62    * the @e withdraw_fee is must match the value of the generated
     63    * coin.  We include this in what is being signed so that we can
     64    * verify a exchange's accounting without needing to access the
     65    * respective denomination key information each time.
     66    */
     67   struct TALER_Amount withdraw_fee;
     68 
     69   /**
     70    * Public key of the reserve that was drained.
     71    */
     72   struct TALER_ReservePublicKeyP reserve_pub;
     73 
     74   /**
     75    * Hash over the blinded message, needed to verify
     76    * the @e reserve_sig.
     77    */
     78   struct TALER_BlindedCoinHashP h_coin_envelope;
     79 
     80   /**
     81    * Signature confirming the withdrawal, matching @e reserve_pub,
     82    * @e denom_pub and @e h_coin_envelope.
     83    */
     84   struct TALER_ReserveSignatureP reserve_sig;
     85 };
     86 
     87 
     88 /**
     89  * Global result from the testcase.
     90  */
     91 static int result;
     92 
     93 /**
     94  * Report line of error if @a cond is true, and jump to label "drop".
     95  */
     96 #define FAILIF(cond)                            \
     97         do {                                          \
     98           if (! (cond)) { break;}                     \
     99           GNUNET_break (0);                           \
    100           goto drop;                                  \
    101         } while (0)
    102 
    103 
    104 /**
    105  * Initializes @a ptr with random data.
    106  */
    107 #define RND_BLK(ptr)                                                    \
    108         GNUNET_CRYPTO_random_block (ptr, \
    109                                     sizeof (*ptr))
    110 
    111 /**
    112  * Initializes @a ptr with zeros.
    113  */
    114 #define ZR_BLK(ptr) \
    115         memset (ptr, 0, sizeof (*ptr))
    116 
    117 
    118 /**
    119  * Currency we use.  Must match test-exchange-db-*.conf.
    120  */
    121 #define CURRENCY "EUR"
    122 
    123 /**
    124  * Database plugin under test.
    125  */
    126 static struct TALER_EXCHANGEDB_PostgresContext *plugin;
    127 
    128 
    129 /**
    130  * Callback that should never be called.
    131  */
    132 static void
    133 dead_prepare_cb (void *cls,
    134                  uint64_t rowid,
    135                  const char *wire_method,
    136                  const char *buf,
    137                  size_t buf_size)
    138 {
    139   (void) cls;
    140   (void) rowid;
    141   (void) wire_method;
    142   (void) buf;
    143   (void) buf_size;
    144   GNUNET_assert (0);
    145 }
    146 
    147 
    148 /**
    149  * Callback that is called with wire prepare data
    150  * and then marks it as finished.
    151  */
    152 static void
    153 mark_prepare_cb (void *cls,
    154                  uint64_t rowid,
    155                  const char *wire_method,
    156                  const char *buf,
    157                  size_t buf_size)
    158 {
    159   (void) cls;
    160   GNUNET_assert (11 == buf_size);
    161   GNUNET_assert (0 == strcasecmp (wire_method,
    162                                   "testcase"));
    163   GNUNET_assert (0 == memcmp (buf,
    164                               "hello world",
    165                               buf_size));
    166   GNUNET_break (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
    167                 plugin->wire_prepare_data_mark_finished (plugin->cls,
    168                                                          rowid));
    169 }
    170 
    171 
    172 /**
    173  * Test API relating to persisting the wire plugins preparation data.
    174  *
    175  * @return #GNUNET_OK on success
    176  */
    177 static enum GNUNET_GenericReturnValue
    178 test_wire_prepare (void)
    179 {
    180   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
    181           plugin->wire_prepare_data_get (plugin->cls,
    182                                          0,
    183                                          1,
    184                                          &dead_prepare_cb,
    185                                          NULL));
    186   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
    187           plugin->wire_prepare_data_insert (plugin->cls,
    188                                             "testcase",
    189                                             "hello world",
    190                                             11));
    191   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
    192           plugin->wire_prepare_data_get (plugin->cls,
    193                                          0,
    194                                          1,
    195                                          &mark_prepare_cb,
    196                                          NULL));
    197   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
    198           plugin->wire_prepare_data_get (plugin->cls,
    199                                          0,
    200                                          1,
    201                                          &dead_prepare_cb,
    202                                          NULL));
    203   return GNUNET_OK;
    204 drop:
    205   return GNUNET_SYSERR;
    206 }
    207 
    208 
    209 /**
    210  * Checks if the given reserve has the given amount of balance and expiry
    211  *
    212  * @param pub the public key of the reserve
    213  * @param value balance value
    214  * @param fraction balance fraction
    215  * @param currency currency of the reserve
    216  * @return #GNUNET_OK if the given reserve has the same balance and expiration
    217  *           as the given parameters; #GNUNET_SYSERR if not
    218  */
    219 static enum GNUNET_GenericReturnValue
    220 check_reserve (const struct TALER_ReservePublicKeyP *pub,
    221                uint64_t value,
    222                uint32_t fraction,
    223                const char *currency)
    224 {
    225   struct TALER_EXCHANGEDB_Reserve reserve;
    226 
    227   reserve.pub = *pub;
    228   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
    229           plugin->reserves_get (plugin->cls,
    230                                 &reserve));
    231   FAILIF (value != reserve.balance.value);
    232   FAILIF (fraction != reserve.balance.fraction);
    233   FAILIF (0 != strcmp (currency,
    234                        reserve.balance.currency));
    235   return GNUNET_OK;
    236 drop:
    237   return GNUNET_SYSERR;
    238 }
    239 
    240 
    241 struct DenomKeyPair
    242 {
    243   struct TALER_DenominationPrivateKey priv;
    244   struct TALER_DenominationPublicKey pub;
    245 };
    246 
    247 
    248 /**
    249  * Destroy a denomination key pair.  The key is not necessarily removed from the DB.
    250  *
    251  * @param dkp the key pair to destroy
    252  */
    253 static void
    254 destroy_denom_key_pair (struct DenomKeyPair *dkp)
    255 {
    256   TALER_denom_pub_free (&dkp->pub);
    257   TALER_denom_priv_free (&dkp->priv);
    258   GNUNET_free (dkp);
    259 }
    260 
    261 
    262 /**
    263  * Create a denomination key pair by registering the denomination in the DB.
    264  *
    265  * @param size the size of the denomination key
    266  * @param now time to use for key generation, legal expiration will be 3h later.
    267  * @param fees fees to use
    268  * @return the denominaiton key pair; NULL upon error
    269  */
    270 static struct DenomKeyPair *
    271 create_denom_key_pair (unsigned int size,
    272                        struct GNUNET_TIME_Timestamp now,
    273                        const struct TALER_Amount *value,
    274                        const struct TALER_DenomFeeSet *fees)
    275 {
    276   struct DenomKeyPair *dkp;
    277   struct TALER_EXCHANGEDB_DenominationKey dki;
    278   struct TALER_EXCHANGEDB_DenominationKeyInformation issue2;
    279 
    280   dkp = GNUNET_new (struct DenomKeyPair);
    281   GNUNET_assert (GNUNET_OK ==
    282                  TALER_denom_priv_create (&dkp->priv,
    283                                           &dkp->pub,
    284                                           GNUNET_CRYPTO_BSA_RSA,
    285                                           size));
    286   /* Using memset() as fields like master key and signature
    287      are not properly initialized for this test. */
    288   memset (&dki,
    289           0,
    290           sizeof (struct TALER_EXCHANGEDB_DenominationKey));
    291   dki.denom_pub = dkp->pub;
    292   dki.issue.start = now;
    293   dki.issue.expire_withdraw
    294     = GNUNET_TIME_absolute_to_timestamp (
    295         GNUNET_TIME_absolute_add (
    296           now.abs_time,
    297           GNUNET_TIME_UNIT_HOURS));
    298   dki.issue.expire_deposit
    299     = GNUNET_TIME_absolute_to_timestamp (
    300         GNUNET_TIME_absolute_add (
    301           now.abs_time,
    302           GNUNET_TIME_relative_multiply (
    303             GNUNET_TIME_UNIT_HOURS, 2)));
    304   dki.issue.expire_legal
    305     = GNUNET_TIME_absolute_to_timestamp (
    306         GNUNET_TIME_absolute_add (
    307           now.abs_time,
    308           GNUNET_TIME_relative_multiply (
    309             GNUNET_TIME_UNIT_HOURS, 3)));
    310   dki.issue.value = *value;
    311   dki.issue.fees = *fees;
    312   TALER_denom_pub_hash (&dkp->pub,
    313                         &dki.issue.denom_hash);
    314   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
    315       plugin->insert_denomination_info (plugin->cls,
    316                                         &dki.denom_pub,
    317                                         &dki.issue))
    318   {
    319     GNUNET_break (0);
    320     destroy_denom_key_pair (dkp);
    321     return NULL;
    322   }
    323   memset (&issue2, 0, sizeof (issue2));
    324   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
    325       plugin->get_denomination_info (plugin->cls,
    326                                      &dki.issue.denom_hash,
    327                                      NULL,
    328                                      &issue2))
    329   {
    330     GNUNET_break (0);
    331     destroy_denom_key_pair (dkp);
    332     return NULL;
    333   }
    334   if (0 != GNUNET_memcmp (&dki.issue,
    335                           &issue2))
    336   {
    337     GNUNET_break (0);
    338     destroy_denom_key_pair (dkp);
    339     return NULL;
    340   }
    341   return dkp;
    342 }
    343 
    344 
    345 static struct TALER_Amount global_amount;
    346 static struct TALER_Amount global_value;
    347 static struct TALER_DenomFeeSet global_fees;
    348 static struct TALER_Amount fee_closing;
    349 
    350 
    351 /**
    352  * Number of newly minted coins to use in the test.
    353  */
    354 #define MELT_NEW_COINS 5
    355 
    356 /**
    357  * Which index was 'randomly' chosen for the reveal for the test?
    358  */
    359 #define MELT_NOREVEAL_INDEX 1
    360 
    361 /**
    362  * How big do we make the RSA keys?
    363  */
    364 #define RSA_KEY_SIZE 1024
    365 
    366 static struct TALER_EXCHANGEDB_RefreshRevealedCoin *revealed_coins;
    367 
    368 static struct TALER_TransferPrivateKeyP tprivs[TALER_CNC_KAPPA];
    369 
    370 static struct TALER_TransferPublicKeyP tpub;
    371 
    372 
    373 /**
    374  * Function called with information about a refresh order.  This
    375  * one should not be called in a successful test.
    376  *
    377  * @param cls closure
    378  * @param rowid unique serial ID for the row in our database
    379  * @param num_freshcoins size of the @a rrcs array
    380  * @param rrcs array of @a num_freshcoins information about coins to be created
    381  */
    382 static void
    383 never_called_cb (void *cls,
    384                  uint32_t num_freshcoins,
    385                  const struct TALER_EXCHANGEDB_RefreshRevealedCoin *rrcs)
    386 {
    387   (void) cls;
    388   (void) num_freshcoins;
    389   (void) rrcs;
    390   GNUNET_assert (0); /* should never be called! */
    391 }
    392 
    393 
    394 /**
    395  * Function called with information about a refresh order.
    396  * Checks that the response matches what we expect to see.
    397  *
    398  * @param cls closure
    399  * @param rowid unique serial ID for the row in our database
    400  * @param num_freshcoins size of the @a rrcs array
    401  * @param rrcs array of @a num_freshcoins information about coins to be created
    402  */
    403 static void
    404 check_refresh_reveal_cb (
    405   struct TALER_EXCHANGEDB_PostgresContext *pg,
    406   uint32_t num_freshcoins,
    407   const struct TALER_EXCHANGEDB_RefreshRevealedCoin *rrcs)
    408 {
    409   (void) cls;
    410   /* compare the refresh commit coin arrays */
    411   for (unsigned int cnt = 0; cnt < num_freshcoins; cnt++)
    412   {
    413     const struct TALER_EXCHANGEDB_RefreshRevealedCoin *acoin =
    414       &revealed_coins[cnt];
    415     const struct TALER_EXCHANGEDB_RefreshRevealedCoin *bcoin = &rrcs[cnt];
    416 
    417     GNUNET_assert (0 ==
    418                    TALER_blinded_planchet_cmp (&acoin->blinded_planchet,
    419                                                &bcoin->blinded_planchet));
    420     GNUNET_assert (0 ==
    421                    GNUNET_memcmp (&acoin->h_denom_pub,
    422                                   &bcoin->h_denom_pub));
    423   }
    424 }
    425 
    426 
    427 /**
    428  * Counter used in auditor-related db functions. Used to count
    429  * expected rows.
    430  */
    431 static unsigned int auditor_row_cnt;
    432 
    433 
    434 /**
    435  * Function called with details about coins that were melted,
    436  * with the goal of auditing the refresh's execution.
    437  *
    438  *
    439  * @param cls closure
    440  * @param rowid unique serial ID for the refresh session in our DB
    441  * @param denom_pub denomination of the @a coin_pub
    442  * @param h_age_commitment hash of age commitment that went into the minting, may be NULL
    443  * @param coin_pub public key of the coin
    444  * @param coin_sig signature from the coin
    445  * @param amount_with_fee amount that was deposited including fee
    446  * @param num_freshcoins how many coins were issued
    447  * @param noreveal_index which index was picked by the exchange in cut-and-choose
    448  * @param rc what is the session hash
    449  * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
    450  */
    451 static enum GNUNET_GenericReturnValue
    452 audit_refresh_session_cb (
    453   struct TALER_EXCHANGEDB_PostgresContext *pg,
    454   uint64_t rowid,
    455   const struct TALER_DenominationPublicKey *denom_pub,
    456   const struct TALER_AgeCommitmentHashP *h_age_commitment,
    457   const struct TALER_CoinSpendPublicKeyP *coin_pub,
    458   const struct TALER_CoinSpendSignatureP *coin_sig,
    459   const struct TALER_Amount *amount_with_fee,
    460   uint32_t noreveal_index,
    461   const struct TALER_RefreshCommitmentP *rc)
    462 {
    463   (void) cls;
    464   (void) rowid;
    465   (void) denom_pub;
    466   (void) coin_pub;
    467   (void) coin_sig;
    468   (void) amount_with_fee;
    469   (void) noreveal_index;
    470   (void) rc;
    471   (void) h_age_commitment;
    472   auditor_row_cnt++;
    473   return GNUNET_OK;
    474 }
    475 
    476 
    477 /**
    478  * Denomination keys used for fresh coins in melt test.
    479  */
    480 static struct DenomKeyPair **new_dkp;
    481 
    482 
    483 /**
    484  * @brief Linked list of refresh information linked to a coin.
    485  */
    486 struct TALER_EXCHANGEDB_LinkList
    487 {
    488   /**
    489    * Information is stored in a NULL-terminated linked list.
    490    */
    491   struct TALER_EXCHANGEDB_LinkList *next;
    492 
    493   /**
    494    * Denomination public key, determines the value of the coin.
    495    */
    496   struct TALER_DenominationPublicKey denom_pub;
    497 
    498   /**
    499    * Signature over the blinded envelope.
    500    */
    501   struct TALER_BlindedDenominationSignature ev_sig;
    502 
    503   /**
    504    * Exchange-provided values during the coin generation.
    505    */
    506   struct TALER_ExchangeBlindingValues alg_values;
    507 
    508   /**
    509    * Signature of the original coin being refreshed over the
    510    * link data, of type #TALER_SIGNATURE_WALLET_COIN_LINK
    511    */
    512   struct TALER_CoinSpendSignatureP orig_coin_link_sig;
    513 
    514   /**
    515    * Session nonce, if cipher has one.
    516    */
    517   union GNUNET_CRYPTO_BlindSessionNonce nonce;
    518 
    519   /**
    520    * Offset that generated this coin in the refresh
    521    * operation.
    522    */
    523   uint32_t coin_refresh_offset;
    524 
    525   /**
    526    * Set to true if @e nonce was initialized.
    527    */
    528   bool have_nonce;
    529 };
    530 
    531 
    532 /**
    533  * Function called with the session hashes and transfer secret
    534  * information for a given coin.
    535  *
    536  * @param cls closure
    537  * @param transfer_pub public transfer key for the session
    538  * @param ldl link data for @a transfer_pub
    539  */
    540 static void
    541 handle_link_data_cb (void *cls,
    542                      const struct TALER_TransferPublicKeyP *transfer_pub,
    543                      const struct TALER_EXCHANGEDB_LinkList *ldl)
    544 {
    545   (void) cls;
    546   (void) transfer_pub;
    547   for (const struct TALER_EXCHANGEDB_LinkList *ldlp = ldl;
    548        NULL != ldlp;
    549        ldlp = ldlp->next)
    550   {
    551     bool found;
    552 
    553     found = false;
    554     for (unsigned int cnt = 0; cnt < MELT_NEW_COINS; cnt++)
    555     {
    556       if ( (0 ==
    557             TALER_denom_pub_cmp (&ldlp->denom_pub,
    558                                  &new_dkp[cnt]->pub)) &&
    559            (0 ==
    560             TALER_blinded_denom_sig_cmp (&ldlp->ev_sig,
    561                                          &revealed_coins[cnt].coin_sig)) )
    562       {
    563         found = true;
    564         break;
    565       }
    566     }
    567     GNUNET_assert (GNUNET_NO != found);
    568   }
    569 }
    570 
    571 
    572 /**
    573  * Callback that should never be called.
    574  */
    575 static void
    576 cb_wt_never (struct TALER_EXCHANGEDB_PostgresContext *pg,
    577              uint64_t serial_id,
    578              const struct TALER_MerchantPublicKeyP *merchant_pub,
    579              const struct TALER_FullPayto account_payto_uri,
    580              const struct TALER_FullPaytoHashP *h_payto,
    581              struct GNUNET_TIME_Timestamp exec_time,
    582              const struct TALER_PrivateContractHashP *h_contract_terms,
    583              const struct TALER_DenominationPublicKey *denom_pub,
    584              const struct TALER_CoinSpendPublicKeyP *coin_pub,
    585              const struct TALER_Amount *coin_value,
    586              const struct TALER_Amount *coin_fee)
    587 {
    588   (void) cls;
    589   (void) serial_id;
    590   (void) merchant_pub;
    591   (void) account_payto_uri;
    592   (void) h_payto;
    593   (void) exec_time;
    594   (void) h_contract_terms;
    595   (void) denom_pub;
    596   (void) coin_pub;
    597   (void) coin_value;
    598   (void) coin_fee;
    599   GNUNET_assert (0); /* this statement should be unreachable */
    600 }
    601 
    602 
    603 static struct TALER_MerchantPublicKeyP merchant_pub_wt;
    604 static struct TALER_MerchantWireHashP h_wire_wt;
    605 static struct TALER_PrivateContractHashP h_contract_terms_wt;
    606 static struct TALER_CoinSpendPublicKeyP coin_pub_wt;
    607 static struct TALER_Amount coin_value_wt;
    608 static struct TALER_Amount coin_fee_wt;
    609 static struct TALER_Amount transfer_value_wt;
    610 static struct GNUNET_TIME_Timestamp wire_out_date;
    611 static struct TALER_WireTransferIdentifierRawP wire_out_wtid;
    612 
    613 
    614 /**
    615  * Callback that should be called with the WT data.
    616  */
    617 static void
    618 cb_wt_check (struct TALER_EXCHANGEDB_PostgresContext *pg,
    619              uint64_t rowid,
    620              const struct TALER_MerchantPublicKeyP *merchant_pub,
    621              const struct TALER_FullPayto account_payto_uri,
    622              const struct TALER_FullPaytoHashP *h_payto,
    623              struct GNUNET_TIME_Timestamp exec_time,
    624              const struct TALER_PrivateContractHashP *h_contract_terms,
    625              const struct TALER_DenominationPublicKey *denom_pub,
    626              const struct TALER_CoinSpendPublicKeyP *coin_pub,
    627              const struct TALER_Amount *coin_value,
    628              const struct TALER_Amount *coin_fee)
    629 {
    630   (void) rowid;
    631   (void) denom_pub;
    632   (void) h_payto;
    633   GNUNET_assert (cls == &cb_wt_never);
    634   GNUNET_assert (0 == GNUNET_memcmp (merchant_pub,
    635                                      &merchant_pub_wt));
    636   GNUNET_assert (0 == strcmp (account_payto_uri.full_payto,
    637                               "payto://iban/DE67830654080004822650?receiver-name=Test"));
    638   GNUNET_assert (GNUNET_TIME_timestamp_cmp (exec_time,
    639                                             ==,
    640                                             wire_out_date));
    641   GNUNET_assert (0 == GNUNET_memcmp (h_contract_terms,
    642                                      &h_contract_terms_wt));
    643   GNUNET_assert (0 == GNUNET_memcmp (coin_pub,
    644                                      &coin_pub_wt));
    645   GNUNET_assert (0 == TALER_amount_cmp (coin_value,
    646                                         &coin_value_wt));
    647   GNUNET_assert (0 == TALER_amount_cmp (coin_fee,
    648                                         &coin_fee_wt));
    649 }
    650 
    651 
    652 /**
    653  * Here we store the hash of the payto URI.
    654  */
    655 static struct TALER_FullPaytoHashP global_wire_target_h_payto;
    656 
    657 
    658 /**
    659  * Callback for #select_coin_deposits_above_serial_id ()
    660  *
    661  * @param cls closure
    662  * @param rowid unique serial ID for the deposit in our DB
    663  * @param exchange_timestamp when did the deposit happen
    664  * @param deposit deposit details
    665  * @param denom_pub denomination of the @a coin_pub
    666  * @param done flag set if the deposit was already executed (or not)
    667  * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
    668  */
    669 static enum GNUNET_GenericReturnValue
    670 audit_deposit_cb (void *cls,
    671                   uint64_t rowid,
    672                   struct GNUNET_TIME_Timestamp exchange_timestamp,
    673                   const struct TALER_EXCHANGEDB_Deposit *deposit,
    674                   const struct TALER_DenominationPublicKey *denom_pub,
    675                   bool done)
    676 {
    677   (void) cls;
    678   (void) rowid;
    679   (void) exchange_timestamp;
    680   (void) deposit;
    681   (void) denom_pub;
    682   (void) done;
    683   auditor_row_cnt++;
    684   return GNUNET_OK;
    685 }
    686 
    687 
    688 /**
    689  * Function called with details about coins that were refunding,
    690  * with the goal of auditing the refund's execution.
    691  *
    692  * @param cls closure
    693  * @param rowid unique serial ID for the refund in our DB
    694  * @param denom_pub denomination of the @a coin_pub
    695  * @param coin_pub public key of the coin
    696  * @param merchant_pub public key of the merchant
    697  * @param merchant_sig signature of the merchant
    698  * @param h_contract_terms hash of the proposal data in
    699  *                        the contract between merchant and customer
    700  * @param rtransaction_id refund transaction ID chosen by the merchant
    701  * @param full_refund the deposit
    702  * @param amount_with_fee amount that was deposited including fee
    703  * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
    704  */
    705 static enum GNUNET_GenericReturnValue
    706 audit_refund_cb (void *cls,
    707                  uint64_t rowid,
    708                  const struct TALER_DenominationPublicKey *denom_pub,
    709                  const struct TALER_CoinSpendPublicKeyP *coin_pub,
    710                  const struct TALER_MerchantPublicKeyP *merchant_pub,
    711                  const struct TALER_MerchantSignatureP *merchant_sig,
    712                  const struct TALER_PrivateContractHashP *h_contract_terms,
    713                  uint64_t rtransaction_id,
    714                  bool full_refund,
    715                  const struct TALER_Amount *amount_with_fee)
    716 {
    717   (void) cls;
    718   (void) rowid;
    719   (void) denom_pub;
    720   (void) coin_pub;
    721   (void) merchant_pub;
    722   (void) merchant_sig;
    723   (void) h_contract_terms;
    724   (void) rtransaction_id;
    725   (void) amount_with_fee;
    726   (void) full_refund;
    727   auditor_row_cnt++;
    728   return GNUNET_OK;
    729 }
    730 
    731 
    732 /**
    733  * Function called with details about incoming wire transfers.
    734  *
    735  * @param cls closure
    736  * @param rowid unique serial ID for the refresh session in our DB
    737  * @param reserve_pub public key of the reserve (also the WTID)
    738  * @param credit amount that was received
    739  * @param sender_account_details information about the sender's bank account
    740  * @param wire_reference unique reference identifying the wire transfer
    741  * @param execution_date when did we receive the funds
    742  * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
    743  */
    744 static enum GNUNET_GenericReturnValue
    745 audit_reserve_in_cb (void *cls,
    746                      uint64_t rowid,
    747                      const struct TALER_ReservePublicKeyP *reserve_pub,
    748                      const struct TALER_Amount *credit,
    749                      const struct TALER_FullPayto sender_account_details,
    750                      uint64_t wire_reference,
    751                      struct GNUNET_TIME_Timestamp execution_date)
    752 {
    753   (void) cls;
    754   (void) rowid;
    755   (void) reserve_pub;
    756   (void) credit;
    757   (void) sender_account_details;
    758   (void) wire_reference;
    759   (void) execution_date;
    760   auditor_row_cnt++;
    761   return GNUNET_OK;
    762 }
    763 
    764 
    765 /**
    766  * Function called with details about withdraw operations.
    767  *
    768  * @param cls closure
    769  * @param rowid unique serial ID for the refresh session in our DB
    770  * @param num_evs number of elements in @e h_blind_evs
    771  * @param h_blind_evs array @e num_evs of blinded hashes of the coin's public keys
    772  * @param denom_serials array @e num_evs of serial ids of denominations
    773  * @param h_planchets running hash over all hashes of blinded planchets in the original withdraw request
    774  * @param blinding_seed seed provided during withdraw, for CS denominations; might be NULL
    775  * @param age_proof_required true if the withdraw request required an age proof.
    776  * @param max_age if @e age_proof_required is true, the maximum age that was set on the coins.
    777  * @param noreveal_index if @e age_proof_required is true, the index that was returned by the exchange for the reveal phase.
    778  * @param reserve_pub public key of the reserve
    779  * @param reserve_sig signature over the withdraw operation
    780  * @param execution_date when did the wallet withdraw the coin
    781  * @param amount_with_fee amount that was withdrawn
    782  * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
    783  */
    784 static enum GNUNET_GenericReturnValue
    785 audit_reserve_out_cb (void *cls,
    786                       uint64_t rowid,
    787                       size_t num_evs,
    788                       const struct TALER_BlindedCoinHashP *h_blind_evs,
    789                       const uint64_t *denom_serials,
    790                       const struct TALER_HashBlindedPlanchetsP *h_planchets,
    791                       const struct TALER_BlindingMasterSeedP *blinding_seed,
    792                       bool age_proof_required,
    793                       uint8_t max_age,
    794                       uint8_t noreveal_index,
    795                       const struct TALER_ReservePublicKeyP *reserve_pub,
    796                       const struct TALER_ReserveSignatureP *reserve_sig,
    797                       struct GNUNET_TIME_Timestamp execution_date,
    798                       const struct TALER_Amount *amount_with_fee)
    799 {
    800   (void) cls;
    801   (void) rowid;
    802   (void) h_blind_evs;
    803   (void) h_planchets;
    804   (void) blinding_seed;
    805   (void) denom_serials;
    806   (void) reserve_pub;
    807   (void) reserve_sig;
    808   (void) execution_date;
    809   (void) amount_with_fee;
    810   auditor_row_cnt++;
    811   return GNUNET_OK;
    812 }
    813 
    814 
    815 /**
    816  * Test garbage collection.
    817  *
    818  * @return #GNUNET_OK on success
    819  */
    820 static enum GNUNET_GenericReturnValue
    821 test_gc (void)
    822 {
    823   struct DenomKeyPair *dkp;
    824   struct GNUNET_TIME_Timestamp now;
    825   struct GNUNET_TIME_Timestamp past;
    826   struct TALER_EXCHANGEDB_DenominationKeyInformation issue2;
    827   struct TALER_DenominationHashP denom_hash;
    828 
    829   now = GNUNET_TIME_timestamp_get ();
    830   past = GNUNET_TIME_absolute_to_timestamp (
    831     GNUNET_TIME_absolute_subtract (now.abs_time,
    832                                    GNUNET_TIME_relative_multiply (
    833                                      GNUNET_TIME_UNIT_HOURS,
    834                                      4)));
    835   dkp = create_denom_key_pair (RSA_KEY_SIZE,
    836                                past,
    837                                &global_value,
    838                                &global_fees);
    839   GNUNET_assert (NULL != dkp);
    840   if (GNUNET_OK !=
    841       plugin->gc (plugin->cls))
    842   {
    843     GNUNET_break (0);
    844     destroy_denom_key_pair (dkp);
    845     return GNUNET_SYSERR;
    846   }
    847   TALER_denom_pub_hash (&dkp->pub,
    848                         &denom_hash);
    849 
    850   if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
    851       plugin->get_denomination_info (plugin->cls,
    852                                      &denom_hash,
    853                                      NULL,
    854                                      &issue2))
    855   {
    856     GNUNET_break (0);
    857     destroy_denom_key_pair (dkp);
    858     return GNUNET_SYSERR;
    859   }
    860   destroy_denom_key_pair (dkp);
    861   return GNUNET_OK;
    862 }
    863 
    864 
    865 /**
    866  * Test wire fee storage.
    867  *
    868  * @return #GNUNET_OK on success
    869  */
    870 static enum GNUNET_GenericReturnValue
    871 test_wire_fees (void)
    872 {
    873   struct GNUNET_TIME_Timestamp start_date;
    874   struct GNUNET_TIME_Timestamp end_date;
    875   struct TALER_WireFeeSet fees;
    876   struct TALER_MasterSignatureP master_sig;
    877   struct GNUNET_TIME_Timestamp sd;
    878   struct GNUNET_TIME_Timestamp ed;
    879   struct TALER_WireFeeSet fees2;
    880   struct TALER_MasterSignatureP ms;
    881   uint64_t rowid;
    882 
    883   start_date = GNUNET_TIME_timestamp_get ();
    884   end_date = GNUNET_TIME_relative_to_timestamp (GNUNET_TIME_UNIT_MINUTES);
    885   GNUNET_assert (GNUNET_OK ==
    886                  TALER_string_to_amount (CURRENCY ":1.424242",
    887                                          &fees.wire));
    888   GNUNET_assert (GNUNET_OK ==
    889                  TALER_string_to_amount (CURRENCY ":2.424242",
    890                                          &fees.closing));
    891   GNUNET_CRYPTO_random_block (&master_sig,
    892                               sizeof (master_sig));
    893   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
    894       plugin->insert_wire_fee (plugin->cls,
    895                                "wire-method",
    896                                start_date,
    897                                end_date,
    898                                &fees,
    899                                &master_sig))
    900   {
    901     GNUNET_break (0);
    902     return GNUNET_SYSERR;
    903   }
    904   if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
    905       plugin->insert_wire_fee (plugin->cls,
    906                                "wire-method",
    907                                start_date,
    908                                end_date,
    909                                &fees,
    910                                &master_sig))
    911   {
    912     GNUNET_break (0);
    913     return GNUNET_SYSERR;
    914   }
    915   /* This must fail as 'end_date' is NOT in the
    916      half-open interval [start_date,end_date) */
    917   if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
    918       plugin->get_wire_fee (plugin->cls,
    919                             "wire-method",
    920                             end_date,
    921                             &rowid,
    922                             &sd,
    923                             &ed,
    924                             &fees2,
    925                             &ms))
    926   {
    927     GNUNET_break (0);
    928     return GNUNET_SYSERR;
    929   }
    930   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
    931       plugin->get_wire_fee (plugin->cls,
    932                             "wire-method",
    933                             start_date,
    934                             &rowid,
    935                             &sd,
    936                             &ed,
    937                             &fees2,
    938                             &ms))
    939   {
    940     GNUNET_break (0);
    941     return GNUNET_SYSERR;
    942   }
    943   if ( (GNUNET_TIME_timestamp_cmp (sd,
    944                                    !=,
    945                                    start_date)) ||
    946        (GNUNET_TIME_timestamp_cmp (ed,
    947                                    !=,
    948                                    end_date)) ||
    949        (0 != TALER_wire_fee_set_cmp (&fees,
    950                                      &fees2)) ||
    951        (0 != GNUNET_memcmp (&ms,
    952                             &master_sig)) )
    953   {
    954     GNUNET_break (0);
    955     return GNUNET_SYSERR;
    956   }
    957   return GNUNET_OK;
    958 }
    959 
    960 
    961 static struct TALER_Amount wire_out_amount;
    962 
    963 
    964 /**
    965  * Callback with data about an executed wire transfer.
    966  *
    967  * @param cls closure
    968  * @param rowid identifier of the respective row in the database
    969  * @param date timestamp of the wire transfer (roughly)
    970  * @param wtid wire transfer subject
    971  * @param wire wire transfer details of the receiver
    972  * @param amount amount that was wired
    973  * @return #GNUNET_OK to continue, #GNUNET_SYSERR to stop iteration
    974  */
    975 static enum GNUNET_GenericReturnValue
    976 audit_wire_cb (void *cls,
    977                uint64_t rowid,
    978                struct GNUNET_TIME_Timestamp date,
    979                const struct TALER_WireTransferIdentifierRawP *wtid,
    980                const struct TALER_FullPayto payto_uri,
    981                const struct TALER_Amount *amount)
    982 {
    983   (void) cls;
    984   (void) rowid;
    985   (void) payto_uri;
    986   auditor_row_cnt++;
    987   GNUNET_assert (0 ==
    988                  TALER_amount_cmp (amount,
    989                                    &wire_out_amount));
    990   GNUNET_assert (0 ==
    991                  GNUNET_memcmp (wtid,
    992                                 &wire_out_wtid));
    993   GNUNET_assert (GNUNET_TIME_timestamp_cmp (date,
    994                                             ==,
    995                                             wire_out_date));
    996   return GNUNET_OK;
    997 }
    998 
    999 
   1000 /**
   1001  * Test API relating to wire_out handling.
   1002  *
   1003  * @param bd batch deposit to test
   1004  * @return #GNUNET_OK on success
   1005  */
   1006 static enum GNUNET_GenericReturnValue
   1007 test_wire_out (const struct TALER_EXCHANGEDB_BatchDeposit *bd)
   1008 {
   1009   const struct TALER_EXCHANGEDB_CoinDepositInformation *deposit = &bd->cdis[0];
   1010   struct TALER_FullPaytoHashP h_payto;
   1011 
   1012   GNUNET_assert (0 < bd->num_cdis);
   1013   TALER_full_payto_hash (bd->receiver_wire_account,
   1014                          &h_payto);
   1015   auditor_row_cnt = 0;
   1016   memset (&wire_out_wtid,
   1017           41,
   1018           sizeof (wire_out_wtid));
   1019   wire_out_date = GNUNET_TIME_timestamp_get ();
   1020   GNUNET_assert (GNUNET_OK ==
   1021                  TALER_string_to_amount (CURRENCY ":1",
   1022                                          &wire_out_amount));
   1023 
   1024   /* we will transiently violate the wtid constraint on
   1025      the aggregation table, so we need to start the special
   1026      transaction where this is allowed... */
   1027   FAILIF (GNUNET_OK !=
   1028           plugin->start_deferred_wire_out (plugin->cls));
   1029 
   1030   /* setup values for wire transfer aggregation data */
   1031   merchant_pub_wt = bd->merchant_pub;
   1032   h_contract_terms_wt = bd->h_contract_terms;
   1033   coin_pub_wt = deposit->coin.coin_pub;
   1034 
   1035   coin_value_wt = deposit->amount_with_fee;
   1036   coin_fee_wt = global_fees.deposit;
   1037   GNUNET_assert (0 <
   1038                  TALER_amount_subtract (&transfer_value_wt,
   1039                                         &coin_value_wt,
   1040                                         &coin_fee_wt));
   1041   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
   1042           plugin->lookup_wire_transfer (plugin->cls,
   1043                                         &wire_out_wtid,
   1044                                         &cb_wt_never,
   1045                                         NULL));
   1046 
   1047   {
   1048     struct TALER_PrivateContractHashP h_contract_terms_wt2 =
   1049       h_contract_terms_wt;
   1050     bool pending;
   1051     struct TALER_WireTransferIdentifierRawP wtid2;
   1052     struct TALER_Amount coin_contribution2;
   1053     struct TALER_Amount coin_fee2;
   1054     struct GNUNET_TIME_Timestamp execution_time2;
   1055     struct TALER_EXCHANGEDB_KycStatus kyc;
   1056     union TALER_AccountPublicKeyP account_pub;
   1057 
   1058     h_contract_terms_wt2.hash.bits[0]++;
   1059     FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
   1060             plugin->lookup_transfer_by_deposit (plugin->cls,
   1061                                                 &h_contract_terms_wt2,
   1062                                                 &h_wire_wt,
   1063                                                 &coin_pub_wt,
   1064                                                 &merchant_pub_wt,
   1065                                                 &pending,
   1066                                                 &wtid2,
   1067                                                 &execution_time2,
   1068                                                 &coin_contribution2,
   1069                                                 &coin_fee2,
   1070                                                 &kyc,
   1071                                                 &account_pub));
   1072   }
   1073   {
   1074     struct TALER_ReservePublicKeyP rpub;
   1075 
   1076     memset (&rpub,
   1077             44,
   1078             sizeof (rpub));
   1079     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1080             plugin->store_wire_transfer_out (plugin->cls,
   1081                                              wire_out_date,
   1082                                              &wire_out_wtid,
   1083                                              &h_payto,
   1084                                              "my-config-section",
   1085                                              &wire_out_amount));
   1086   }
   1087   /* And now the commit should still succeed! */
   1088   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
   1089           plugin->commit (plugin->cls));
   1090 
   1091   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1092           plugin->lookup_wire_transfer (plugin->cls,
   1093                                         &wire_out_wtid,
   1094                                         &cb_wt_check,
   1095                                         &cb_wt_never));
   1096   {
   1097     bool pending;
   1098     struct TALER_WireTransferIdentifierRawP wtid2;
   1099     struct TALER_Amount coin_contribution2;
   1100     struct TALER_Amount coin_fee2;
   1101     struct GNUNET_TIME_Timestamp execution_time2;
   1102     struct TALER_EXCHANGEDB_KycStatus kyc;
   1103     union TALER_AccountPublicKeyP account_pub;
   1104 
   1105     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1106             plugin->lookup_transfer_by_deposit (plugin->cls,
   1107                                                 &h_contract_terms_wt,
   1108                                                 &h_wire_wt,
   1109                                                 &coin_pub_wt,
   1110                                                 &merchant_pub_wt,
   1111                                                 &pending,
   1112                                                 &wtid2,
   1113                                                 &execution_time2,
   1114                                                 &coin_contribution2,
   1115                                                 &coin_fee2,
   1116                                                 &kyc,
   1117                                                 &account_pub));
   1118     GNUNET_assert (0 == GNUNET_memcmp (&wtid2,
   1119                                        &wire_out_wtid));
   1120     GNUNET_assert (GNUNET_TIME_timestamp_cmp (execution_time2,
   1121                                               ==,
   1122                                               wire_out_date));
   1123     GNUNET_assert (0 == TALER_amount_cmp (&coin_contribution2,
   1124                                           &coin_value_wt));
   1125     GNUNET_assert (0 == TALER_amount_cmp (&coin_fee2,
   1126                                           &coin_fee_wt));
   1127   }
   1128   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1129           plugin->select_wire_out_above_serial_id (plugin->cls,
   1130                                                    0,
   1131                                                    &audit_wire_cb,
   1132                                                    NULL));
   1133   FAILIF (1 != auditor_row_cnt);
   1134 
   1135   return GNUNET_OK;
   1136 drop:
   1137   return GNUNET_SYSERR;
   1138 }
   1139 
   1140 
   1141 /**
   1142  * Function called about recoups the exchange has to perform.
   1143  *
   1144  * @param cls closure with the expected value for @a coin_blind
   1145  * @param rowid row identifier used to uniquely identify the recoup operation
   1146  * @param timestamp when did we receive the recoup request
   1147  * @param amount how much should be added back to the reserve
   1148  * @param reserve_pub public key of the reserve
   1149  * @param coin public information about the coin
   1150  * @param denom_pub denomination key of @a coin
   1151  * @param coin_sig signature with @e coin_pub of type #TALER_SIGNATURE_WALLET_COIN_RECOUP
   1152  * @param coin_blind blinding factor used to blind the coin
   1153  * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
   1154  */
   1155 static enum GNUNET_GenericReturnValue
   1156 recoup_cb (void *cls,
   1157            uint64_t rowid,
   1158            struct GNUNET_TIME_Timestamp timestamp,
   1159            const struct TALER_Amount *amount,
   1160            const struct TALER_ReservePublicKeyP *reserve_pub,
   1161            const struct TALER_CoinPublicInfo *coin,
   1162            const struct TALER_DenominationPublicKey *denom_pub,
   1163            const struct TALER_CoinSpendSignatureP *coin_sig,
   1164            const union GNUNET_CRYPTO_BlindingSecretP *coin_blind)
   1165 {
   1166   const union GNUNET_CRYPTO_BlindingSecretP *cb = cls;
   1167 
   1168   (void) rowid;
   1169   (void) timestamp;
   1170   (void) amount;
   1171   (void) reserve_pub;
   1172   (void) coin_sig;
   1173   (void) coin;
   1174   (void) denom_pub;
   1175   FAILIF (NULL == cb);
   1176   FAILIF (0 != GNUNET_memcmp (cb,
   1177                               coin_blind));
   1178   return GNUNET_OK;
   1179 drop:
   1180   return GNUNET_SYSERR;
   1181 }
   1182 
   1183 
   1184 /**
   1185  * Function called on batch deposits that may require a
   1186  * wire transfer.
   1187  *
   1188  * @param cls closure a `struct TALER_EXCHANGEDB_Deposit *`
   1189  * @param batch_deposit_serial_id where in the table are we
   1190  * @param total_amount value of all missing deposits, including fees
   1191  * @param wire_target_h_payto hash of the recipient account's payto URI
   1192  * @param deadline what was the earliest requested wire transfer deadline
   1193  */
   1194 static void
   1195 wire_missing_cb (
   1196   struct TALER_EXCHANGEDB_PostgresContext *pg,
   1197   uint64_t batch_deposit_serial_id,
   1198   const struct TALER_Amount *total_amount,
   1199   const struct TALER_FullPaytoHashP *wire_target_h_payto,
   1200   struct GNUNET_TIME_Timestamp deadline)
   1201 {
   1202   const struct TALER_EXCHANGEDB_CoinDepositInformation *deposit = cls;
   1203 
   1204   (void) batch_deposit_serial_id;
   1205   (void) deadline;
   1206   (void) wire_target_h_payto;
   1207   if (0 ==
   1208       TALER_amount_cmp (total_amount,
   1209                         &deposit->amount_with_fee))
   1210     result = 8;
   1211 }
   1212 
   1213 
   1214 /**
   1215  * Callback invoked with information about refunds applicable
   1216  * to a particular coin.
   1217  *
   1218  * @param cls closure with the `struct TALER_EXCHANGEDB_Refund *` we expect to get
   1219  * @param amount_with_fee amount being refunded
   1220  * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
   1221  */
   1222 static enum GNUNET_GenericReturnValue
   1223 check_refund_cb (void *cls,
   1224                  const struct TALER_Amount *amount_with_fee)
   1225 {
   1226   const struct TALER_EXCHANGEDB_Refund *refund = cls;
   1227 
   1228   if (0 != TALER_amount_cmp (amount_with_fee,
   1229                              &refund->details.refund_amount))
   1230   {
   1231     GNUNET_break (0);
   1232     result = 66;
   1233   }
   1234   return GNUNET_OK;
   1235 }
   1236 
   1237 
   1238 /**
   1239  * Information about a melt operation.
   1240  */
   1241 struct TALER_EXCHANGEDB_Melt
   1242 {
   1243 
   1244   /**
   1245    * Overall session data.
   1246    */
   1247   struct TALER_EXCHANGEDB_Refresh session;
   1248 
   1249   /**
   1250    * Melt fee the exchange charged.
   1251    */
   1252   struct TALER_Amount melt_fee;
   1253 
   1254 };
   1255 
   1256 
   1257 /**
   1258  * Main function that will be run by the scheduler.
   1259  *
   1260  * @param cls closure with config
   1261  */
   1262 static void
   1263 run (struct TALER_EXCHANGEDB_PostgresContext *pg)
   1264 {
   1265   struct GNUNET_CONFIGURATION_Handle *cfg = cls;
   1266   struct TALER_CoinSpendSignatureP coin_sig;
   1267   struct GNUNET_TIME_Timestamp deadline;
   1268   union GNUNET_CRYPTO_BlindingSecretP coin_blind;
   1269   struct TALER_ReservePublicKeyP reserve_pub;
   1270   struct TALER_ReservePublicKeyP reserve_pub2;
   1271   struct TALER_ReservePublicKeyP reserve_pub3;
   1272   struct DenomKeyPair *dkp = NULL;
   1273   struct TALER_MasterSignatureP master_sig;
   1274   struct TALER_EXCHANGEDB_CollectableBlindcoin cbc;
   1275   struct TALER_EXCHANGEDB_ReserveHistory *rh = NULL;
   1276   struct TALER_EXCHANGEDB_ReserveHistory *rh_head;
   1277   struct TALER_EXCHANGEDB_BankTransfer *bt;
   1278   struct TALER_EXCHANGEDB_Withdraw withdraw;
   1279   struct TALER_HashBlindedPlanchetsP h_planchets;
   1280   struct TALER_EXCHANGEDB_CoinDepositInformation deposit;
   1281   struct TALER_EXCHANGEDB_BatchDeposit bd;
   1282   struct TALER_CoinSpendPublicKeyP cpub2;
   1283   struct TALER_MerchantPublicKeyP mpub2;
   1284   struct TALER_EXCHANGEDB_Refund refund;
   1285   const struct TALER_FullPayto sndr = {
   1286     (char *) "payto://x-taler-bank/localhost:8080/1?receiver-name=1"
   1287   };
   1288   const struct TALER_FullPayto rcvr = {
   1289     (char *) "payto://x-taler-bank/localhost:8080/2?receiver-name=1"
   1290   };
   1291   const uint32_t num_partitions = 10;
   1292   unsigned int matched;
   1293   enum GNUNET_DB_QueryStatus qs;
   1294   struct GNUNET_TIME_Timestamp now;
   1295   struct TALER_WireSaltP salt;
   1296   struct TALER_CoinPubHashP c_hash;
   1297   uint64_t known_coin_id;
   1298   uint64_t rrc_serial;
   1299   struct TALER_EXCHANGEDB_Refresh refresh;
   1300   struct TALER_DenominationPublicKey *new_denom_pubs = NULL;
   1301   uint64_t withdraw_serial_id;
   1302   uint64_t melt_serial_id;
   1303   struct TALER_PlanchetMasterSecretP ps;
   1304   union GNUNET_CRYPTO_BlindingSecretP bks;
   1305   struct TALER_Amount amount_with_fee;
   1306   const struct TALER_ExchangeBlindingValues *alg_values
   1307     = TALER_denom_ewv_rsa_singleton ();
   1308 
   1309   memset (&deposit,
   1310           0,
   1311           sizeof (deposit));
   1312   memset (&bd,
   1313           0,
   1314           sizeof (bd));
   1315   bd.receiver_wire_account = rcvr;
   1316   bd.cdis = &deposit;
   1317   bd.num_cdis = 1;
   1318   memset (&salt,
   1319           45,
   1320           sizeof (salt));
   1321   memset (&refresh,
   1322           0,
   1323           sizeof (refresh));
   1324   ZR_BLK (&cbc);
   1325   ZR_BLK (&withdraw);
   1326   if (NULL ==
   1327       (plugin = TALER_EXCHANGEDB_plugin_load (cfg,
   1328                                               true)))
   1329   {
   1330     result = 77;
   1331     return;
   1332   }
   1333   (void) plugin->drop_tables (plugin->cls);
   1334   if (GNUNET_OK !=
   1335       plugin->create_tables (plugin->cls,
   1336                              true,
   1337                              num_partitions))
   1338   {
   1339     result = 77;
   1340     goto cleanup;
   1341   }
   1342   plugin->preflight (plugin->cls);
   1343   FAILIF (GNUNET_OK !=
   1344           plugin->start (plugin->cls,
   1345                          "test-1"));
   1346 
   1347 
   1348   /* test DB is empty */
   1349   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
   1350           plugin->select_recoup_above_serial_id (plugin->cls,
   1351                                                  0,
   1352                                                  &recoup_cb,
   1353                                                  NULL));
   1354 
   1355   RND_BLK (&reserve_pub);
   1356   GNUNET_assert (GNUNET_OK ==
   1357                  TALER_string_to_amount (CURRENCY ":1.000000",
   1358                                          &global_amount));
   1359   GNUNET_assert (GNUNET_OK ==
   1360                  TALER_string_to_amount (CURRENCY ":1.000010",
   1361                                          &global_value));
   1362   GNUNET_assert (GNUNET_OK ==
   1363                  TALER_string_to_amount (CURRENCY ":0.000010",
   1364                                          &global_fees.withdraw));
   1365   GNUNET_assert (GNUNET_OK ==
   1366                  TALER_string_to_amount (CURRENCY ":0.000010",
   1367                                          &global_fees.deposit));
   1368   GNUNET_assert (GNUNET_OK ==
   1369                  TALER_string_to_amount (CURRENCY ":0.000010",
   1370                                          &global_fees.refresh));
   1371   GNUNET_assert (GNUNET_OK ==
   1372                  TALER_string_to_amount (CURRENCY ":0.000010",
   1373                                          &global_fees.refund));
   1374   GNUNET_assert (GNUNET_OK ==
   1375                  TALER_string_to_amount (CURRENCY ":1.000010",
   1376                                          &amount_with_fee));
   1377   result = 4;
   1378   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
   1379           plugin->commit (plugin->cls));
   1380   now = GNUNET_TIME_timestamp_get ();
   1381   {
   1382     struct TALER_EXCHANGEDB_ReserveInInfo reserve = {
   1383       .reserve_pub = &reserve_pub,
   1384       .balance = &global_value,
   1385       .execution_time = now,
   1386       .sender_account_details = sndr,
   1387       .exchange_account_name = "exchange-account-1",
   1388       .wire_reference = 4
   1389     };
   1390     enum GNUNET_DB_QueryStatus qsr;
   1391 
   1392     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1393             plugin->reserves_in_insert (plugin->cls,
   1394                                         &reserve,
   1395                                         1,
   1396                                         &qsr));
   1397     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1398             qsr);
   1399   }
   1400   FAILIF (GNUNET_OK !=
   1401           check_reserve (&reserve_pub,
   1402                          global_value.value,
   1403                          global_value.fraction,
   1404                          global_value.currency));
   1405   now = GNUNET_TIME_timestamp_get ();
   1406   RND_BLK (&reserve_pub2);
   1407   {
   1408     struct TALER_EXCHANGEDB_ReserveInInfo reserve = {
   1409       .reserve_pub = &reserve_pub2,
   1410       .balance = &global_value,
   1411       .execution_time = now,
   1412       .sender_account_details = sndr,
   1413       .exchange_account_name = "exchange-account-1",
   1414       .wire_reference = 5
   1415     };
   1416     enum GNUNET_DB_QueryStatus qsr;
   1417 
   1418     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1419             plugin->reserves_in_insert (plugin->cls,
   1420                                         &reserve,
   1421                                         1,
   1422                                         &qsr));
   1423     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1424             qsr);
   1425   }
   1426   FAILIF (GNUNET_OK !=
   1427           plugin->start (plugin->cls,
   1428                          "test-2"));
   1429   FAILIF (GNUNET_OK !=
   1430           check_reserve (&reserve_pub,
   1431                          global_value.value,
   1432                          global_value.fraction,
   1433                          global_value.currency));
   1434   FAILIF (GNUNET_OK !=
   1435           check_reserve (&reserve_pub2,
   1436                          global_value.value,
   1437                          global_value.fraction,
   1438                          global_value.currency));
   1439   result = 5;
   1440   now = GNUNET_TIME_timestamp_get ();
   1441   dkp = create_denom_key_pair (RSA_KEY_SIZE,
   1442                                now,
   1443                                &global_value,
   1444                                &global_fees);
   1445   GNUNET_assert (NULL != dkp);
   1446   TALER_denom_pub_hash (&dkp->pub,
   1447                         &cbc.denom_pub_hash);
   1448   RND_BLK (&cbc.reserve_sig);
   1449   RND_BLK (&ps);
   1450   TALER_planchet_blinding_secret_create (&ps,
   1451                                          alg_values,
   1452                                          &bks);
   1453   {
   1454     struct TALER_PlanchetDetail pd;
   1455     struct TALER_CoinSpendPublicKeyP coin_pub;
   1456 
   1457 
   1458     RND_BLK (&coin_pub);
   1459     GNUNET_assert (GNUNET_OK ==
   1460                    TALER_denom_blind (&dkp->pub,
   1461                                       &bks,
   1462                                       NULL,
   1463                                       NULL,
   1464                                       &coin_pub,
   1465                                       alg_values,
   1466                                       &c_hash,
   1467                                       &pd.blinded_planchet));
   1468     TALER_coin_ev_hash (&pd.blinded_planchet,
   1469                         &cbc.denom_pub_hash,
   1470                         &cbc.h_coin_envelope);
   1471 
   1472     GNUNET_assert (
   1473       GNUNET_OK ==
   1474       TALER_denom_sign_blinded (
   1475         &cbc.sig,
   1476         &dkp->priv,
   1477         false,
   1478         &pd.blinded_planchet));
   1479 
   1480     TALER_wallet_blinded_planchets_hash (
   1481       1,
   1482       &pd.blinded_planchet,
   1483       &cbc.denom_pub_hash,
   1484       &h_planchets);
   1485 
   1486     TALER_blinded_planchet_free (&pd.blinded_planchet);
   1487   }
   1488 
   1489   cbc.reserve_pub = reserve_pub;
   1490   cbc.amount_with_fee = global_value;
   1491   GNUNET_assert (GNUNET_OK ==
   1492                  TALER_amount_set_zero (CURRENCY,
   1493                                         &cbc.withdraw_fee));
   1494 
   1495   {
   1496     bool balance_ok;
   1497     bool age_ok;
   1498     bool idempotent;
   1499     uint16_t noreveal_index;
   1500     bool nonce_reuse;
   1501     uint16_t maximum_age;
   1502     uint32_t reserve_birthday;
   1503     uint64_t denom_serial = 1; /* bold assumption */
   1504     struct TALER_Amount reserve_balance;
   1505     struct TALER_BlindingMasterSeedP blinding_seed = {0};
   1506     struct GNUNET_CRYPTO_CSPublicRPairP cs_r_pubs = {0};
   1507     struct TALER_EXCHANGEDB_Withdraw withdraw_in = {
   1508       .amount_with_fee = global_value,
   1509       .age_proof_required = true,
   1510       .max_age = 0,
   1511       .noreveal_index = 42,
   1512       .reserve_pub = reserve_pub,
   1513       .reserve_sig = cbc.reserve_sig,
   1514       .h_planchets = h_planchets,
   1515       .no_blinding_seed = false,
   1516       .blinding_seed = blinding_seed,
   1517       .num_coins = 1,
   1518       .h_coin_evs = &cbc.h_coin_envelope,
   1519       .denom_sigs = &cbc.sig,
   1520       .denom_serials = &denom_serial,
   1521       .num_cs_r_pubs = 1,
   1522       .cs_r_pubs = &cs_r_pubs,
   1523     };
   1524     struct TALER_Amount zero_amount;
   1525 
   1526     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1527             plugin->do_withdraw (plugin->cls,
   1528                                  &withdraw_in,
   1529                                  &now,
   1530                                  &balance_ok,
   1531                                  &reserve_balance,
   1532                                  &age_ok,
   1533                                  &maximum_age,
   1534                                  &reserve_birthday,
   1535                                  &idempotent,
   1536                                  &noreveal_index,
   1537                                  &nonce_reuse));
   1538     GNUNET_assert (! idempotent);
   1539     GNUNET_assert (! nonce_reuse);
   1540     GNUNET_assert (balance_ok);
   1541 
   1542 
   1543     /**
   1544      * Set the amount in the withdraw to zero,
   1545      * to avoid triggering balance_ok issues for
   1546      * the conflict and nonce_reuse tests.
   1547      */
   1548     GNUNET_assert  (GNUNET_OK ==
   1549                     TALER_string_to_amount (CURRENCY ":0.000000",
   1550                                             &zero_amount));
   1551     withdraw_in.amount_with_fee = zero_amount;
   1552 
   1553     /**
   1554      * Change some values to trigger conflict
   1555      * due to h_planchet, not nonce.
   1556      */
   1557     withdraw_in.blinding_seed.key_data[0] = 1;
   1558     noreveal_index = -1;
   1559     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1560             plugin->do_withdraw (plugin->cls,
   1561                                  &withdraw_in,
   1562                                  &now,
   1563                                  &balance_ok,
   1564                                  &reserve_balance,
   1565                                  &age_ok,
   1566                                  &maximum_age,
   1567                                  &reserve_birthday,
   1568                                  &idempotent,
   1569                                  &noreveal_index,
   1570                                  &nonce_reuse));
   1571     GNUNET_assert (! nonce_reuse);
   1572     GNUNET_assert (idempotent);
   1573     GNUNET_assert (42 == noreveal_index);
   1574 
   1575     /**
   1576      * Make h_planchet unique again, but trigger
   1577      * conflict with blinding_seed.
   1578      */
   1579     withdraw_in.blinding_seed.key_data[0] = 0;
   1580     withdraw_in.h_planchets.hash.bits[0] += 1;
   1581     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1582             plugin->do_withdraw (plugin->cls,
   1583                                  &withdraw_in,
   1584                                  &now,
   1585                                  &balance_ok,
   1586                                  &reserve_balance,
   1587                                  &age_ok,
   1588                                  &maximum_age,
   1589                                  &reserve_birthday,
   1590                                  &idempotent,
   1591                                  &noreveal_index,
   1592                                  &nonce_reuse));
   1593     GNUNET_assert (! idempotent);
   1594     GNUNET_assert (nonce_reuse);
   1595   }
   1596 
   1597   FAILIF (GNUNET_OK !=
   1598           check_reserve (&reserve_pub,
   1599                          0,
   1600                          0,
   1601                          global_value.currency));
   1602   FAILIF (GNUNET_OK !=
   1603           check_reserve (&reserve_pub2,
   1604                          global_value.value,
   1605                          global_value.fraction,
   1606                          global_value.currency));
   1607   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1608           plugin->get_reserve_by_h_planchets (plugin->cls,
   1609                                               &h_planchets,
   1610                                               &reserve_pub3,
   1611                                               &withdraw_serial_id));
   1612   FAILIF (0 != GNUNET_memcmp (&reserve_pub,
   1613                               &reserve_pub3));
   1614   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1615           plugin->get_withdraw (plugin->cls,
   1616                                 &h_planchets,
   1617                                 &withdraw));
   1618   FAILIF (0 != GNUNET_memcmp (&withdraw.reserve_sig,
   1619                               &cbc.reserve_sig));
   1620   FAILIF (0 != GNUNET_memcmp (&withdraw.reserve_pub,
   1621                               &cbc.reserve_pub));
   1622   result = 6;
   1623 
   1624   {
   1625     struct TALER_DenominationSignature ds;
   1626 
   1627     GNUNET_assert (GNUNET_OK ==
   1628                    TALER_denom_sig_unblind (&ds,
   1629                                             &withdraw.denom_sigs[0],
   1630                                             &bks,
   1631                                             &c_hash,
   1632                                             alg_values,
   1633                                             &dkp->pub));
   1634     FAILIF (GNUNET_OK !=
   1635             TALER_denom_pub_verify (&dkp->pub,
   1636                                     &ds,
   1637                                     &c_hash));
   1638     TALER_denom_sig_free (&ds);
   1639   }
   1640 
   1641   RND_BLK (&coin_sig);
   1642   RND_BLK (&coin_blind);
   1643   RND_BLK (&deposit.coin.coin_pub);
   1644   TALER_denom_pub_hash (&dkp->pub,
   1645                         &deposit.coin.denom_pub_hash);
   1646   GNUNET_assert (GNUNET_OK ==
   1647                  TALER_denom_sig_unblind (&deposit.coin.denom_sig,
   1648                                           &cbc.sig,
   1649                                           &bks,
   1650                                           &c_hash,
   1651                                           alg_values,
   1652                                           &dkp->pub));
   1653   deadline = GNUNET_TIME_timestamp_get ();
   1654   {
   1655     struct TALER_DenominationHashP dph;
   1656     struct TALER_AgeCommitmentHashP agh;
   1657 
   1658     FAILIF (TALER_EXCHANGEDB_CKS_ADDED !=
   1659             plugin->ensure_coin_known (plugin->cls,
   1660                                        &deposit.coin,
   1661                                        &known_coin_id,
   1662                                        &dph,
   1663                                        &agh));
   1664   }
   1665   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
   1666           plugin->commit (plugin->cls));
   1667   {
   1668     struct GNUNET_TIME_Timestamp deposit_timestamp
   1669       = GNUNET_TIME_timestamp_get ();
   1670     bool balance_ok;
   1671     uint32_t bad_balance_idx;
   1672     bool in_conflict;
   1673     struct TALER_FullPaytoHashP h_payto;
   1674 
   1675     RND_BLK (&h_payto);
   1676     bd.refund_deadline
   1677       = GNUNET_TIME_relative_to_timestamp (GNUNET_TIME_UNIT_MONTHS);
   1678     bd.wire_deadline
   1679       = GNUNET_TIME_relative_to_timestamp (GNUNET_TIME_UNIT_MONTHS);
   1680     deposit.amount_with_fee = global_value;
   1681     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1682             plugin->do_deposit (plugin->cls,
   1683                                 &bd,
   1684                                 &deposit_timestamp,
   1685                                 &balance_ok,
   1686                                 &bad_balance_idx,
   1687                                 &in_conflict));
   1688     FAILIF (! balance_ok);
   1689     FAILIF (in_conflict);
   1690   }
   1691 
   1692   {
   1693     bool not_found;
   1694     bool refund_ok;
   1695     bool gone;
   1696     bool conflict;
   1697 
   1698     refund.coin = deposit.coin;
   1699     refund.details.merchant_pub = bd.merchant_pub;
   1700     RND_BLK (&refund.details.merchant_sig);
   1701     refund.details.h_contract_terms = bd.h_contract_terms;
   1702     refund.details.rtransaction_id = 1;
   1703     refund.details.refund_amount = global_value;
   1704     refund.details.refund_fee = global_fees.refund;
   1705     RND_BLK (&refund.details.merchant_sig);
   1706     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1707             plugin->do_refund (plugin->cls,
   1708                                &refund,
   1709                                &global_fees.deposit,
   1710                                known_coin_id,
   1711                                &not_found,
   1712                                &refund_ok,
   1713                                &gone,
   1714                                &conflict));
   1715     FAILIF (not_found);
   1716     FAILIF (! refund_ok);
   1717     FAILIF (gone);
   1718     FAILIF (conflict);
   1719 
   1720     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1721             plugin->select_refunds_by_coin (plugin->cls,
   1722                                             &refund.coin.coin_pub,
   1723                                             &refund.details.merchant_pub,
   1724                                             &refund.details.h_contract_terms,
   1725                                             &check_refund_cb,
   1726                                             &refund));
   1727   }
   1728 
   1729 
   1730   /* test do_refresh */
   1731 #pragma message "add refresh test for new refresh"
   1732 #if 0
   1733   {
   1734     bool zombie_required = false;
   1735     bool balance_ok;
   1736     bool idempotent;
   1737     uint16_t idem_noreveal_index;
   1738     struct TALER_Amount insufficient_funds;
   1739     struct TALER_EXCHANGEDB_Refresh_v26 refresh_v26;
   1740 
   1741     refresh_v26.coin = deposit.coin;
   1742     RND_BLK (&refresh_v26.coin_sig);
   1743     RND_BLK (&refresh_v26.rc);
   1744     refresh_v26.amount_with_fee = global_value;
   1745     refresh_v26.noreveal_index = MELT_NOREVEAL_INDEX;
   1746     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1747             plugin->do_refresh (plugin->cls,
   1748                                 &refresh_v26,
   1749                                 NULL,
   1750                                 &idempotent,
   1751                                 &idem_noreveal_index,
   1752                                 &zombie_required,
   1753                                 &balance_ok,
   1754                                 &insufficient_funds));
   1755     FAILIF (! balance_ok);
   1756     FAILIF (zombie_required);
   1757   }
   1758 #endif
   1759 
   1760 
   1761   /* test do_melt */
   1762   {
   1763     bool zombie_required = false;
   1764     bool balance_ok;
   1765 
   1766     refresh.coin = deposit.coin;
   1767     RND_BLK (&refresh.coin_sig);
   1768     RND_BLK (&refresh.rc);
   1769     refresh.amount_with_fee = global_value;
   1770     refresh.noreveal_index = MELT_NOREVEAL_INDEX;
   1771     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1772             plugin->do_melt (plugin->cls,
   1773                              NULL,
   1774                              &refresh,
   1775                              known_coin_id,
   1776                              &zombie_required,
   1777                              &balance_ok));
   1778     FAILIF (! balance_ok);
   1779     FAILIF (zombie_required);
   1780   }
   1781 
   1782   /* test get_melt */
   1783   {
   1784     struct TALER_EXCHANGEDB_Melt ret_refresh_session;
   1785 
   1786     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1787             plugin->get_melt (plugin->cls,
   1788                               &refresh.rc,
   1789                               &ret_refresh_session,
   1790                               &melt_serial_id));
   1791     FAILIF (refresh.noreveal_index !=
   1792             ret_refresh_session.session.noreveal_index);
   1793     FAILIF (0 !=
   1794             TALER_amount_cmp (&refresh.amount_with_fee,
   1795                               &ret_refresh_session.session.amount_with_fee));
   1796     FAILIF (0 !=
   1797             TALER_amount_cmp (&global_fees.refresh,
   1798                               &ret_refresh_session.melt_fee));
   1799     FAILIF (0 !=
   1800             GNUNET_memcmp (&refresh.rc,
   1801                            &ret_refresh_session.session.rc));
   1802     FAILIF (0 != GNUNET_memcmp (&refresh.coin_sig,
   1803                                 &ret_refresh_session.session.coin_sig));
   1804     FAILIF (0 !=
   1805             GNUNET_memcmp (&refresh.coin.coin_pub,
   1806                            &ret_refresh_session.session.coin.coin_pub));
   1807     FAILIF (0 !=
   1808             GNUNET_memcmp (&refresh.coin.denom_pub_hash,
   1809                            &ret_refresh_session.session.coin.denom_pub_hash));
   1810   }
   1811 
   1812   {
   1813     /* test 'select_refreshes_above_serial_id' */
   1814     auditor_row_cnt = 0;
   1815     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1816             plugin->select_refreshes_above_serial_id (plugin->cls,
   1817                                                       0,
   1818                                                       &audit_refresh_session_cb,
   1819                                                       NULL));
   1820     FAILIF (1 != auditor_row_cnt);
   1821   }
   1822 
   1823   /* do refresh-reveal */
   1824   now = GNUNET_TIME_timestamp_get ();
   1825   {
   1826     new_dkp = GNUNET_new_array (MELT_NEW_COINS,
   1827                                 struct DenomKeyPair *);
   1828     new_denom_pubs = GNUNET_new_array (MELT_NEW_COINS,
   1829                                        struct TALER_DenominationPublicKey);
   1830     revealed_coins
   1831       = GNUNET_new_array (MELT_NEW_COINS,
   1832                           struct TALER_EXCHANGEDB_RefreshRevealedCoin);
   1833     for (unsigned int cnt = 0; cnt < MELT_NEW_COINS; cnt++)
   1834     {
   1835       struct TALER_EXCHANGEDB_RefreshRevealedCoin *ccoin;
   1836       struct GNUNET_CRYPTO_BlindedMessage *rp;
   1837       struct GNUNET_CRYPTO_RsaBlindedMessage *rsa;
   1838       struct TALER_BlindedPlanchet *bp;
   1839 
   1840       new_dkp[cnt] = create_denom_key_pair (RSA_KEY_SIZE,
   1841                                             now,
   1842                                             &global_value,
   1843                                             &global_fees);
   1844       GNUNET_assert (NULL != new_dkp[cnt]);
   1845       new_denom_pubs[cnt] = new_dkp[cnt]->pub;
   1846       ccoin = &revealed_coins[cnt];
   1847       bp = &ccoin->blinded_planchet;
   1848       rp = GNUNET_new (struct GNUNET_CRYPTO_BlindedMessage);
   1849       bp->blinded_message = rp;
   1850       rp->cipher = GNUNET_CRYPTO_BSA_RSA;
   1851       rp->rc = 1;
   1852       rsa = &rp->details.rsa_blinded_message;
   1853       rsa->blinded_msg_size = 1 + (size_t) GNUNET_CRYPTO_random_u64 (
   1854         (RSA_KEY_SIZE / 8) - 1);
   1855       rsa->blinded_msg = GNUNET_malloc (rsa->blinded_msg_size);
   1856       GNUNET_CRYPTO_random_block (rsa->blinded_msg,
   1857                                   rsa->blinded_msg_size);
   1858       TALER_denom_pub_hash (&new_dkp[cnt]->pub,
   1859                             &ccoin->h_denom_pub);
   1860       TALER_denom_ewv_copy (&ccoin->exchange_vals,
   1861                             alg_values);
   1862       TALER_coin_ev_hash (bp,
   1863                           &ccoin->h_denom_pub,
   1864                           &ccoin->coin_envelope_hash);
   1865       GNUNET_assert (GNUNET_OK ==
   1866                      TALER_denom_sign_blinded (&ccoin->coin_sig,
   1867                                                &new_dkp[cnt]->priv,
   1868                                                true,
   1869                                                bp));
   1870     }
   1871     RND_BLK (&tprivs);
   1872     RND_BLK (&tpub);
   1873     FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
   1874             plugin->get_refresh_reveal (plugin->cls,
   1875                                         &refresh.rc,
   1876                                         &never_called_cb,
   1877                                         NULL));
   1878     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1879             plugin->insert_refresh_reveal (plugin->cls,
   1880                                            melt_serial_id,
   1881                                            MELT_NEW_COINS,
   1882                                            revealed_coins,
   1883                                            TALER_CNC_KAPPA - 1,
   1884                                            tprivs,
   1885                                            &tpub));
   1886     {
   1887       struct TALER_BlindedCoinHashP h_coin_ev;
   1888       struct TALER_CoinSpendPublicKeyP ocp;
   1889       struct TALER_DenominationHashP denom_hash;
   1890 
   1891       TALER_denom_pub_hash (&new_denom_pubs[0],
   1892                             &denom_hash);
   1893       TALER_coin_ev_hash (&revealed_coins[0].blinded_planchet,
   1894                           &denom_hash,
   1895                           &h_coin_ev);
   1896       FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1897               plugin->get_old_coin_by_h_blind (plugin->cls,
   1898                                                &h_coin_ev,
   1899                                                &ocp,
   1900                                                &rrc_serial));
   1901       FAILIF (0 !=
   1902               GNUNET_memcmp (&ocp,
   1903                              &refresh.coin.coin_pub));
   1904     }
   1905     FAILIF (0 >=
   1906             plugin->get_refresh_reveal (plugin->cls,
   1907                                         &refresh.rc,
   1908                                         &check_refresh_reveal_cb,
   1909                                         NULL));
   1910     qs = plugin->get_link_data (plugin->cls,
   1911                                 &refresh.coin.coin_pub,
   1912                                 &handle_link_data_cb,
   1913                                 NULL);
   1914     FAILIF (0 >= qs);
   1915     {
   1916       /* Just to test fetching a coin with melt history */
   1917       struct TALER_EXCHANGEDB_TransactionList *tl;
   1918       uint64_t etag;
   1919       struct TALER_Amount balance;
   1920       struct TALER_DenominationHashP h_denom_pub;
   1921 
   1922       qs = plugin->get_coin_transactions (plugin->cls,
   1923                                           true,
   1924                                           &refresh.coin.coin_pub,
   1925                                           0,
   1926                                           0,
   1927                                           &etag,
   1928                                           &balance,
   1929                                           &h_denom_pub,
   1930                                           &tl);
   1931       FAILIF (0 >= qs);
   1932       FAILIF (NULL == tl);
   1933       plugin->free_coin_transaction_list (plugin->cls,
   1934                                           tl);
   1935     }
   1936   }
   1937 
   1938   /* do recoup-refresh */
   1939   {
   1940     struct GNUNET_TIME_Timestamp recoup_timestamp
   1941       = GNUNET_TIME_timestamp_get ();
   1942     union GNUNET_CRYPTO_BlindingSecretP coin_bks;
   1943     uint64_t new_known_coin_id;
   1944     struct TALER_CoinPublicInfo new_coin;
   1945     struct TALER_DenominationHashP dph;
   1946     struct TALER_AgeCommitmentHashP agh;
   1947     bool recoup_ok;
   1948     bool internal_failure;
   1949 
   1950     new_coin = deposit.coin; /* steal basic data */
   1951     RND_BLK (&new_coin.coin_pub);
   1952     FAILIF (TALER_EXCHANGEDB_CKS_ADDED !=
   1953             plugin->ensure_coin_known (plugin->cls,
   1954                                        &new_coin,
   1955                                        &new_known_coin_id,
   1956                                        &dph,
   1957                                        &agh));
   1958     RND_BLK (&coin_bks);
   1959     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1960             plugin->do_recoup_refresh (plugin->cls,
   1961                                        &deposit.coin.coin_pub,
   1962                                        rrc_serial,
   1963                                        &coin_bks,
   1964                                        &new_coin.coin_pub,
   1965                                        new_known_coin_id,
   1966                                        &coin_sig,
   1967                                        &recoup_timestamp,
   1968                                        &recoup_ok,
   1969                                        &internal_failure));
   1970     FAILIF (! recoup_ok);
   1971     FAILIF (internal_failure);
   1972   }
   1973 
   1974   /* do recoup */
   1975   {
   1976     struct TALER_EXCHANGEDB_Reserve pre_reserve;
   1977     struct TALER_EXCHANGEDB_Reserve post_reserve;
   1978     struct TALER_Amount delta;
   1979     bool recoup_ok;
   1980     bool internal_failure;
   1981     struct GNUNET_TIME_Timestamp recoup_timestamp
   1982       = GNUNET_TIME_timestamp_get ();
   1983 
   1984     pre_reserve.pub = reserve_pub;
   1985     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1986             plugin->reserves_get (plugin->cls,
   1987                                   &pre_reserve));
   1988     FAILIF (! TALER_amount_is_zero (&pre_reserve.balance));
   1989     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1990             plugin->do_recoup (plugin->cls,
   1991                                &reserve_pub,
   1992                                withdraw_serial_id,
   1993                                &coin_blind,
   1994                                &deposit.coin.coin_pub,
   1995                                known_coin_id,
   1996                                &coin_sig,
   1997                                &recoup_timestamp,
   1998                                &recoup_ok,
   1999                                &internal_failure));
   2000     FAILIF (internal_failure);
   2001     FAILIF (! recoup_ok);
   2002     post_reserve.pub = reserve_pub;
   2003     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   2004             plugin->reserves_get (plugin->cls,
   2005                                   &post_reserve));
   2006     FAILIF (0 >=
   2007             TALER_amount_subtract (&delta,
   2008                                    &post_reserve.balance,
   2009                                    &pre_reserve.balance));
   2010     FAILIF (0 !=
   2011             TALER_amount_cmp (&delta,
   2012                               &global_value));
   2013   }
   2014 
   2015   FAILIF (GNUNET_OK !=
   2016           plugin->start (plugin->cls,
   2017                          "test-3"));
   2018 
   2019   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   2020           plugin->select_recoup_above_serial_id (plugin->cls,
   2021                                                  0,
   2022                                                  &recoup_cb,
   2023                                                  &coin_blind));
   2024   /* Do reserve close */
   2025   now = GNUNET_TIME_timestamp_get ();
   2026   GNUNET_assert (GNUNET_OK ==
   2027                  TALER_string_to_amount (CURRENCY ":0.000010",
   2028                                          &fee_closing));
   2029   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   2030           plugin->insert_reserve_closed (plugin->cls,
   2031                                          &reserve_pub2,
   2032                                          now,
   2033                                          sndr,
   2034                                          &wire_out_wtid,
   2035                                          &amount_with_fee,
   2036                                          &fee_closing,
   2037                                          0));
   2038   FAILIF (GNUNET_OK !=
   2039           check_reserve (&reserve_pub2,
   2040                          0,
   2041                          0,
   2042                          global_value.currency));
   2043   now = GNUNET_TIME_timestamp_get ();
   2044   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   2045           plugin->insert_reserve_closed (plugin->cls,
   2046                                          &reserve_pub,
   2047                                          now,
   2048                                          sndr,
   2049                                          &wire_out_wtid,
   2050                                          &global_value,
   2051                                          &fee_closing,
   2052                                          0));
   2053   FAILIF (GNUNET_OK !=
   2054           check_reserve (&reserve_pub,
   2055                          0,
   2056                          0,
   2057                          global_value.currency));
   2058   result = 7;
   2059   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
   2060           plugin->commit (plugin->cls));
   2061 
   2062 
   2063   /* check reserve history */
   2064   {
   2065     struct TALER_Amount balance;
   2066     uint64_t etag_out;
   2067 
   2068     qs = plugin->get_reserve_history (plugin->cls,
   2069                                       &reserve_pub,
   2070                                       0,
   2071                                       0,
   2072                                       &etag_out,
   2073                                       &balance,
   2074                                       &rh);
   2075   }
   2076   FAILIF (0 > qs);
   2077   FAILIF (NULL == rh);
   2078   rh_head = rh;
   2079   {
   2080     unsigned int cnt;
   2081 
   2082     for (cnt = 0;
   2083          NULL != rh_head;
   2084          rh_head = rh_head->next, cnt++)
   2085     {
   2086       switch (rh_head->type)
   2087       {
   2088       case TALER_EXCHANGEDB_RO_BANK_TO_EXCHANGE:
   2089         bt = rh_head->details.bank;
   2090         FAILIF (0 !=
   2091                 GNUNET_memcmp (&bt->reserve_pub,
   2092                                &reserve_pub));
   2093         /* this is the amount we transferred twice*/
   2094         FAILIF (1 != bt->amount.value);
   2095         FAILIF (1000 != bt->amount.fraction);
   2096         FAILIF (0 != strcmp (CURRENCY,
   2097                              bt->amount.currency));
   2098         FAILIF (NULL == bt->sender_account_details.full_payto);
   2099         break;
   2100       case TALER_EXCHANGEDB_RO_WITHDRAW_COINS:
   2101         {
   2102           struct TALER_EXCHANGEDB_Withdraw *rh_withdraw  =
   2103             rh_head->details.withdraw;
   2104           FAILIF (0 !=
   2105                   GNUNET_memcmp (&rh_withdraw->reserve_pub,
   2106                                  &reserve_pub));
   2107 #pragma message "maybe more tests!?"
   2108         }
   2109         break;
   2110       case TALER_EXCHANGEDB_RO_RECOUP_COIN:
   2111         {
   2112           struct TALER_EXCHANGEDB_Recoup *recoup = rh_head->details.recoup;
   2113 
   2114           FAILIF (0 !=
   2115                   GNUNET_memcmp (&recoup->coin_sig,
   2116                                  &coin_sig));
   2117           FAILIF (0 !=
   2118                   GNUNET_memcmp (&recoup->coin_blind,
   2119                                  &coin_blind));
   2120           FAILIF (0 !=
   2121                   GNUNET_memcmp (&recoup->reserve_pub,
   2122                                  &reserve_pub));
   2123           FAILIF (0 !=
   2124                   GNUNET_memcmp (&recoup->coin.coin_pub,
   2125                                  &deposit.coin.coin_pub));
   2126           FAILIF (0 !=
   2127                   TALER_amount_cmp (&recoup->value,
   2128                                     &global_value));
   2129         }
   2130         break;
   2131       case TALER_EXCHANGEDB_RO_EXCHANGE_TO_BANK:
   2132         {
   2133           struct TALER_EXCHANGEDB_ClosingTransfer *closing
   2134             = rh_head->details.closing;
   2135 
   2136           FAILIF (0 !=
   2137                   GNUNET_memcmp (&closing->reserve_pub,
   2138                                  &reserve_pub));
   2139           FAILIF (0 != TALER_amount_cmp (&closing->amount,
   2140                                          &amount_with_fee));
   2141           FAILIF (0 != TALER_amount_cmp (&closing->closing_fee,
   2142                                          &fee_closing));
   2143         }
   2144         break;
   2145       case TALER_EXCHANGEDB_RO_PURSE_MERGE:
   2146         {
   2147           /* FIXME: not yet tested */
   2148           break;
   2149         }
   2150       case TALER_EXCHANGEDB_RO_HISTORY_REQUEST:
   2151         {
   2152           /* FIXME: not yet tested */
   2153           break;
   2154         }
   2155       case TALER_EXCHANGEDB_RO_OPEN_REQUEST:
   2156         {
   2157           /* FIXME: not yet tested */
   2158           break;
   2159         }
   2160       case TALER_EXCHANGEDB_RO_CLOSE_REQUEST:
   2161         {
   2162           /* FIXME: not yet tested */
   2163           break;
   2164         }
   2165       }
   2166     }
   2167     GNUNET_assert (4 == cnt);
   2168     FAILIF (4 != cnt);
   2169   }
   2170 
   2171   auditor_row_cnt = 0;
   2172   FAILIF (0 >=
   2173           plugin->select_reserves_in_above_serial_id (plugin->cls,
   2174                                                       0,
   2175                                                       &audit_reserve_in_cb,
   2176                                                       NULL));
   2177   FAILIF (0 >=
   2178           plugin->select_withdrawals_above_serial_id (plugin->cls,
   2179                                                       0,
   2180                                                       &audit_reserve_out_cb,
   2181                                                       NULL));
   2182   FAILIF (3 != auditor_row_cnt);
   2183 
   2184 
   2185   auditor_row_cnt = 0;
   2186   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   2187           plugin->select_refunds_above_serial_id (plugin->cls,
   2188                                                   0,
   2189                                                   &audit_refund_cb,
   2190                                                   NULL));
   2191   FAILIF (1 != auditor_row_cnt);
   2192   {
   2193     uint64_t etag = 0;
   2194     struct TALER_Amount balance;
   2195     struct TALER_DenominationHashP h_denom_pub;
   2196     struct TALER_EXCHANGEDB_TransactionList *tl;
   2197 
   2198     qs = plugin->get_coin_transactions (plugin->cls,
   2199                                         true,
   2200                                         &refund.coin.coin_pub,
   2201                                         0,
   2202                                         0,
   2203                                         &etag,
   2204                                         &balance,
   2205                                         &h_denom_pub,
   2206                                         &tl);
   2207     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs);
   2208     GNUNET_assert (NULL != tl);
   2209     matched = 0;
   2210     for (struct TALER_EXCHANGEDB_TransactionList *tlp = tl;
   2211          NULL != tlp;
   2212          tlp = tlp->next)
   2213     {
   2214       switch (tlp->type)
   2215       {
   2216       case TALER_EXCHANGEDB_TT_DEPOSIT:
   2217         {
   2218           struct TALER_EXCHANGEDB_DepositListEntry *have = tlp->details.deposit;
   2219 
   2220           /* Note: we're not comparing the denomination keys, as there is
   2221              still the question of whether we should even bother exporting
   2222              them here. */
   2223           FAILIF (0 !=
   2224                   GNUNET_memcmp (&have->csig,
   2225                                  &deposit.csig));
   2226           FAILIF (0 !=
   2227                   GNUNET_memcmp (&have->merchant_pub,
   2228                                  &bd.merchant_pub));
   2229           FAILIF (0 !=
   2230                   GNUNET_memcmp (&have->h_contract_terms,
   2231                                  &bd.h_contract_terms));
   2232           FAILIF (0 !=
   2233                   GNUNET_memcmp (&have->wire_salt,
   2234                                  &bd.wire_salt));
   2235           FAILIF (GNUNET_TIME_timestamp_cmp (have->timestamp,
   2236                                              !=,
   2237                                              bd.wallet_timestamp));
   2238           FAILIF (GNUNET_TIME_timestamp_cmp (have->refund_deadline,
   2239                                              !=,
   2240                                              bd.refund_deadline));
   2241           FAILIF (GNUNET_TIME_timestamp_cmp (have->wire_deadline,
   2242                                              !=,
   2243                                              bd.wire_deadline));
   2244           FAILIF (0 != TALER_amount_cmp (&have->amount_with_fee,
   2245                                          &deposit.amount_with_fee));
   2246           matched |= 1;
   2247           break;
   2248         }
   2249       /* this coin pub was actually never melted... */
   2250       case TALER_EXCHANGEDB_TT_MELT:
   2251         FAILIF (0 !=
   2252                 GNUNET_memcmp (&refresh.rc,
   2253                                &tlp->details.melt->rc));
   2254         matched |= 2;
   2255         break;
   2256       case TALER_EXCHANGEDB_TT_REFUND:
   2257         {
   2258           struct TALER_EXCHANGEDB_RefundListEntry *have = tlp->details.refund;
   2259 
   2260           /* Note: we're not comparing the denomination keys, as there is
   2261              still the question of whether we should even bother exporting
   2262              them here. */
   2263           FAILIF (0 != GNUNET_memcmp (&have->merchant_pub,
   2264                                       &refund.details.merchant_pub));
   2265           FAILIF (0 != GNUNET_memcmp (&have->merchant_sig,
   2266                                       &refund.details.merchant_sig));
   2267           FAILIF (0 != GNUNET_memcmp (&have->h_contract_terms,
   2268                                       &refund.details.h_contract_terms));
   2269           FAILIF (have->rtransaction_id != refund.details.rtransaction_id);
   2270           FAILIF (0 != TALER_amount_cmp (&have->refund_amount,
   2271                                          &refund.details.refund_amount));
   2272           FAILIF (0 != TALER_amount_cmp (&have->refund_fee,
   2273                                          &refund.details.refund_fee));
   2274           matched |= 4;
   2275           break;
   2276         }
   2277       case TALER_EXCHANGEDB_TT_RECOUP:
   2278         {
   2279           struct TALER_EXCHANGEDB_RecoupListEntry *recoup =
   2280             tlp->details.recoup;
   2281 
   2282           FAILIF (0 != GNUNET_memcmp (&recoup->coin_sig,
   2283                                       &coin_sig));
   2284           FAILIF (0 != GNUNET_memcmp (&recoup->coin_blind,
   2285                                       &coin_blind));
   2286           FAILIF (0 != GNUNET_memcmp (&recoup->reserve_pub,
   2287                                       &reserve_pub));
   2288           FAILIF (0 != TALER_amount_cmp (&recoup->value,
   2289                                          &global_value));
   2290           matched |= 8;
   2291           break;
   2292         }
   2293       case TALER_EXCHANGEDB_TT_OLD_COIN_RECOUP:
   2294         /* FIXME: check fields better... */
   2295 #pragma \
   2296         message "TALER_EXCHANGEDB_TT_OLD_COIN_RECOUP case doesn't work right now"
   2297         matched |= 16;
   2298         break;
   2299       default:
   2300         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   2301                     "Unexpected coin history transaction type: %d\n",
   2302                     tlp->type);
   2303         FAILIF (1);
   2304         break;
   2305       }
   2306     }
   2307     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2308                 "matched=%d, SKIPPING FAILIF(31 != matched) FOR NOW\n",
   2309                 matched);
   2310 #pragma message "skipping FAILIF(31 != matched) check for now"
   2311 #if 0
   2312     FAILIF (31 != matched);
   2313 #endif
   2314 
   2315     plugin->free_coin_transaction_list (plugin->cls,
   2316                                         tl);
   2317   }
   2318 
   2319   /* Tests for deposits+wire */
   2320   TALER_denom_sig_free (&deposit.coin.denom_sig);
   2321   memset (&deposit,
   2322           0,
   2323           sizeof (deposit));
   2324   RND_BLK (&deposit.coin.coin_pub);
   2325   TALER_denom_pub_hash (&dkp->pub,
   2326                         &deposit.coin.denom_pub_hash);
   2327   GNUNET_assert (GNUNET_OK ==
   2328                  TALER_denom_sig_unblind (&deposit.coin.denom_sig,
   2329                                           &cbc.sig,
   2330                                           &bks,
   2331                                           &c_hash,
   2332                                           alg_values,
   2333                                           &dkp->pub));
   2334   RND_BLK (&deposit.csig);
   2335   RND_BLK (&bd.merchant_pub);
   2336   RND_BLK (&bd.h_contract_terms);
   2337   RND_BLK (&bd.wire_salt);
   2338   bd.receiver_wire_account.full_payto =
   2339     (char *) "payto://iban/DE67830654080004822650?receiver-name=Test";
   2340   TALER_merchant_wire_signature_hash (
   2341     bd.receiver_wire_account,
   2342     &bd.wire_salt,
   2343     &h_wire_wt);
   2344   deposit.amount_with_fee = global_value;
   2345   bd.refund_deadline = deadline;
   2346   bd.wire_deadline = deadline;
   2347   result = 8;
   2348   FAILIF (GNUNET_OK !=
   2349           plugin->start (plugin->cls,
   2350                          "test-3"));
   2351   {
   2352     uint64_t known_coin_id2;
   2353     struct TALER_DenominationHashP dph;
   2354     struct TALER_AgeCommitmentHashP agh;
   2355 
   2356     FAILIF (TALER_EXCHANGEDB_CKS_ADDED !=
   2357             plugin->ensure_coin_known (plugin->cls,
   2358                                        &deposit.coin,
   2359                                        &known_coin_id2,
   2360                                        &dph,
   2361                                        &agh));
   2362   }
   2363   now = GNUNET_TIME_timestamp_get ();
   2364   {
   2365     struct GNUNET_TIME_Timestamp r;
   2366     struct TALER_Amount deposit_fee;
   2367     struct TALER_MerchantWireHashP h_wire;
   2368     bool balance_ok;
   2369     uint32_t bad_idx;
   2370     bool ctr_conflict;
   2371 
   2372     TALER_full_payto_hash (bd.receiver_wire_account,
   2373                            &bd.wire_target_h_payto);
   2374     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   2375             plugin->do_deposit (plugin->cls,
   2376                                 &bd,
   2377                                 &now,
   2378                                 &balance_ok,
   2379                                 &bad_idx,
   2380                                 &ctr_conflict));
   2381     TALER_merchant_wire_signature_hash (bd.receiver_wire_account,
   2382                                         &bd.wire_salt,
   2383                                         &h_wire);
   2384     FAILIF (1 !=
   2385             plugin->have_deposit2 (plugin->cls,
   2386                                    &bd.h_contract_terms,
   2387                                    &h_wire,
   2388                                    &deposit.coin.coin_pub,
   2389                                    &bd.merchant_pub,
   2390                                    bd.refund_deadline,
   2391                                    &deposit_fee,
   2392                                    &r));
   2393     FAILIF (GNUNET_TIME_timestamp_cmp (now,
   2394                                        !=,
   2395                                        r));
   2396   }
   2397   {
   2398     result = 66;
   2399     FAILIF (0 >=
   2400             plugin->select_batch_deposits_missing_wire (plugin->cls,
   2401                                                         0,
   2402                                                         &wire_missing_cb,
   2403                                                         &deposit));
   2404     FAILIF (8 != result);
   2405   }
   2406   auditor_row_cnt = 0;
   2407   FAILIF (0 >=
   2408           plugin->select_coin_deposits_above_serial_id (plugin->cls,
   2409                                                         0,
   2410                                                         &audit_deposit_cb,
   2411                                                         NULL));
   2412   FAILIF (0 == auditor_row_cnt);
   2413   result = 8;
   2414   sleep (2); /* give deposit time to be ready */
   2415   {
   2416     struct TALER_MerchantPublicKeyP merchant_pub2;
   2417     struct TALER_FullPayto payto_uri2;
   2418 
   2419     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   2420             plugin->get_ready_deposit (plugin->cls,
   2421                                        0,
   2422                                        INT32_MAX,
   2423                                        &merchant_pub2,
   2424                                        &payto_uri2));
   2425     FAILIF (0 != GNUNET_memcmp (&merchant_pub2,
   2426                                 &bd.merchant_pub));
   2427     FAILIF (0 != TALER_full_payto_cmp (payto_uri2,
   2428                                        bd.receiver_wire_account));
   2429     TALER_full_payto_hash (payto_uri2,
   2430                            &global_wire_target_h_payto);
   2431     GNUNET_free (payto_uri2.full_payto);
   2432   }
   2433 
   2434   {
   2435     struct TALER_Amount total;
   2436     struct TALER_WireTransferIdentifierRawP wtid;
   2437 
   2438     memset (&wtid,
   2439             41,
   2440             sizeof (wtid));
   2441     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   2442             plugin->aggregate (plugin->cls,
   2443                                &global_wire_target_h_payto,
   2444                                &bd.merchant_pub,
   2445                                &wtid,
   2446                                &total));
   2447   }
   2448   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
   2449           plugin->commit (plugin->cls));
   2450   FAILIF (GNUNET_OK !=
   2451           plugin->start (plugin->cls,
   2452                          "test-3"));
   2453   {
   2454     struct TALER_WireTransferIdentifierRawP wtid;
   2455     struct TALER_Amount total;
   2456     struct TALER_WireTransferIdentifierRawP wtid2;
   2457     struct TALER_Amount total2;
   2458 
   2459     memset (&wtid,
   2460             42,
   2461             sizeof (wtid));
   2462     GNUNET_assert (GNUNET_OK ==
   2463                    TALER_string_to_amount (CURRENCY ":42",
   2464                                            &total));
   2465     FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
   2466             plugin->select_aggregation_transient (
   2467               plugin->cls,
   2468               &global_wire_target_h_payto,
   2469               &bd.merchant_pub,
   2470               "x-bank",
   2471               &wtid2,
   2472               &total2));
   2473     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   2474             plugin->create_aggregation_transient (
   2475               plugin->cls,
   2476               &global_wire_target_h_payto,
   2477               "x-bank",
   2478               &bd.merchant_pub,
   2479               &wtid,
   2480               0,
   2481               &total));
   2482     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   2483             plugin->select_aggregation_transient (
   2484               plugin->cls,
   2485               &global_wire_target_h_payto,
   2486               &bd.merchant_pub,
   2487               "x-bank",
   2488               &wtid2,
   2489               &total2));
   2490     FAILIF (0 !=
   2491             GNUNET_memcmp (&wtid2,
   2492                            &wtid));
   2493     FAILIF (0 !=
   2494             TALER_amount_cmp (&total2,
   2495                               &total));
   2496     GNUNET_assert (GNUNET_OK ==
   2497                    TALER_string_to_amount (CURRENCY ":43",
   2498                                            &total));
   2499     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   2500             plugin->update_aggregation_transient (
   2501               plugin->cls,
   2502               &global_wire_target_h_payto,
   2503               &wtid,
   2504               0,
   2505               &total));
   2506     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   2507             plugin->select_aggregation_transient (
   2508               plugin->cls,
   2509               &global_wire_target_h_payto,
   2510               &bd.merchant_pub,
   2511               "x-bank",
   2512               &wtid2,
   2513               &total2));
   2514     FAILIF (0 !=
   2515             GNUNET_memcmp (&wtid2,
   2516                            &wtid));
   2517     FAILIF (0 !=
   2518             TALER_amount_cmp (&total2,
   2519                               &total));
   2520     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   2521             plugin->delete_aggregation_transient (
   2522               plugin->cls,
   2523               &global_wire_target_h_payto,
   2524               &wtid));
   2525     FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
   2526             plugin->select_aggregation_transient (
   2527               plugin->cls,
   2528               &global_wire_target_h_payto,
   2529               &bd.merchant_pub,
   2530               "x-bank",
   2531               &wtid2,
   2532               &total2));
   2533   }
   2534   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
   2535           plugin->commit (plugin->cls));
   2536 
   2537   result = 10;
   2538   FAILIF (GNUNET_OK !=
   2539           plugin->start (plugin->cls,
   2540                          "test-2"));
   2541   RND_BLK (&mpub2); /* should fail if merchant is different */
   2542   {
   2543     struct TALER_MerchantWireHashP h_wire;
   2544     struct GNUNET_TIME_Timestamp r;
   2545     struct TALER_Amount deposit_fee;
   2546 
   2547     TALER_merchant_wire_signature_hash (bd.receiver_wire_account,
   2548                                         &bd.wire_salt,
   2549                                         &h_wire);
   2550     FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
   2551             plugin->have_deposit2 (plugin->cls,
   2552                                    &bd.h_contract_terms,
   2553                                    &h_wire,
   2554                                    &deposit.coin.coin_pub,
   2555                                    &mpub2,
   2556                                    bd.refund_deadline,
   2557                                    &deposit_fee,
   2558                                    &r));
   2559     RND_BLK (&cpub2); /* should fail if coin is different */
   2560     FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
   2561             plugin->have_deposit2 (plugin->cls,
   2562                                    &bd.h_contract_terms,
   2563                                    &h_wire,
   2564                                    &cpub2,
   2565                                    &bd.merchant_pub,
   2566                                    bd.refund_deadline,
   2567                                    &deposit_fee,
   2568                                    &r));
   2569   }
   2570   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
   2571           plugin->commit (plugin->cls));
   2572 
   2573 
   2574   /* test revocation */
   2575   FAILIF (GNUNET_OK !=
   2576           plugin->start (plugin->cls,
   2577                          "test-3b"));
   2578   RND_BLK (&master_sig);
   2579   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   2580           plugin->insert_denomination_revocation (plugin->cls,
   2581                                                   &cbc.denom_pub_hash,
   2582                                                   &master_sig));
   2583   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
   2584           plugin->commit (plugin->cls));
   2585   plugin->preflight (plugin->cls);
   2586   FAILIF (GNUNET_OK !=
   2587           plugin->start (plugin->cls,
   2588                          "test-4"));
   2589   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
   2590           plugin->insert_denomination_revocation (plugin->cls,
   2591                                                   &cbc.denom_pub_hash,
   2592                                                   &master_sig));
   2593   plugin->rollback (plugin->cls);
   2594   plugin->preflight (plugin->cls);
   2595   FAILIF (GNUNET_OK !=
   2596           plugin->start (plugin->cls,
   2597                          "test-5"));
   2598   {
   2599     struct TALER_MasterSignatureP msig;
   2600     uint64_t rev_rowid;
   2601 
   2602     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   2603             plugin->get_denomination_revocation (plugin->cls,
   2604                                                  &cbc.denom_pub_hash,
   2605                                                  &msig,
   2606                                                  &rev_rowid));
   2607     FAILIF (0 != GNUNET_memcmp (&msig,
   2608                                 &master_sig));
   2609   }
   2610 
   2611 
   2612   plugin->rollback (plugin->cls);
   2613   FAILIF (GNUNET_OK !=
   2614           test_wire_prepare ());
   2615   FAILIF (GNUNET_OK !=
   2616           test_wire_out (&bd));
   2617   FAILIF (GNUNET_OK !=
   2618           test_gc ());
   2619   FAILIF (GNUNET_OK !=
   2620           test_wire_fees ());
   2621 
   2622   plugin->preflight (plugin->cls);
   2623 
   2624   result = 0;
   2625 
   2626 drop:
   2627   if (0 != result)
   2628     plugin->rollback (plugin->cls);
   2629   if (NULL != rh)
   2630     plugin->free_reserve_history (plugin->cls,
   2631                                   rh);
   2632   rh = NULL;
   2633   GNUNET_break (GNUNET_OK ==
   2634                 plugin->drop_tables (plugin->cls));
   2635 cleanup:
   2636   if (NULL != dkp)
   2637     destroy_denom_key_pair (dkp);
   2638   if (NULL != revealed_coins)
   2639   {
   2640     for (unsigned int cnt = 0; cnt < MELT_NEW_COINS; cnt++)
   2641     {
   2642       TALER_blinded_denom_sig_free (&revealed_coins[cnt].coin_sig);
   2643       TALER_blinded_planchet_free (&revealed_coins[cnt].blinded_planchet);
   2644     }
   2645     GNUNET_free (revealed_coins);
   2646     revealed_coins = NULL;
   2647   }
   2648   GNUNET_free (new_denom_pubs);
   2649   for (unsigned int cnt = 0;
   2650        (NULL != new_dkp) && (cnt < MELT_NEW_COINS) && (NULL != new_dkp[cnt]);
   2651        cnt++)
   2652     destroy_denom_key_pair (new_dkp[cnt]);
   2653   GNUNET_free (new_dkp);
   2654   TALER_denom_sig_free (&deposit.coin.denom_sig);
   2655   TALER_blinded_denom_sig_free (&cbc.sig);
   2656   TALER_blinded_denom_sig_free (withdraw.denom_sigs);
   2657   dkp = NULL;
   2658   TALER_EXCHANGEDB_plugin_unload (plugin);
   2659   plugin = NULL;
   2660 }
   2661 
   2662 
   2663 int
   2664 main (int argc,
   2665       char *const argv[])
   2666 {
   2667   const char *plugin_name;
   2668   char *config_filename;
   2669   char *testname;
   2670   struct GNUNET_CONFIGURATION_Handle *cfg;
   2671 
   2672   (void) argc;
   2673   result = -1;
   2674   if (NULL == (plugin_name = strrchr (argv[0], (int) '-')))
   2675   {
   2676     GNUNET_break (0);
   2677     return -1;
   2678   }
   2679   GNUNET_log_setup (argv[0],
   2680                     "INFO",
   2681                     NULL);
   2682   plugin_name++;
   2683   (void) GNUNET_asprintf (&testname,
   2684                           "test-exchange-db-%s",
   2685                           plugin_name);
   2686   (void) GNUNET_asprintf (&config_filename,
   2687                           "%s.conf",
   2688                           testname);
   2689   cfg = GNUNET_CONFIGURATION_create (TALER_EXCHANGE_project_data ());
   2690   if (GNUNET_OK !=
   2691       GNUNET_CONFIGURATION_parse (cfg,
   2692                                   config_filename))
   2693   {
   2694     GNUNET_break (0);
   2695     GNUNET_free (config_filename);
   2696     GNUNET_free (testname);
   2697     return 2;
   2698   }
   2699   GNUNET_SCHEDULER_run (&run,
   2700                         cfg);
   2701   GNUNET_CONFIGURATION_destroy (cfg);
   2702   GNUNET_free (config_filename);
   2703   GNUNET_free (testname);
   2704   return result;
   2705 }
   2706 
   2707 
   2708 /* end of test_exchangedb.c */