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


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