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


      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 (GNUNET_CRYPTO_QUALITY_WEAK, 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 (GNUNET_CRYPTO_QUALITY_WEAK,
    892                               &master_sig,
    893                               sizeof (master_sig));
    894   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
    895       plugin->insert_wire_fee (plugin->cls,
    896                                "wire-method",
    897                                start_date,
    898                                end_date,
    899                                &fees,
    900                                &master_sig))
    901   {
    902     GNUNET_break (0);
    903     return GNUNET_SYSERR;
    904   }
    905   if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
    906       plugin->insert_wire_fee (plugin->cls,
    907                                "wire-method",
    908                                start_date,
    909                                end_date,
    910                                &fees,
    911                                &master_sig))
    912   {
    913     GNUNET_break (0);
    914     return GNUNET_SYSERR;
    915   }
    916   /* This must fail as 'end_date' is NOT in the
    917      half-open interval [start_date,end_date) */
    918   if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
    919       plugin->get_wire_fee (plugin->cls,
    920                             "wire-method",
    921                             end_date,
    922                             &rowid,
    923                             &sd,
    924                             &ed,
    925                             &fees2,
    926                             &ms))
    927   {
    928     GNUNET_break (0);
    929     return GNUNET_SYSERR;
    930   }
    931   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
    932       plugin->get_wire_fee (plugin->cls,
    933                             "wire-method",
    934                             start_date,
    935                             &rowid,
    936                             &sd,
    937                             &ed,
    938                             &fees2,
    939                             &ms))
    940   {
    941     GNUNET_break (0);
    942     return GNUNET_SYSERR;
    943   }
    944   if ( (GNUNET_TIME_timestamp_cmp (sd,
    945                                    !=,
    946                                    start_date)) ||
    947        (GNUNET_TIME_timestamp_cmp (ed,
    948                                    !=,
    949                                    end_date)) ||
    950        (0 != TALER_wire_fee_set_cmp (&fees,
    951                                      &fees2)) ||
    952        (0 != GNUNET_memcmp (&ms,
    953                             &master_sig)) )
    954   {
    955     GNUNET_break (0);
    956     return GNUNET_SYSERR;
    957   }
    958   return GNUNET_OK;
    959 }
    960 
    961 
    962 static struct TALER_Amount wire_out_amount;
    963 
    964 
    965 /**
    966  * Callback with data about an executed wire transfer.
    967  *
    968  * @param cls closure
    969  * @param rowid identifier of the respective row in the database
    970  * @param date timestamp of the wire transfer (roughly)
    971  * @param wtid wire transfer subject
    972  * @param wire wire transfer details of the receiver
    973  * @param amount amount that was wired
    974  * @return #GNUNET_OK to continue, #GNUNET_SYSERR to stop iteration
    975  */
    976 static enum GNUNET_GenericReturnValue
    977 audit_wire_cb (void *cls,
    978                uint64_t rowid,
    979                struct GNUNET_TIME_Timestamp date,
    980                const struct TALER_WireTransferIdentifierRawP *wtid,
    981                const struct TALER_FullPayto payto_uri,
    982                const struct TALER_Amount *amount)
    983 {
    984   (void) cls;
    985   (void) rowid;
    986   (void) payto_uri;
    987   auditor_row_cnt++;
    988   GNUNET_assert (0 ==
    989                  TALER_amount_cmp (amount,
    990                                    &wire_out_amount));
    991   GNUNET_assert (0 ==
    992                  GNUNET_memcmp (wtid,
    993                                 &wire_out_wtid));
    994   GNUNET_assert (GNUNET_TIME_timestamp_cmp (date,
    995                                             ==,
    996                                             wire_out_date));
    997   return GNUNET_OK;
    998 }
    999 
   1000 
   1001 /**
   1002  * Test API relating to wire_out handling.
   1003  *
   1004  * @param bd batch deposit to test
   1005  * @return #GNUNET_OK on success
   1006  */
   1007 static enum GNUNET_GenericReturnValue
   1008 test_wire_out (const struct TALER_EXCHANGEDB_BatchDeposit *bd)
   1009 {
   1010   const struct TALER_EXCHANGEDB_CoinDepositInformation *deposit = &bd->cdis[0];
   1011   struct TALER_FullPaytoHashP h_payto;
   1012 
   1013   GNUNET_assert (0 < bd->num_cdis);
   1014   TALER_full_payto_hash (bd->receiver_wire_account,
   1015                          &h_payto);
   1016   auditor_row_cnt = 0;
   1017   memset (&wire_out_wtid,
   1018           41,
   1019           sizeof (wire_out_wtid));
   1020   wire_out_date = GNUNET_TIME_timestamp_get ();
   1021   GNUNET_assert (GNUNET_OK ==
   1022                  TALER_string_to_amount (CURRENCY ":1",
   1023                                          &wire_out_amount));
   1024 
   1025   /* we will transiently violate the wtid constraint on
   1026      the aggregation table, so we need to start the special
   1027      transaction where this is allowed... */
   1028   FAILIF (GNUNET_OK !=
   1029           plugin->start_deferred_wire_out (plugin->cls));
   1030 
   1031   /* setup values for wire transfer aggregation data */
   1032   merchant_pub_wt = bd->merchant_pub;
   1033   h_contract_terms_wt = bd->h_contract_terms;
   1034   coin_pub_wt = deposit->coin.coin_pub;
   1035 
   1036   coin_value_wt = deposit->amount_with_fee;
   1037   coin_fee_wt = global_fees.deposit;
   1038   GNUNET_assert (0 <
   1039                  TALER_amount_subtract (&transfer_value_wt,
   1040                                         &coin_value_wt,
   1041                                         &coin_fee_wt));
   1042   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
   1043           plugin->lookup_wire_transfer (plugin->cls,
   1044                                         &wire_out_wtid,
   1045                                         &cb_wt_never,
   1046                                         NULL));
   1047 
   1048   {
   1049     struct TALER_PrivateContractHashP h_contract_terms_wt2 =
   1050       h_contract_terms_wt;
   1051     bool pending;
   1052     struct TALER_WireTransferIdentifierRawP wtid2;
   1053     struct TALER_Amount coin_contribution2;
   1054     struct TALER_Amount coin_fee2;
   1055     struct GNUNET_TIME_Timestamp execution_time2;
   1056     struct TALER_EXCHANGEDB_KycStatus kyc;
   1057     union TALER_AccountPublicKeyP account_pub;
   1058 
   1059     h_contract_terms_wt2.hash.bits[0]++;
   1060     FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
   1061             plugin->lookup_transfer_by_deposit (plugin->cls,
   1062                                                 &h_contract_terms_wt2,
   1063                                                 &h_wire_wt,
   1064                                                 &coin_pub_wt,
   1065                                                 &merchant_pub_wt,
   1066                                                 &pending,
   1067                                                 &wtid2,
   1068                                                 &execution_time2,
   1069                                                 &coin_contribution2,
   1070                                                 &coin_fee2,
   1071                                                 &kyc,
   1072                                                 &account_pub));
   1073   }
   1074   {
   1075     struct TALER_ReservePublicKeyP rpub;
   1076 
   1077     memset (&rpub,
   1078             44,
   1079             sizeof (rpub));
   1080     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1081             plugin->store_wire_transfer_out (plugin->cls,
   1082                                              wire_out_date,
   1083                                              &wire_out_wtid,
   1084                                              &h_payto,
   1085                                              "my-config-section",
   1086                                              &wire_out_amount));
   1087   }
   1088   /* And now the commit should still succeed! */
   1089   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
   1090           plugin->commit (plugin->cls));
   1091 
   1092   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1093           plugin->lookup_wire_transfer (plugin->cls,
   1094                                         &wire_out_wtid,
   1095                                         &cb_wt_check,
   1096                                         &cb_wt_never));
   1097   {
   1098     bool pending;
   1099     struct TALER_WireTransferIdentifierRawP wtid2;
   1100     struct TALER_Amount coin_contribution2;
   1101     struct TALER_Amount coin_fee2;
   1102     struct GNUNET_TIME_Timestamp execution_time2;
   1103     struct TALER_EXCHANGEDB_KycStatus kyc;
   1104     union TALER_AccountPublicKeyP account_pub;
   1105 
   1106     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1107             plugin->lookup_transfer_by_deposit (plugin->cls,
   1108                                                 &h_contract_terms_wt,
   1109                                                 &h_wire_wt,
   1110                                                 &coin_pub_wt,
   1111                                                 &merchant_pub_wt,
   1112                                                 &pending,
   1113                                                 &wtid2,
   1114                                                 &execution_time2,
   1115                                                 &coin_contribution2,
   1116                                                 &coin_fee2,
   1117                                                 &kyc,
   1118                                                 &account_pub));
   1119     GNUNET_assert (0 == GNUNET_memcmp (&wtid2,
   1120                                        &wire_out_wtid));
   1121     GNUNET_assert (GNUNET_TIME_timestamp_cmp (execution_time2,
   1122                                               ==,
   1123                                               wire_out_date));
   1124     GNUNET_assert (0 == TALER_amount_cmp (&coin_contribution2,
   1125                                           &coin_value_wt));
   1126     GNUNET_assert (0 == TALER_amount_cmp (&coin_fee2,
   1127                                           &coin_fee_wt));
   1128   }
   1129   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1130           plugin->select_wire_out_above_serial_id (plugin->cls,
   1131                                                    0,
   1132                                                    &audit_wire_cb,
   1133                                                    NULL));
   1134   FAILIF (1 != auditor_row_cnt);
   1135 
   1136   return GNUNET_OK;
   1137 drop:
   1138   return GNUNET_SYSERR;
   1139 }
   1140 
   1141 
   1142 /**
   1143  * Function called about recoups the exchange has to perform.
   1144  *
   1145  * @param cls closure with the expected value for @a coin_blind
   1146  * @param rowid row identifier used to uniquely identify the recoup operation
   1147  * @param timestamp when did we receive the recoup request
   1148  * @param amount how much should be added back to the reserve
   1149  * @param reserve_pub public key of the reserve
   1150  * @param coin public information about the coin
   1151  * @param denom_pub denomination key of @a coin
   1152  * @param coin_sig signature with @e coin_pub of type #TALER_SIGNATURE_WALLET_COIN_RECOUP
   1153  * @param coin_blind blinding factor used to blind the coin
   1154  * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
   1155  */
   1156 static enum GNUNET_GenericReturnValue
   1157 recoup_cb (void *cls,
   1158            uint64_t rowid,
   1159            struct GNUNET_TIME_Timestamp timestamp,
   1160            const struct TALER_Amount *amount,
   1161            const struct TALER_ReservePublicKeyP *reserve_pub,
   1162            const struct TALER_CoinPublicInfo *coin,
   1163            const struct TALER_DenominationPublicKey *denom_pub,
   1164            const struct TALER_CoinSpendSignatureP *coin_sig,
   1165            const union GNUNET_CRYPTO_BlindingSecretP *coin_blind)
   1166 {
   1167   const union GNUNET_CRYPTO_BlindingSecretP *cb = cls;
   1168 
   1169   (void) rowid;
   1170   (void) timestamp;
   1171   (void) amount;
   1172   (void) reserve_pub;
   1173   (void) coin_sig;
   1174   (void) coin;
   1175   (void) denom_pub;
   1176   FAILIF (NULL == cb);
   1177   FAILIF (0 != GNUNET_memcmp (cb,
   1178                               coin_blind));
   1179   return GNUNET_OK;
   1180 drop:
   1181   return GNUNET_SYSERR;
   1182 }
   1183 
   1184 
   1185 /**
   1186  * Function called on batch deposits that may require a
   1187  * wire transfer.
   1188  *
   1189  * @param cls closure a `struct TALER_EXCHANGEDB_Deposit *`
   1190  * @param batch_deposit_serial_id where in the table are we
   1191  * @param total_amount value of all missing deposits, including fees
   1192  * @param wire_target_h_payto hash of the recipient account's payto URI
   1193  * @param deadline what was the earliest requested wire transfer deadline
   1194  */
   1195 static void
   1196 wire_missing_cb (
   1197   struct TALER_EXCHANGEDB_PostgresContext *pg,
   1198   uint64_t batch_deposit_serial_id,
   1199   const struct TALER_Amount *total_amount,
   1200   const struct TALER_FullPaytoHashP *wire_target_h_payto,
   1201   struct GNUNET_TIME_Timestamp deadline)
   1202 {
   1203   const struct TALER_EXCHANGEDB_CoinDepositInformation *deposit = cls;
   1204 
   1205   (void) batch_deposit_serial_id;
   1206   (void) deadline;
   1207   (void) wire_target_h_payto;
   1208   if (0 ==
   1209       TALER_amount_cmp (total_amount,
   1210                         &deposit->amount_with_fee))
   1211     result = 8;
   1212 }
   1213 
   1214 
   1215 /**
   1216  * Callback invoked with information about refunds applicable
   1217  * to a particular coin.
   1218  *
   1219  * @param cls closure with the `struct TALER_EXCHANGEDB_Refund *` we expect to get
   1220  * @param amount_with_fee amount being refunded
   1221  * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
   1222  */
   1223 static enum GNUNET_GenericReturnValue
   1224 check_refund_cb (void *cls,
   1225                  const struct TALER_Amount *amount_with_fee)
   1226 {
   1227   const struct TALER_EXCHANGEDB_Refund *refund = cls;
   1228 
   1229   if (0 != TALER_amount_cmp (amount_with_fee,
   1230                              &refund->details.refund_amount))
   1231   {
   1232     GNUNET_break (0);
   1233     result = 66;
   1234   }
   1235   return GNUNET_OK;
   1236 }
   1237 
   1238 
   1239 /**
   1240  * Information about a melt operation.
   1241  */
   1242 struct TALER_EXCHANGEDB_Melt
   1243 {
   1244 
   1245   /**
   1246    * Overall session data.
   1247    */
   1248   struct TALER_EXCHANGEDB_Refresh session;
   1249 
   1250   /**
   1251    * Melt fee the exchange charged.
   1252    */
   1253   struct TALER_Amount melt_fee;
   1254 
   1255 };
   1256 
   1257 
   1258 /**
   1259  * Main function that will be run by the scheduler.
   1260  *
   1261  * @param cls closure with config
   1262  */
   1263 static void
   1264 run (struct TALER_EXCHANGEDB_PostgresContext *pg)
   1265 {
   1266   struct GNUNET_CONFIGURATION_Handle *cfg = cls;
   1267   struct TALER_CoinSpendSignatureP coin_sig;
   1268   struct GNUNET_TIME_Timestamp deadline;
   1269   union GNUNET_CRYPTO_BlindingSecretP coin_blind;
   1270   struct TALER_ReservePublicKeyP reserve_pub;
   1271   struct TALER_ReservePublicKeyP reserve_pub2;
   1272   struct TALER_ReservePublicKeyP reserve_pub3;
   1273   struct DenomKeyPair *dkp = NULL;
   1274   struct TALER_MasterSignatureP master_sig;
   1275   struct TALER_EXCHANGEDB_CollectableBlindcoin cbc;
   1276   struct TALER_EXCHANGEDB_ReserveHistory *rh = NULL;
   1277   struct TALER_EXCHANGEDB_ReserveHistory *rh_head;
   1278   struct TALER_EXCHANGEDB_BankTransfer *bt;
   1279   struct TALER_EXCHANGEDB_Withdraw withdraw;
   1280   struct TALER_HashBlindedPlanchetsP h_planchets;
   1281   struct TALER_EXCHANGEDB_CoinDepositInformation deposit;
   1282   struct TALER_EXCHANGEDB_BatchDeposit bd;
   1283   struct TALER_CoinSpendPublicKeyP cpub2;
   1284   struct TALER_MerchantPublicKeyP mpub2;
   1285   struct TALER_EXCHANGEDB_Refund refund;
   1286   const struct TALER_FullPayto sndr = {
   1287     (char *) "payto://x-taler-bank/localhost:8080/1?receiver-name=1"
   1288   };
   1289   const struct TALER_FullPayto rcvr = {
   1290     (char *) "payto://x-taler-bank/localhost:8080/2?receiver-name=1"
   1291   };
   1292   const uint32_t num_partitions = 10;
   1293   unsigned int matched;
   1294   enum GNUNET_DB_QueryStatus qs;
   1295   struct GNUNET_TIME_Timestamp now;
   1296   struct TALER_WireSaltP salt;
   1297   struct TALER_CoinPubHashP c_hash;
   1298   uint64_t known_coin_id;
   1299   uint64_t rrc_serial;
   1300   struct TALER_EXCHANGEDB_Refresh refresh;
   1301   struct TALER_DenominationPublicKey *new_denom_pubs = NULL;
   1302   uint64_t withdraw_serial_id;
   1303   uint64_t melt_serial_id;
   1304   struct TALER_PlanchetMasterSecretP ps;
   1305   union GNUNET_CRYPTO_BlindingSecretP bks;
   1306   struct TALER_Amount amount_with_fee;
   1307   const struct TALER_ExchangeBlindingValues *alg_values
   1308     = TALER_denom_ewv_rsa_singleton ();
   1309 
   1310   memset (&deposit,
   1311           0,
   1312           sizeof (deposit));
   1313   memset (&bd,
   1314           0,
   1315           sizeof (bd));
   1316   bd.receiver_wire_account = rcvr;
   1317   bd.cdis = &deposit;
   1318   bd.num_cdis = 1;
   1319   memset (&salt,
   1320           45,
   1321           sizeof (salt));
   1322   memset (&refresh,
   1323           0,
   1324           sizeof (refresh));
   1325   ZR_BLK (&cbc);
   1326   ZR_BLK (&withdraw);
   1327   if (NULL ==
   1328       (plugin = TALER_EXCHANGEDB_plugin_load (cfg,
   1329                                               true)))
   1330   {
   1331     result = 77;
   1332     return;
   1333   }
   1334   (void) plugin->drop_tables (plugin->cls);
   1335   if (GNUNET_OK !=
   1336       plugin->create_tables (plugin->cls,
   1337                              true,
   1338                              num_partitions))
   1339   {
   1340     result = 77;
   1341     goto cleanup;
   1342   }
   1343   plugin->preflight (plugin->cls);
   1344   FAILIF (GNUNET_OK !=
   1345           plugin->start (plugin->cls,
   1346                          "test-1"));
   1347 
   1348 
   1349   /* test DB is empty */
   1350   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
   1351           plugin->select_recoup_above_serial_id (plugin->cls,
   1352                                                  0,
   1353                                                  &recoup_cb,
   1354                                                  NULL));
   1355 
   1356   RND_BLK (&reserve_pub);
   1357   GNUNET_assert (GNUNET_OK ==
   1358                  TALER_string_to_amount (CURRENCY ":1.000000",
   1359                                          &global_amount));
   1360   GNUNET_assert (GNUNET_OK ==
   1361                  TALER_string_to_amount (CURRENCY ":1.000010",
   1362                                          &global_value));
   1363   GNUNET_assert (GNUNET_OK ==
   1364                  TALER_string_to_amount (CURRENCY ":0.000010",
   1365                                          &global_fees.withdraw));
   1366   GNUNET_assert (GNUNET_OK ==
   1367                  TALER_string_to_amount (CURRENCY ":0.000010",
   1368                                          &global_fees.deposit));
   1369   GNUNET_assert (GNUNET_OK ==
   1370                  TALER_string_to_amount (CURRENCY ":0.000010",
   1371                                          &global_fees.refresh));
   1372   GNUNET_assert (GNUNET_OK ==
   1373                  TALER_string_to_amount (CURRENCY ":0.000010",
   1374                                          &global_fees.refund));
   1375   GNUNET_assert (GNUNET_OK ==
   1376                  TALER_string_to_amount (CURRENCY ":1.000010",
   1377                                          &amount_with_fee));
   1378   result = 4;
   1379   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
   1380           plugin->commit (plugin->cls));
   1381   now = GNUNET_TIME_timestamp_get ();
   1382   {
   1383     struct TALER_EXCHANGEDB_ReserveInInfo reserve = {
   1384       .reserve_pub = &reserve_pub,
   1385       .balance = &global_value,
   1386       .execution_time = now,
   1387       .sender_account_details = sndr,
   1388       .exchange_account_name = "exchange-account-1",
   1389       .wire_reference = 4
   1390     };
   1391     enum GNUNET_DB_QueryStatus qsr;
   1392 
   1393     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1394             plugin->reserves_in_insert (plugin->cls,
   1395                                         &reserve,
   1396                                         1,
   1397                                         &qsr));
   1398     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1399             qsr);
   1400   }
   1401   FAILIF (GNUNET_OK !=
   1402           check_reserve (&reserve_pub,
   1403                          global_value.value,
   1404                          global_value.fraction,
   1405                          global_value.currency));
   1406   now = GNUNET_TIME_timestamp_get ();
   1407   RND_BLK (&reserve_pub2);
   1408   {
   1409     struct TALER_EXCHANGEDB_ReserveInInfo reserve = {
   1410       .reserve_pub = &reserve_pub2,
   1411       .balance = &global_value,
   1412       .execution_time = now,
   1413       .sender_account_details = sndr,
   1414       .exchange_account_name = "exchange-account-1",
   1415       .wire_reference = 5
   1416     };
   1417     enum GNUNET_DB_QueryStatus qsr;
   1418 
   1419     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1420             plugin->reserves_in_insert (plugin->cls,
   1421                                         &reserve,
   1422                                         1,
   1423                                         &qsr));
   1424     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1425             qsr);
   1426   }
   1427   FAILIF (GNUNET_OK !=
   1428           plugin->start (plugin->cls,
   1429                          "test-2"));
   1430   FAILIF (GNUNET_OK !=
   1431           check_reserve (&reserve_pub,
   1432                          global_value.value,
   1433                          global_value.fraction,
   1434                          global_value.currency));
   1435   FAILIF (GNUNET_OK !=
   1436           check_reserve (&reserve_pub2,
   1437                          global_value.value,
   1438                          global_value.fraction,
   1439                          global_value.currency));
   1440   result = 5;
   1441   now = GNUNET_TIME_timestamp_get ();
   1442   dkp = create_denom_key_pair (RSA_KEY_SIZE,
   1443                                now,
   1444                                &global_value,
   1445                                &global_fees);
   1446   GNUNET_assert (NULL != dkp);
   1447   TALER_denom_pub_hash (&dkp->pub,
   1448                         &cbc.denom_pub_hash);
   1449   RND_BLK (&cbc.reserve_sig);
   1450   RND_BLK (&ps);
   1451   TALER_planchet_blinding_secret_create (&ps,
   1452                                          alg_values,
   1453                                          &bks);
   1454   {
   1455     struct TALER_PlanchetDetail pd;
   1456     struct TALER_CoinSpendPublicKeyP coin_pub;
   1457 
   1458 
   1459     RND_BLK (&coin_pub);
   1460     GNUNET_assert (GNUNET_OK ==
   1461                    TALER_denom_blind (&dkp->pub,
   1462                                       &bks,
   1463                                       NULL,
   1464                                       NULL,
   1465                                       &coin_pub,
   1466                                       alg_values,
   1467                                       &c_hash,
   1468                                       &pd.blinded_planchet));
   1469     TALER_coin_ev_hash (&pd.blinded_planchet,
   1470                         &cbc.denom_pub_hash,
   1471                         &cbc.h_coin_envelope);
   1472 
   1473     GNUNET_assert (
   1474       GNUNET_OK ==
   1475       TALER_denom_sign_blinded (
   1476         &cbc.sig,
   1477         &dkp->priv,
   1478         false,
   1479         &pd.blinded_planchet));
   1480 
   1481     TALER_wallet_blinded_planchets_hash (
   1482       1,
   1483       &pd.blinded_planchet,
   1484       &cbc.denom_pub_hash,
   1485       &h_planchets);
   1486 
   1487     TALER_blinded_planchet_free (&pd.blinded_planchet);
   1488   }
   1489 
   1490   cbc.reserve_pub = reserve_pub;
   1491   cbc.amount_with_fee = global_value;
   1492   GNUNET_assert (GNUNET_OK ==
   1493                  TALER_amount_set_zero (CURRENCY,
   1494                                         &cbc.withdraw_fee));
   1495 
   1496   {
   1497     bool balance_ok;
   1498     bool age_ok;
   1499     bool idempotent;
   1500     uint16_t noreveal_index;
   1501     bool nonce_reuse;
   1502     uint16_t maximum_age;
   1503     uint32_t reserve_birthday;
   1504     uint64_t denom_serial = 1; /* bold assumption */
   1505     struct TALER_Amount reserve_balance;
   1506     struct TALER_BlindingMasterSeedP blinding_seed = {0};
   1507     struct GNUNET_CRYPTO_CSPublicRPairP cs_r_pubs = {0};
   1508     struct TALER_EXCHANGEDB_Withdraw withdraw_in = {
   1509       .amount_with_fee = global_value,
   1510       .age_proof_required = true,
   1511       .max_age = 0,
   1512       .noreveal_index = 42,
   1513       .reserve_pub = reserve_pub,
   1514       .reserve_sig = cbc.reserve_sig,
   1515       .h_planchets = h_planchets,
   1516       .no_blinding_seed = false,
   1517       .blinding_seed = blinding_seed,
   1518       .num_coins = 1,
   1519       .h_coin_evs = &cbc.h_coin_envelope,
   1520       .denom_sigs = &cbc.sig,
   1521       .denom_serials = &denom_serial,
   1522       .num_cs_r_pubs = 1,
   1523       .cs_r_pubs = &cs_r_pubs,
   1524     };
   1525     struct TALER_Amount zero_amount;
   1526 
   1527     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1528             plugin->do_withdraw (plugin->cls,
   1529                                  &withdraw_in,
   1530                                  &now,
   1531                                  &balance_ok,
   1532                                  &reserve_balance,
   1533                                  &age_ok,
   1534                                  &maximum_age,
   1535                                  &reserve_birthday,
   1536                                  &idempotent,
   1537                                  &noreveal_index,
   1538                                  &nonce_reuse));
   1539     GNUNET_assert (! idempotent);
   1540     GNUNET_assert (! nonce_reuse);
   1541     GNUNET_assert (balance_ok);
   1542 
   1543 
   1544     /**
   1545      * Set the amount in the withdraw to zero,
   1546      * to avoid triggering balance_ok issues for
   1547      * the conflict and nonce_reuse tests.
   1548      */
   1549     GNUNET_assert  (GNUNET_OK ==
   1550                     TALER_string_to_amount (CURRENCY ":0.000000",
   1551                                             &zero_amount));
   1552     withdraw_in.amount_with_fee = zero_amount;
   1553 
   1554     /**
   1555      * Change some values to trigger conflict
   1556      * due to h_planchet, not nonce.
   1557      */
   1558     withdraw_in.blinding_seed.key_data[0] = 1;
   1559     noreveal_index = -1;
   1560     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1561             plugin->do_withdraw (plugin->cls,
   1562                                  &withdraw_in,
   1563                                  &now,
   1564                                  &balance_ok,
   1565                                  &reserve_balance,
   1566                                  &age_ok,
   1567                                  &maximum_age,
   1568                                  &reserve_birthday,
   1569                                  &idempotent,
   1570                                  &noreveal_index,
   1571                                  &nonce_reuse));
   1572     GNUNET_assert (! nonce_reuse);
   1573     GNUNET_assert (idempotent);
   1574     GNUNET_assert (42 == noreveal_index);
   1575 
   1576     /**
   1577      * Make h_planchet unique again, but trigger
   1578      * conflict with blinding_seed.
   1579      */
   1580     withdraw_in.blinding_seed.key_data[0] = 0;
   1581     withdraw_in.h_planchets.hash.bits[0] += 1;
   1582     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1583             plugin->do_withdraw (plugin->cls,
   1584                                  &withdraw_in,
   1585                                  &now,
   1586                                  &balance_ok,
   1587                                  &reserve_balance,
   1588                                  &age_ok,
   1589                                  &maximum_age,
   1590                                  &reserve_birthday,
   1591                                  &idempotent,
   1592                                  &noreveal_index,
   1593                                  &nonce_reuse));
   1594     GNUNET_assert (! idempotent);
   1595     GNUNET_assert (nonce_reuse);
   1596   }
   1597 
   1598   FAILIF (GNUNET_OK !=
   1599           check_reserve (&reserve_pub,
   1600                          0,
   1601                          0,
   1602                          global_value.currency));
   1603   FAILIF (GNUNET_OK !=
   1604           check_reserve (&reserve_pub2,
   1605                          global_value.value,
   1606                          global_value.fraction,
   1607                          global_value.currency));
   1608   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1609           plugin->get_reserve_by_h_planchets (plugin->cls,
   1610                                               &h_planchets,
   1611                                               &reserve_pub3,
   1612                                               &withdraw_serial_id));
   1613   FAILIF (0 != GNUNET_memcmp (&reserve_pub,
   1614                               &reserve_pub3));
   1615   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1616           plugin->get_withdraw (plugin->cls,
   1617                                 &h_planchets,
   1618                                 &withdraw));
   1619   FAILIF (0 != GNUNET_memcmp (&withdraw.reserve_sig,
   1620                               &cbc.reserve_sig));
   1621   FAILIF (0 != GNUNET_memcmp (&withdraw.reserve_pub,
   1622                               &cbc.reserve_pub));
   1623   result = 6;
   1624 
   1625   {
   1626     struct TALER_DenominationSignature ds;
   1627 
   1628     GNUNET_assert (GNUNET_OK ==
   1629                    TALER_denom_sig_unblind (&ds,
   1630                                             &withdraw.denom_sigs[0],
   1631                                             &bks,
   1632                                             &c_hash,
   1633                                             alg_values,
   1634                                             &dkp->pub));
   1635     FAILIF (GNUNET_OK !=
   1636             TALER_denom_pub_verify (&dkp->pub,
   1637                                     &ds,
   1638                                     &c_hash));
   1639     TALER_denom_sig_free (&ds);
   1640   }
   1641 
   1642   RND_BLK (&coin_sig);
   1643   RND_BLK (&coin_blind);
   1644   RND_BLK (&deposit.coin.coin_pub);
   1645   TALER_denom_pub_hash (&dkp->pub,
   1646                         &deposit.coin.denom_pub_hash);
   1647   GNUNET_assert (GNUNET_OK ==
   1648                  TALER_denom_sig_unblind (&deposit.coin.denom_sig,
   1649                                           &cbc.sig,
   1650                                           &bks,
   1651                                           &c_hash,
   1652                                           alg_values,
   1653                                           &dkp->pub));
   1654   deadline = GNUNET_TIME_timestamp_get ();
   1655   {
   1656     struct TALER_DenominationHashP dph;
   1657     struct TALER_AgeCommitmentHashP agh;
   1658 
   1659     FAILIF (TALER_EXCHANGEDB_CKS_ADDED !=
   1660             plugin->ensure_coin_known (plugin->cls,
   1661                                        &deposit.coin,
   1662                                        &known_coin_id,
   1663                                        &dph,
   1664                                        &agh));
   1665   }
   1666   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
   1667           plugin->commit (plugin->cls));
   1668   {
   1669     struct GNUNET_TIME_Timestamp deposit_timestamp
   1670       = GNUNET_TIME_timestamp_get ();
   1671     bool balance_ok;
   1672     uint32_t bad_balance_idx;
   1673     bool in_conflict;
   1674     struct TALER_FullPaytoHashP h_payto;
   1675 
   1676     RND_BLK (&h_payto);
   1677     bd.refund_deadline
   1678       = GNUNET_TIME_relative_to_timestamp (GNUNET_TIME_UNIT_MONTHS);
   1679     bd.wire_deadline
   1680       = GNUNET_TIME_relative_to_timestamp (GNUNET_TIME_UNIT_MONTHS);
   1681     deposit.amount_with_fee = global_value;
   1682     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1683             plugin->do_deposit (plugin->cls,
   1684                                 &bd,
   1685                                 &deposit_timestamp,
   1686                                 &balance_ok,
   1687                                 &bad_balance_idx,
   1688                                 &in_conflict));
   1689     FAILIF (! balance_ok);
   1690     FAILIF (in_conflict);
   1691   }
   1692 
   1693   {
   1694     bool not_found;
   1695     bool refund_ok;
   1696     bool gone;
   1697     bool conflict;
   1698 
   1699     refund.coin = deposit.coin;
   1700     refund.details.merchant_pub = bd.merchant_pub;
   1701     RND_BLK (&refund.details.merchant_sig);
   1702     refund.details.h_contract_terms = bd.h_contract_terms;
   1703     refund.details.rtransaction_id = 1;
   1704     refund.details.refund_amount = global_value;
   1705     refund.details.refund_fee = global_fees.refund;
   1706     RND_BLK (&refund.details.merchant_sig);
   1707     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1708             plugin->do_refund (plugin->cls,
   1709                                &refund,
   1710                                &global_fees.deposit,
   1711                                known_coin_id,
   1712                                &not_found,
   1713                                &refund_ok,
   1714                                &gone,
   1715                                &conflict));
   1716     FAILIF (not_found);
   1717     FAILIF (! refund_ok);
   1718     FAILIF (gone);
   1719     FAILIF (conflict);
   1720 
   1721     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1722             plugin->select_refunds_by_coin (plugin->cls,
   1723                                             &refund.coin.coin_pub,
   1724                                             &refund.details.merchant_pub,
   1725                                             &refund.details.h_contract_terms,
   1726                                             &check_refund_cb,
   1727                                             &refund));
   1728   }
   1729 
   1730 
   1731   /* test do_refresh */
   1732 #pragma message "add refresh test for new refresh"
   1733 #if 0
   1734   {
   1735     bool zombie_required = false;
   1736     bool balance_ok;
   1737     bool idempotent;
   1738     uint16_t idem_noreveal_index;
   1739     struct TALER_Amount insufficient_funds;
   1740     struct TALER_EXCHANGEDB_Refresh_v26 refresh_v26;
   1741 
   1742     refresh_v26.coin = deposit.coin;
   1743     RND_BLK (&refresh_v26.coin_sig);
   1744     RND_BLK (&refresh_v26.rc);
   1745     refresh_v26.amount_with_fee = global_value;
   1746     refresh_v26.noreveal_index = MELT_NOREVEAL_INDEX;
   1747     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1748             plugin->do_refresh (plugin->cls,
   1749                                 &refresh_v26,
   1750                                 NULL,
   1751                                 &idempotent,
   1752                                 &idem_noreveal_index,
   1753                                 &zombie_required,
   1754                                 &balance_ok,
   1755                                 &insufficient_funds));
   1756     FAILIF (! balance_ok);
   1757     FAILIF (zombie_required);
   1758   }
   1759 #endif
   1760 
   1761 
   1762   /* test do_melt */
   1763   {
   1764     bool zombie_required = false;
   1765     bool balance_ok;
   1766 
   1767     refresh.coin = deposit.coin;
   1768     RND_BLK (&refresh.coin_sig);
   1769     RND_BLK (&refresh.rc);
   1770     refresh.amount_with_fee = global_value;
   1771     refresh.noreveal_index = MELT_NOREVEAL_INDEX;
   1772     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1773             plugin->do_melt (plugin->cls,
   1774                              NULL,
   1775                              &refresh,
   1776                              known_coin_id,
   1777                              &zombie_required,
   1778                              &balance_ok));
   1779     FAILIF (! balance_ok);
   1780     FAILIF (zombie_required);
   1781   }
   1782 
   1783   /* test get_melt */
   1784   {
   1785     struct TALER_EXCHANGEDB_Melt ret_refresh_session;
   1786 
   1787     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1788             plugin->get_melt (plugin->cls,
   1789                               &refresh.rc,
   1790                               &ret_refresh_session,
   1791                               &melt_serial_id));
   1792     FAILIF (refresh.noreveal_index !=
   1793             ret_refresh_session.session.noreveal_index);
   1794     FAILIF (0 !=
   1795             TALER_amount_cmp (&refresh.amount_with_fee,
   1796                               &ret_refresh_session.session.amount_with_fee));
   1797     FAILIF (0 !=
   1798             TALER_amount_cmp (&global_fees.refresh,
   1799                               &ret_refresh_session.melt_fee));
   1800     FAILIF (0 !=
   1801             GNUNET_memcmp (&refresh.rc,
   1802                            &ret_refresh_session.session.rc));
   1803     FAILIF (0 != GNUNET_memcmp (&refresh.coin_sig,
   1804                                 &ret_refresh_session.session.coin_sig));
   1805     FAILIF (0 !=
   1806             GNUNET_memcmp (&refresh.coin.coin_pub,
   1807                            &ret_refresh_session.session.coin.coin_pub));
   1808     FAILIF (0 !=
   1809             GNUNET_memcmp (&refresh.coin.denom_pub_hash,
   1810                            &ret_refresh_session.session.coin.denom_pub_hash));
   1811   }
   1812 
   1813   {
   1814     /* test 'select_refreshes_above_serial_id' */
   1815     auditor_row_cnt = 0;
   1816     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1817             plugin->select_refreshes_above_serial_id (plugin->cls,
   1818                                                       0,
   1819                                                       &audit_refresh_session_cb,
   1820                                                       NULL));
   1821     FAILIF (1 != auditor_row_cnt);
   1822   }
   1823 
   1824   /* do refresh-reveal */
   1825   now = GNUNET_TIME_timestamp_get ();
   1826   {
   1827     new_dkp = GNUNET_new_array (MELT_NEW_COINS,
   1828                                 struct DenomKeyPair *);
   1829     new_denom_pubs = GNUNET_new_array (MELT_NEW_COINS,
   1830                                        struct TALER_DenominationPublicKey);
   1831     revealed_coins
   1832       = GNUNET_new_array (MELT_NEW_COINS,
   1833                           struct TALER_EXCHANGEDB_RefreshRevealedCoin);
   1834     for (unsigned int cnt = 0; cnt < MELT_NEW_COINS; cnt++)
   1835     {
   1836       struct TALER_EXCHANGEDB_RefreshRevealedCoin *ccoin;
   1837       struct GNUNET_CRYPTO_BlindedMessage *rp;
   1838       struct GNUNET_CRYPTO_RsaBlindedMessage *rsa;
   1839       struct TALER_BlindedPlanchet *bp;
   1840 
   1841       new_dkp[cnt] = create_denom_key_pair (RSA_KEY_SIZE,
   1842                                             now,
   1843                                             &global_value,
   1844                                             &global_fees);
   1845       GNUNET_assert (NULL != new_dkp[cnt]);
   1846       new_denom_pubs[cnt] = new_dkp[cnt]->pub;
   1847       ccoin = &revealed_coins[cnt];
   1848       bp = &ccoin->blinded_planchet;
   1849       rp = GNUNET_new (struct GNUNET_CRYPTO_BlindedMessage);
   1850       bp->blinded_message = rp;
   1851       rp->cipher = GNUNET_CRYPTO_BSA_RSA;
   1852       rp->rc = 1;
   1853       rsa = &rp->details.rsa_blinded_message;
   1854       rsa->blinded_msg_size = 1 + (size_t) GNUNET_CRYPTO_random_u64 (
   1855         GNUNET_CRYPTO_QUALITY_WEAK,
   1856         (RSA_KEY_SIZE / 8) - 1);
   1857       rsa->blinded_msg = GNUNET_malloc (rsa->blinded_msg_size);
   1858       GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
   1859                                   rsa->blinded_msg,
   1860                                   rsa->blinded_msg_size);
   1861       TALER_denom_pub_hash (&new_dkp[cnt]->pub,
   1862                             &ccoin->h_denom_pub);
   1863       TALER_denom_ewv_copy (&ccoin->exchange_vals,
   1864                             alg_values);
   1865       TALER_coin_ev_hash (bp,
   1866                           &ccoin->h_denom_pub,
   1867                           &ccoin->coin_envelope_hash);
   1868       GNUNET_assert (GNUNET_OK ==
   1869                      TALER_denom_sign_blinded (&ccoin->coin_sig,
   1870                                                &new_dkp[cnt]->priv,
   1871                                                true,
   1872                                                bp));
   1873     }
   1874     RND_BLK (&tprivs);
   1875     RND_BLK (&tpub);
   1876     FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
   1877             plugin->get_refresh_reveal (plugin->cls,
   1878                                         &refresh.rc,
   1879                                         &never_called_cb,
   1880                                         NULL));
   1881     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1882             plugin->insert_refresh_reveal (plugin->cls,
   1883                                            melt_serial_id,
   1884                                            MELT_NEW_COINS,
   1885                                            revealed_coins,
   1886                                            TALER_CNC_KAPPA - 1,
   1887                                            tprivs,
   1888                                            &tpub));
   1889     {
   1890       struct TALER_BlindedCoinHashP h_coin_ev;
   1891       struct TALER_CoinSpendPublicKeyP ocp;
   1892       struct TALER_DenominationHashP denom_hash;
   1893 
   1894       TALER_denom_pub_hash (&new_denom_pubs[0],
   1895                             &denom_hash);
   1896       TALER_coin_ev_hash (&revealed_coins[0].blinded_planchet,
   1897                           &denom_hash,
   1898                           &h_coin_ev);
   1899       FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1900               plugin->get_old_coin_by_h_blind (plugin->cls,
   1901                                                &h_coin_ev,
   1902                                                &ocp,
   1903                                                &rrc_serial));
   1904       FAILIF (0 !=
   1905               GNUNET_memcmp (&ocp,
   1906                              &refresh.coin.coin_pub));
   1907     }
   1908     FAILIF (0 >=
   1909             plugin->get_refresh_reveal (plugin->cls,
   1910                                         &refresh.rc,
   1911                                         &check_refresh_reveal_cb,
   1912                                         NULL));
   1913     qs = plugin->get_link_data (plugin->cls,
   1914                                 &refresh.coin.coin_pub,
   1915                                 &handle_link_data_cb,
   1916                                 NULL);
   1917     FAILIF (0 >= qs);
   1918     {
   1919       /* Just to test fetching a coin with melt history */
   1920       struct TALER_EXCHANGEDB_TransactionList *tl;
   1921       uint64_t etag;
   1922       struct TALER_Amount balance;
   1923       struct TALER_DenominationHashP h_denom_pub;
   1924 
   1925       qs = plugin->get_coin_transactions (plugin->cls,
   1926                                           true,
   1927                                           &refresh.coin.coin_pub,
   1928                                           0,
   1929                                           0,
   1930                                           &etag,
   1931                                           &balance,
   1932                                           &h_denom_pub,
   1933                                           &tl);
   1934       FAILIF (0 >= qs);
   1935       FAILIF (NULL == tl);
   1936       plugin->free_coin_transaction_list (plugin->cls,
   1937                                           tl);
   1938     }
   1939   }
   1940 
   1941   /* do recoup-refresh */
   1942   {
   1943     struct GNUNET_TIME_Timestamp recoup_timestamp
   1944       = GNUNET_TIME_timestamp_get ();
   1945     union GNUNET_CRYPTO_BlindingSecretP coin_bks;
   1946     uint64_t new_known_coin_id;
   1947     struct TALER_CoinPublicInfo new_coin;
   1948     struct TALER_DenominationHashP dph;
   1949     struct TALER_AgeCommitmentHashP agh;
   1950     bool recoup_ok;
   1951     bool internal_failure;
   1952 
   1953     new_coin = deposit.coin; /* steal basic data */
   1954     RND_BLK (&new_coin.coin_pub);
   1955     FAILIF (TALER_EXCHANGEDB_CKS_ADDED !=
   1956             plugin->ensure_coin_known (plugin->cls,
   1957                                        &new_coin,
   1958                                        &new_known_coin_id,
   1959                                        &dph,
   1960                                        &agh));
   1961     RND_BLK (&coin_bks);
   1962     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1963             plugin->do_recoup_refresh (plugin->cls,
   1964                                        &deposit.coin.coin_pub,
   1965                                        rrc_serial,
   1966                                        &coin_bks,
   1967                                        &new_coin.coin_pub,
   1968                                        new_known_coin_id,
   1969                                        &coin_sig,
   1970                                        &recoup_timestamp,
   1971                                        &recoup_ok,
   1972                                        &internal_failure));
   1973     FAILIF (! recoup_ok);
   1974     FAILIF (internal_failure);
   1975   }
   1976 
   1977   /* do recoup */
   1978   {
   1979     struct TALER_EXCHANGEDB_Reserve pre_reserve;
   1980     struct TALER_EXCHANGEDB_Reserve post_reserve;
   1981     struct TALER_Amount delta;
   1982     bool recoup_ok;
   1983     bool internal_failure;
   1984     struct GNUNET_TIME_Timestamp recoup_timestamp
   1985       = GNUNET_TIME_timestamp_get ();
   1986 
   1987     pre_reserve.pub = reserve_pub;
   1988     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1989             plugin->reserves_get (plugin->cls,
   1990                                   &pre_reserve));
   1991     FAILIF (! TALER_amount_is_zero (&pre_reserve.balance));
   1992     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1993             plugin->do_recoup (plugin->cls,
   1994                                &reserve_pub,
   1995                                withdraw_serial_id,
   1996                                &coin_blind,
   1997                                &deposit.coin.coin_pub,
   1998                                known_coin_id,
   1999                                &coin_sig,
   2000                                &recoup_timestamp,
   2001                                &recoup_ok,
   2002                                &internal_failure));
   2003     FAILIF (internal_failure);
   2004     FAILIF (! recoup_ok);
   2005     post_reserve.pub = reserve_pub;
   2006     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   2007             plugin->reserves_get (plugin->cls,
   2008                                   &post_reserve));
   2009     FAILIF (0 >=
   2010             TALER_amount_subtract (&delta,
   2011                                    &post_reserve.balance,
   2012                                    &pre_reserve.balance));
   2013     FAILIF (0 !=
   2014             TALER_amount_cmp (&delta,
   2015                               &global_value));
   2016   }
   2017 
   2018   FAILIF (GNUNET_OK !=
   2019           plugin->start (plugin->cls,
   2020                          "test-3"));
   2021 
   2022   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   2023           plugin->select_recoup_above_serial_id (plugin->cls,
   2024                                                  0,
   2025                                                  &recoup_cb,
   2026                                                  &coin_blind));
   2027   /* Do reserve close */
   2028   now = GNUNET_TIME_timestamp_get ();
   2029   GNUNET_assert (GNUNET_OK ==
   2030                  TALER_string_to_amount (CURRENCY ":0.000010",
   2031                                          &fee_closing));
   2032   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   2033           plugin->insert_reserve_closed (plugin->cls,
   2034                                          &reserve_pub2,
   2035                                          now,
   2036                                          sndr,
   2037                                          &wire_out_wtid,
   2038                                          &amount_with_fee,
   2039                                          &fee_closing,
   2040                                          0));
   2041   FAILIF (GNUNET_OK !=
   2042           check_reserve (&reserve_pub2,
   2043                          0,
   2044                          0,
   2045                          global_value.currency));
   2046   now = GNUNET_TIME_timestamp_get ();
   2047   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   2048           plugin->insert_reserve_closed (plugin->cls,
   2049                                          &reserve_pub,
   2050                                          now,
   2051                                          sndr,
   2052                                          &wire_out_wtid,
   2053                                          &global_value,
   2054                                          &fee_closing,
   2055                                          0));
   2056   FAILIF (GNUNET_OK !=
   2057           check_reserve (&reserve_pub,
   2058                          0,
   2059                          0,
   2060                          global_value.currency));
   2061   result = 7;
   2062   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
   2063           plugin->commit (plugin->cls));
   2064 
   2065 
   2066   /* check reserve history */
   2067   {
   2068     struct TALER_Amount balance;
   2069     uint64_t etag_out;
   2070 
   2071     qs = plugin->get_reserve_history (plugin->cls,
   2072                                       &reserve_pub,
   2073                                       0,
   2074                                       0,
   2075                                       &etag_out,
   2076                                       &balance,
   2077                                       &rh);
   2078   }
   2079   FAILIF (0 > qs);
   2080   FAILIF (NULL == rh);
   2081   rh_head = rh;
   2082   {
   2083     unsigned int cnt;
   2084 
   2085     for (cnt = 0;
   2086          NULL != rh_head;
   2087          rh_head = rh_head->next, cnt++)
   2088     {
   2089       switch (rh_head->type)
   2090       {
   2091       case TALER_EXCHANGEDB_RO_BANK_TO_EXCHANGE:
   2092         bt = rh_head->details.bank;
   2093         FAILIF (0 !=
   2094                 GNUNET_memcmp (&bt->reserve_pub,
   2095                                &reserve_pub));
   2096         /* this is the amount we transferred twice*/
   2097         FAILIF (1 != bt->amount.value);
   2098         FAILIF (1000 != bt->amount.fraction);
   2099         FAILIF (0 != strcmp (CURRENCY,
   2100                              bt->amount.currency));
   2101         FAILIF (NULL == bt->sender_account_details.full_payto);
   2102         break;
   2103       case TALER_EXCHANGEDB_RO_WITHDRAW_COINS:
   2104         {
   2105           struct TALER_EXCHANGEDB_Withdraw *rh_withdraw  =
   2106             rh_head->details.withdraw;
   2107           FAILIF (0 !=
   2108                   GNUNET_memcmp (&rh_withdraw->reserve_pub,
   2109                                  &reserve_pub));
   2110 #pragma message "maybe more tests!?"
   2111         }
   2112         break;
   2113       case TALER_EXCHANGEDB_RO_RECOUP_COIN:
   2114         {
   2115           struct TALER_EXCHANGEDB_Recoup *recoup = rh_head->details.recoup;
   2116 
   2117           FAILIF (0 !=
   2118                   GNUNET_memcmp (&recoup->coin_sig,
   2119                                  &coin_sig));
   2120           FAILIF (0 !=
   2121                   GNUNET_memcmp (&recoup->coin_blind,
   2122                                  &coin_blind));
   2123           FAILIF (0 !=
   2124                   GNUNET_memcmp (&recoup->reserve_pub,
   2125                                  &reserve_pub));
   2126           FAILIF (0 !=
   2127                   GNUNET_memcmp (&recoup->coin.coin_pub,
   2128                                  &deposit.coin.coin_pub));
   2129           FAILIF (0 !=
   2130                   TALER_amount_cmp (&recoup->value,
   2131                                     &global_value));
   2132         }
   2133         break;
   2134       case TALER_EXCHANGEDB_RO_EXCHANGE_TO_BANK:
   2135         {
   2136           struct TALER_EXCHANGEDB_ClosingTransfer *closing
   2137             = rh_head->details.closing;
   2138 
   2139           FAILIF (0 !=
   2140                   GNUNET_memcmp (&closing->reserve_pub,
   2141                                  &reserve_pub));
   2142           FAILIF (0 != TALER_amount_cmp (&closing->amount,
   2143                                          &amount_with_fee));
   2144           FAILIF (0 != TALER_amount_cmp (&closing->closing_fee,
   2145                                          &fee_closing));
   2146         }
   2147         break;
   2148       case TALER_EXCHANGEDB_RO_PURSE_MERGE:
   2149         {
   2150           /* FIXME: not yet tested */
   2151           break;
   2152         }
   2153       case TALER_EXCHANGEDB_RO_HISTORY_REQUEST:
   2154         {
   2155           /* FIXME: not yet tested */
   2156           break;
   2157         }
   2158       case TALER_EXCHANGEDB_RO_OPEN_REQUEST:
   2159         {
   2160           /* FIXME: not yet tested */
   2161           break;
   2162         }
   2163       case TALER_EXCHANGEDB_RO_CLOSE_REQUEST:
   2164         {
   2165           /* FIXME: not yet tested */
   2166           break;
   2167         }
   2168       }
   2169     }
   2170     GNUNET_assert (4 == cnt);
   2171     FAILIF (4 != cnt);
   2172   }
   2173 
   2174   auditor_row_cnt = 0;
   2175   FAILIF (0 >=
   2176           plugin->select_reserves_in_above_serial_id (plugin->cls,
   2177                                                       0,
   2178                                                       &audit_reserve_in_cb,
   2179                                                       NULL));
   2180   FAILIF (0 >=
   2181           plugin->select_withdrawals_above_serial_id (plugin->cls,
   2182                                                       0,
   2183                                                       &audit_reserve_out_cb,
   2184                                                       NULL));
   2185   FAILIF (3 != auditor_row_cnt);
   2186 
   2187 
   2188   auditor_row_cnt = 0;
   2189   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   2190           plugin->select_refunds_above_serial_id (plugin->cls,
   2191                                                   0,
   2192                                                   &audit_refund_cb,
   2193                                                   NULL));
   2194   FAILIF (1 != auditor_row_cnt);
   2195   {
   2196     uint64_t etag = 0;
   2197     struct TALER_Amount balance;
   2198     struct TALER_DenominationHashP h_denom_pub;
   2199     struct TALER_EXCHANGEDB_TransactionList *tl;
   2200 
   2201     qs = plugin->get_coin_transactions (plugin->cls,
   2202                                         true,
   2203                                         &refund.coin.coin_pub,
   2204                                         0,
   2205                                         0,
   2206                                         &etag,
   2207                                         &balance,
   2208                                         &h_denom_pub,
   2209                                         &tl);
   2210     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs);
   2211     GNUNET_assert (NULL != tl);
   2212     matched = 0;
   2213     for (struct TALER_EXCHANGEDB_TransactionList *tlp = tl;
   2214          NULL != tlp;
   2215          tlp = tlp->next)
   2216     {
   2217       switch (tlp->type)
   2218       {
   2219       case TALER_EXCHANGEDB_TT_DEPOSIT:
   2220         {
   2221           struct TALER_EXCHANGEDB_DepositListEntry *have = tlp->details.deposit;
   2222 
   2223           /* Note: we're not comparing the denomination keys, as there is
   2224              still the question of whether we should even bother exporting
   2225              them here. */
   2226           FAILIF (0 !=
   2227                   GNUNET_memcmp (&have->csig,
   2228                                  &deposit.csig));
   2229           FAILIF (0 !=
   2230                   GNUNET_memcmp (&have->merchant_pub,
   2231                                  &bd.merchant_pub));
   2232           FAILIF (0 !=
   2233                   GNUNET_memcmp (&have->h_contract_terms,
   2234                                  &bd.h_contract_terms));
   2235           FAILIF (0 !=
   2236                   GNUNET_memcmp (&have->wire_salt,
   2237                                  &bd.wire_salt));
   2238           FAILIF (GNUNET_TIME_timestamp_cmp (have->timestamp,
   2239                                              !=,
   2240                                              bd.wallet_timestamp));
   2241           FAILIF (GNUNET_TIME_timestamp_cmp (have->refund_deadline,
   2242                                              !=,
   2243                                              bd.refund_deadline));
   2244           FAILIF (GNUNET_TIME_timestamp_cmp (have->wire_deadline,
   2245                                              !=,
   2246                                              bd.wire_deadline));
   2247           FAILIF (0 != TALER_amount_cmp (&have->amount_with_fee,
   2248                                          &deposit.amount_with_fee));
   2249           matched |= 1;
   2250           break;
   2251         }
   2252       /* this coin pub was actually never melted... */
   2253       case TALER_EXCHANGEDB_TT_MELT:
   2254         FAILIF (0 !=
   2255                 GNUNET_memcmp (&refresh.rc,
   2256                                &tlp->details.melt->rc));
   2257         matched |= 2;
   2258         break;
   2259       case TALER_EXCHANGEDB_TT_REFUND:
   2260         {
   2261           struct TALER_EXCHANGEDB_RefundListEntry *have = tlp->details.refund;
   2262 
   2263           /* Note: we're not comparing the denomination keys, as there is
   2264              still the question of whether we should even bother exporting
   2265              them here. */
   2266           FAILIF (0 != GNUNET_memcmp (&have->merchant_pub,
   2267                                       &refund.details.merchant_pub));
   2268           FAILIF (0 != GNUNET_memcmp (&have->merchant_sig,
   2269                                       &refund.details.merchant_sig));
   2270           FAILIF (0 != GNUNET_memcmp (&have->h_contract_terms,
   2271                                       &refund.details.h_contract_terms));
   2272           FAILIF (have->rtransaction_id != refund.details.rtransaction_id);
   2273           FAILIF (0 != TALER_amount_cmp (&have->refund_amount,
   2274                                          &refund.details.refund_amount));
   2275           FAILIF (0 != TALER_amount_cmp (&have->refund_fee,
   2276                                          &refund.details.refund_fee));
   2277           matched |= 4;
   2278           break;
   2279         }
   2280       case TALER_EXCHANGEDB_TT_RECOUP:
   2281         {
   2282           struct TALER_EXCHANGEDB_RecoupListEntry *recoup =
   2283             tlp->details.recoup;
   2284 
   2285           FAILIF (0 != GNUNET_memcmp (&recoup->coin_sig,
   2286                                       &coin_sig));
   2287           FAILIF (0 != GNUNET_memcmp (&recoup->coin_blind,
   2288                                       &coin_blind));
   2289           FAILIF (0 != GNUNET_memcmp (&recoup->reserve_pub,
   2290                                       &reserve_pub));
   2291           FAILIF (0 != TALER_amount_cmp (&recoup->value,
   2292                                          &global_value));
   2293           matched |= 8;
   2294           break;
   2295         }
   2296       case TALER_EXCHANGEDB_TT_OLD_COIN_RECOUP:
   2297         /* FIXME: check fields better... */
   2298 #pragma \
   2299         message "TALER_EXCHANGEDB_TT_OLD_COIN_RECOUP case doesn't work right now"
   2300         matched |= 16;
   2301         break;
   2302       default:
   2303         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   2304                     "Unexpected coin history transaction type: %d\n",
   2305                     tlp->type);
   2306         FAILIF (1);
   2307         break;
   2308       }
   2309     }
   2310     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2311                 "matched=%d, SKIPPING FAILIF(31 != matched) FOR NOW\n",
   2312                 matched);
   2313 #pragma message "skipping FAILIF(31 != matched) check for now"
   2314 #if 0
   2315     FAILIF (31 != matched);
   2316 #endif
   2317 
   2318     plugin->free_coin_transaction_list (plugin->cls,
   2319                                         tl);
   2320   }
   2321 
   2322   /* Tests for deposits+wire */
   2323   TALER_denom_sig_free (&deposit.coin.denom_sig);
   2324   memset (&deposit,
   2325           0,
   2326           sizeof (deposit));
   2327   RND_BLK (&deposit.coin.coin_pub);
   2328   TALER_denom_pub_hash (&dkp->pub,
   2329                         &deposit.coin.denom_pub_hash);
   2330   GNUNET_assert (GNUNET_OK ==
   2331                  TALER_denom_sig_unblind (&deposit.coin.denom_sig,
   2332                                           &cbc.sig,
   2333                                           &bks,
   2334                                           &c_hash,
   2335                                           alg_values,
   2336                                           &dkp->pub));
   2337   RND_BLK (&deposit.csig);
   2338   RND_BLK (&bd.merchant_pub);
   2339   RND_BLK (&bd.h_contract_terms);
   2340   RND_BLK (&bd.wire_salt);
   2341   bd.receiver_wire_account.full_payto =
   2342     (char *) "payto://iban/DE67830654080004822650?receiver-name=Test";
   2343   TALER_merchant_wire_signature_hash (
   2344     bd.receiver_wire_account,
   2345     &bd.wire_salt,
   2346     &h_wire_wt);
   2347   deposit.amount_with_fee = global_value;
   2348   bd.refund_deadline = deadline;
   2349   bd.wire_deadline = deadline;
   2350   result = 8;
   2351   FAILIF (GNUNET_OK !=
   2352           plugin->start (plugin->cls,
   2353                          "test-3"));
   2354   {
   2355     uint64_t known_coin_id2;
   2356     struct TALER_DenominationHashP dph;
   2357     struct TALER_AgeCommitmentHashP agh;
   2358 
   2359     FAILIF (TALER_EXCHANGEDB_CKS_ADDED !=
   2360             plugin->ensure_coin_known (plugin->cls,
   2361                                        &deposit.coin,
   2362                                        &known_coin_id2,
   2363                                        &dph,
   2364                                        &agh));
   2365   }
   2366   now = GNUNET_TIME_timestamp_get ();
   2367   {
   2368     struct GNUNET_TIME_Timestamp r;
   2369     struct TALER_Amount deposit_fee;
   2370     struct TALER_MerchantWireHashP h_wire;
   2371     bool balance_ok;
   2372     uint32_t bad_idx;
   2373     bool ctr_conflict;
   2374 
   2375     TALER_full_payto_hash (bd.receiver_wire_account,
   2376                            &bd.wire_target_h_payto);
   2377     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   2378             plugin->do_deposit (plugin->cls,
   2379                                 &bd,
   2380                                 &now,
   2381                                 &balance_ok,
   2382                                 &bad_idx,
   2383                                 &ctr_conflict));
   2384     TALER_merchant_wire_signature_hash (bd.receiver_wire_account,
   2385                                         &bd.wire_salt,
   2386                                         &h_wire);
   2387     FAILIF (1 !=
   2388             plugin->have_deposit2 (plugin->cls,
   2389                                    &bd.h_contract_terms,
   2390                                    &h_wire,
   2391                                    &deposit.coin.coin_pub,
   2392                                    &bd.merchant_pub,
   2393                                    bd.refund_deadline,
   2394                                    &deposit_fee,
   2395                                    &r));
   2396     FAILIF (GNUNET_TIME_timestamp_cmp (now,
   2397                                        !=,
   2398                                        r));
   2399   }
   2400   {
   2401     result = 66;
   2402     FAILIF (0 >=
   2403             plugin->select_batch_deposits_missing_wire (plugin->cls,
   2404                                                         0,
   2405                                                         &wire_missing_cb,
   2406                                                         &deposit));
   2407     FAILIF (8 != result);
   2408   }
   2409   auditor_row_cnt = 0;
   2410   FAILIF (0 >=
   2411           plugin->select_coin_deposits_above_serial_id (plugin->cls,
   2412                                                         0,
   2413                                                         &audit_deposit_cb,
   2414                                                         NULL));
   2415   FAILIF (0 == auditor_row_cnt);
   2416   result = 8;
   2417   sleep (2); /* give deposit time to be ready */
   2418   {
   2419     struct TALER_MerchantPublicKeyP merchant_pub2;
   2420     struct TALER_FullPayto payto_uri2;
   2421 
   2422     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   2423             plugin->get_ready_deposit (plugin->cls,
   2424                                        0,
   2425                                        INT32_MAX,
   2426                                        &merchant_pub2,
   2427                                        &payto_uri2));
   2428     FAILIF (0 != GNUNET_memcmp (&merchant_pub2,
   2429                                 &bd.merchant_pub));
   2430     FAILIF (0 != TALER_full_payto_cmp (payto_uri2,
   2431                                        bd.receiver_wire_account));
   2432     TALER_full_payto_hash (payto_uri2,
   2433                            &global_wire_target_h_payto);
   2434     GNUNET_free (payto_uri2.full_payto);
   2435   }
   2436 
   2437   {
   2438     struct TALER_Amount total;
   2439     struct TALER_WireTransferIdentifierRawP wtid;
   2440 
   2441     memset (&wtid,
   2442             41,
   2443             sizeof (wtid));
   2444     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   2445             plugin->aggregate (plugin->cls,
   2446                                &global_wire_target_h_payto,
   2447                                &bd.merchant_pub,
   2448                                &wtid,
   2449                                &total));
   2450   }
   2451   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
   2452           plugin->commit (plugin->cls));
   2453   FAILIF (GNUNET_OK !=
   2454           plugin->start (plugin->cls,
   2455                          "test-3"));
   2456   {
   2457     struct TALER_WireTransferIdentifierRawP wtid;
   2458     struct TALER_Amount total;
   2459     struct TALER_WireTransferIdentifierRawP wtid2;
   2460     struct TALER_Amount total2;
   2461 
   2462     memset (&wtid,
   2463             42,
   2464             sizeof (wtid));
   2465     GNUNET_assert (GNUNET_OK ==
   2466                    TALER_string_to_amount (CURRENCY ":42",
   2467                                            &total));
   2468     FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
   2469             plugin->select_aggregation_transient (
   2470               plugin->cls,
   2471               &global_wire_target_h_payto,
   2472               &bd.merchant_pub,
   2473               "x-bank",
   2474               &wtid2,
   2475               &total2));
   2476     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   2477             plugin->create_aggregation_transient (
   2478               plugin->cls,
   2479               &global_wire_target_h_payto,
   2480               "x-bank",
   2481               &bd.merchant_pub,
   2482               &wtid,
   2483               0,
   2484               &total));
   2485     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   2486             plugin->select_aggregation_transient (
   2487               plugin->cls,
   2488               &global_wire_target_h_payto,
   2489               &bd.merchant_pub,
   2490               "x-bank",
   2491               &wtid2,
   2492               &total2));
   2493     FAILIF (0 !=
   2494             GNUNET_memcmp (&wtid2,
   2495                            &wtid));
   2496     FAILIF (0 !=
   2497             TALER_amount_cmp (&total2,
   2498                               &total));
   2499     GNUNET_assert (GNUNET_OK ==
   2500                    TALER_string_to_amount (CURRENCY ":43",
   2501                                            &total));
   2502     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   2503             plugin->update_aggregation_transient (
   2504               plugin->cls,
   2505               &global_wire_target_h_payto,
   2506               &wtid,
   2507               0,
   2508               &total));
   2509     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   2510             plugin->select_aggregation_transient (
   2511               plugin->cls,
   2512               &global_wire_target_h_payto,
   2513               &bd.merchant_pub,
   2514               "x-bank",
   2515               &wtid2,
   2516               &total2));
   2517     FAILIF (0 !=
   2518             GNUNET_memcmp (&wtid2,
   2519                            &wtid));
   2520     FAILIF (0 !=
   2521             TALER_amount_cmp (&total2,
   2522                               &total));
   2523     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   2524             plugin->delete_aggregation_transient (
   2525               plugin->cls,
   2526               &global_wire_target_h_payto,
   2527               &wtid));
   2528     FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
   2529             plugin->select_aggregation_transient (
   2530               plugin->cls,
   2531               &global_wire_target_h_payto,
   2532               &bd.merchant_pub,
   2533               "x-bank",
   2534               &wtid2,
   2535               &total2));
   2536   }
   2537   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
   2538           plugin->commit (plugin->cls));
   2539 
   2540   result = 10;
   2541   FAILIF (GNUNET_OK !=
   2542           plugin->start (plugin->cls,
   2543                          "test-2"));
   2544   RND_BLK (&mpub2); /* should fail if merchant is different */
   2545   {
   2546     struct TALER_MerchantWireHashP h_wire;
   2547     struct GNUNET_TIME_Timestamp r;
   2548     struct TALER_Amount deposit_fee;
   2549 
   2550     TALER_merchant_wire_signature_hash (bd.receiver_wire_account,
   2551                                         &bd.wire_salt,
   2552                                         &h_wire);
   2553     FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
   2554             plugin->have_deposit2 (plugin->cls,
   2555                                    &bd.h_contract_terms,
   2556                                    &h_wire,
   2557                                    &deposit.coin.coin_pub,
   2558                                    &mpub2,
   2559                                    bd.refund_deadline,
   2560                                    &deposit_fee,
   2561                                    &r));
   2562     RND_BLK (&cpub2); /* should fail if coin is different */
   2563     FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
   2564             plugin->have_deposit2 (plugin->cls,
   2565                                    &bd.h_contract_terms,
   2566                                    &h_wire,
   2567                                    &cpub2,
   2568                                    &bd.merchant_pub,
   2569                                    bd.refund_deadline,
   2570                                    &deposit_fee,
   2571                                    &r));
   2572   }
   2573   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
   2574           plugin->commit (plugin->cls));
   2575 
   2576 
   2577   /* test revocation */
   2578   FAILIF (GNUNET_OK !=
   2579           plugin->start (plugin->cls,
   2580                          "test-3b"));
   2581   RND_BLK (&master_sig);
   2582   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   2583           plugin->insert_denomination_revocation (plugin->cls,
   2584                                                   &cbc.denom_pub_hash,
   2585                                                   &master_sig));
   2586   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
   2587           plugin->commit (plugin->cls));
   2588   plugin->preflight (plugin->cls);
   2589   FAILIF (GNUNET_OK !=
   2590           plugin->start (plugin->cls,
   2591                          "test-4"));
   2592   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
   2593           plugin->insert_denomination_revocation (plugin->cls,
   2594                                                   &cbc.denom_pub_hash,
   2595                                                   &master_sig));
   2596   plugin->rollback (plugin->cls);
   2597   plugin->preflight (plugin->cls);
   2598   FAILIF (GNUNET_OK !=
   2599           plugin->start (plugin->cls,
   2600                          "test-5"));
   2601   {
   2602     struct TALER_MasterSignatureP msig;
   2603     uint64_t rev_rowid;
   2604 
   2605     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   2606             plugin->get_denomination_revocation (plugin->cls,
   2607                                                  &cbc.denom_pub_hash,
   2608                                                  &msig,
   2609                                                  &rev_rowid));
   2610     FAILIF (0 != GNUNET_memcmp (&msig,
   2611                                 &master_sig));
   2612   }
   2613 
   2614 
   2615   plugin->rollback (plugin->cls);
   2616   FAILIF (GNUNET_OK !=
   2617           test_wire_prepare ());
   2618   FAILIF (GNUNET_OK !=
   2619           test_wire_out (&bd));
   2620   FAILIF (GNUNET_OK !=
   2621           test_gc ());
   2622   FAILIF (GNUNET_OK !=
   2623           test_wire_fees ());
   2624 
   2625   plugin->preflight (plugin->cls);
   2626 
   2627   result = 0;
   2628 
   2629 drop:
   2630   if (0 != result)
   2631     plugin->rollback (plugin->cls);
   2632   if (NULL != rh)
   2633     plugin->free_reserve_history (plugin->cls,
   2634                                   rh);
   2635   rh = NULL;
   2636   GNUNET_break (GNUNET_OK ==
   2637                 plugin->drop_tables (plugin->cls));
   2638 cleanup:
   2639   if (NULL != dkp)
   2640     destroy_denom_key_pair (dkp);
   2641   if (NULL != revealed_coins)
   2642   {
   2643     for (unsigned int cnt = 0; cnt < MELT_NEW_COINS; cnt++)
   2644     {
   2645       TALER_blinded_denom_sig_free (&revealed_coins[cnt].coin_sig);
   2646       TALER_blinded_planchet_free (&revealed_coins[cnt].blinded_planchet);
   2647     }
   2648     GNUNET_free (revealed_coins);
   2649     revealed_coins = NULL;
   2650   }
   2651   GNUNET_free (new_denom_pubs);
   2652   for (unsigned int cnt = 0;
   2653        (NULL != new_dkp) && (cnt < MELT_NEW_COINS) && (NULL != new_dkp[cnt]);
   2654        cnt++)
   2655     destroy_denom_key_pair (new_dkp[cnt]);
   2656   GNUNET_free (new_dkp);
   2657   TALER_denom_sig_free (&deposit.coin.denom_sig);
   2658   TALER_blinded_denom_sig_free (&cbc.sig);
   2659   TALER_blinded_denom_sig_free (withdraw.denom_sigs);
   2660   dkp = NULL;
   2661   TALER_EXCHANGEDB_plugin_unload (plugin);
   2662   plugin = NULL;
   2663 }
   2664 
   2665 
   2666 int
   2667 main (int argc,
   2668       char *const argv[])
   2669 {
   2670   const char *plugin_name;
   2671   char *config_filename;
   2672   char *testname;
   2673   struct GNUNET_CONFIGURATION_Handle *cfg;
   2674 
   2675   (void) argc;
   2676   result = -1;
   2677   if (NULL == (plugin_name = strrchr (argv[0], (int) '-')))
   2678   {
   2679     GNUNET_break (0);
   2680     return -1;
   2681   }
   2682   GNUNET_log_setup (argv[0],
   2683                     "INFO",
   2684                     NULL);
   2685   plugin_name++;
   2686   (void) GNUNET_asprintf (&testname,
   2687                           "test-exchange-db-%s",
   2688                           plugin_name);
   2689   (void) GNUNET_asprintf (&config_filename,
   2690                           "%s.conf",
   2691                           testname);
   2692   cfg = GNUNET_CONFIGURATION_create (TALER_EXCHANGE_project_data ());
   2693   if (GNUNET_OK !=
   2694       GNUNET_CONFIGURATION_parse (cfg,
   2695                                   config_filename))
   2696   {
   2697     GNUNET_break (0);
   2698     GNUNET_free (config_filename);
   2699     GNUNET_free (testname);
   2700     return 2;
   2701   }
   2702   GNUNET_SCHEDULER_run (&run,
   2703                         cfg);
   2704   GNUNET_CONFIGURATION_destroy (cfg);
   2705   GNUNET_free (config_filename);
   2706   GNUNET_free (testname);
   2707   return result;
   2708 }
   2709 
   2710 
   2711 /* end of test_exchangedb.c */