LCOV - code coverage report
Current view: top level - exchange - taler-exchange-httpd_batch-deposit.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 248 404 61.4 %
Date: 2025-07-14 11:22:44 Functions: 14 15 93.3 %

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2014-2024 Taler Systems SA
       4             : 
       5             :   TALER is free software; you can redistribute it and/or modify it under the
       6             :   terms of the GNU Affero 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 Affero General Public License for more details.
      12             : 
      13             :   You should have received a copy of the GNU Affero General Public License along with
      14             :   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
      15             : */
      16             : /**
      17             :  * @file taler-exchange-httpd_batch-deposit.c
      18             :  * @brief Handle /batch-deposit requests; parses the POST and JSON and
      19             :  *        verifies the coin signatures before handing things off
      20             :  *        to the database.
      21             :  * @author Florian Dold
      22             :  * @author Benedikt Mueller
      23             :  * @author Christian Grothoff
      24             :  */
      25             : #include "taler/platform.h"
      26             : #include <gnunet/gnunet_util_lib.h>
      27             : #include <gnunet/gnunet_json_lib.h>
      28             : #include <jansson.h>
      29             : #include <microhttpd.h>
      30             : #include <pthread.h>
      31             : #include "taler/taler_extensions_policy.h"
      32             : #include "taler/taler_json_lib.h"
      33             : #include "taler/taler_mhd_lib.h"
      34             : #include "taler-exchange-httpd_common_kyc.h"
      35             : #include "taler-exchange-httpd_batch-deposit.h"
      36             : #include "taler-exchange-httpd_responses.h"
      37             : #include "taler/taler_exchangedb_lib.h"
      38             : #include "taler-exchange-httpd_keys.h"
      39             : 
      40             : 
      41             : /**
      42             :  * Closure for #batch_deposit_transaction.
      43             :  */
      44             : struct BatchDepositContext
      45             : {
      46             : 
      47             :   /**
      48             :    * Kept in a DLL.
      49             :    */
      50             :   struct BatchDepositContext *next;
      51             : 
      52             :   /**
      53             :    * Kept in a DLL.
      54             :    */
      55             :   struct BatchDepositContext *prev;
      56             : 
      57             :   /**
      58             :    * The request we are working on.
      59             :    */
      60             :   struct TEH_RequestContext *rc;
      61             : 
      62             :   /**
      63             :    * Handle for the legitimization check.
      64             :    */
      65             :   struct TEH_LegitimizationCheckHandle *lch;
      66             : 
      67             :   /**
      68             :    * Array with the individual coin deposit fees.
      69             :    */
      70             :   struct TALER_Amount *deposit_fees;
      71             : 
      72             :   /**
      73             :    * Information about deposited coins.
      74             :    */
      75             :   struct TALER_EXCHANGEDB_CoinDepositInformation *cdis;
      76             : 
      77             :   /**
      78             :    * Additional details for policy extension relevant for this
      79             :    * deposit operation, possibly NULL!
      80             :    */
      81             :   json_t *policy_json;
      82             : 
      83             :   /**
      84             :    * Response to return, if set.
      85             :    */
      86             :   struct MHD_Response *response;
      87             : 
      88             :   /**
      89             :    * KYC status of the reserve used for the operation.
      90             :    */
      91             :   struct TALER_EXCHANGEDB_KycStatus kyc;
      92             : 
      93             :   /**
      94             :    * Hash over @e policy_details, might be all zero
      95             :    */
      96             :   struct TALER_ExtensionPolicyHashP h_policy;
      97             : 
      98             :   /**
      99             :    * Hash over the merchant's payto://-URI with the wire salt.
     100             :    */
     101             :   struct TALER_MerchantWireHashP h_wire;
     102             : 
     103             :   /**
     104             :    * When @e policy_details are persisted, this contains the id of the record
     105             :    * in the policy_details table.
     106             :    */
     107             :   uint64_t policy_details_serial_id;
     108             : 
     109             :   /**
     110             :    * Hash over the normalized payto://-URI of the account we are
     111             :    * depositing into.
     112             :    */
     113             :   struct TALER_NormalizedPaytoHashP nph;
     114             : 
     115             :   /**
     116             :    * Our timestamp (when we received the request).
     117             :    * Possibly updated by the transaction if the
     118             :    * request is idempotent (was repeated).
     119             :    */
     120             :   struct GNUNET_TIME_Timestamp exchange_timestamp;
     121             : 
     122             :   /**
     123             :    * Total amount that is accumulated with this deposit,
     124             :    * without fee.
     125             :    */
     126             :   struct TALER_Amount accumulated_total_without_fee;
     127             : 
     128             :   /**
     129             :    * Details about the batch deposit operation.
     130             :    */
     131             :   struct TALER_EXCHANGEDB_BatchDeposit bd;
     132             : 
     133             :   /**
     134             :    * If @e policy_json was present, the corresponding policy extension
     135             :    * calculates these details.  These will be persisted in the policy_details
     136             :    * table.
     137             :    */
     138             :   struct TALER_PolicyDetails policy_details;
     139             : 
     140             :   /**
     141             :    * HTTP status to return with @e response, or 0.
     142             :    */
     143             :   unsigned int http_status;
     144             : 
     145             :   /**
     146             :    * Our current state in the state machine.
     147             :    */
     148             :   enum
     149             :   {
     150             :     BDC_PHASE_INIT = 0,
     151             :     BDC_PHASE_PARSE = 1,
     152             :     BDC_PHASE_POLICY = 2,
     153             :     BDC_PHASE_KYC = 3,
     154             :     BDC_PHASE_TRANSACT = 4,
     155             :     BDC_PHASE_REPLY_SUCCESS = 5,
     156             :     BDC_PHASE_SUSPENDED,
     157             :     BDC_PHASE_CHECK_KYC_RESULT,
     158             :     BDC_PHASE_GENERATE_REPLY_FAILURE,
     159             :     BDC_PHASE_RETURN_YES,
     160             :     BDC_PHASE_RETURN_NO,
     161             :   } phase;
     162             : 
     163             :   /**
     164             :    * True, if no policy was present in the request. Then
     165             :    * @e policy_json is NULL and @e h_policy will be all zero.
     166             :    */
     167             :   bool has_no_policy;
     168             : 
     169             :   /**
     170             :    * KYC failed because a KYC auth transfer is needed
     171             :    * to establish the merchant_pub.
     172             :    */
     173             :   bool bad_kyc_auth;
     174             : };
     175             : 
     176             : 
     177             : /**
     178             :  * Head of list of suspended batch deposit operations.
     179             :  */
     180             : static struct BatchDepositContext *bdc_head;
     181             : 
     182             : /**
     183             :  * Tail of list of suspended batch deposit operations.
     184             :  */
     185             : static struct BatchDepositContext *bdc_tail;
     186             : 
     187             : 
     188             : void
     189          21 : TEH_batch_deposit_cleanup ()
     190             : {
     191             :   struct BatchDepositContext *bdc;
     192             : 
     193          21 :   while (NULL != (bdc = bdc_head))
     194             :   {
     195           0 :     GNUNET_assert (BDC_PHASE_SUSPENDED == bdc->phase);
     196           0 :     bdc->phase = BDC_PHASE_RETURN_NO;
     197           0 :     MHD_resume_connection (bdc->rc->connection);
     198           0 :     GNUNET_CONTAINER_DLL_remove (bdc_head,
     199             :                                  bdc_tail,
     200             :                                  bdc);
     201             :   }
     202          21 : }
     203             : 
     204             : 
     205             : /**
     206             :  * Terminate the main loop by returning the final
     207             :  * result.
     208             :  *
     209             :  * @param[in,out] bdc context to update phase for
     210             :  * @param mres MHD status to return
     211             :  */
     212             : static void
     213         104 : finish_loop (struct BatchDepositContext *bdc,
     214             :              MHD_RESULT mres)
     215             : {
     216         104 :   bdc->phase = (MHD_YES == mres)
     217             :     ? BDC_PHASE_RETURN_YES
     218         104 :     : BDC_PHASE_RETURN_NO;
     219         104 : }
     220             : 
     221             : 
     222             : /**
     223             :  * Send confirmation of batch deposit success to client.  This function will
     224             :  * create a signed message affirming the given information and return it to
     225             :  * the client.  By this, the exchange affirms that the coins had sufficient
     226             :  * (residual) value for the specified transaction and that it will execute the
     227             :  * requested batch deposit operation with the given wiring details.
     228             :  *
     229             :  * @param[in,out] bdc information about the batch deposit
     230             :  */
     231             : static void
     232          90 : bdc_phase_reply_success (
     233             :   struct BatchDepositContext *bdc)
     234          90 : {
     235          90 :   const struct TALER_EXCHANGEDB_BatchDeposit *bd = &bdc->bd;
     236          90 :   const struct TALER_CoinSpendSignatureP *csigs[GNUNET_NZL (bd->num_cdis)];
     237             :   enum TALER_ErrorCode ec;
     238             :   struct TALER_ExchangePublicKeyP pub;
     239             :   struct TALER_ExchangeSignatureP sig;
     240             : 
     241         182 :   for (unsigned int i = 0; i<bdc->bd.num_cdis; i++)
     242          92 :     csigs[i] = &bd->cdis[i].csig;
     243          90 :   if (TALER_EC_NONE !=
     244          90 :       (ec = TALER_exchange_online_deposit_confirmation_sign (
     245             :          &TEH_keys_exchange_sign_,
     246             :          &bd->h_contract_terms,
     247          90 :          &bdc->h_wire,
     248          90 :          bdc->has_no_policy ? NULL : &bdc->h_policy,
     249             :          bdc->exchange_timestamp,
     250             :          bd->wire_deadline,
     251             :          bd->refund_deadline,
     252          90 :          &bdc->accumulated_total_without_fee,
     253          90 :          bd->num_cdis,
     254             :          csigs,
     255          90 :          &bdc->bd.merchant_pub,
     256             :          &pub,
     257             :          &sig)))
     258             :   {
     259           0 :     GNUNET_break (0);
     260           0 :     finish_loop (bdc,
     261           0 :                  TALER_MHD_reply_with_ec (bdc->rc->connection,
     262             :                                           ec,
     263             :                                           NULL));
     264           0 :     return;
     265             :   }
     266         180 :   finish_loop (bdc,
     267         180 :                TALER_MHD_REPLY_JSON_PACK (
     268             :                  bdc->rc->connection,
     269             :                  MHD_HTTP_OK,
     270             :                  GNUNET_JSON_pack_timestamp ("exchange_timestamp",
     271             :                                              bdc->exchange_timestamp),
     272             :                  GNUNET_JSON_pack_data_auto ("exchange_pub",
     273             :                                              &pub),
     274             :                  GNUNET_JSON_pack_data_auto ("exchange_sig",
     275             :                                              &sig)));
     276             : }
     277             : 
     278             : 
     279             : /**
     280             :  * Execute database transaction for /batch-deposit.  Runs the transaction
     281             :  * logic; IF it returns a non-error code, the transaction logic MUST
     282             :  * NOT queue a MHD response.  IF it returns an hard error, the
     283             :  * transaction logic MUST queue a MHD response and set @a mhd_ret.  IF
     284             :  * it returns the soft error code, the function MAY be called again to
     285             :  * retry and MUST not queue a MHD response.
     286             :  *
     287             :  * @param cls a `struct BatchDepositContext`
     288             :  * @param connection MHD request context
     289             :  * @param[out] mhd_ret set to MHD status on error
     290             :  * @return transaction status
     291             :  */
     292             : static enum GNUNET_DB_QueryStatus
     293          99 : batch_deposit_transaction (void *cls,
     294             :                            struct MHD_Connection *connection,
     295             :                            MHD_RESULT *mhd_ret)
     296             : {
     297          99 :   struct BatchDepositContext *bdc = cls;
     298          99 :   const struct TALER_EXCHANGEDB_BatchDeposit *bd = &bdc->bd;
     299          99 :   enum GNUNET_DB_QueryStatus qs = GNUNET_DB_STATUS_HARD_ERROR;
     300          99 :   uint32_t bad_balance_coin_index = UINT32_MAX;
     301             :   bool balance_ok;
     302             :   bool in_conflict;
     303             : 
     304             :   /* If the deposit has a policy associated to it, persist it.  This will
     305             :    * insert or update the record. */
     306          99 :   if (! bdc->has_no_policy)
     307             :   {
     308           0 :     qs = TEH_plugin->persist_policy_details (
     309           0 :       TEH_plugin->cls,
     310           0 :       &bdc->policy_details,
     311             :       &bdc->bd.policy_details_serial_id,
     312             :       &bdc->accumulated_total_without_fee,
     313             :       &bdc->policy_details.fulfillment_state);
     314           0 :     if (qs < 0)
     315           0 :       return qs;
     316             : 
     317           0 :     bdc->bd.policy_blocked =
     318           0 :       bdc->policy_details.fulfillment_state != TALER_PolicyFulfillmentSuccess;
     319             :   }
     320             : 
     321             :   /* FIXME-#9373: replace by batch insert! */
     322         199 :   for (unsigned int i = 0; i<bdc->bd.num_cdis; i++)
     323             :   {
     324         101 :     const struct TALER_EXCHANGEDB_CoinDepositInformation *cdi
     325         101 :       = &bdc->cdis[i];
     326             :     uint64_t known_coin_id;
     327             : 
     328         101 :     qs = TEH_make_coin_known (&cdi->coin,
     329             :                               connection,
     330             :                               &known_coin_id,
     331             :                               mhd_ret);
     332         101 :     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     333             :                 "make coin known (%s) returned %d\n",
     334             :                 TALER_B2S (&cdi->coin.coin_pub),
     335             :                 qs);
     336         101 :     if (qs < 0)
     337           1 :       return qs;
     338             :   }
     339             : 
     340          98 :   qs = TEH_plugin->do_deposit (
     341          98 :     TEH_plugin->cls,
     342             :     bd,
     343             :     &bdc->exchange_timestamp,
     344             :     &balance_ok,
     345             :     &bad_balance_coin_index,
     346             :     &in_conflict);
     347          98 :   if (qs <= 0)
     348             :   {
     349           0 :     if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
     350           0 :       return qs;
     351           0 :     TALER_LOG_WARNING (
     352             :       "Failed to store /batch-deposit information in database\n");
     353           0 :     *mhd_ret = TALER_MHD_reply_with_error (
     354             :       connection,
     355             :       MHD_HTTP_INTERNAL_SERVER_ERROR,
     356             :       TALER_EC_GENERIC_DB_STORE_FAILED,
     357             :       "batch-deposit");
     358           0 :     return qs;
     359             :   }
     360          98 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     361             :               "do_deposit returned: %d / %s[%u] / %s\n",
     362             :               qs,
     363             :               balance_ok ? "balance ok" : "balance insufficient",
     364             :               (unsigned int) bad_balance_coin_index,
     365             :               in_conflict ? "in conflict" : "no conflict");
     366          98 :   if (in_conflict)
     367             :   {
     368             :     struct TALER_MerchantWireHashP h_wire;
     369             : 
     370           4 :     if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     371           4 :         TEH_plugin->get_wire_hash_for_contract (
     372           4 :           TEH_plugin->cls,
     373             :           &bd->merchant_pub,
     374             :           &bd->h_contract_terms,
     375             :           &h_wire))
     376             :     {
     377           0 :       TALER_LOG_WARNING (
     378             :         "Failed to retrieve conflicting contract details from database\n");
     379           0 :       *mhd_ret = TALER_MHD_reply_with_error (
     380             :         connection,
     381             :         MHD_HTTP_INTERNAL_SERVER_ERROR,
     382             :         TALER_EC_GENERIC_DB_STORE_FAILED,
     383             :         "batch-deposit");
     384           0 :       return qs;
     385             :     }
     386             : 
     387             :     *mhd_ret
     388           4 :       = TEH_RESPONSE_reply_coin_conflicting_contract (
     389             :           connection,
     390             :           TALER_EC_EXCHANGE_DEPOSIT_CONFLICTING_CONTRACT,
     391             :           &h_wire);
     392           4 :     return GNUNET_DB_STATUS_HARD_ERROR;
     393             :   }
     394          94 :   if (! balance_ok)
     395             :   {
     396           4 :     GNUNET_assert (bad_balance_coin_index < bdc->bd.num_cdis);
     397           4 :     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     398             :                 "returning history of conflicting coin (%s)\n",
     399             :                 TALER_B2S (&bdc->cdis[bad_balance_coin_index].coin.coin_pub));
     400             :     *mhd_ret
     401           8 :       = TEH_RESPONSE_reply_coin_insufficient_funds (
     402             :           connection,
     403             :           TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS,
     404           4 :           &bdc->cdis[bad_balance_coin_index].coin.denom_pub_hash,
     405           4 :           &bdc->cdis[bad_balance_coin_index].coin.coin_pub);
     406           4 :     return GNUNET_DB_STATUS_HARD_ERROR;
     407             :   }
     408          90 :   TEH_METRICS_num_success[TEH_MT_SUCCESS_DEPOSIT]++;
     409          90 :   return qs;
     410             : }
     411             : 
     412             : 
     413             : /**
     414             :  * Run database transaction.
     415             :  *
     416             :  * @param[in,out] bdc request context
     417             :  */
     418             : static void
     419          99 : bdc_phase_transact (struct BatchDepositContext *bdc)
     420             : {
     421             :   MHD_RESULT mhd_ret;
     422             : 
     423          99 :   if (GNUNET_SYSERR ==
     424          99 :       TEH_plugin->preflight (TEH_plugin->cls))
     425             :   {
     426           0 :     GNUNET_break (0);
     427           0 :     finish_loop (bdc,
     428             :                  TALER_MHD_reply_with_error (
     429           0 :                    bdc->rc->connection,
     430             :                    MHD_HTTP_INTERNAL_SERVER_ERROR,
     431             :                    TALER_EC_GENERIC_DB_START_FAILED,
     432             :                    "preflight failure"));
     433           9 :     return;
     434             :   }
     435             : 
     436          99 :   if (GNUNET_OK !=
     437          99 :       TEH_DB_run_transaction (bdc->rc->connection,
     438             :                               "execute batch deposit",
     439             :                               TEH_MT_REQUEST_BATCH_DEPOSIT,
     440             :                               &mhd_ret,
     441             :                               &batch_deposit_transaction,
     442             :                               bdc))
     443             :   {
     444           9 :     finish_loop (bdc,
     445             :                  mhd_ret);
     446           9 :     return;
     447             :   }
     448          90 :   bdc->phase++;
     449             : }
     450             : 
     451             : 
     452             : /**
     453             :  * Check if the @a bdc is replayed and we already have an
     454             :  * answer. If so, replay the existing answer and return the
     455             :  * HTTP response.
     456             :  *
     457             :  * @param bdc parsed request data
     458             :  * @return true if the request is idempotent with an existing request
     459             :  *    false if we did not find the request in the DB and did not set @a mret
     460             :  */
     461             : static bool
     462           5 : check_request_idempotent (
     463             :   struct BatchDepositContext *bdc)
     464             : {
     465           5 :   const struct TEH_RequestContext *rc = bdc->rc;
     466             :   enum GNUNET_DB_QueryStatus qs;
     467             :   bool is_idempotent;
     468             : 
     469           5 :   qs = TEH_plugin->do_check_deposit_idempotent (
     470           5 :     TEH_plugin->cls,
     471           5 :     &bdc->bd,
     472             :     &bdc->exchange_timestamp,
     473             :     &is_idempotent);
     474           5 :   if (0 > qs)
     475             :   {
     476           0 :     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
     477           0 :     finish_loop (bdc,
     478             :                  TALER_MHD_reply_with_error (
     479           0 :                    rc->connection,
     480             :                    MHD_HTTP_INTERNAL_SERVER_ERROR,
     481             :                    TALER_EC_GENERIC_DB_FETCH_FAILED,
     482             :                    "do_check_deposit_idempotent"));
     483           0 :     return true;
     484             :   }
     485           5 :   if ( (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) ||
     486           5 :        (! is_idempotent) )
     487           5 :     return false;
     488           0 :   bdc->phase = BDC_PHASE_REPLY_SUCCESS;
     489           0 :   return true;
     490             : }
     491             : 
     492             : 
     493             : /**
     494             :  * Check the KYC result.
     495             :  *
     496             :  * @param bdc storage for request processing
     497             :  */
     498             : static void
     499          66 : bdc_phase_check_kyc_result (struct BatchDepositContext *bdc)
     500             : {
     501             :   /* return final positive response */
     502          66 :   if ( (! bdc->kyc.ok) ||
     503          66 :        (bdc->bad_kyc_auth) )
     504             :   {
     505           5 :     if (check_request_idempotent (bdc))
     506             :     {
     507           0 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     508             :                   "Request is idempotent!\n");
     509           0 :       return;
     510             :     }
     511             :     /* KYC required */
     512           5 :     finish_loop (bdc,
     513             :                  TEH_RESPONSE_reply_kyc_required (
     514           5 :                    bdc->rc->connection,
     515           5 :                    &bdc->nph,
     516           5 :                    &bdc->kyc,
     517           5 :                    bdc->bad_kyc_auth));
     518           5 :     return;
     519             :   }
     520          61 :   bdc->phase = BDC_PHASE_TRANSACT;
     521             : }
     522             : 
     523             : 
     524             : /**
     525             :  * Function called with the result of a legitimization
     526             :  * check.
     527             :  *
     528             :  * @param cls closure
     529             :  * @param lcr legitimization check result
     530             :  */
     531             : static void
     532          66 : deposit_legi_cb (
     533             :   void *cls,
     534             :   const struct TEH_LegitimizationCheckResult *lcr)
     535             : {
     536          66 :   struct BatchDepositContext *bdc = cls;
     537             : 
     538          66 :   bdc->lch = NULL;
     539          66 :   GNUNET_assert (BDC_PHASE_SUSPENDED ==
     540             :                  bdc->phase);
     541          66 :   MHD_resume_connection (bdc->rc->connection);
     542          66 :   GNUNET_CONTAINER_DLL_remove (bdc_head,
     543             :                                bdc_tail,
     544             :                                bdc);
     545          66 :   TALER_MHD_daemon_trigger ();
     546          66 :   if (NULL != lcr->response)
     547             :   {
     548           0 :     bdc->response = lcr->response;
     549           0 :     bdc->http_status = lcr->http_status;
     550           0 :     bdc->phase = BDC_PHASE_GENERATE_REPLY_FAILURE;
     551           0 :     return;
     552             :   }
     553          66 :   bdc->kyc = lcr->kyc;
     554          66 :   bdc->bad_kyc_auth = lcr->bad_kyc_auth;
     555          66 :   bdc->phase = BDC_PHASE_CHECK_KYC_RESULT;
     556             : }
     557             : 
     558             : 
     559             : /**
     560             :  * Function called to iterate over KYC-relevant transaction amounts for a
     561             :  * particular time range. Called within a database transaction, so must
     562             :  * not start a new one.
     563             :  *
     564             :  * @param cls closure, identifies the event type and account to iterate
     565             :  *        over events for
     566             :  * @param limit maximum time-range for which events should be fetched
     567             :  *        (timestamp in the past)
     568             :  * @param cb function to call on each event found, events must be returned
     569             :  *        in reverse chronological order
     570             :  * @param cb_cls closure for @a cb, of type struct AgeWithdrawContext
     571             :  * @return transaction status
     572             :  */
     573             : static enum GNUNET_DB_QueryStatus
     574           0 : deposit_amount_cb (
     575             :   void *cls,
     576             :   struct GNUNET_TIME_Absolute limit,
     577             :   TALER_EXCHANGEDB_KycAmountCallback cb,
     578             :   void *cb_cls)
     579             : {
     580           0 :   struct BatchDepositContext *bdc = cls;
     581             :   enum GNUNET_GenericReturnValue ret;
     582             :   enum GNUNET_DB_QueryStatus qs;
     583             : 
     584           0 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     585             :               "Signaling amount %s for KYC check during deposit\n",
     586             :               TALER_amount2s (&bdc->accumulated_total_without_fee));
     587           0 :   ret = cb (cb_cls,
     588           0 :             &bdc->accumulated_total_without_fee,
     589             :             bdc->exchange_timestamp.abs_time);
     590           0 :   GNUNET_break (GNUNET_SYSERR != ret);
     591           0 :   if (GNUNET_OK != ret)
     592           0 :     return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
     593           0 :   qs = TEH_plugin->select_deposit_amounts_for_kyc_check (
     594           0 :     TEH_plugin->cls,
     595           0 :     &bdc->nph,
     596             :     limit,
     597             :     cb,
     598             :     cb_cls);
     599           0 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     600             :               "Got %d additional transactions for this deposit and limit %llu\n",
     601             :               qs,
     602             :               (unsigned long long) limit.abs_value_us);
     603           0 :   GNUNET_break (qs >= 0);
     604           0 :   return qs;
     605             : }
     606             : 
     607             : 
     608             : /**
     609             :  * Run KYC check.
     610             :  *
     611             :  * @param[in,out] bdc request context
     612             :  */
     613             : static void
     614         104 : bdc_phase_kyc (struct BatchDepositContext *bdc)
     615             : {
     616         104 :   if (GNUNET_YES != TEH_enable_kyc)
     617             :   {
     618          38 :     bdc->phase++;
     619          38 :     return;
     620             :   }
     621          66 :   TALER_full_payto_normalize_and_hash (bdc->bd.receiver_wire_account,
     622             :                                        &bdc->nph);
     623         132 :   bdc->lch = TEH_legitimization_check2 (
     624          66 :     &bdc->rc->async_scope_id,
     625             :     TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT,
     626             :     bdc->bd.receiver_wire_account,
     627          66 :     &bdc->nph,
     628          66 :     &bdc->bd.merchant_pub,
     629             :     &deposit_amount_cb,
     630             :     bdc,
     631             :     &deposit_legi_cb,
     632             :     bdc);
     633          66 :   GNUNET_assert (NULL != bdc->lch);
     634          66 :   GNUNET_CONTAINER_DLL_insert (bdc_head,
     635             :                                bdc_tail,
     636             :                                bdc);
     637          66 :   MHD_suspend_connection (bdc->rc->connection);
     638          66 :   bdc->phase = BDC_PHASE_SUSPENDED;
     639             : }
     640             : 
     641             : 
     642             : /**
     643             :  * Handle policy.
     644             :  *
     645             :  * @param[in,out] bdc request context
     646             :  */
     647             : static void
     648         104 : bdc_phase_policy (struct BatchDepositContext *bdc)
     649             : {
     650         104 :   const char *error_hint = NULL;
     651             : 
     652         104 :   if (bdc->has_no_policy)
     653             :   {
     654         104 :     bdc->phase++;
     655         104 :     return;
     656             :   }
     657           0 :   if (GNUNET_OK !=
     658           0 :       TALER_extensions_create_policy_details (
     659             :         TEH_currency,
     660           0 :         bdc->policy_json,
     661             :         &bdc->policy_details,
     662             :         &error_hint))
     663             :   {
     664           0 :     GNUNET_break_op (0);
     665           0 :     finish_loop (bdc,
     666             :                  TALER_MHD_reply_with_error (
     667           0 :                    bdc->rc->connection,
     668             :                    MHD_HTTP_BAD_REQUEST,
     669             :                    TALER_EC_EXCHANGE_DEPOSITS_POLICY_NOT_ACCEPTED,
     670             :                    error_hint));
     671           0 :     return;
     672             :   }
     673             : 
     674           0 :   TALER_deposit_policy_hash (bdc->policy_json,
     675             :                              &bdc->h_policy);
     676           0 :   bdc->phase++;
     677             : }
     678             : 
     679             : 
     680             : /**
     681             :  * Parse per-coin deposit information from @a jcoin
     682             :  * into @a deposit. Fill in generic information from
     683             :  * @a ctx.
     684             :  *
     685             :  * @param bdc information about the overall batch
     686             :  * @param jcoin coin data to parse
     687             :  * @param[out] cdi where to store the result
     688             :  * @param[out] deposit_fee where to write the deposit fee
     689             :  * @return #GNUNET_OK on success, #GNUNET_NO if an error was returned,
     690             :  *         #GNUNET_SYSERR on failure and no error could be returned
     691             :  */
     692             : static enum GNUNET_GenericReturnValue
     693         106 : parse_coin (const struct BatchDepositContext *bdc,
     694             :             json_t *jcoin,
     695             :             struct TALER_EXCHANGEDB_CoinDepositInformation *cdi,
     696             :             struct TALER_Amount *deposit_fee)
     697             : {
     698         106 :   const struct TALER_EXCHANGEDB_BatchDeposit *bd = &bdc->bd;
     699             :   struct GNUNET_JSON_Specification spec[] = {
     700         106 :     TALER_JSON_spec_amount ("contribution",
     701             :                             TEH_currency,
     702             :                             &cdi->amount_with_fee),
     703         106 :     GNUNET_JSON_spec_fixed_auto ("denom_pub_hash",
     704             :                                  &cdi->coin.denom_pub_hash),
     705         106 :     TALER_JSON_spec_denom_sig ("ub_sig",
     706             :                                &cdi->coin.denom_sig),
     707         106 :     GNUNET_JSON_spec_fixed_auto ("coin_pub",
     708             :                                  &cdi->coin.coin_pub),
     709         106 :     GNUNET_JSON_spec_mark_optional (
     710         106 :       GNUNET_JSON_spec_fixed_auto ("h_age_commitment",
     711             :                                    &cdi->coin.h_age_commitment),
     712             :       &cdi->coin.no_age_commitment),
     713         106 :     GNUNET_JSON_spec_fixed_auto ("coin_sig",
     714             :                                  &cdi->csig),
     715         106 :     GNUNET_JSON_spec_end ()
     716             :   };
     717             :   enum GNUNET_GenericReturnValue res;
     718             : 
     719         106 :   if (GNUNET_OK !=
     720         106 :       (res = TALER_MHD_parse_json_data (bdc->rc->connection,
     721             :                                         jcoin,
     722             :                                         spec)))
     723           0 :     return res;
     724             :   /* check denomination exists and is valid */
     725             :   {
     726             :     struct TEH_DenominationKey *dk;
     727             :     MHD_RESULT mret;
     728             : 
     729         106 :     dk = TEH_keys_denomination_by_hash (
     730         106 :       &cdi->coin.denom_pub_hash,
     731         106 :       bdc->rc->connection,
     732             :       &mret);
     733         106 :     if (NULL == dk)
     734             :     {
     735           0 :       GNUNET_JSON_parse_free (spec);
     736           0 :       return (MHD_YES == mret)
     737             :         ? GNUNET_NO
     738           0 :         : GNUNET_SYSERR;
     739             :     }
     740         106 :     if (0 > TALER_amount_cmp (&dk->meta.value,
     741         106 :                               &cdi->amount_with_fee))
     742             :     {
     743           0 :       GNUNET_break_op (0);
     744           0 :       GNUNET_JSON_parse_free (spec);
     745             :       return (MHD_YES ==
     746           0 :               TALER_MHD_reply_with_error (
     747           0 :                 bdc->rc->connection,
     748             :                 MHD_HTTP_BAD_REQUEST,
     749             :                 TALER_EC_EXCHANGE_GENERIC_AMOUNT_EXCEEDS_DENOMINATION_VALUE,
     750             :                 NULL))
     751             :         ? GNUNET_NO
     752           0 :         : GNUNET_SYSERR;
     753             :     }
     754         106 :     if (GNUNET_TIME_absolute_is_past (dk->meta.expire_deposit.abs_time))
     755             :     {
     756             :       /* This denomination is past the expiration time for deposits */
     757           0 :       GNUNET_JSON_parse_free (spec);
     758             :       return (MHD_YES ==
     759           0 :               TEH_RESPONSE_reply_expired_denom_pub_hash (
     760           0 :                 bdc->rc->connection,
     761           0 :                 &cdi->coin.denom_pub_hash,
     762             :                 TALER_EC_EXCHANGE_GENERIC_DENOMINATION_EXPIRED,
     763             :                 "DEPOSIT"))
     764             :         ? GNUNET_NO
     765           0 :         : GNUNET_SYSERR;
     766             :     }
     767         106 :     if (GNUNET_TIME_absolute_is_future (dk->meta.start.abs_time))
     768             :     {
     769             :       /* This denomination is not yet valid */
     770           0 :       GNUNET_JSON_parse_free (spec);
     771             :       return (MHD_YES ==
     772           0 :               TEH_RESPONSE_reply_expired_denom_pub_hash (
     773           0 :                 bdc->rc->connection,
     774           0 :                 &cdi->coin.denom_pub_hash,
     775             :                 TALER_EC_EXCHANGE_GENERIC_DENOMINATION_VALIDITY_IN_FUTURE,
     776             :                 "DEPOSIT"))
     777             :         ? GNUNET_NO
     778           0 :         : GNUNET_SYSERR;
     779             :     }
     780         106 :     if (dk->recoup_possible)
     781             :     {
     782             :       /* This denomination has been revoked */
     783           0 :       GNUNET_JSON_parse_free (spec);
     784             :       return (MHD_YES ==
     785           0 :               TEH_RESPONSE_reply_expired_denom_pub_hash (
     786           0 :                 bdc->rc->connection,
     787           0 :                 &cdi->coin.denom_pub_hash,
     788             :                 TALER_EC_EXCHANGE_GENERIC_DENOMINATION_REVOKED,
     789             :                 "DEPOSIT"))
     790             :         ? GNUNET_NO
     791           0 :         : GNUNET_SYSERR;
     792             :     }
     793         106 :     if (dk->denom_pub.bsign_pub_key->cipher !=
     794         106 :         cdi->coin.denom_sig.unblinded_sig->cipher)
     795             :     {
     796             :       /* denomination cipher and denomination signature cipher not the same */
     797           0 :       GNUNET_JSON_parse_free (spec);
     798             :       return (MHD_YES ==
     799           0 :               TALER_MHD_reply_with_error (
     800           0 :                 bdc->rc->connection,
     801             :                 MHD_HTTP_BAD_REQUEST,
     802             :                 TALER_EC_EXCHANGE_GENERIC_CIPHER_MISMATCH,
     803             :                 NULL))
     804             :         ? GNUNET_NO
     805           0 :         : GNUNET_SYSERR;
     806             :     }
     807             : 
     808         106 :     *deposit_fee = dk->meta.fees.deposit;
     809             :     /* check coin signature */
     810         106 :     switch (dk->denom_pub.bsign_pub_key->cipher)
     811             :     {
     812          57 :     case GNUNET_CRYPTO_BSA_RSA:
     813          57 :       TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_RSA]++;
     814          57 :       break;
     815          49 :     case GNUNET_CRYPTO_BSA_CS:
     816          49 :       TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_CS]++;
     817          49 :       break;
     818           0 :     default:
     819           0 :       break;
     820             :     }
     821         106 :     if (GNUNET_YES !=
     822         106 :         TALER_test_coin_valid (&cdi->coin,
     823         106 :                                &dk->denom_pub))
     824             :     {
     825           0 :       TALER_LOG_WARNING ("Invalid coin passed for /batch-deposit\n");
     826           0 :       GNUNET_JSON_parse_free (spec);
     827             :       return (MHD_YES ==
     828           0 :               TALER_MHD_reply_with_error (
     829           0 :                 bdc->rc->connection,
     830             :                 MHD_HTTP_FORBIDDEN,
     831             :                 TALER_EC_EXCHANGE_DENOMINATION_SIGNATURE_INVALID,
     832             :                 NULL))
     833             :         ? GNUNET_NO
     834           0 :         : GNUNET_SYSERR;
     835             :     }
     836             :   }
     837         106 :   if (0 < TALER_amount_cmp (deposit_fee,
     838         106 :                             &cdi->amount_with_fee))
     839             :   {
     840           0 :     GNUNET_break_op (0);
     841           0 :     GNUNET_JSON_parse_free (spec);
     842             :     return (MHD_YES ==
     843           0 :             TALER_MHD_reply_with_error (
     844           0 :               bdc->rc->connection,
     845             :               MHD_HTTP_BAD_REQUEST,
     846             :               TALER_EC_EXCHANGE_DEPOSIT_NEGATIVE_VALUE_AFTER_FEE,
     847             :               NULL))
     848             :         ? GNUNET_NO
     849           0 :         : GNUNET_SYSERR;
     850             :   }
     851             : 
     852         106 :   TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++;
     853         106 :   if (GNUNET_OK !=
     854         212 :       TALER_wallet_deposit_verify (
     855         106 :         &cdi->amount_with_fee,
     856             :         deposit_fee,
     857             :         &bdc->h_wire,
     858             :         &bd->h_contract_terms,
     859             :         &bd->wallet_data_hash,
     860         106 :         cdi->coin.no_age_commitment
     861             :         ? NULL
     862             :         : &cdi->coin.h_age_commitment,
     863         106 :         NULL != bdc->policy_json ? &bdc->h_policy : NULL,
     864         106 :         &cdi->coin.denom_pub_hash,
     865             :         bd->wallet_timestamp,
     866             :         &bd->merchant_pub,
     867             :         bd->refund_deadline,
     868         106 :         &cdi->coin.coin_pub,
     869         106 :         &cdi->csig))
     870             :   {
     871           0 :     TALER_LOG_WARNING ("Invalid signature on /batch-deposit request\n");
     872           0 :     GNUNET_JSON_parse_free (spec);
     873             :     return (MHD_YES ==
     874           0 :             TALER_MHD_reply_with_error (
     875           0 :               bdc->rc->connection,
     876             :               MHD_HTTP_FORBIDDEN,
     877             :               TALER_EC_EXCHANGE_DEPOSIT_COIN_SIGNATURE_INVALID,
     878           0 :               TALER_B2S (&cdi->coin.coin_pub)))
     879             :       ? GNUNET_NO
     880           0 :       : GNUNET_SYSERR;
     881             :   }
     882         106 :   return GNUNET_OK;
     883             : }
     884             : 
     885             : 
     886             : /**
     887             :  * Run processing phase that parses the request.
     888             :  *
     889             :  * @param[in,out] bdc request context
     890             :  * @param root JSON object that was POSTed
     891             :  */
     892             : static void
     893         104 : bdc_phase_parse (struct BatchDepositContext *bdc,
     894             :                  const json_t *root)
     895             : {
     896         104 :   struct TALER_EXCHANGEDB_BatchDeposit *bd = &bdc->bd;
     897             :   const json_t *coins;
     898             :   const json_t *policy_json;
     899         104 :   bool no_refund_deadline = true;
     900             :   struct GNUNET_JSON_Specification spec[] = {
     901         104 :     TALER_JSON_spec_full_payto_uri ("merchant_payto_uri",
     902             :                                     &bd->receiver_wire_account),
     903         104 :     GNUNET_JSON_spec_fixed_auto ("wire_salt",
     904             :                                  &bd->wire_salt),
     905         104 :     GNUNET_JSON_spec_fixed_auto ("merchant_pub",
     906             :                                  &bd->merchant_pub),
     907         104 :     GNUNET_JSON_spec_fixed_auto ("merchant_sig",
     908             :                                  &bd->merchant_sig),
     909         104 :     GNUNET_JSON_spec_fixed_auto ("h_contract_terms",
     910             :                                  &bd->h_contract_terms),
     911         104 :     GNUNET_JSON_spec_mark_optional (
     912         104 :       GNUNET_JSON_spec_fixed_auto ("wallet_data_hash",
     913             :                                    &bd->wallet_data_hash),
     914             :       &bd->no_wallet_data_hash),
     915         104 :     GNUNET_JSON_spec_array_const ("coins",
     916             :                                   &coins),
     917         104 :     GNUNET_JSON_spec_mark_optional (
     918             :       GNUNET_JSON_spec_object_const ("policy",
     919             :                                      &policy_json),
     920             :       &bdc->has_no_policy),
     921         104 :     GNUNET_JSON_spec_timestamp ("timestamp",
     922             :                                 &bd->wallet_timestamp),
     923         104 :     GNUNET_JSON_spec_mark_optional (
     924             :       GNUNET_JSON_spec_timestamp ("refund_deadline",
     925             :                                   &bd->refund_deadline),
     926             :       &no_refund_deadline),
     927         104 :     GNUNET_JSON_spec_timestamp ("wire_transfer_deadline",
     928             :                                 &bd->wire_deadline),
     929         104 :     GNUNET_JSON_spec_end ()
     930             :   };
     931             : 
     932             :   {
     933             :     enum GNUNET_GenericReturnValue res;
     934             : 
     935         104 :     res = TALER_MHD_parse_json_data (bdc->rc->connection,
     936             :                                      root,
     937             :                                      spec);
     938         104 :     if (GNUNET_SYSERR == res)
     939             :     {
     940             :       /* hard failure */
     941           0 :       GNUNET_break (0);
     942           0 :       finish_loop (bdc,
     943             :                    MHD_NO);
     944           0 :       return;
     945             :     }
     946         104 :     if (GNUNET_NO == res)
     947             :     {
     948             :       /* failure */
     949           0 :       GNUNET_break_op (0);
     950           0 :       finish_loop (bdc,
     951             :                    MHD_YES);
     952           0 :       return;
     953             :     }
     954             :   }
     955         104 :   if (GNUNET_OK !=
     956         104 :       TALER_merchant_contract_verify (
     957         104 :         &bd->h_contract_terms,
     958         104 :         &bd->merchant_pub,
     959             :         &bd->merchant_sig))
     960             :   {
     961           0 :     GNUNET_break_op (0);
     962           0 :     GNUNET_JSON_parse_free (spec);
     963           0 :     finish_loop (bdc,
     964             :                  TALER_MHD_reply_with_error (
     965           0 :                    bdc->rc->connection,
     966             :                    MHD_HTTP_BAD_REQUEST,
     967             :                    TALER_EC_GENERIC_PARAMETER_MALFORMED,
     968             :                    "merchant_sig"));
     969           0 :     return;
     970             :   }
     971             :   bdc->policy_json
     972         104 :     = json_incref ((json_t *) policy_json);
     973         104 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     974             :               "Batch deposit into contract %s\n",
     975             :               GNUNET_h2s (&bd->h_contract_terms.hash));
     976             : 
     977             :   /* validate merchant's wire details (as far as we can) */
     978             :   {
     979             :     char *emsg;
     980             : 
     981         104 :     emsg = TALER_payto_validate (bd->receiver_wire_account);
     982         104 :     if (NULL != emsg)
     983             :     {
     984             :       MHD_RESULT ret;
     985             : 
     986           0 :       GNUNET_break_op (0);
     987           0 :       GNUNET_JSON_parse_free (spec);
     988           0 :       ret = TALER_MHD_reply_with_error (bdc->rc->connection,
     989             :                                         MHD_HTTP_BAD_REQUEST,
     990             :                                         TALER_EC_GENERIC_PARAMETER_MALFORMED,
     991             :                                         emsg);
     992           0 :       GNUNET_free (emsg);
     993           0 :       finish_loop (bdc,
     994             :                    ret);
     995           0 :       return;
     996             :     }
     997             :   }
     998         104 :   if (GNUNET_TIME_timestamp_cmp (bd->refund_deadline,
     999             :                                  >,
    1000             :                                  bd->wire_deadline))
    1001             :   {
    1002           0 :     GNUNET_break_op (0);
    1003           0 :     GNUNET_JSON_parse_free (spec);
    1004           0 :     finish_loop (bdc,
    1005             :                  TALER_MHD_reply_with_error (
    1006           0 :                    bdc->rc->connection,
    1007             :                    MHD_HTTP_BAD_REQUEST,
    1008             :                    TALER_EC_EXCHANGE_DEPOSIT_REFUND_DEADLINE_AFTER_WIRE_DEADLINE,
    1009             :                    NULL));
    1010           0 :     return;
    1011             :   }
    1012         104 :   if (GNUNET_TIME_absolute_is_never (bd->wire_deadline.abs_time))
    1013             :   {
    1014           0 :     GNUNET_break_op (0);
    1015           0 :     GNUNET_JSON_parse_free (spec);
    1016           0 :     finish_loop (bdc,
    1017             :                  TALER_MHD_reply_with_error (
    1018           0 :                    bdc->rc->connection,
    1019             :                    MHD_HTTP_BAD_REQUEST,
    1020             :                    TALER_EC_EXCHANGE_DEPOSIT_WIRE_DEADLINE_IS_NEVER,
    1021             :                    NULL));
    1022           0 :     return;
    1023             :   }
    1024         104 :   TALER_full_payto_hash (bd->receiver_wire_account,
    1025             :                          &bd->wire_target_h_payto);
    1026         104 :   TALER_merchant_wire_signature_hash (bd->receiver_wire_account,
    1027         104 :                                       &bd->wire_salt,
    1028             :                                       &bdc->h_wire);
    1029         104 :   bd->num_cdis = json_array_size (coins);
    1030         104 :   if (0 == bd->num_cdis)
    1031             :   {
    1032           0 :     GNUNET_break_op (0);
    1033           0 :     GNUNET_JSON_parse_free (spec);
    1034           0 :     finish_loop (bdc,
    1035             :                  TALER_MHD_reply_with_error (
    1036           0 :                    bdc->rc->connection,
    1037             :                    MHD_HTTP_BAD_REQUEST,
    1038             :                    TALER_EC_GENERIC_PARAMETER_MALFORMED,
    1039             :                    "coins"));
    1040           0 :     return;
    1041             :   }
    1042         104 :   if (TALER_MAX_COINS < bd->num_cdis)
    1043             :   {
    1044           0 :     GNUNET_break_op (0);
    1045           0 :     GNUNET_JSON_parse_free (spec);
    1046           0 :     finish_loop (bdc,
    1047             :                  TALER_MHD_reply_with_error (
    1048           0 :                    bdc->rc->connection,
    1049             :                    MHD_HTTP_BAD_REQUEST,
    1050             :                    TALER_EC_GENERIC_PARAMETER_MALFORMED,
    1051             :                    "coins"));
    1052           0 :     return;
    1053             :   }
    1054             : 
    1055             :   bdc->cdis
    1056         104 :     = GNUNET_new_array (bd->num_cdis,
    1057             :                         struct TALER_EXCHANGEDB_CoinDepositInformation);
    1058             :   bdc->deposit_fees
    1059         104 :     = GNUNET_new_array (bd->num_cdis,
    1060             :                         struct TALER_Amount);
    1061         104 :   bd->cdis = bdc->cdis;
    1062         210 :   for (unsigned i = 0; i<bd->num_cdis; i++)
    1063             :   {
    1064             :     struct TALER_Amount amount_without_fee;
    1065             :     enum GNUNET_GenericReturnValue res;
    1066             : 
    1067         106 :     res = parse_coin (bdc,
    1068             :                       json_array_get (coins,
    1069             :                                       i),
    1070         106 :                       &bdc->cdis[i],
    1071         106 :                       &bdc->deposit_fees[i]);
    1072         106 :     if (GNUNET_OK != res)
    1073             :     {
    1074           0 :       finish_loop (bdc,
    1075             :                    (GNUNET_NO == res)
    1076             :                    ? MHD_YES
    1077             :                    : MHD_NO);
    1078           0 :       return;
    1079             :     }
    1080         106 :     GNUNET_assert (0 <=
    1081             :                    TALER_amount_subtract (
    1082             :                      &amount_without_fee,
    1083             :                      &bdc->cdis[i].amount_with_fee,
    1084             :                      &bdc->deposit_fees[i]));
    1085             : 
    1086         106 :     GNUNET_assert (0 <=
    1087             :                    TALER_amount_add (
    1088             :                      &bdc->accumulated_total_without_fee,
    1089             :                      &bdc->accumulated_total_without_fee,
    1090             :                      &amount_without_fee));
    1091             :   }
    1092             : 
    1093         104 :   GNUNET_JSON_parse_free (spec);
    1094         104 :   bdc->phase++;
    1095             : }
    1096             : 
    1097             : 
    1098             : /**
    1099             :  * Function called to clean up a context.
    1100             :  *
    1101             :  * @param rc request context with data to clean up
    1102             :  */
    1103             : static void
    1104         104 : bdc_cleaner (struct TEH_RequestContext *rc)
    1105             : {
    1106         104 :   struct BatchDepositContext *bdc = rc->rh_ctx;
    1107             : 
    1108         104 :   if (NULL != bdc->lch)
    1109             :   {
    1110           0 :     TEH_legitimization_check_cancel (bdc->lch);
    1111           0 :     bdc->lch = NULL;
    1112             :   }
    1113         210 :   for (unsigned int i = 0; i<bdc->bd.num_cdis; i++)
    1114         106 :     TALER_denom_sig_free (&bdc->cdis[i].coin.denom_sig);
    1115         104 :   GNUNET_free (bdc->cdis);
    1116         104 :   GNUNET_free (bdc->deposit_fees);
    1117         104 :   json_decref (bdc->policy_json);
    1118         104 :   GNUNET_free (bdc);
    1119         104 : }
    1120             : 
    1121             : 
    1122             : MHD_RESULT
    1123         170 : TEH_handler_batch_deposit (struct TEH_RequestContext *rc,
    1124             :                            const json_t *root,
    1125             :                            const char *const args[])
    1126             : {
    1127         170 :   struct BatchDepositContext *bdc = rc->rh_ctx;
    1128             : 
    1129             :   (void) args;
    1130         170 :   if (NULL == bdc)
    1131             :   {
    1132         104 :     bdc = GNUNET_new (struct BatchDepositContext);
    1133         104 :     bdc->rc = rc;
    1134         104 :     rc->rh_ctx = bdc;
    1135         104 :     rc->rh_cleaner = &bdc_cleaner;
    1136         104 :     bdc->phase = BDC_PHASE_PARSE;
    1137         104 :     bdc->exchange_timestamp = GNUNET_TIME_timestamp_get ();
    1138         104 :     GNUNET_assert (GNUNET_OK ==
    1139             :                    TALER_amount_set_zero (TEH_currency,
    1140             :                                           &bdc->accumulated_total_without_fee));
    1141             :   }
    1142             :   while (1)
    1143             :   {
    1144         737 :     switch (bdc->phase)
    1145             :     {
    1146           0 :     case BDC_PHASE_INIT:
    1147           0 :       GNUNET_break (0);
    1148           0 :       bdc->phase = BDC_PHASE_RETURN_NO;
    1149           0 :       break;
    1150         104 :     case BDC_PHASE_PARSE:
    1151         104 :       bdc_phase_parse (bdc,
    1152             :                        root);
    1153         104 :       break;
    1154         104 :     case BDC_PHASE_POLICY:
    1155         104 :       bdc_phase_policy (bdc);
    1156         104 :       break;
    1157         104 :     case BDC_PHASE_KYC:
    1158         104 :       bdc_phase_kyc (bdc);
    1159         104 :       break;
    1160          99 :     case BDC_PHASE_TRANSACT:
    1161          99 :       bdc_phase_transact (bdc);
    1162          99 :       break;
    1163          90 :     case BDC_PHASE_REPLY_SUCCESS:
    1164          90 :       bdc_phase_reply_success (bdc);
    1165          90 :       break;
    1166          66 :     case BDC_PHASE_SUSPENDED:
    1167          66 :       return MHD_YES;
    1168          66 :     case BDC_PHASE_CHECK_KYC_RESULT:
    1169          66 :       bdc_phase_check_kyc_result (bdc);
    1170          66 :       break;
    1171           0 :     case BDC_PHASE_GENERATE_REPLY_FAILURE:
    1172           0 :       return MHD_queue_response (bdc->rc->connection,
    1173             :                                  bdc->http_status,
    1174             :                                  bdc->response);
    1175         104 :     case BDC_PHASE_RETURN_YES:
    1176         104 :       return MHD_YES;
    1177           0 :     case BDC_PHASE_RETURN_NO:
    1178           0 :       return MHD_NO;
    1179             :     }
    1180             :   }
    1181             : }
    1182             : 
    1183             : 
    1184             : /* end of taler-exchange-httpd_batch-deposit.c */

Generated by: LCOV version 1.16