LCOV - code coverage report
Current view: top level - testing - testing_api_cmd_insert_deposit.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 89 110 80.9 %
Date: 2025-06-05 21:03:14 Functions: 4 4 100.0 %

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2018, 2024 Taler Systems SA
       4             : 
       5             :   TALER is free software; you can redistribute it and/or modify it
       6             :   under the terms of the GNU General Public License as published
       7             :   by the Free Software Foundation; either version 3, or (at your
       8             :   option) any later version.
       9             : 
      10             :   TALER is distributed in the hope that it will be useful, but
      11             :   WITHOUT ANY WARRANTY; without even the implied warranty of
      12             :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13             :   GNU General Public License for more details.
      14             : 
      15             :   You should have received a copy of the GNU General Public
      16             :   License along with TALER; see the file COPYING.  If not,
      17             :   see <http://www.gnu.org/licenses/>
      18             : */
      19             : /**
      20             :  * @file testing/testing_api_cmd_insert_deposit.c
      21             :  * @brief deposit a coin directly into the database.
      22             :  * @author Marcello Stanisci
      23             :  * @author Christian Grothoff
      24             :  */
      25             : #include "platform.h"
      26             : #include "taler_util.h"
      27             : #include "taler_json_lib.h"
      28             : #include <gnunet/gnunet_curl_lib.h>
      29             : #include "taler_signatures.h"
      30             : #include "taler_testing_lib.h"
      31             : #include "taler_exchangedb_plugin.h"
      32             : #include "taler_exchangedb_lib.h"
      33             : 
      34             : 
      35             : /**
      36             :  * State for a "insert-deposit" CMD.
      37             :  */
      38             : struct InsertDepositState
      39             : {
      40             :   /**
      41             :    * Database connection we use.
      42             :    */
      43             :   struct TALER_EXCHANGEDB_Plugin *plugin;
      44             : 
      45             :   /**
      46             :    * Human-readable name of the shop.
      47             :    */
      48             :   const char *merchant_name;
      49             : 
      50             :   /**
      51             :    * Merchant account name (NOT a payto-URI).
      52             :    */
      53             :   const char *merchant_account;
      54             : 
      55             :   /**
      56             :    * Deadline before which the aggregator should
      57             :    * send the payment to the merchant.
      58             :    */
      59             :   struct GNUNET_TIME_Relative wire_deadline;
      60             : 
      61             :   /**
      62             :    * When did the exchange receive the deposit?
      63             :    */
      64             :   struct GNUNET_TIME_Timestamp exchange_timestamp;
      65             : 
      66             :   /**
      67             :    * Amount to deposit, inclusive of deposit fee.
      68             :    */
      69             :   const char *amount_with_fee;
      70             : 
      71             :   /**
      72             :    * Deposit fee.
      73             :    */
      74             :   const char *deposit_fee;
      75             : 
      76             :   /**
      77             :    * Do we used a cached @e plugin?
      78             :    */
      79             :   bool cached;
      80             : };
      81             : 
      82             : /**
      83             :  * Setup (fake) information about a coin used in deposit.
      84             :  *
      85             :  * @param[out] issue information to initialize with "valid" data
      86             :  */
      87             : static void
      88          24 : fake_issue (struct TALER_EXCHANGEDB_DenominationKeyInformation *issue)
      89             : {
      90             :   struct GNUNET_TIME_Timestamp now;
      91             : 
      92          24 :   memset (issue,
      93             :           0,
      94             :           sizeof (*issue));
      95          24 :   now = GNUNET_TIME_timestamp_get ();
      96             :   issue->start
      97          24 :     = now;
      98             :   issue->expire_withdraw
      99          24 :     = GNUNET_TIME_relative_to_timestamp (GNUNET_TIME_UNIT_MINUTES);
     100             :   issue->expire_deposit
     101          24 :     = GNUNET_TIME_relative_to_timestamp (GNUNET_TIME_UNIT_HOURS);
     102             :   issue->expire_legal
     103          24 :     = GNUNET_TIME_relative_to_timestamp (GNUNET_TIME_UNIT_DAYS);
     104          24 :   GNUNET_assert (GNUNET_OK ==
     105             :                  TALER_string_to_amount ("EUR:1",
     106             :                                          &issue->value));
     107          24 :   GNUNET_assert (GNUNET_OK ==
     108             :                  TALER_string_to_amount ("EUR:0.1",
     109             :                                          &issue->fees.withdraw));
     110          24 :   GNUNET_assert (GNUNET_OK ==
     111             :                  TALER_string_to_amount ("EUR:0.1",
     112             :                                          &issue->fees.deposit));
     113          24 :   GNUNET_assert (GNUNET_OK ==
     114             :                  TALER_string_to_amount ("EUR:0.1",
     115             :                                          &issue->fees.refresh));
     116          24 :   GNUNET_assert (GNUNET_OK ==
     117             :                  TALER_string_to_amount ("EUR:0.1",
     118             :                                          &issue->fees.refund));
     119          24 : }
     120             : 
     121             : 
     122             : /**
     123             :  * Run the command.
     124             :  *
     125             :  * @param cls closure.
     126             :  * @param cmd the commaind being run.
     127             :  * @param is interpreter state.
     128             :  */
     129             : static void
     130          24 : insert_deposit_run (void *cls,
     131             :                     const struct TALER_TESTING_Command *cmd,
     132             :                     struct TALER_TESTING_Interpreter *is)
     133             : {
     134          24 :   struct InsertDepositState *ids = cls;
     135             :   struct TALER_EXCHANGEDB_CoinDepositInformation deposit;
     136             :   struct TALER_EXCHANGEDB_BatchDeposit bd;
     137             :   struct TALER_MerchantPrivateKeyP merchant_priv;
     138             :   struct TALER_EXCHANGEDB_DenominationKeyInformation issue;
     139             :   struct TALER_DenominationPublicKey dpk;
     140             :   struct TALER_DenominationPrivateKey denom_priv;
     141             :   struct TALER_FullPayto receiver_wire_account;
     142             : 
     143             :   (void) cmd;
     144          24 :   if (NULL == ids->plugin)
     145             :   {
     146           0 :     GNUNET_break (0);
     147           0 :     TALER_TESTING_interpreter_fail (is);
     148           0 :     return;
     149             :   }
     150          24 :   if (GNUNET_OK !=
     151          24 :       ids->plugin->preflight (ids->plugin->cls))
     152             :   {
     153           0 :     GNUNET_break (0);
     154           0 :     TALER_TESTING_interpreter_fail (is);
     155           0 :     return;
     156             :   }
     157          24 :   fake_issue (&issue);
     158          24 :   GNUNET_assert (GNUNET_OK ==
     159             :                  TALER_denom_priv_create (&denom_priv,
     160             :                                           &dpk,
     161             :                                           GNUNET_CRYPTO_BSA_RSA,
     162             :                                           1024));
     163          24 :   TALER_denom_pub_hash (&dpk,
     164             :                         &issue.denom_hash);
     165             : 
     166          24 :   if ( (GNUNET_OK !=
     167          24 :         ids->plugin->start (ids->plugin->cls,
     168          24 :                             "talertestinglib: denomination insertion")) ||
     169             :        (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     170          24 :         ids->plugin->insert_denomination_info (ids->plugin->cls,
     171             :                                                &dpk,
     172          24 :                                                &issue)) ||
     173             :        (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     174          24 :         ids->plugin->commit (ids->plugin->cls)) )
     175             :   {
     176           0 :     TALER_TESTING_interpreter_fail (is);
     177           0 :     TALER_denom_pub_free (&dpk);
     178           0 :     TALER_denom_priv_free (&denom_priv);
     179           0 :     return;
     180             :   }
     181             : 
     182             :   /* prepare and store deposit now. */
     183          24 :   memset (&deposit,
     184             :           0,
     185             :           sizeof (deposit));
     186          24 :   memset (&bd,
     187             :           0,
     188             :           sizeof (bd));
     189          24 :   bd.cdis = &deposit;
     190          24 :   bd.num_cdis = 1;
     191             : 
     192          24 :   GNUNET_assert (
     193             :     GNUNET_YES ==
     194             :     GNUNET_CRYPTO_kdf (&merchant_priv,
     195             :                        sizeof (struct TALER_MerchantPrivateKeyP),
     196             :                        "merchant-priv",
     197             :                        strlen ("merchant-priv"),
     198             :                        ids->merchant_name,
     199             :                        strlen (ids->merchant_name),
     200             :                        NULL,
     201             :                        0));
     202          24 :   GNUNET_assert (
     203             :     GNUNET_YES ==
     204             :     GNUNET_CRYPTO_kdf (&bd.merchant_sig,
     205             :                        sizeof (struct TALER_MerchantSignatureP),
     206             :                        "merchant-sig",
     207             :                        strlen ("merchant-sig"),
     208             :                        ids->merchant_name,
     209             :                        strlen (ids->merchant_name),
     210             :                        NULL,
     211             :                        0));
     212          24 :   GNUNET_CRYPTO_eddsa_key_get_public (&merchant_priv.eddsa_priv,
     213             :                                       &bd.merchant_pub.eddsa_pub);
     214          24 :   GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK,
     215             :                                     &bd.h_contract_terms.hash);
     216          24 :   if (GNUNET_OK !=
     217          24 :       TALER_string_to_amount (ids->amount_with_fee,
     218             :                               &deposit.amount_with_fee))
     219             :   {
     220           0 :     TALER_TESTING_interpreter_fail (is);
     221           0 :     TALER_denom_pub_free (&dpk);
     222           0 :     TALER_denom_priv_free (&denom_priv);
     223           0 :     return;
     224             :   }
     225             : 
     226          24 :   TALER_denom_pub_hash (&dpk,
     227             :                         &deposit.coin.denom_pub_hash);
     228          24 :   GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
     229             :                               &deposit.coin.coin_pub,
     230             :                               sizeof (deposit.coin.coin_pub));
     231             :   {
     232             :     struct TALER_CoinPubHashP c_hash;
     233             :     struct TALER_PlanchetDetail pd;
     234             :     struct TALER_BlindedDenominationSignature bds;
     235             :     struct TALER_PlanchetMasterSecretP ps;
     236             :     union GNUNET_CRYPTO_BlindingSecretP bks;
     237             :     const struct TALER_ExchangeBlindingValues *alg_values;
     238             : 
     239          24 :     alg_values = TALER_denom_ewv_rsa_singleton ();
     240          24 :     TALER_planchet_blinding_secret_create (&ps,
     241             :                                            alg_values,
     242             :                                            &bks);
     243          24 :     GNUNET_assert (GNUNET_OK ==
     244             :                    TALER_denom_blind (&dpk,
     245             :                                       &bks,
     246             :                                       NULL, /* no age restriction active */
     247             :                                       NULL, /* no nonce needed */
     248             :                                       &deposit.coin.coin_pub,
     249             :                                       alg_values,
     250             :                                       &c_hash,
     251             :                                       &pd.blinded_planchet));
     252          24 :     GNUNET_assert (GNUNET_OK ==
     253             :                    TALER_denom_sign_blinded (&bds,
     254             :                                              &denom_priv,
     255             :                                              false,
     256             :                                              &pd.blinded_planchet));
     257          24 :     TALER_blinded_planchet_free (&pd.blinded_planchet);
     258          24 :     GNUNET_assert (GNUNET_OK ==
     259             :                    TALER_denom_sig_unblind (&deposit.coin.denom_sig,
     260             :                                             &bds,
     261             :                                             &bks,
     262             :                                             &c_hash,
     263             :                                             alg_values,
     264             :                                             &dpk));
     265          24 :     TALER_blinded_denom_sig_free (&bds);
     266             :   }
     267          24 :   GNUNET_asprintf (&receiver_wire_account.full_payto,
     268             :                    "payto://x-taler-bank/localhost/%s?receiver-name=%s",
     269             :                    ids->merchant_account,
     270             :                    ids->merchant_account);
     271          24 :   bd.receiver_wire_account = receiver_wire_account;
     272          24 :   TALER_full_payto_hash (bd.receiver_wire_account,
     273             :                          &bd.wire_target_h_payto);
     274          24 :   memset (&bd.wire_salt,
     275             :           46,
     276             :           sizeof (bd.wire_salt));
     277          24 :   bd.wallet_timestamp = GNUNET_TIME_timestamp_get ();
     278          24 :   bd.wire_deadline = GNUNET_TIME_relative_to_timestamp (
     279             :     ids->wire_deadline);
     280             :   /* finally, actually perform the DB operation */
     281             :   {
     282             :     uint64_t known_coin_id;
     283             :     struct TALER_DenominationHashP dph;
     284             :     struct TALER_AgeCommitmentHash agh;
     285             :     bool balance_ok;
     286             :     uint32_t bad_index;
     287             :     bool ctr_conflict;
     288             : 
     289          24 :     if ( (GNUNET_OK !=
     290          24 :           ids->plugin->start (ids->plugin->cls,
     291          24 :                               "libtalertesting: insert deposit")) ||
     292             :          (0 >
     293          24 :           ids->plugin->ensure_coin_known (ids->plugin->cls,
     294             :                                           &deposit.coin,
     295             :                                           &known_coin_id,
     296             :                                           &dph,
     297          24 :                                           &agh)) ||
     298             :          (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     299          24 :           ids->plugin->do_deposit (ids->plugin->cls,
     300             :                                    &bd,
     301             :                                    &ids->exchange_timestamp,
     302             :                                    &balance_ok,
     303             :                                    &bad_index,
     304          24 :                                    &ctr_conflict)) ||
     305             :          (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     306          24 :           ids->plugin->commit (ids->plugin->cls)) )
     307             :     {
     308           0 :       GNUNET_break (0);
     309           0 :       ids->plugin->rollback (ids->plugin->cls);
     310           0 :       GNUNET_free (receiver_wire_account.full_payto);
     311           0 :       TALER_denom_pub_free (&dpk);
     312           0 :       TALER_denom_priv_free (&denom_priv);
     313           0 :       TALER_TESTING_interpreter_fail (is);
     314           0 :       return;
     315             :     }
     316             :   }
     317             : 
     318          24 :   TALER_denom_sig_free (&deposit.coin.denom_sig);
     319          24 :   TALER_denom_pub_free (&dpk);
     320          24 :   TALER_denom_priv_free (&denom_priv);
     321          24 :   GNUNET_free (receiver_wire_account.full_payto);
     322          24 :   TALER_TESTING_interpreter_next (is);
     323             : }
     324             : 
     325             : 
     326             : /**
     327             :  * Free the state of a "auditor-dbinit" CMD, and possibly kills its
     328             :  * process if it did not terminate correctly.
     329             :  *
     330             :  * @param cls closure.
     331             :  * @param cmd the command being freed.
     332             :  */
     333             : static void
     334          24 : insert_deposit_cleanup (void *cls,
     335             :                         const struct TALER_TESTING_Command *cmd)
     336             : {
     337          24 :   struct InsertDepositState *ids = cls;
     338             : 
     339             :   (void) cmd;
     340          24 :   if ( (NULL != ids->plugin) &&
     341          24 :        (! ids->cached) )
     342             :   {
     343             :     // FIXME: historically, we also did:
     344             :     // ids->plugin->drop_tables (ids->plugin->cls);
     345           1 :     TALER_EXCHANGEDB_plugin_unload (ids->plugin);
     346           1 :     ids->plugin = NULL;
     347             :   }
     348          24 :   GNUNET_free (ids);
     349          24 : }
     350             : 
     351             : 
     352             : struct TALER_TESTING_Command
     353          24 : TALER_TESTING_cmd_insert_deposit (
     354             :   const char *label,
     355             :   const struct GNUNET_CONFIGURATION_Handle *db_cfg,
     356             :   const char *merchant_name,
     357             :   const char *merchant_account,
     358             :   struct GNUNET_TIME_Timestamp exchange_timestamp,
     359             :   struct GNUNET_TIME_Relative wire_deadline,
     360             :   const char *amount_with_fee,
     361             :   const char *deposit_fee)
     362             : {
     363             :   static struct TALER_EXCHANGEDB_Plugin *pluginc;
     364             :   static const struct GNUNET_CONFIGURATION_Handle *db_cfgc;
     365             :   struct InsertDepositState *ids;
     366             : 
     367          24 :   ids = GNUNET_new (struct InsertDepositState);
     368          24 :   if (db_cfgc == db_cfg)
     369             :   {
     370          23 :     ids->plugin = pluginc;
     371          23 :     ids->cached = true;
     372             :   }
     373             :   else
     374             :   {
     375           1 :     ids->plugin = TALER_EXCHANGEDB_plugin_load (db_cfg,
     376             :                                                 false);
     377           1 :     pluginc = ids->plugin;
     378           1 :     db_cfgc = db_cfg;
     379             :   }
     380          24 :   ids->merchant_name = merchant_name;
     381          24 :   ids->merchant_account = merchant_account;
     382          24 :   ids->exchange_timestamp = exchange_timestamp;
     383          24 :   ids->wire_deadline = wire_deadline;
     384          24 :   ids->amount_with_fee = amount_with_fee;
     385          24 :   ids->deposit_fee = deposit_fee;
     386             : 
     387             :   {
     388          24 :     struct TALER_TESTING_Command cmd = {
     389             :       .cls = ids,
     390             :       .label = label,
     391             :       .run = &insert_deposit_run,
     392             :       .cleanup = &insert_deposit_cleanup
     393             :     };
     394             : 
     395          24 :     return cmd;
     396             :   }
     397             : }
     398             : 
     399             : 
     400             : /* end of testing_api_cmd_insert_deposit.c */

Generated by: LCOV version 1.16