LCOV - code coverage report
Current view: top level - backend - taler-merchant-httpd_post-orders-ID-pay.c (source / functions) Hit Total Coverage
Test: GNU Taler merchant coverage report Lines: 4 772 0.5 %
Date: 2022-06-30 06:15:34 Functions: 1 26 3.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    This file is part of TALER
       3             :    (C) 2014-2022 Taler Systems SA
       4             : 
       5             :    TALER is free software; you can redistribute it and/or modify
       6             :    it under the terms of the GNU Affero General Public License as
       7             :    published by the Free Software Foundation; either version 3,
       8             :    or (at your 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             : /**
      21             :  * @file taler-merchant-httpd_post-orders-ID-pay.c
      22             :  * @brief handling of POST /orders/$ID/pay requests
      23             :  * @author Marcello Stanisci
      24             :  * @author Christian Grothoff
      25             :  * @author Florian Dold
      26             :  */
      27             : #include "platform.h"
      28             : #include <taler/taler_dbevents.h>
      29             : #include <taler/taler_signatures.h>
      30             : #include <taler/taler_json_lib.h>
      31             : #include <taler/taler_exchange_service.h>
      32             : #include "taler-merchant-httpd_auditors.h"
      33             : #include "taler-merchant-httpd_exchanges.h"
      34             : #include "taler-merchant-httpd_helper.h"
      35             : #include "taler-merchant-httpd_post-orders-ID-pay.h"
      36             : #include "taler-merchant-httpd_private-get-orders.h"
      37             : 
      38             : 
      39             : /**
      40             :  * How often do we retry the (complex!) database transaction?
      41             :  */
      42             : #define MAX_RETRIES 5
      43             : 
      44             : /**
      45             :  * Maximum number of coins that we allow per transaction
      46             :  */
      47             : #define MAX_COIN_ALLOWED_COINS 1024
      48             : 
      49             : /**
      50             :  * How often do we ask the exchange again about our
      51             :  * KYC status? Very rarely, as if the user actively
      52             :  * changes it, we should usually notice anyway.
      53             :  */
      54             : #define KYC_RETRY_FREQUENCY GNUNET_TIME_UNIT_WEEKS
      55             : 
      56             : /**
      57             :  * Information we keep for an individual call to the pay handler.
      58             :  */
      59             : struct PayContext;
      60             : 
      61             : /**
      62             :  * Information kept during a pay request for each coin.
      63             :  */
      64             : struct DepositConfirmation
      65             : {
      66             : 
      67             :   /**
      68             :    * Reference to the main PayContext
      69             :    */
      70             :   struct PayContext *pc;
      71             : 
      72             :   /**
      73             :    * Handle to the deposit operation we are performing for
      74             :    * this coin, NULL after the operation is done.
      75             :    */
      76             :   struct TALER_EXCHANGE_DepositHandle *dh;
      77             : 
      78             :   /**
      79             :    * URL of the exchange that issued this coin.
      80             :    */
      81             :   char *exchange_url;
      82             : 
      83             :   /**
      84             :    * Hash of the denomination of this coin.
      85             :    */
      86             :   struct TALER_DenominationHashP h_denom;
      87             : 
      88             :   /**
      89             :    * Amount this coin contributes to the total purchase price.
      90             :    * This amount includes the deposit fee.
      91             :    */
      92             :   struct TALER_Amount amount_with_fee;
      93             : 
      94             :   /**
      95             :    * Fee charged by the exchange for the deposit operation of this coin.
      96             :    */
      97             :   struct TALER_Amount deposit_fee;
      98             : 
      99             :   /**
     100             :    * Fee charged by the exchange for the refund operation of this coin.
     101             :    */
     102             :   struct TALER_Amount refund_fee;
     103             : 
     104             :   /**
     105             :    * Wire fee charged by the exchange of this coin.
     106             :    */
     107             :   struct TALER_Amount wire_fee;
     108             : 
     109             :   /**
     110             :    * Public key of the coin.
     111             :    */
     112             :   struct TALER_CoinSpendPublicKeyP coin_pub;
     113             : 
     114             :   /**
     115             :    * Signature using the @e denom key over the @e coin_pub.
     116             :    */
     117             :   struct TALER_DenominationSignature ub_sig;
     118             : 
     119             :   /**
     120             :    * Signature of the coin's private key over the contract.
     121             :    */
     122             :   struct TALER_CoinSpendSignatureP coin_sig;
     123             : 
     124             :   /**
     125             :    * If a minimum age was required (i. e. pc->minimum_age is large enough),
     126             :    * this is the signature of the minimum age (as a single uint8_t), using the
     127             :    * private key to the corresponding age group.  Might be all zeroes for no
     128             :    * age attestation.
     129             :    */
     130             :   struct TALER_AgeAttestation minimum_age_sig;
     131             : 
     132             :   /* true, if no field "minimum_age_sig" was found in the JSON blob */
     133             :   bool no_minimum_age_sig;
     134             : 
     135             :   /**
     136             :    * If a minimum age was required (i. e. pc->minimum_age is large enough),
     137             :    * this is the age commitment (i. e. age mask and vector of EdDSA public
     138             :    * keys, one per age group) that went into the mining of the coin.  The
     139             :    * SHA256 hash of the mask and the vector of public keys was bound to the
     140             :    * key.
     141             :    */
     142             :   struct TALER_AgeCommitment age_commitment;
     143             : 
     144             :   /* true, if no field "age_commitment" was found in the JSON blob */
     145             :   bool no_age_commitment;
     146             : 
     147             :   /**
     148             :    * In the case that somebody pays with a coin that is age restricted, but the
     149             :    * the contract did not ask for a minimum age, the merchant still needs the
     150             :    * hash of the age commitment in order to a) verify the coin and b) deposit
     151             :    * it.
     152             :    */
     153             :   struct TALER_AgeCommitmentHash h_age_commitment;
     154             : 
     155             :   /* true, if no field "h_age_commitment" was found in the JSON blob */
     156             :   bool no_h_age_commitment;
     157             : 
     158             :   /**
     159             :    * Age mask in the denomination that defines the age groups.  Only
     160             :    * applicable, if minimum age was required.
     161             :    */
     162             :   struct TALER_AgeMask age_mask;
     163             : 
     164             :   /**
     165             :    * Offset of this coin into the `dc` array of all coins in the
     166             :    * @e pc.
     167             :    */
     168             :   unsigned int index;
     169             : 
     170             :   /**
     171             :    * true if we found this coin in the database.
     172             :    */
     173             :   bool found_in_db;
     174             : 
     175             :   /**
     176             :    * true if we #deposit_paid_check() matched this coin in the database.
     177             :    */
     178             :   bool matched_in_db;
     179             : 
     180             : };
     181             : 
     182             : 
     183             : /**
     184             :  * Information we keep for an individual call to the /pay handler.
     185             :  */
     186             : struct PayContext
     187             : {
     188             : 
     189             :   /**
     190             :    * Stored in a DLL.
     191             :    */
     192             :   struct PayContext *next;
     193             : 
     194             :   /**
     195             :    * Stored in a DLL.
     196             :    */
     197             :   struct PayContext *prev;
     198             : 
     199             :   /**
     200             :    * Array with @e coins_cnt coins we are despositing.
     201             :    */
     202             :   struct DepositConfirmation *dc;
     203             : 
     204             :   /**
     205             :    * MHD connection to return to
     206             :    */
     207             :   struct MHD_Connection *connection;
     208             : 
     209             :   /**
     210             :    * Details about the client's request.
     211             :    */
     212             :   struct TMH_HandlerContext *hc;
     213             : 
     214             :   /**
     215             :    * What wire method (of the @e mi) was selected by the wallet?
     216             :    * Set in #parse_pay().
     217             :    */
     218             :   struct TMH_WireMethod *wm;
     219             : 
     220             :   /**
     221             :    * Task called when the (suspended) processing for
     222             :    * the /pay request times out.
     223             :    * Happens when we don't get a response from the exchange.
     224             :    */
     225             :   struct GNUNET_SCHEDULER_Task *timeout_task;
     226             : 
     227             :   /**
     228             :    * Response to return, NULL if we don't have one yet.
     229             :    */
     230             :   struct MHD_Response *response;
     231             : 
     232             :   /**
     233             :    * Handle for operation to lookup /keys (and auditors) from
     234             :    * the exchange used for this transaction; NULL if no operation is
     235             :    * pending.
     236             :    */
     237             :   struct TMH_EXCHANGES_FindOperation *fo;
     238             : 
     239             :   /**
     240             :    * URL of the exchange used for the last @e fo.
     241             :    */
     242             :   const char *current_exchange;
     243             : 
     244             :   /**
     245             :    * Placeholder for #TALER_MHD_parse_post_json() to keep its internal state.
     246             :    */
     247             :   void *json_parse_context;
     248             : 
     249             :   /**
     250             :    * Optional session id given in @e root.
     251             :    * NULL if not given.
     252             :    */
     253             :   char *session_id;
     254             : 
     255             :   /**
     256             :    * Transaction ID given in @e root.
     257             :    */
     258             :   const char *order_id;
     259             : 
     260             :   /**
     261             :    * Fulfillment URL from the contract, or NULL if we don't have one.
     262             :    */
     263             :   char *fulfillment_url;
     264             : 
     265             :   /**
     266             :    * Serial number of this order in the database (set once we did the lookup).
     267             :    */
     268             :   uint64_t order_serial;
     269             : 
     270             :   /**
     271             :    * Hashed proposal.
     272             :    */
     273             :   struct TALER_PrivateContractHashP h_contract_terms;
     274             : 
     275             :   /**
     276             :    * "h_wire" from @e contract_terms.  Used to identify
     277             :    * the instance's wire transfer method.
     278             :    */
     279             :   struct TALER_MerchantWireHashP h_wire;
     280             : 
     281             :   /**
     282             :    * Maximum fee the merchant is willing to pay, from @e root.
     283             :    * Note that IF the total fee of the exchange is higher, that is
     284             :    * acceptable to the merchant if the customer is willing to
     285             :    * pay the difference
     286             :    * (i.e. amount - max_fee <= actual-amount - actual-fee).
     287             :    */
     288             :   struct TALER_Amount max_fee;
     289             : 
     290             :   /**
     291             :    * Maximum wire fee the merchant is willing to pay, from @e root.
     292             :    * Note that IF the total fee of the exchange is higher, that is
     293             :    * acceptable to the merchant if the customer is willing to
     294             :    * pay the amorized difference.  Wire fees are charged over an
     295             :    * aggregate of several translations, hence unlike the deposit
     296             :    * fees, they are amortized over several customer's transactions.
     297             :    * The contract specifies under @e wire_fee_amortization how many
     298             :    * customer's transactions he expects the wire fees to be amortized
     299             :    * over on average.  Thus, if the wire fees are larger than
     300             :    * @e max_wire_fee, each customer is expected to contribute
     301             :    * $\frac{actual-wire-fee - max_wire_fee}{wire_fee_amortization}$.
     302             :    * The customer's contribution may be further reduced by the
     303             :    * difference between @e max_fee and the sum of the deposit fees.
     304             :    *
     305             :    * Default is that the merchant is unwilling to pay any wire fees.
     306             :    */
     307             :   struct TALER_Amount max_wire_fee;
     308             : 
     309             :   /**
     310             :    * Minimum age required for this purchase.
     311             :    */
     312             :   unsigned int minimum_age;
     313             : 
     314             :   /**
     315             :    * Amount from @e root.  This is the amount the merchant expects
     316             :    * to make, minus @e max_fee.
     317             :    */
     318             :   struct TALER_Amount amount;
     319             : 
     320             :   /**
     321             :    * Considering all the coins with the "found_in_db" flag
     322             :    * set, what is the total amount we were so far paid on
     323             :    * this contract?
     324             :    */
     325             :   struct TALER_Amount total_paid;
     326             : 
     327             :   /**
     328             :    * Considering all the coins with the "found_in_db" flag
     329             :    * set, what is the total amount we had to pay in deposit
     330             :    * fees so far on this contract?
     331             :    */
     332             :   struct TALER_Amount total_fees_paid;
     333             : 
     334             :   /**
     335             :    * Considering all the coins with the "found_in_db" flag
     336             :    * set, what is the total amount we already refunded?
     337             :    */
     338             :   struct TALER_Amount total_refunded;
     339             : 
     340             :   /**
     341             :    * Wire transfer deadline. How soon would the merchant like the
     342             :    * wire transfer to be executed?
     343             :    */
     344             :   struct GNUNET_TIME_Timestamp wire_transfer_deadline;
     345             : 
     346             :   /**
     347             :    * Timestamp from @e contract_terms.
     348             :    */
     349             :   struct GNUNET_TIME_Timestamp timestamp;
     350             : 
     351             :   /**
     352             :    * Refund deadline from @e contract_terms.
     353             :    */
     354             :   struct GNUNET_TIME_Timestamp refund_deadline;
     355             : 
     356             :   /**
     357             :    * Deadline for the customer to pay for this proposal.
     358             :    */
     359             :   struct GNUNET_TIME_Timestamp pay_deadline;
     360             : 
     361             :   /**
     362             :    * Number of transactions that the wire fees are expected to be
     363             :    * amortized over.  Never zero, defaults (conservateively) to 1.
     364             :    * May be higher if merchants expect many small transactions to
     365             :    * be aggregated and thus wire fees to be reasonably amortized
     366             :    * due to aggregation.
     367             :    */
     368             :   uint32_t wire_fee_amortization;
     369             : 
     370             :   /**
     371             :    * Number of coins this payment is made of.  Length
     372             :    * of the @e dc array.
     373             :    */
     374             :   unsigned int coins_cnt;
     375             : 
     376             :   /**
     377             :    * How often have we retried the 'main' transaction?
     378             :    */
     379             :   unsigned int retry_counter;
     380             : 
     381             :   /**
     382             :    * Number of transactions still pending.  Initially set to
     383             :    * @e coins_cnt, decremented on each transaction that
     384             :    * successfully finished.
     385             :    */
     386             :   unsigned int pending;
     387             : 
     388             :   /**
     389             :    * Number of transactions still pending for the currently selected
     390             :    * exchange.  Initially set to the number of coins started at the
     391             :    * exchange, decremented on each transaction that successfully
     392             :    * finished.  Once it hits zero, we pick the next exchange.
     393             :    */
     394             :   unsigned int pending_at_ce;
     395             : 
     396             :   /**
     397             :    * HTTP status code to use for the reply, i.e 200 for "OK".
     398             :    * Special value UINT_MAX is used to indicate hard errors
     399             :    * (no reply, return #MHD_NO).
     400             :    */
     401             :   unsigned int response_code;
     402             : 
     403             :   /**
     404             :    * #GNUNET_NO if the @e connection was not suspended,
     405             :    * #GNUNET_YES if the @e connection was suspended,
     406             :    * #GNUNET_SYSERR if @e connection was resumed to as
     407             :    * part of #MH_force_pc_resume during shutdown.
     408             :    */
     409             :   enum GNUNET_GenericReturnValue suspended;
     410             : 
     411             :   /**
     412             :    * true if we already tried a forced /keys download.
     413             :    */
     414             :   bool tried_force_keys;
     415             : 
     416             : };
     417             : 
     418             : 
     419             : /**
     420             :  * Active KYC operation with an exchange.
     421             :  */
     422             : struct KycContext
     423             : {
     424             :   /**
     425             :    * Kept in a DLL.
     426             :    */
     427             :   struct KycContext *next;
     428             : 
     429             :   /**
     430             :    * Kept in a DLL.
     431             :    */
     432             :   struct KycContext *prev;
     433             : 
     434             :   /**
     435             :    * Looking for the exchange.
     436             :    */
     437             :   struct TMH_EXCHANGES_FindOperation *fo;
     438             : 
     439             :   /**
     440             :    * Exchange this is about.
     441             :    */
     442             :   char *exchange_url;
     443             : 
     444             :   /**
     445             :    * Merchant instance this is for.
     446             :    */
     447             :   struct TMH_MerchantInstance *mi;
     448             : 
     449             :   /**
     450             :    * Wire method we are checking the status of.
     451             :    */
     452             :   struct TMH_WireMethod *wm;
     453             : 
     454             :   /**
     455             :    * Handle for the GET /deposits operation.
     456             :    */
     457             :   struct TALER_EXCHANGE_DepositGetHandle *dg;
     458             : 
     459             :   /**
     460             :    * Contract we are looking up.
     461             :    */
     462             :   struct TALER_PrivateContractHashP h_contract_terms;
     463             : 
     464             :   /**
     465             :    * Coin we are looking up.
     466             :    */
     467             :   struct TALER_CoinSpendPublicKeyP coin_pub;
     468             : 
     469             :   /**
     470             :    * Initial DB timestamp.
     471             :    */
     472             :   struct GNUNET_TIME_Timestamp kyc_timestamp;
     473             : 
     474             :   /**
     475             :    * Initial KYC status.
     476             :    */
     477             :   bool kyc_ok;
     478             : 
     479             : };
     480             : 
     481             : 
     482             : /**
     483             :  * Head of active pay context DLL.
     484             :  */
     485             : static struct PayContext *pc_head;
     486             : 
     487             : /**
     488             :  * Tail of active pay context DLL.
     489             :  */
     490             : static struct PayContext *pc_tail;
     491             : 
     492             : /**
     493             :  * Head of active KYC context DLL.
     494             :  */
     495             : static struct KycContext *kc_head;
     496             : 
     497             : /**
     498             :  * Tail of active KYC context DLL.
     499             :  */
     500             : static struct KycContext *kc_tail;
     501             : 
     502             : 
     503             : /**
     504             :  * Free resources used by @a kc.
     505             :  *
     506             :  * @param[in] kc object to free
     507             :  */
     508             : static void
     509           0 : destroy_kc (struct KycContext *kc)
     510             : {
     511           0 :   if (NULL != kc->fo)
     512             :   {
     513           0 :     TMH_EXCHANGES_find_exchange_cancel (kc->fo);
     514           0 :     kc->fo = NULL;
     515             :   }
     516           0 :   if (NULL != kc->dg)
     517             :   {
     518           0 :     TALER_EXCHANGE_deposits_get_cancel (kc->dg);
     519           0 :     kc->dg = NULL;
     520             :   }
     521           0 :   TMH_instance_decref (kc->mi);
     522           0 :   kc->mi = NULL;
     523           0 :   GNUNET_free (kc->exchange_url);
     524           0 :   GNUNET_CONTAINER_DLL_remove (kc_head,
     525             :                                kc_tail,
     526             :                                kc);
     527           0 :   GNUNET_free (kc);
     528           0 : }
     529             : 
     530             : 
     531             : /**
     532             :  * Compute the timeout for a /pay request based on the number of coins
     533             :  * involved.
     534             :  *
     535             :  * @param num_coins number of coins
     536             :  * @returns timeout for the /pay request
     537             :  */
     538             : static struct GNUNET_TIME_Relative
     539           0 : get_pay_timeout (unsigned int num_coins)
     540             : {
     541             :   struct GNUNET_TIME_Relative t;
     542             : 
     543             :   /* FIXME:  Do some benchmarking to come up with a better timeout.
     544             :    * We've increased this value so the wallet integration test passes again
     545             :    * on my (Florian) machine.
     546             :    */
     547           0 :   t = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
     548           0 :                                      15 * (1 + (num_coins / 5)));
     549             : 
     550           0 :   return t;
     551             : }
     552             : 
     553             : 
     554             : /**
     555             :  * Abort all pending /deposit operations.
     556             :  *
     557             :  * @param pc pay context to abort
     558             :  */
     559             : static void
     560           0 : abort_active_deposits (struct PayContext *pc)
     561             : {
     562           0 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     563             :               "Aborting pending /deposit operations\n");
     564           0 :   for (unsigned int i = 0; i<pc->coins_cnt; i++)
     565             :   {
     566           0 :     struct DepositConfirmation *dci = &pc->dc[i];
     567             : 
     568           0 :     if (NULL != dci->dh)
     569             :     {
     570           0 :       TALER_EXCHANGE_deposit_cancel (dci->dh);
     571           0 :       dci->dh = NULL;
     572             :     }
     573             :   }
     574           0 : }
     575             : 
     576             : 
     577             : void
     578           3 : TMH_force_pc_resume ()
     579             : {
     580             :   struct KycContext *kc;
     581             : 
     582           3 :   while (NULL != (kc = kc_head))
     583             :   {
     584           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     585             :                 "Aborting KYC check at %s\n",
     586             :                 kc->exchange_url);
     587           0 :     destroy_kc (kc);
     588             :   }
     589           3 :   for (struct PayContext *pc = pc_head;
     590             :        NULL != pc;
     591           0 :        pc = pc->next)
     592             :   {
     593           0 :     abort_active_deposits (pc);
     594           0 :     if (NULL != pc->timeout_task)
     595             :     {
     596           0 :       GNUNET_SCHEDULER_cancel (pc->timeout_task);
     597           0 :       pc->timeout_task = NULL;
     598             :     }
     599           0 :     if (GNUNET_YES == pc->suspended)
     600             :     {
     601           0 :       pc->suspended = GNUNET_SYSERR;
     602           0 :       MHD_resume_connection (pc->connection);
     603             :     }
     604             :   }
     605           3 : }
     606             : 
     607             : 
     608             : /**
     609             :  * Resume the given pay context and send the given response.
     610             :  * Stores the response in the @a pc and signals MHD to resume
     611             :  * the connection.  Also ensures MHD runs immediately.
     612             :  *
     613             :  * @param pc payment context
     614             :  * @param response_code response code to use
     615             :  * @param response response data to send back
     616             :  */
     617             : static void
     618           0 : resume_pay_with_response (struct PayContext *pc,
     619             :                           unsigned int response_code,
     620             :                           struct MHD_Response *response)
     621             : {
     622           0 :   abort_active_deposits (pc);
     623           0 :   pc->response_code = response_code;
     624           0 :   pc->response = response;
     625           0 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     626             :               "Resuming /pay handling. HTTP status for our reply is %u.\n",
     627             :               response_code);
     628           0 :   if (NULL != pc->timeout_task)
     629             :   {
     630           0 :     GNUNET_SCHEDULER_cancel (pc->timeout_task);
     631           0 :     pc->timeout_task = NULL;
     632             :   }
     633           0 :   GNUNET_assert (GNUNET_YES == pc->suspended);
     634           0 :   pc->suspended = GNUNET_NO;
     635           0 :   MHD_resume_connection (pc->connection);
     636           0 :   TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */
     637           0 : }
     638             : 
     639             : 
     640             : /**
     641             :  * Resume payment processing with an error.
     642             :  *
     643             :  * @param pc operation to resume
     644             :  * @param http_status http status code to return
     645             :  * @param ec taler error code to return
     646             :  * @param msg human readable error message
     647             :  */
     648             : static void
     649           0 : resume_pay_with_error (struct PayContext *pc,
     650             :                        unsigned int http_status,
     651             :                        enum TALER_ErrorCode ec,
     652             :                        const char *msg)
     653             : {
     654           0 :   resume_pay_with_response (pc,
     655             :                             http_status,
     656             :                             TALER_MHD_make_error (ec,
     657             :                                                   msg));
     658           0 : }
     659             : 
     660             : 
     661             : /**
     662             :  * Custom cleanup routine for a `struct PayContext`.
     663             :  *
     664             :  * @param cls the `struct PayContext` to clean up.
     665             :  */
     666             : static void
     667           0 : pay_context_cleanup (void *cls)
     668             : {
     669           0 :   struct PayContext *pc = cls;
     670             : 
     671           0 :   if (NULL != pc->timeout_task)
     672             :   {
     673           0 :     GNUNET_SCHEDULER_cancel (pc->timeout_task);
     674           0 :     pc->timeout_task = NULL;
     675             :   }
     676           0 :   abort_active_deposits (pc);
     677           0 :   for (unsigned int i = 0; i<pc->coins_cnt; i++)
     678             :   {
     679           0 :     struct DepositConfirmation *dc = &pc->dc[i];
     680             : 
     681           0 :     TALER_denom_sig_free (&dc->ub_sig);
     682           0 :     GNUNET_free (dc->exchange_url);
     683             :   }
     684           0 :   GNUNET_free (pc->dc);
     685           0 :   if (NULL != pc->fo)
     686             :   {
     687           0 :     TMH_EXCHANGES_find_exchange_cancel (pc->fo);
     688           0 :     pc->fo = NULL;
     689             :   }
     690           0 :   if (NULL != pc->response)
     691             :   {
     692           0 :     MHD_destroy_response (pc->response);
     693           0 :     pc->response = NULL;
     694             :   }
     695           0 :   GNUNET_free (pc->fulfillment_url);
     696           0 :   GNUNET_free (pc->session_id);
     697           0 :   GNUNET_CONTAINER_DLL_remove (pc_head,
     698             :                                pc_tail,
     699             :                                pc);
     700           0 :   GNUNET_free (pc);
     701           0 : }
     702             : 
     703             : 
     704             : /**
     705             :  * Find the exchange we need to talk to for the next
     706             :  * pending deposit permission.
     707             :  *
     708             :  * @param pc payment context we are processing
     709             :  */
     710             : static void
     711             : find_next_exchange (struct PayContext *pc);
     712             : 
     713             : 
     714             : /**
     715             :  * Execute the DB transaction.  If required (from
     716             :  * soft/serialization errors), the transaction can be
     717             :  * restarted here.
     718             :  *
     719             :  * @param pc payment context to transact
     720             :  */
     721             : static void
     722             : execute_pay_transaction (struct PayContext *pc);
     723             : 
     724             : 
     725             : /**
     726             :  * Function called with detailed wire transfer data.
     727             :  *
     728             :  * @param cls a `struct KycContext *`
     729             :  * @param dr HTTP response data
     730             :  */
     731             : static void
     732           0 : deposit_get_callback (
     733             :   void *cls,
     734             :   const struct TALER_EXCHANGE_GetDepositResponse *dr)
     735             : {
     736           0 :   struct KycContext *kc = cls;
     737             :   enum GNUNET_DB_QueryStatus qs;
     738             :   struct GNUNET_TIME_Timestamp now;
     739             : 
     740           0 :   kc->dg = NULL;
     741           0 :   now = GNUNET_TIME_timestamp_get ();
     742           0 :   switch (dr->hr.http_status)
     743             :   {
     744           0 :   case MHD_HTTP_OK:
     745           0 :     qs = TMH_db->account_kyc_set_status (
     746           0 :       TMH_db->cls,
     747           0 :       kc->mi->settings.id,
     748           0 :       &kc->wm->h_wire,
     749           0 :       kc->exchange_url,
     750             :       dr->details.success.payment_target_uuid,
     751             :       NULL, /* no signature */
     752             :       NULL, /* no signature */
     753             :       now,
     754             :       true);
     755           0 :     GNUNET_break (qs > 0);
     756           0 :     break;
     757           0 :   case MHD_HTTP_ACCEPTED:
     758           0 :     qs = TMH_db->account_kyc_set_status (
     759           0 :       TMH_db->cls,
     760           0 :       kc->mi->settings.id,
     761           0 :       &kc->wm->h_wire,
     762           0 :       kc->exchange_url,
     763             :       dr->details.accepted.payment_target_uuid,
     764             :       NULL, /* no signature */
     765             :       NULL, /* no signature */
     766             :       now,
     767           0 :       dr->details.accepted.kyc_ok);
     768           0 :     GNUNET_break (qs > 0);
     769           0 :     break;
     770           0 :   default:
     771           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     772             :                 "KYC check failed at %s with unexpected status %u\n",
     773             :                 kc->exchange_url,
     774             :                 dr->hr.http_status);
     775             :   }
     776           0 :   destroy_kc (kc);
     777           0 : }
     778             : 
     779             : 
     780             : /**
     781             :  * Function called with the result of our exchange lookup.
     782             :  *
     783             :  * @param cls the `struct KycContext`
     784             :  * @param hr HTTP response details
     785             :  * @param exchange_handle NULL if exchange was not found to be acceptable
     786             :  * @param payto_uri payto://-URI of the exchange
     787             :  * @param wire_fee current applicable fee for dealing with @a exchange_handle,
     788             :  *        NULL if not available
     789             :  * @param exchange_trusted true if this exchange is
     790             :  *        trusted by config
     791             :  */
     792             : static void
     793           0 : process_kyc_with_exchange (
     794             :   void *cls,
     795             :   const struct TALER_EXCHANGE_HttpResponse *hr,
     796             :   struct TALER_EXCHANGE_Handle *exchange_handle,
     797             :   const char *payto_uri,
     798             :   const struct TALER_Amount *wire_fee,
     799             :   bool exchange_trusted)
     800             : {
     801           0 :   struct KycContext *kc = cls;
     802             : 
     803           0 :   kc->fo = NULL;
     804           0 :   if (NULL == exchange_handle)
     805             :   {
     806           0 :     destroy_kc (kc);
     807           0 :     return;
     808             :   }
     809           0 :   kc->dg = TALER_EXCHANGE_deposits_get (exchange_handle,
     810           0 :                                         &kc->mi->merchant_priv,
     811           0 :                                         &kc->wm->h_wire,
     812           0 :                                         &kc->h_contract_terms,
     813           0 :                                         &kc->coin_pub,
     814             :                                         &deposit_get_callback,
     815             :                                         kc);
     816           0 :   if (NULL == kc->dg)
     817             :   {
     818           0 :     GNUNET_break (0);
     819           0 :     destroy_kc (kc);
     820             :   }
     821             : }
     822             : 
     823             : 
     824             : /**
     825             :  * Function called from ``account_kyc_get_status``
     826             :  * with KYC status information for this merchant.
     827             :  *
     828             :  * @param cls a `struct KycContext *`
     829             :  * @param h_wire hash of the wire account
     830             :  * @param exchange_kyc_serial serial number for the KYC process at the exchange, 0 if unknown
     831             :  * @param payto_uri payto:// URI of the merchant's bank account
     832             :  * @param exchange_url base URL of the exchange for which this is a status
     833             :  * @param last_check when did we last get an update on our KYC status from the exchange
     834             :  * @param kyc_ok true if we satisfied the KYC requirements
     835             :  */
     836             : static void
     837           0 : kyc_cb (
     838             :   void *cls,
     839             :   const struct TALER_MerchantWireHashP *h_wire,
     840             :   uint64_t exchange_kyc_serial,
     841             :   const char *payto_uri,
     842             :   const char *exchange_url,
     843             :   struct GNUNET_TIME_Timestamp last_check,
     844             :   bool kyc_ok)
     845             : {
     846           0 :   struct KycContext *kc = cls;
     847             : 
     848           0 :   kc->kyc_timestamp = last_check;
     849           0 :   kc->kyc_ok = kyc_ok;
     850           0 : }
     851             : 
     852             : 
     853             : /**
     854             :  * Check for our KYC status at @a exchange_url for the
     855             :  * payment of @a pc. First checks if we already have a
     856             :  * positive result from the exchange, and if not checks
     857             :  * with the exchange.
     858             :  *
     859             :  * @param pc payment context to use as starting point
     860             :  * @param dc deposit confirmation we are triggering on
     861             :  */
     862             : static void
     863           0 : check_kyc (struct PayContext *pc,
     864             :            const struct DepositConfirmation *dc)
     865             : {
     866             :   enum GNUNET_DB_QueryStatus qs;
     867             :   struct KycContext *kc;
     868             : 
     869           0 :   kc = GNUNET_new (struct KycContext);
     870           0 :   qs = TMH_db->account_kyc_get_status (TMH_db->cls,
     871           0 :                                        pc->hc->instance->settings.id,
     872           0 :                                        &pc->wm->h_wire,
     873           0 :                                        dc->exchange_url,
     874             :                                        &kyc_cb,
     875             :                                        kc);
     876           0 :   if (qs < 0)
     877             :   {
     878           0 :     GNUNET_break (0);
     879           0 :     GNUNET_free (kc);
     880           0 :     return;
     881             :   }
     882           0 :   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
     883             :   {
     884           0 :     if (kc->kyc_ok)
     885             :     {
     886           0 :       GNUNET_free (kc);
     887           0 :       return; /* we are done */
     888             :     }
     889           0 :     if (GNUNET_TIME_relative_cmp (
     890             :           GNUNET_TIME_absolute_get_duration (
     891             :             kc->kyc_timestamp.abs_time),
     892             :           <,
     893             :           KYC_RETRY_FREQUENCY))
     894             :     {
     895           0 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     896             :                   "Not re-checking KYC status at `%s', as we already recently asked\n",
     897             :                   dc->exchange_url);
     898           0 :       GNUNET_free (kc);
     899           0 :       return;
     900             :     }
     901             :   }
     902           0 :   kc->mi = pc->hc->instance;
     903           0 :   kc->mi->rc++;
     904           0 :   kc->wm = pc->wm;
     905           0 :   kc->exchange_url = GNUNET_strdup (dc->exchange_url);
     906           0 :   kc->h_contract_terms = pc->h_contract_terms;
     907           0 :   kc->coin_pub = dc->coin_pub;
     908           0 :   GNUNET_CONTAINER_DLL_insert (kc_head,
     909             :                                kc_tail,
     910             :                                kc);
     911           0 :   kc->fo = TMH_EXCHANGES_find_exchange (dc->exchange_url,
     912             :                                         NULL,
     913             :                                         GNUNET_NO,
     914             :                                         &process_kyc_with_exchange,
     915             :                                         kc);
     916           0 :   if (NULL == kc->fo)
     917             :   {
     918           0 :     GNUNET_break (0);
     919           0 :     destroy_kc (kc);
     920             :   }
     921             : }
     922             : 
     923             : 
     924             : /**
     925             :  * Callback to handle a deposit permission's response.
     926             :  *
     927             :  * @param cls a `struct DepositConfirmation` (i.e. a pointer
     928             :  *   into the global array of confirmations and an index for this call
     929             :  *   in that array). That way, the last executed callback can detect
     930             :  *   that no other confirmations are on the way, and can pack a response
     931             :  *   for the wallet
     932             :  * @param dr HTTP response code details
     933             :  */
     934             : static void
     935           0 : deposit_cb (void *cls,
     936             :             const struct TALER_EXCHANGE_DepositResult *dr)
     937             : {
     938           0 :   struct DepositConfirmation *dc = cls;
     939           0 :   struct PayContext *pc = dc->pc;
     940             : 
     941           0 :   dc->dh = NULL;
     942           0 :   GNUNET_assert (GNUNET_YES == pc->suspended);
     943           0 :   pc->pending_at_ce--;
     944           0 :   switch (dr->hr.http_status)
     945             :   {
     946           0 :   case MHD_HTTP_OK:
     947             :     {
     948             :       /* store result to DB */
     949           0 :       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     950             :                   "Storing successful payment %s (%s) at instance `%s'\n",
     951             :                   pc->hc->infix,
     952             :                   GNUNET_h2s (&pc->h_contract_terms.hash),
     953             :                   pc->hc->instance->settings.id);
     954           0 :       TMH_db->preflight (TMH_db->cls);
     955             :       {
     956             :         enum GNUNET_DB_QueryStatus qs;
     957             : 
     958             :         /* NOTE: We might want to check if the order was fully paid concurrently
     959             :            by some other wallet here, and if so, issue an auto-refund. Right now,
     960             :            it is possible to over-pay if two wallets literally make a concurrent
     961             :            payment, as the earlier check for 'paid' is not in the same transaction
     962             :            scope as this 'insert' operation. */
     963           0 :         qs = TMH_db->insert_deposit (
     964           0 :           TMH_db->cls,
     965           0 :           pc->hc->instance->settings.id,
     966             :           dr->details.success.deposit_timestamp,
     967           0 :           &pc->h_contract_terms,
     968           0 :           &dc->coin_pub,
     969           0 :           dc->exchange_url,
     970           0 :           &dc->amount_with_fee,
     971           0 :           &dc->deposit_fee,
     972           0 :           &dc->refund_fee,
     973           0 :           &dc->wire_fee,
     974           0 :           &pc->wm->h_wire,
     975             :           dr->details.success.exchange_sig,
     976             :           dr->details.success.exchange_pub);
     977           0 :         if (0 > qs)
     978             :         {
     979             :           /* Special report if retries insufficient */
     980           0 :           if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
     981             :           {
     982           0 :             execute_pay_transaction (pc);
     983           0 :             return;
     984             :           }
     985             :           /* Always report on hard error as well to enable diagnostics */
     986           0 :           GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
     987             :           /* Forward error including 'proof' for the body */
     988           0 :           resume_pay_with_error (pc,
     989             :                                  MHD_HTTP_INTERNAL_SERVER_ERROR,
     990             :                                  TALER_EC_GENERIC_DB_STORE_FAILED,
     991             :                                  "insert_deposit");
     992           0 :           return;
     993             :         }
     994             :       }
     995             : 
     996           0 :       dc->found_in_db = true; /* well, at least NOW it'd be true ;-) */
     997           0 :       pc->pending--;
     998             : 
     999           0 :       if (0 != pc->pending_at_ce)
    1000           0 :         return; /* still more to do with current exchange */
    1001           0 :       check_kyc (pc,
    1002             :                  dc);
    1003           0 :       find_next_exchange (pc);
    1004           0 :       return;
    1005             :     }
    1006           0 :   default:
    1007           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1008             :                 "Deposit operation failed with HTTP code %u/%d\n",
    1009             :                 dr->hr.http_status,
    1010             :                 (int) dr->hr.ec);
    1011             :     /* Transaction failed */
    1012           0 :     if (5 == dr->hr.http_status / 100)
    1013             :     {
    1014             :       /* internal server error at exchange */
    1015           0 :       resume_pay_with_response (pc,
    1016             :                                 MHD_HTTP_BAD_GATEWAY,
    1017           0 :                                 TALER_MHD_MAKE_JSON_PACK (
    1018             :                                   TALER_JSON_pack_ec (
    1019             :                                     TALER_EC_MERCHANT_GENERIC_EXCHANGE_UNEXPECTED_STATUS),
    1020             :                                   TMH_pack_exchange_reply (&dr->hr)));
    1021           0 :       return;
    1022             :     }
    1023           0 :     if (NULL == dr->hr.reply)
    1024             :     {
    1025             :       /* We can't do anything meaningful here, the exchange did something wrong */
    1026           0 :       resume_pay_with_response (
    1027             :         pc,
    1028             :         MHD_HTTP_BAD_GATEWAY,
    1029           0 :         TALER_MHD_MAKE_JSON_PACK (
    1030             :           TALER_JSON_pack_ec (
    1031             :             TALER_EC_MERCHANT_GENERIC_EXCHANGE_REPLY_MALFORMED),
    1032             :           TMH_pack_exchange_reply (&dr->hr)));
    1033           0 :       return;
    1034             :     }
    1035             : 
    1036             :     /* Forward error, adding the "coin_pub" for which the
    1037             :        error was being generated */
    1038           0 :     if (TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS == dr->hr.ec)
    1039             :     {
    1040           0 :       resume_pay_with_response (
    1041             :         pc,
    1042             :         MHD_HTTP_CONFLICT,
    1043           0 :         TALER_MHD_MAKE_JSON_PACK (
    1044             :           TALER_JSON_pack_ec (
    1045             :             TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_INSUFFICIENT_FUNDS),
    1046             :           TMH_pack_exchange_reply (&dr->hr),
    1047             :           GNUNET_JSON_pack_data_auto ("coin_pub",
    1048             :                                       &dc->coin_pub)));
    1049           0 :       return;
    1050             :     }
    1051           0 :     resume_pay_with_response (
    1052             :       pc,
    1053             :       MHD_HTTP_BAD_GATEWAY,
    1054           0 :       TALER_MHD_MAKE_JSON_PACK (
    1055             :         TALER_JSON_pack_ec (
    1056             :           TALER_EC_MERCHANT_GENERIC_EXCHANGE_UNEXPECTED_STATUS),
    1057             :         TMH_pack_exchange_reply (&dr->hr),
    1058             :         GNUNET_JSON_pack_data_auto ("coin_pub",
    1059             :                                     &dc->coin_pub)));
    1060           0 :     return;
    1061             :   } /* end switch */
    1062             : }
    1063             : 
    1064             : 
    1065             : /**
    1066             :  * Function called with the result of our exchange lookup.
    1067             :  *
    1068             :  * @param cls the `struct PayContext`
    1069             :  * @param hr HTTP response details
    1070             :  * @param exchange_handle NULL if exchange was not found to be acceptable
    1071             :  * @param payto_uri payto://-URI of the exchange
    1072             :  * @param wire_fee current applicable fee for dealing with @a exchange_handle,
    1073             :  *        NULL if not available
    1074             :  * @param exchange_trusted true if this exchange is
    1075             :  *        trusted by config
    1076             :  */
    1077             : static void
    1078           0 : process_pay_with_exchange (
    1079             :   void *cls,
    1080             :   const struct TALER_EXCHANGE_HttpResponse *hr,
    1081             :   struct TALER_EXCHANGE_Handle *exchange_handle,
    1082             :   const char *payto_uri,
    1083             :   const struct TALER_Amount *wire_fee,
    1084             :   bool exchange_trusted)
    1085             : {
    1086           0 :   struct PayContext *pc = cls;
    1087           0 :   struct TMH_HandlerContext *hc = pc->hc;
    1088             :   const struct TALER_EXCHANGE_Keys *keys;
    1089             : 
    1090             :   (void) payto_uri;
    1091           0 :   pc->fo = NULL;
    1092           0 :   GNUNET_assert (GNUNET_YES == pc->suspended);
    1093           0 :   if (NULL == hr)
    1094             :   {
    1095           0 :     resume_pay_with_response (
    1096             :       pc,
    1097             :       MHD_HTTP_GATEWAY_TIMEOUT,
    1098           0 :       TALER_MHD_MAKE_JSON_PACK (
    1099             :         TALER_JSON_pack_ec (TALER_EC_MERCHANT_GENERIC_EXCHANGE_TIMEOUT)));
    1100           0 :     return;
    1101             :   }
    1102           0 :   if ( (MHD_HTTP_OK != hr->http_status) ||
    1103             :        (NULL == exchange_handle) )
    1104             :   {
    1105           0 :     resume_pay_with_response (
    1106             :       pc,
    1107             :       MHD_HTTP_BAD_GATEWAY,
    1108           0 :       TALER_MHD_MAKE_JSON_PACK (
    1109             :         TALER_JSON_pack_ec (
    1110             :           TALER_EC_MERCHANT_GENERIC_EXCHANGE_CONNECT_FAILURE),
    1111             :         TMH_pack_exchange_reply (hr)));
    1112           0 :     return;
    1113             :   }
    1114           0 :   keys = TALER_EXCHANGE_get_keys (exchange_handle);
    1115           0 :   if (NULL == keys)
    1116             :   {
    1117           0 :     GNUNET_break (0); /* should not be possible if HTTP status is #MHD_HTTP_OK */
    1118           0 :     resume_pay_with_error (pc,
    1119             :                            MHD_HTTP_BAD_GATEWAY,
    1120             :                            TALER_EC_MERCHANT_GENERIC_EXCHANGE_KEYS_FAILURE,
    1121             :                            NULL);
    1122           0 :     return;
    1123             :   }
    1124             : 
    1125             :   /* Initiate /deposit operation for all coins of
    1126             :      the current exchange (!) */
    1127           0 :   GNUNET_assert (0 == pc->pending_at_ce);
    1128           0 :   for (unsigned int i = 0; i<pc->coins_cnt; i++)
    1129             :   {
    1130           0 :     struct DepositConfirmation *dc = &pc->dc[i];
    1131             :     const struct TALER_EXCHANGE_DenomPublicKey *denom_details;
    1132             :     enum TALER_ErrorCode ec;
    1133             :     unsigned int http_status;
    1134           0 :     bool is_age_restricted_denom = false;
    1135             : 
    1136           0 :     if (NULL != dc->dh)
    1137           0 :       continue; /* we were here before (can happen due to
    1138             :                          tried_force_keys logic), don't go again */
    1139           0 :     if (dc->found_in_db)
    1140           0 :       continue;
    1141           0 :     if (0 != strcmp (dc->exchange_url,
    1142             :                      pc->current_exchange))
    1143           0 :       continue;
    1144             :     denom_details
    1145           0 :       = TALER_EXCHANGE_get_denomination_key_by_hash (keys,
    1146           0 :                                                      &dc->h_denom);
    1147           0 :     if (NULL == denom_details)
    1148             :     {
    1149           0 :       if (! pc->tried_force_keys)
    1150             :       {
    1151             :         /* let's try *forcing* a re-download of /keys from the exchange.
    1152             :            Maybe the wallet has seen /keys that we missed. */
    1153           0 :         pc->tried_force_keys = true;
    1154           0 :         pc->fo = TMH_EXCHANGES_find_exchange (pc->current_exchange,
    1155           0 :                                               pc->wm->wire_method,
    1156             :                                               GNUNET_YES,
    1157             :                                               &process_pay_with_exchange,
    1158             :                                               pc);
    1159           0 :         if (NULL != pc->fo)
    1160           0 :           return;
    1161             :       }
    1162             :       /* Forcing failed or we already did it, give up */
    1163           0 :       resume_pay_with_response (
    1164             :         pc,
    1165             :         MHD_HTTP_BAD_REQUEST,
    1166           0 :         TALER_MHD_MAKE_JSON_PACK (
    1167             :           TALER_JSON_pack_ec (
    1168             :             TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_DENOMINATION_KEY_NOT_FOUND),
    1169             :           GNUNET_JSON_pack_data_auto ("h_denom_pub",
    1170             :                                       &dc->h_denom),
    1171             :           GNUNET_JSON_pack_allow_null (
    1172             :             GNUNET_JSON_pack_object_incref (
    1173             :               "exchange_keys",
    1174             :               (json_t *) TALER_EXCHANGE_get_keys_raw (exchange_handle)))));
    1175           0 :       return;
    1176             :     }
    1177             : 
    1178           0 :     if (GNUNET_OK !=
    1179           0 :         TMH_AUDITORS_check_dk (exchange_handle,
    1180             :                                denom_details,
    1181             :                                exchange_trusted,
    1182             :                                &http_status,
    1183             :                                &ec))
    1184             :     {
    1185           0 :       if (! pc->tried_force_keys)
    1186             :       {
    1187             :         /* let's try *forcing* a re-download of /keys from the exchange.
    1188             :            Maybe the wallet has seen auditors that we missed. */
    1189           0 :         pc->tried_force_keys = true;
    1190           0 :         pc->fo = TMH_EXCHANGES_find_exchange (pc->current_exchange,
    1191           0 :                                               pc->wm->wire_method,
    1192             :                                               GNUNET_YES,
    1193             :                                               &process_pay_with_exchange,
    1194             :                                               pc);
    1195           0 :         if (NULL != pc->fo)
    1196           0 :           return;
    1197             :       }
    1198           0 :       resume_pay_with_response (
    1199             :         pc,
    1200             :         http_status,
    1201           0 :         TALER_MHD_MAKE_JSON_PACK (
    1202             :           TALER_JSON_pack_ec (ec),
    1203             :           GNUNET_JSON_pack_data_auto ("h_denom_pub",
    1204             :                                       &denom_details->h_key)));
    1205           0 :       return;
    1206             :     }
    1207             : 
    1208             : 
    1209             :     /* Now that we have the details about the denomination, we can verify age
    1210             :      * restriction requirements, if applicable. Note that denominations with an
    1211             :      * age_mask equal to zero always pass the age verification.  */
    1212           0 :     is_age_restricted_denom = 0 < denom_details->key.age_mask.bits;
    1213             : 
    1214           0 :     if (is_age_restricted_denom
    1215           0 :         && (0 < pc->minimum_age))
    1216           0 :     {
    1217             :       /* Minimum age given and restricted coind provided: We need to verify the
    1218             :        * minimum age */
    1219           0 :       unsigned int code = 0;
    1220             : 
    1221           0 :       if (dc->no_age_commitment)
    1222             :       {
    1223           0 :         GNUNET_break_op (0);
    1224           0 :         code = TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AGE_COMMITMENT_MISSING;
    1225           0 :         goto AGE_FAIL;
    1226             :       }
    1227             : 
    1228           0 :       dc->age_commitment.mask = denom_details->key.age_mask;
    1229           0 :       if ((dc->age_commitment.num + 1) !=
    1230           0 :           __builtin_popcount (dc->age_commitment.mask.bits))
    1231             :       {
    1232           0 :         GNUNET_break_op (0);
    1233           0 :         code =
    1234             :           TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AGE_COMMITMENT_SIZE_MISMATCH;
    1235           0 :         goto AGE_FAIL;
    1236             :       }
    1237             : 
    1238           0 :       if (GNUNET_OK !=
    1239           0 :           TALER_age_commitment_verify (
    1240           0 :             &dc->age_commitment,
    1241           0 :             pc->minimum_age,
    1242           0 :             &dc->minimum_age_sig))
    1243           0 :         code = TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AGE_VERIFICATION_FAILED;
    1244             : 
    1245           0 : AGE_FAIL:
    1246           0 :       if (0 < code)
    1247             :       {
    1248           0 :         GNUNET_free (dc->age_commitment.keys);
    1249           0 :         resume_pay_with_response (
    1250             :           pc,
    1251             :           MHD_HTTP_BAD_REQUEST,
    1252           0 :           TALER_MHD_MAKE_JSON_PACK (
    1253             :             TALER_JSON_pack_ec (code),
    1254             :             GNUNET_JSON_pack_data_auto ("h_denom_pub",
    1255             :                                         &denom_details->h_key)));
    1256           0 :         return;
    1257             :       }
    1258             : 
    1259             :       /* Age restriction successfully verified!
    1260             :        * Calculate the hash of the age commitment. */
    1261           0 :       TALER_age_commitment_hash (&dc->age_commitment,
    1262             :                                  &dc->h_age_commitment);
    1263           0 :       GNUNET_free (dc->age_commitment.keys);
    1264             :     }
    1265           0 :     else if (is_age_restricted_denom)
    1266             :     {
    1267             :       /* The contract did not ask for a minimum_age but the client paid
    1268             :        * with a coin that has age restriction enabled.  We need the hash
    1269             :        * of the age commitment in this case in order to verify the coin
    1270             :        * and to deposit it with the exchange. */
    1271           0 :       if (dc->no_h_age_commitment)
    1272             :       {
    1273           0 :         GNUNET_break_op (0);
    1274           0 :         resume_pay_with_response (
    1275             :           pc,
    1276             :           MHD_HTTP_BAD_REQUEST,
    1277           0 :           TALER_MHD_MAKE_JSON_PACK (
    1278             :             TALER_JSON_pack_ec (
    1279             :               TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AGE_COMMITMENT_HASH_MISSING),
    1280             :             GNUNET_JSON_pack_data_auto ("h_denom_pub",
    1281             :                                         &denom_details->h_key)));
    1282           0 :         return;
    1283             :       }
    1284             :     }
    1285             : 
    1286           0 :     dc->deposit_fee = denom_details->fees.deposit;
    1287           0 :     dc->refund_fee = denom_details->fees.refund;
    1288           0 :     dc->wire_fee = *wire_fee;
    1289           0 :     GNUNET_assert (NULL != pc->wm);
    1290           0 :     TMH_db->preflight (TMH_db->cls);
    1291             :     {
    1292           0 :       struct TALER_EXCHANGE_CoinDepositDetail cdd = {
    1293             :         .amount = dc->amount_with_fee,
    1294             :         .coin_pub = dc->coin_pub,
    1295             :         .coin_sig = dc->coin_sig,
    1296             :         .denom_sig = dc->ub_sig,
    1297             :         .h_denom_pub = denom_details->h_key,
    1298             :         .h_age_commitment = dc->h_age_commitment
    1299             :       };
    1300           0 :       struct TALER_EXCHANGE_DepositContractDetail dcd = {
    1301             :         .wire_deadline = pc->wire_transfer_deadline,
    1302           0 :         .merchant_payto_uri = pc->wm->payto_uri,
    1303           0 :         .wire_salt = pc->wm->wire_salt,
    1304             :         .h_contract_terms = pc->h_contract_terms,
    1305             :         .extension_details = NULL /* FIXME-OEC */,
    1306             :         .timestamp = pc->timestamp,
    1307           0 :         .merchant_pub = hc->instance->merchant_pub,
    1308             :         .refund_deadline = pc->refund_deadline
    1309             :       };
    1310             : 
    1311           0 :       dc->dh = TALER_EXCHANGE_deposit (exchange_handle,
    1312             :                                        &dcd,
    1313             :                                        &cdd,
    1314             :                                        &deposit_cb,
    1315             :                                        dc,
    1316             :                                        &ec);
    1317             :     }
    1318           0 :     if (NULL == dc->dh)
    1319             :     {
    1320             :       /* Signature was invalid or some other constraint was not satisfied.  If
    1321             :          the exchange was unavailable, we'd get that information in the
    1322             :          callback. */
    1323           0 :       GNUNET_break_op (0);
    1324           0 :       resume_pay_with_response (
    1325             :         pc,
    1326             :         TALER_ErrorCode_get_http_status_safe (ec),
    1327           0 :         TALER_MHD_MAKE_JSON_PACK (
    1328             :           TALER_JSON_pack_ec (ec),
    1329             :           GNUNET_JSON_pack_uint64 ("coin_idx",
    1330             :                                    i)));
    1331           0 :       return;
    1332             :     }
    1333           0 :     if (TMH_force_audit)
    1334           0 :       TALER_EXCHANGE_deposit_force_dc (dc->dh);
    1335           0 :     pc->pending_at_ce++;
    1336             :   }
    1337             : }
    1338             : 
    1339             : 
    1340             : /**
    1341             :  * Find the exchange we need to talk to for the next
    1342             :  * pending deposit permission.
    1343             :  *
    1344             :  * @param pc payment context we are processing
    1345             :  */
    1346             : static void
    1347           0 : find_next_exchange (struct PayContext *pc)
    1348             : {
    1349           0 :   GNUNET_assert (0 == pc->pending_at_ce);
    1350           0 :   for (unsigned int i = 0; i<pc->coins_cnt; i++)
    1351             :   {
    1352           0 :     struct DepositConfirmation *dc = &pc->dc[i];
    1353             : 
    1354           0 :     if (dc->found_in_db)
    1355           0 :       continue;
    1356             : 
    1357           0 :     pc->current_exchange = dc->exchange_url;
    1358           0 :     pc->fo = TMH_EXCHANGES_find_exchange (pc->current_exchange,
    1359           0 :                                           pc->wm->wire_method,
    1360             :                                           GNUNET_NO,
    1361             :                                           &process_pay_with_exchange,
    1362             :                                           pc);
    1363           0 :     if (NULL == pc->fo)
    1364             :     {
    1365           0 :       GNUNET_break (0);
    1366           0 :       resume_pay_with_error (pc,
    1367             :                              MHD_HTTP_INTERNAL_SERVER_ERROR,
    1368             :                              TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_EXCHANGE_LOOKUP_FAILED,
    1369             :                              "Failed to lookup exchange by URL");
    1370           0 :       return;
    1371             :     }
    1372           0 :     return;
    1373             :   }
    1374           0 :   pc->current_exchange = NULL;
    1375             :   /* We are done with all the HTTP requests, go back and try
    1376             :      the 'big' database transaction! (It should work now!) */
    1377           0 :   GNUNET_assert (0 == pc->pending);
    1378           0 :   execute_pay_transaction (pc);
    1379             : }
    1380             : 
    1381             : 
    1382             : /**
    1383             :  * Function called with information about a coin that was deposited.
    1384             :  *
    1385             :  * @param cls closure
    1386             :  * @param exchange_url exchange where @a coin_pub was deposited
    1387             :  * @param coin_pub public key of the coin
    1388             :  * @param amount_with_fee amount the exchange will deposit for this coin
    1389             :  * @param deposit_fee fee the exchange will charge for this coin
    1390             :  * @param refund_fee fee the exchange will charge for refunding this coin
    1391             :  * @param wire_fee wire fee the exchange of this coin charges
    1392             :  */
    1393             : static void
    1394           0 : check_coin_paid (void *cls,
    1395             :                  const char *exchange_url,
    1396             :                  const struct TALER_CoinSpendPublicKeyP *coin_pub,
    1397             :                  const struct TALER_Amount *amount_with_fee,
    1398             :                  const struct TALER_Amount *deposit_fee,
    1399             :                  const struct TALER_Amount *refund_fee,
    1400             :                  const struct TALER_Amount *wire_fee)
    1401             : {
    1402           0 :   struct PayContext *pc = cls;
    1403             : 
    1404           0 :   for (unsigned int i = 0; i<pc->coins_cnt; i++)
    1405             :   {
    1406           0 :     struct DepositConfirmation *dc = &pc->dc[i];
    1407             : 
    1408           0 :     if (dc->found_in_db)
    1409           0 :       continue; /* processed earlier, skip "expensive" memcmp() */
    1410             :     /* Get matching coin from results*/
    1411           0 :     if ( (0 != GNUNET_memcmp (coin_pub,
    1412           0 :                               &dc->coin_pub)) ||
    1413             :          (0 !=
    1414           0 :           strcmp (exchange_url,
    1415           0 :                   dc->exchange_url)) ||
    1416           0 :          (0 != TALER_amount_cmp (amount_with_fee,
    1417           0 :                                  &dc->amount_with_fee)) )
    1418           0 :       continue; /* does not match, skip */
    1419           0 :     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    1420             :                 "Deposit of coin `%s' already in our DB.\n",
    1421             :                 TALER_B2S (coin_pub));
    1422             : 
    1423           0 :     GNUNET_assert (0 <=
    1424             :                    TALER_amount_add (&pc->total_paid,
    1425             :                                      &pc->total_paid,
    1426             :                                      amount_with_fee));
    1427           0 :     GNUNET_assert (0 <=
    1428             :                    TALER_amount_add (&pc->total_fees_paid,
    1429             :                                      &pc->total_fees_paid,
    1430             :                                      deposit_fee));
    1431           0 :     dc->deposit_fee = *deposit_fee;
    1432           0 :     dc->refund_fee = *refund_fee;
    1433           0 :     dc->wire_fee = *wire_fee;
    1434           0 :     dc->amount_with_fee = *amount_with_fee;
    1435           0 :     dc->found_in_db = true;
    1436           0 :     pc->pending--;
    1437             :   }
    1438           0 : }
    1439             : 
    1440             : 
    1441             : /**
    1442             :  * Function called with information about a refund.  Check if this coin was
    1443             :  * claimed by the wallet for the transaction, and if so add the refunded
    1444             :  * amount to the pc's "total_refunded" amount.
    1445             :  *
    1446             :  * @param cls closure with a `struct PayContext`
    1447             :  * @param coin_pub public coin from which the refund comes from
    1448             :  * @param refund_amount refund amount which is being taken from @a coin_pub
    1449             :  */
    1450             : static void
    1451           0 : check_coin_refunded (void *cls,
    1452             :                      const struct TALER_CoinSpendPublicKeyP *coin_pub,
    1453             :                      const struct TALER_Amount *refund_amount)
    1454             : {
    1455           0 :   struct PayContext *pc = cls;
    1456             : 
    1457             :   /* We look at refunds here that apply to the coins
    1458             :      that the customer is currently trying to pay us with.
    1459             : 
    1460             :      Such refunds are not "normal" refunds, but abort-pay refunds, which are
    1461             :      given in the case that the wallet aborts the payment.
    1462             :      In the case the wallet then decides to complete the payment *after* doing
    1463             :      an abort-pay refund (an unusual but possible case), we need
    1464             :      to make sure that existing refunds are accounted for. */
    1465             : 
    1466           0 :   for (unsigned int i = 0; i<pc->coins_cnt; i++)
    1467             :   {
    1468           0 :     struct DepositConfirmation *dc = &pc->dc[i];
    1469             : 
    1470             :     /* Get matching coins from results.  */
    1471           0 :     if (0 != GNUNET_memcmp (coin_pub,
    1472             :                             &dc->coin_pub))
    1473           0 :       continue;
    1474           0 :     GNUNET_assert (0 <=
    1475             :                    TALER_amount_add (&pc->total_refunded,
    1476             :                                      &pc->total_refunded,
    1477             :                                      refund_amount));
    1478           0 :     break;
    1479             :   }
    1480           0 : }
    1481             : 
    1482             : 
    1483             : /**
    1484             :  * Check whether the amount paid is sufficient to cover the price.
    1485             :  *
    1486             :  * @param pc payment context to check
    1487             :  * @return true if the payment is sufficient, false if it is
    1488             :  *         insufficient
    1489             :  */
    1490             : static bool
    1491           0 : check_payment_sufficient (struct PayContext *pc)
    1492             : {
    1493             :   struct TALER_Amount acc_fee;
    1494             :   struct TALER_Amount acc_amount;
    1495             :   struct TALER_Amount final_amount;
    1496             :   struct TALER_Amount wire_fee_delta;
    1497             :   struct TALER_Amount wire_fee_customer_contribution;
    1498             :   struct TALER_Amount total_wire_fee;
    1499             :   struct TALER_Amount total_needed;
    1500             : 
    1501           0 :   if (0 == pc->coins_cnt)
    1502             :   {
    1503           0 :     return ((0 == pc->amount.value) &&
    1504           0 :             (0 == pc->amount.fraction));
    1505             :   }
    1506             : 
    1507           0 :   acc_fee = pc->dc[0].deposit_fee;
    1508           0 :   total_wire_fee = pc->dc[0].wire_fee;
    1509           0 :   acc_amount = pc->dc[0].amount_with_fee;
    1510             : 
    1511             :   /**
    1512             :    * This loops calculates what are the deposit fee / total
    1513             :    * amount with fee / and wire fee, for all the coins.
    1514             :    */
    1515           0 :   for (unsigned int i = 1; i<pc->coins_cnt; i++)
    1516             :   {
    1517           0 :     struct DepositConfirmation *dc = &pc->dc[i];
    1518             : 
    1519           0 :     GNUNET_assert (dc->found_in_db);
    1520           0 :     if ( (0 >
    1521           0 :           TALER_amount_add (&acc_fee,
    1522           0 :                             &dc->deposit_fee,
    1523           0 :                             &acc_fee)) ||
    1524             :          (0 >
    1525           0 :           TALER_amount_add (&acc_amount,
    1526           0 :                             &dc->amount_with_fee,
    1527             :                             &acc_amount)) )
    1528             :     {
    1529           0 :       GNUNET_break (0);
    1530             :       /* Overflow in these amounts? Very strange. */
    1531           0 :       resume_pay_with_error (pc,
    1532             :                              MHD_HTTP_INTERNAL_SERVER_ERROR,
    1533             :                              TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AMOUNT_OVERFLOW,
    1534             :                              "Overflow adding up amounts");
    1535           0 :       return false;
    1536             :     }
    1537           0 :     if (1 ==
    1538           0 :         TALER_amount_cmp (&dc->deposit_fee,
    1539           0 :                           &dc->amount_with_fee))
    1540             :     {
    1541           0 :       GNUNET_break_op (0);
    1542           0 :       resume_pay_with_error (pc,
    1543             :                              MHD_HTTP_BAD_REQUEST,
    1544             :                              TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_FEES_EXCEED_PAYMENT,
    1545             :                              "Deposit fees exceed coin's contribution");
    1546           0 :       return false;
    1547             :     }
    1548             : 
    1549             :     /* If exchange differs, add wire fee */
    1550             :     {
    1551           0 :       bool new_exchange = true;
    1552             : 
    1553           0 :       for (unsigned int j = 0; j<i; j++)
    1554           0 :         if (0 == strcasecmp (dc->exchange_url,
    1555           0 :                              pc->dc[j].exchange_url))
    1556             :         {
    1557           0 :           new_exchange = false;
    1558           0 :           break;
    1559             :         }
    1560             : 
    1561           0 :       if (! new_exchange)
    1562           0 :         continue;
    1563             : 
    1564           0 :       if (GNUNET_OK !=
    1565           0 :           TALER_amount_cmp_currency (&total_wire_fee,
    1566           0 :                                      &dc->wire_fee))
    1567             :       {
    1568           0 :         GNUNET_break_op (0);
    1569           0 :         resume_pay_with_error (pc,
    1570             :                                MHD_HTTP_CONFLICT,
    1571             :                                TALER_EC_GENERIC_CURRENCY_MISMATCH,
    1572             :                                total_wire_fee.currency);
    1573           0 :         return false;
    1574             :       }
    1575           0 :       if (0 >
    1576           0 :           TALER_amount_add (&total_wire_fee,
    1577             :                             &total_wire_fee,
    1578           0 :                             &dc->wire_fee))
    1579             :       {
    1580           0 :         GNUNET_break (0);
    1581           0 :         resume_pay_with_error (pc,
    1582             :                                MHD_HTTP_INTERNAL_SERVER_ERROR,
    1583             :                                TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_EXCHANGE_WIRE_FEE_ADDITION_FAILED,
    1584             :                                "could not add exchange wire fee to total");
    1585           0 :         return false;
    1586             :       }
    1587             :     }
    1588             :   } /* deposit loop */
    1589             : 
    1590           0 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    1591             :               "Amount received from wallet: %s\n",
    1592             :               TALER_amount2s (&acc_amount));
    1593           0 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    1594             :               "Deposit fee for all coins: %s\n",
    1595             :               TALER_amount2s (&acc_fee));
    1596           0 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    1597             :               "Total wire fee: %s\n",
    1598             :               TALER_amount2s (&total_wire_fee));
    1599           0 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    1600             :               "Max wire fee: %s\n",
    1601             :               TALER_amount2s (&pc->max_wire_fee));
    1602           0 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    1603             :               "Deposit fee limit for merchant: %s\n",
    1604             :               TALER_amount2s (&pc->max_fee));
    1605           0 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    1606             :               "Total refunded amount: %s\n",
    1607             :               TALER_amount2s (&pc->total_refunded));
    1608             : 
    1609             :   /* Now compare exchange wire fee compared to
    1610             :    * what we are willing to pay */
    1611           0 :   if (GNUNET_YES !=
    1612           0 :       TALER_amount_cmp_currency (&total_wire_fee,
    1613           0 :                                  &pc->max_wire_fee))
    1614             :   {
    1615           0 :     GNUNET_break (0);
    1616           0 :     resume_pay_with_error (pc,
    1617             :                            MHD_HTTP_CONFLICT,
    1618             :                            TALER_EC_GENERIC_CURRENCY_MISMATCH,
    1619             :                            total_wire_fee.currency);
    1620           0 :     return false;
    1621             :   }
    1622             : 
    1623           0 :   switch (TALER_amount_subtract (&wire_fee_delta,
    1624             :                                  &total_wire_fee,
    1625           0 :                                  &pc->max_wire_fee))
    1626             :   {
    1627           0 :   case TALER_AAR_RESULT_POSITIVE:
    1628             :     /* Actual wire fee is indeed higher than our maximum,
    1629             :        compute how much the customer is expected to cover!  */
    1630           0 :     TALER_amount_divide (&wire_fee_customer_contribution,
    1631             :                          &wire_fee_delta,
    1632             :                          pc->wire_fee_amortization);
    1633           0 :     break;
    1634           0 :   case TALER_AAR_RESULT_ZERO:
    1635             :   case TALER_AAR_INVALID_NEGATIVE_RESULT:
    1636             :     /* Wire fee threshold is still above the wire fee amount.
    1637             :        Customer is not going to contribute on this.  */
    1638           0 :     GNUNET_assert (GNUNET_OK ==
    1639             :                    TALER_amount_set_zero (total_wire_fee.currency,
    1640             :                                           &wire_fee_customer_contribution));
    1641           0 :     break;
    1642           0 :   default:
    1643           0 :     GNUNET_assert (0);
    1644             :   }
    1645             : 
    1646             :   /* add wire fee contribution to the total fees */
    1647           0 :   if (0 >
    1648           0 :       TALER_amount_add (&acc_fee,
    1649             :                         &acc_fee,
    1650             :                         &wire_fee_customer_contribution))
    1651             :   {
    1652           0 :     GNUNET_break (0);
    1653           0 :     resume_pay_with_error (pc,
    1654             :                            MHD_HTTP_INTERNAL_SERVER_ERROR,
    1655             :                            TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AMOUNT_OVERFLOW,
    1656             :                            "Overflow adding up amounts");
    1657           0 :     return false;
    1658             :   }
    1659           0 :   if (-1 == TALER_amount_cmp (&pc->max_fee,
    1660             :                               &acc_fee))
    1661             :   {
    1662             :     /**
    1663             :      * Sum of fees of *all* the different exchanges of all the coins are
    1664             :      * higher than the fixed limit that the merchant is willing to pay.  The
    1665             :      * difference must be paid by the customer.
    1666             :      *///
    1667             :     struct TALER_Amount excess_fee;
    1668             : 
    1669             :     /* compute fee amount to be covered by customer */
    1670           0 :     GNUNET_assert (TALER_AAR_RESULT_POSITIVE ==
    1671             :                    TALER_amount_subtract (&excess_fee,
    1672             :                                           &acc_fee,
    1673             :                                           &pc->max_fee));
    1674             :     /* add that to the total */
    1675           0 :     if (0 >
    1676           0 :         TALER_amount_add (&total_needed,
    1677             :                           &excess_fee,
    1678           0 :                           &pc->amount))
    1679             :     {
    1680           0 :       GNUNET_break (0);
    1681           0 :       resume_pay_with_error (pc,
    1682             :                              MHD_HTTP_INTERNAL_SERVER_ERROR,
    1683             :                              TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AMOUNT_OVERFLOW,
    1684             :                              "Overflow adding up amounts");
    1685           0 :       return false;
    1686             :     }
    1687             :   }
    1688             :   else
    1689             :   {
    1690             :     /* Fees are fully covered by the merchant, all we require
    1691             :        is that the total payment is not below the contract's amount */
    1692           0 :     total_needed = pc->amount;
    1693             :   }
    1694             : 
    1695             :   /* Do not count refunds towards the payment */
    1696           0 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1697             :               "Subtracting total refunds from paid amount: %s\n",
    1698             :               TALER_amount2s (&pc->total_refunded));
    1699           0 :   if (0 >
    1700           0 :       TALER_amount_subtract (&final_amount,
    1701             :                              &acc_amount,
    1702           0 :                              &pc->total_refunded))
    1703             :   {
    1704           0 :     GNUNET_break (0);
    1705           0 :     resume_pay_with_error (pc,
    1706             :                            MHD_HTTP_INTERNAL_SERVER_ERROR,
    1707             :                            TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_REFUNDS_EXCEED_PAYMENTS,
    1708             :                            "refunded amount exceeds total payments");
    1709           0 :     return false;
    1710             :   }
    1711             : 
    1712           0 :   if (-1 == TALER_amount_cmp (&final_amount,
    1713             :                               &total_needed))
    1714             :   {
    1715             :     /* acc_amount < total_needed */
    1716           0 :     if (-1 < TALER_amount_cmp (&acc_amount,
    1717             :                                &total_needed))
    1718             :     {
    1719           0 :       GNUNET_break_op (0);
    1720           0 :       resume_pay_with_error (pc,
    1721             :                              MHD_HTTP_PAYMENT_REQUIRED,
    1722             :                              TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_REFUNDED,
    1723             :                              "contract not paid up due to refunds");
    1724             :     }
    1725           0 :     else if (-1 < TALER_amount_cmp (&acc_amount,
    1726           0 :                                     &pc->amount))
    1727             :     {
    1728           0 :       GNUNET_break_op (0);
    1729           0 :       resume_pay_with_error (pc,
    1730             :                              MHD_HTTP_NOT_ACCEPTABLE,
    1731             :                              TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_INSUFFICIENT_DUE_TO_FEES,
    1732             :                              "contract not paid up due to fees (client may have calculated them badly)");
    1733             :     }
    1734             :     else
    1735             :     {
    1736           0 :       GNUNET_break_op (0);
    1737           0 :       resume_pay_with_error (pc,
    1738             :                              MHD_HTTP_NOT_ACCEPTABLE,
    1739             :                              TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_PAYMENT_INSUFFICIENT,
    1740             :                              "payment insufficient");
    1741             :     }
    1742           0 :     return false;
    1743             :   }
    1744           0 :   return true;
    1745             : }
    1746             : 
    1747             : 
    1748             : /**
    1749             :  * Use database to notify other clients about the
    1750             :  * payment being completed.
    1751             :  *
    1752             :  * @param pc context to trigger notification for
    1753             :  */
    1754             : static void
    1755           0 : trigger_payment_notification (struct PayContext *pc)
    1756             : {
    1757             :   {
    1758           0 :     struct TMH_OrderPayEventP pay_eh = {
    1759           0 :       .header.size = htons (sizeof (pay_eh)),
    1760           0 :       .header.type = htons (TALER_DBEVENT_MERCHANT_ORDER_PAID),
    1761           0 :       .merchant_pub = pc->hc->instance->merchant_pub
    1762             :     };
    1763             : 
    1764           0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1765             :                 "Notifying clients about payment of order %s\n",
    1766             :                 pc->order_id);
    1767           0 :     GNUNET_CRYPTO_hash (pc->order_id,
    1768             :                         strlen (pc->order_id),
    1769             :                         &pay_eh.h_order_id);
    1770           0 :     TMH_db->event_notify (TMH_db->cls,
    1771             :                           &pay_eh.header,
    1772             :                           NULL,
    1773             :                           0);
    1774             :   }
    1775           0 :   if ( (NULL != pc->session_id) &&
    1776           0 :        (NULL != pc->fulfillment_url) )
    1777             :   {
    1778           0 :     struct TMH_SessionEventP session_eh = {
    1779           0 :       .header.size = htons (sizeof (session_eh)),
    1780           0 :       .header.type = htons (TALER_DBEVENT_MERCHANT_SESSION_CAPTURED),
    1781           0 :       .merchant_pub = pc->hc->instance->merchant_pub
    1782             :     };
    1783             : 
    1784           0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1785             :                 "Notifying clients about session change to %s for %s\n",
    1786             :                 pc->session_id,
    1787             :                 pc->fulfillment_url);
    1788           0 :     GNUNET_CRYPTO_hash (pc->session_id,
    1789           0 :                         strlen (pc->session_id),
    1790             :                         &session_eh.h_session_id);
    1791           0 :     GNUNET_CRYPTO_hash (pc->fulfillment_url,
    1792           0 :                         strlen (pc->fulfillment_url),
    1793             :                         &session_eh.h_fulfillment_url);
    1794           0 :     TMH_db->event_notify (TMH_db->cls,
    1795             :                           &session_eh.header,
    1796             :                           NULL,
    1797             :                           0);
    1798             :   }
    1799           0 : }
    1800             : 
    1801             : 
    1802             : /**
    1803             :  * Generate response (payment successful)
    1804             :  *
    1805             :  * @param[in,out] pc payment context where the payment was successful
    1806             :  */
    1807             : static void
    1808           0 : generate_success_response (struct PayContext *pc)
    1809             : {
    1810             :   struct GNUNET_CRYPTO_EddsaSignature sig;
    1811             : 
    1812             :   /* Sign on our end (as the payment did go through, even if it may
    1813             :      have been refunded already) */
    1814           0 :   TALER_merchant_pay_sign (&pc->h_contract_terms,
    1815           0 :                            &pc->hc->instance->merchant_priv,
    1816             :                            &sig);
    1817             :   /* Build the response */
    1818           0 :   resume_pay_with_response (
    1819             :     pc,
    1820             :     MHD_HTTP_OK,
    1821           0 :     TALER_MHD_MAKE_JSON_PACK (
    1822             :       GNUNET_JSON_pack_data_auto ("sig",
    1823             :                                   &sig)));
    1824           0 : }
    1825             : 
    1826             : 
    1827             : static void
    1828           0 : execute_pay_transaction (struct PayContext *pc)
    1829             : {
    1830           0 :   struct TMH_HandlerContext *hc = pc->hc;
    1831           0 :   const char *instance_id = hc->instance->settings.id;
    1832             : 
    1833             :   /* Avoid re-trying transactions on soft errors forever! */
    1834           0 :   if (pc->retry_counter++ > MAX_RETRIES)
    1835             :   {
    1836           0 :     GNUNET_break (0);
    1837           0 :     resume_pay_with_error (pc,
    1838             :                            MHD_HTTP_INTERNAL_SERVER_ERROR,
    1839             :                            TALER_EC_GENERIC_DB_SOFT_FAILURE,
    1840             :                            NULL);
    1841           0 :     return;
    1842             :   }
    1843           0 :   GNUNET_assert (GNUNET_YES == pc->suspended);
    1844             : 
    1845             :   /* Initialize some amount accumulators
    1846             :      (used in check_coin_paid(), check_coin_refunded()
    1847             :      and check_payment_sufficient()). */
    1848           0 :   GNUNET_break (GNUNET_OK ==
    1849             :                 TALER_amount_set_zero (pc->amount.currency,
    1850             :                                        &pc->total_paid));
    1851           0 :   GNUNET_break (GNUNET_OK ==
    1852             :                 TALER_amount_set_zero (pc->amount.currency,
    1853             :                                        &pc->total_fees_paid));
    1854           0 :   GNUNET_break (GNUNET_OK ==
    1855             :                 TALER_amount_set_zero (pc->amount.currency,
    1856             :                                        &pc->total_refunded));
    1857           0 :   for (unsigned int i = 0; i<pc->coins_cnt; i++)
    1858           0 :     pc->dc[i].found_in_db = false;
    1859           0 :   pc->pending = pc->coins_cnt;
    1860             : 
    1861             :   /* First, try to see if we have all we need already done */
    1862           0 :   TMH_db->preflight (TMH_db->cls);
    1863           0 :   if (GNUNET_OK !=
    1864           0 :       TMH_db->start (TMH_db->cls,
    1865             :                      "run pay"))
    1866             :   {
    1867           0 :     GNUNET_break (0);
    1868           0 :     resume_pay_with_error (pc,
    1869             :                            MHD_HTTP_INTERNAL_SERVER_ERROR,
    1870             :                            TALER_EC_GENERIC_DB_START_FAILED,
    1871             :                            NULL);
    1872           0 :     return;
    1873             :   }
    1874             : 
    1875             :   {
    1876             :     enum GNUNET_DB_QueryStatus qs;
    1877             : 
    1878             :     /* Check if some of these coins already succeeded for _this_ contract.  */
    1879           0 :     qs = TMH_db->lookup_deposits (TMH_db->cls,
    1880             :                                   instance_id,
    1881           0 :                                   &pc->h_contract_terms,
    1882             :                                   &check_coin_paid,
    1883             :                                   pc);
    1884           0 :     if (0 > qs)
    1885             :     {
    1886           0 :       TMH_db->rollback (TMH_db->cls);
    1887           0 :       if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
    1888             :       {
    1889           0 :         execute_pay_transaction (pc);
    1890           0 :         return;
    1891             :       }
    1892             :       /* Always report on hard error as well to enable diagnostics */
    1893           0 :       GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
    1894           0 :       resume_pay_with_error (pc,
    1895             :                              MHD_HTTP_INTERNAL_SERVER_ERROR,
    1896             :                              TALER_EC_GENERIC_DB_FETCH_FAILED,
    1897             :                              "lookup deposits");
    1898           0 :       return;
    1899             :     }
    1900             :   }
    1901             : 
    1902             : 
    1903             :   {
    1904             :     enum GNUNET_DB_QueryStatus qs;
    1905             : 
    1906             :     /* Check if we refunded some of the coins */
    1907           0 :     qs = TMH_db->lookup_refunds (TMH_db->cls,
    1908             :                                  instance_id,
    1909           0 :                                  &pc->h_contract_terms,
    1910             :                                  &check_coin_refunded,
    1911             :                                  pc);
    1912           0 :     if (0 > qs)
    1913             :     {
    1914           0 :       TMH_db->rollback (TMH_db->cls);
    1915           0 :       if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
    1916             :       {
    1917           0 :         execute_pay_transaction (pc);
    1918           0 :         return;
    1919             :       }
    1920             :       /* Always report on hard error as well to enable diagnostics */
    1921           0 :       GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
    1922           0 :       resume_pay_with_error (pc,
    1923             :                              MHD_HTTP_INTERNAL_SERVER_ERROR,
    1924             :                              TALER_EC_GENERIC_DB_FETCH_FAILED,
    1925             :                              "lookup refunds");
    1926           0 :       return;
    1927             :     }
    1928             :   }
    1929             : 
    1930             :   /* Check if there are coins that still need to be processed */
    1931           0 :   if (0 != pc->pending)
    1932             :   {
    1933             :     /* we made no DB changes, so we can just rollback */
    1934           0 :     TMH_db->rollback (TMH_db->cls);
    1935             : 
    1936             :     /* Ok, we need to first go to the network to process more coins.
    1937             :        We that interaction in *tiny* transactions (hence the rollback
    1938             :        above). */
    1939           0 :     find_next_exchange (pc);
    1940           0 :     return;
    1941             :   }
    1942             : 
    1943             :   /* 0 == pc->pending: all coins processed, let's see if that was enough */
    1944           0 :   if (! check_payment_sufficient (pc))
    1945             :   {
    1946             :     /* check_payment_sufficient() will have queued an error already.
    1947             :        We need to still abort the transaction. */
    1948           0 :     TMH_db->rollback (TMH_db->cls);
    1949           0 :     return;
    1950             :   }
    1951             :   /* Payment succeeded, save in database */
    1952           0 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1953             :               "Order `%s' (%s) was fully paid\n",
    1954             :               pc->order_id,
    1955             :               GNUNET_h2s (&pc->h_contract_terms.hash));
    1956             :   {
    1957             :     enum GNUNET_DB_QueryStatus qs;
    1958             : 
    1959           0 :     qs = TMH_db->mark_contract_paid (TMH_db->cls,
    1960             :                                      instance_id,
    1961           0 :                                      &pc->h_contract_terms,
    1962           0 :                                      pc->session_id);
    1963           0 :     if (qs < 0)
    1964             :     {
    1965           0 :       TMH_db->rollback (TMH_db->cls);
    1966           0 :       if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
    1967             :       {
    1968           0 :         execute_pay_transaction (pc);
    1969           0 :         return;
    1970             :       }
    1971           0 :       GNUNET_break (0);
    1972           0 :       resume_pay_with_error (pc,
    1973             :                              MHD_HTTP_INTERNAL_SERVER_ERROR,
    1974             :                              TALER_EC_GENERIC_DB_STORE_FAILED,
    1975             :                              "mark contract paid");
    1976           0 :       return;
    1977             :     }
    1978             :   }
    1979             : 
    1980           0 :   TMH_notify_order_change (hc->instance,
    1981             :                            TMH_OSF_CLAIMED | TMH_OSF_PAID,
    1982             :                            pc->timestamp,
    1983             :                            pc->order_serial);
    1984             : 
    1985             :   {
    1986             :     enum GNUNET_DB_QueryStatus qs;
    1987             : 
    1988             :     /* Now commit! */
    1989           0 :     qs = TMH_db->commit (TMH_db->cls);
    1990           0 :     if (0 > qs)
    1991             :     {
    1992             :       /* commit failed */
    1993           0 :       TMH_db->rollback (TMH_db->cls);
    1994           0 :       if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
    1995             :       {
    1996           0 :         execute_pay_transaction (pc);
    1997           0 :         return;
    1998             :       }
    1999           0 :       GNUNET_break (0);
    2000           0 :       resume_pay_with_error (pc,
    2001             :                              MHD_HTTP_INTERNAL_SERVER_ERROR,
    2002             :                              TALER_EC_GENERIC_DB_COMMIT_FAILED,
    2003             :                              NULL);
    2004           0 :       return;
    2005             :     }
    2006           0 :     trigger_payment_notification (pc);
    2007             :   }
    2008           0 :   generate_success_response (pc);
    2009             : }
    2010             : 
    2011             : 
    2012             : /**
    2013             :  * Try to parse the pay request into the given pay context.
    2014             :  * Schedules an error response in the connection on failure.
    2015             :  *
    2016             :  * @param[in,out] pc context we use to handle the payment
    2017             :  * @return #GNUNET_OK on success,
    2018             :  *         #GNUNET_NO on failure (response was queued with MHD)
    2019             :  *         #GNUNET_SYSERR on hard error (MHD connection must be dropped)
    2020             :  */
    2021             : static enum GNUNET_GenericReturnValue
    2022           0 : parse_pay (struct PayContext *pc)
    2023             : {
    2024           0 :   const char *session_id = NULL;
    2025             :   json_t *coins;
    2026             :   struct GNUNET_JSON_Specification spec[] = {
    2027           0 :     GNUNET_JSON_spec_json ("coins",
    2028             :                            &coins),
    2029           0 :     GNUNET_JSON_spec_mark_optional (
    2030             :       GNUNET_JSON_spec_string ("session_id",
    2031             :                                &session_id),
    2032             :       NULL),
    2033           0 :     GNUNET_JSON_spec_end ()
    2034             :   };
    2035             : 
    2036             :   {
    2037             :     enum GNUNET_GenericReturnValue res;
    2038             : 
    2039           0 :     res = TALER_MHD_parse_json_data (pc->connection,
    2040           0 :                                      pc->hc->request_body,
    2041             :                                      spec);
    2042           0 :     if (GNUNET_YES != res)
    2043             :     {
    2044           0 :       GNUNET_break_op (0);
    2045           0 :       return res;
    2046             :     }
    2047             :   }
    2048             : 
    2049             :   /* copy session ID (if set) */
    2050           0 :   if (NULL != session_id)
    2051             :   {
    2052           0 :     pc->session_id = GNUNET_strdup (session_id);
    2053             :   }
    2054             :   else
    2055             :   {
    2056             :     /* use empty string as default if client didn't specify it */
    2057           0 :     pc->session_id = GNUNET_strdup ("");
    2058             :   }
    2059             : 
    2060           0 :   if (! json_is_array (coins))
    2061             :   {
    2062           0 :     GNUNET_break_op (0);
    2063           0 :     GNUNET_JSON_parse_free (spec);
    2064             :     return (MHD_YES ==
    2065           0 :             TALER_MHD_reply_with_error (pc->connection,
    2066             :                                         MHD_HTTP_BAD_REQUEST,
    2067             :                                         TALER_EC_GENERIC_PARAMETER_MISSING,
    2068             :                                         "'coins' must be an array"))
    2069             :         ? GNUNET_NO
    2070           0 :         : GNUNET_SYSERR;
    2071             :   }
    2072             : 
    2073           0 :   pc->coins_cnt = json_array_size (coins);
    2074           0 :   if (pc->coins_cnt > MAX_COIN_ALLOWED_COINS)
    2075             :   {
    2076           0 :     GNUNET_break_op (0);
    2077           0 :     GNUNET_JSON_parse_free (spec);
    2078             :     return (MHD_YES ==
    2079           0 :             TALER_MHD_reply_with_error (
    2080             :               pc->connection,
    2081             :               MHD_HTTP_BAD_REQUEST,
    2082             :               TALER_EC_GENERIC_PARAMETER_MALFORMED,
    2083             :               "'coins' array too long"))
    2084             :         ? GNUNET_NO
    2085           0 :         : GNUNET_SYSERR;
    2086             :   }
    2087             : 
    2088             :   /* note: 1 coin = 1 deposit confirmation expected */
    2089           0 :   pc->dc = GNUNET_new_array (pc->coins_cnt,
    2090             :                              struct DepositConfirmation);
    2091             : 
    2092             :   /* This loop populates the array 'dc' in 'pc' */
    2093             :   {
    2094             :     unsigned int coins_index;
    2095             :     json_t *coin;
    2096             : 
    2097           0 :     json_array_foreach (coins, coins_index, coin)
    2098             :     {
    2099           0 :       struct DepositConfirmation *dc = &pc->dc[coins_index];
    2100             :       const char *exchange_url;
    2101             :       struct GNUNET_JSON_Specification ispec[] = {
    2102           0 :         GNUNET_JSON_spec_fixed_auto ("coin_sig",
    2103             :                                      &dc->coin_sig),
    2104           0 :         GNUNET_JSON_spec_fixed_auto ("coin_pub",
    2105             :                                      &dc->coin_pub),
    2106           0 :         TALER_JSON_spec_denom_sig ("ub_sig",
    2107             :                                    &dc->ub_sig),
    2108           0 :         GNUNET_JSON_spec_fixed_auto ("h_denom",
    2109             :                                      &dc->h_denom),
    2110           0 :         TALER_JSON_spec_amount ("contribution",
    2111             :                                 TMH_currency,
    2112             :                                 &dc->amount_with_fee),
    2113           0 :         GNUNET_JSON_spec_string ("exchange_url",
    2114             :                                  &exchange_url),
    2115             :         /* if a minimum age was required, the minimum_age_sig and
    2116             :          * age_commitment must be provided */
    2117           0 :         GNUNET_JSON_spec_mark_optional (
    2118           0 :           GNUNET_JSON_spec_fixed_auto ("minimum_age_sig",
    2119             :                                        &dc->minimum_age_sig),
    2120             :           &dc->no_minimum_age_sig),
    2121           0 :         GNUNET_JSON_spec_mark_optional (
    2122             :           TALER_JSON_spec_age_commitment ("age_commitment",
    2123             :                                           &dc->age_commitment),
    2124             :           &dc->no_age_commitment),
    2125             :         /* if minimum age was not required, but coin with age restriction set
    2126             :          * was used, h_age_commitment must be provided. */
    2127           0 :         GNUNET_JSON_spec_mark_optional (
    2128           0 :           GNUNET_JSON_spec_fixed_auto ("h_age_commitment",
    2129             :                                        &dc->h_age_commitment),
    2130             :           &dc->no_h_age_commitment),
    2131           0 :         GNUNET_JSON_spec_end ()
    2132             :       };
    2133             :       enum GNUNET_GenericReturnValue res;
    2134             : 
    2135           0 :       res = TALER_MHD_parse_json_data (pc->connection,
    2136             :                                        coin,
    2137             :                                        ispec);
    2138           0 :       if (GNUNET_YES != res)
    2139             :       {
    2140           0 :         GNUNET_break_op (0);
    2141           0 :         GNUNET_JSON_parse_free (spec);
    2142           0 :         return res;
    2143             :       }
    2144             : 
    2145           0 :       for (unsigned int j = 0; j<coins_index; j++)
    2146             :       {
    2147           0 :         if (0 ==
    2148           0 :             GNUNET_memcmp (&dc->coin_pub,
    2149             :                            &pc->dc[j].coin_pub))
    2150             :         {
    2151           0 :           GNUNET_break_op (0);
    2152             :           return (MHD_YES ==
    2153           0 :                   TALER_MHD_reply_with_error (pc->connection,
    2154             :                                               MHD_HTTP_BAD_REQUEST,
    2155             :                                               TALER_EC_GENERIC_PARAMETER_MALFORMED,
    2156             :                                               "duplicate coin in list"))
    2157             :                 ? GNUNET_NO
    2158           0 :                 : GNUNET_SYSERR;
    2159             :         }
    2160             :       }
    2161             : 
    2162           0 :       dc->exchange_url = GNUNET_strdup (exchange_url);
    2163           0 :       dc->index = coins_index;
    2164           0 :       dc->pc = pc;
    2165             : 
    2166           0 :       if (0 !=
    2167           0 :           strcasecmp (dc->amount_with_fee.currency,
    2168             :                       TMH_currency))
    2169             :       {
    2170           0 :         GNUNET_break_op (0);
    2171           0 :         GNUNET_JSON_parse_free (spec);
    2172             :         return (MHD_YES ==
    2173           0 :                 TALER_MHD_reply_with_error (pc->connection,
    2174             :                                             MHD_HTTP_CONFLICT,
    2175             :                                             TALER_EC_GENERIC_CURRENCY_MISMATCH,
    2176             :                                             TMH_currency))
    2177             :               ? GNUNET_NO
    2178           0 :               : GNUNET_SYSERR;
    2179             :       }
    2180             : 
    2181             :       // Check the consistency of the (potential) age restriction
    2182             :       // information.
    2183           0 :       if (dc->no_age_commitment != dc->no_minimum_age_sig)
    2184             :       {
    2185           0 :         GNUNET_break_op (0);
    2186           0 :         GNUNET_JSON_parse_free (spec);
    2187             :         return (MHD_YES ==
    2188           0 :                 TALER_MHD_reply_with_error (
    2189             :                   pc->connection,
    2190             :                   MHD_HTTP_BAD_REQUEST,
    2191             :                   TALER_EC_GENERIC_PARAMETER_MALFORMED,
    2192             :                   "inconsistent: 'age_commitment' vs. 'minimum_age_sig'"
    2193             :                   )
    2194             :                 )
    2195             :               ? GNUNET_NO
    2196           0 :               : GNUNET_SYSERR;
    2197             :       }
    2198             :     }
    2199             :   }
    2200           0 :   GNUNET_JSON_parse_free (spec);
    2201           0 :   return GNUNET_OK;
    2202             : }
    2203             : 
    2204             : 
    2205             : /**
    2206             :  * Function called with information about a coin that was deposited.
    2207             :  * Checks if this coin is in our list of deposits as well.
    2208             :  *
    2209             :  * @param cls closure with our `struct PayContext *`
    2210             :  * @param deposit_serial which deposit operation is this about
    2211             :  * @param exchange_url URL of the exchange that issued the coin
    2212             :  * @param amount_with_fee amount the exchange will deposit for this coin
    2213             :  * @param deposit_fee fee the exchange will charge for this coin
    2214             :  * @param h_wire hash of merchant's wire details
    2215             :  * @param coin_pub public key of the coin
    2216             :  */
    2217             : static void
    2218           0 : deposit_paid_check (
    2219             :   void *cls,
    2220             :   uint64_t deposit_serial,
    2221             :   const char *exchange_url,
    2222             :   const struct TALER_MerchantWireHashP *h_wire,
    2223             :   const struct TALER_Amount *amount_with_fee,
    2224             :   const struct TALER_Amount *deposit_fee,
    2225             :   const struct TALER_CoinSpendPublicKeyP *coin_pub)
    2226             : {
    2227           0 :   struct PayContext *pc = cls;
    2228             : 
    2229           0 :   for (unsigned int i = 0; i<pc->coins_cnt; i++)
    2230             :   {
    2231           0 :     struct DepositConfirmation *dci = &pc->dc[i];
    2232             : 
    2233           0 :     if ( (0 ==
    2234           0 :           GNUNET_memcmp (&dci->coin_pub,
    2235           0 :                          coin_pub)) &&
    2236             :          (0 ==
    2237           0 :           strcmp (dci->exchange_url,
    2238           0 :                   exchange_url)) &&
    2239             :          (0 ==
    2240           0 :           TALER_amount_cmp (&dci->amount_with_fee,
    2241             :                             amount_with_fee)) )
    2242             :     {
    2243           0 :       dci->matched_in_db = true;
    2244           0 :       break;
    2245             :     }
    2246             :   }
    2247           0 : }
    2248             : 
    2249             : 
    2250             : /**
    2251             :  * Handle case where contract was already paid. Either decides
    2252             :  * the payment is idempotent, or refunds the excess payment.
    2253             :  *
    2254             :  * @param[in,out] pc context we use to handle the payment
    2255             :  * @return #GNUNET_NO if response was queued with MHD
    2256             :  *         #GNUNET_SYSERR on hard error (MHD connection must be dropped)
    2257             :  */
    2258             : static enum GNUNET_GenericReturnValue
    2259           0 : handle_contract_paid (struct PayContext *pc)
    2260             : {
    2261             :   enum GNUNET_DB_QueryStatus qs;
    2262           0 :   bool unmatched = false;
    2263             :   json_t *refunds;
    2264             : 
    2265           0 :   qs = TMH_db->lookup_deposits_by_order (TMH_db->cls,
    2266             :                                          pc->order_serial,
    2267             :                                          &deposit_paid_check,
    2268             :                                          pc);
    2269           0 :   if (qs <= 0)
    2270             :   {
    2271           0 :     GNUNET_break (0);
    2272             :     return (MHD_YES ==
    2273           0 :             TALER_MHD_reply_with_error (pc->connection,
    2274             :                                         MHD_HTTP_INTERNAL_SERVER_ERROR,
    2275             :                                         TALER_EC_GENERIC_DB_FETCH_FAILED,
    2276             :                                         "lookup_deposits_by_order"))
    2277             :        ? GNUNET_NO
    2278           0 :        : GNUNET_SYSERR;
    2279             :   }
    2280           0 :   for (unsigned int i = 0; i<pc->coins_cnt; i++)
    2281             :   {
    2282           0 :     struct DepositConfirmation *dci = &pc->dc[i];
    2283             : 
    2284           0 :     if (! dci->matched_in_db)
    2285           0 :       unmatched = true;
    2286             :   }
    2287           0 :   if (! unmatched)
    2288             :   {
    2289             :     /* Everything fine, idempotent request */
    2290             :     struct GNUNET_CRYPTO_EddsaSignature sig;
    2291             : 
    2292           0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    2293             :                 "Idempotent pay request for order `%s', signing again\n",
    2294             :                 pc->order_id);
    2295           0 :     TALER_merchant_pay_sign (&pc->h_contract_terms,
    2296           0 :                              &pc->hc->instance->merchant_priv,
    2297             :                              &sig);
    2298             :     return (MHD_YES ==
    2299           0 :             TALER_MHD_REPLY_JSON_PACK (
    2300             :               pc->connection,
    2301             :               MHD_HTTP_OK,
    2302             :               GNUNET_JSON_pack_data_auto ("sig",
    2303             :                                           &sig)))
    2304             :        ? GNUNET_NO
    2305           0 :        : GNUNET_SYSERR;
    2306             :   }
    2307             :   /* Conflict, double-payment detected! */
    2308           0 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    2309             :               "Client attempted to pay extra for already paid order `%s'\n",
    2310             :               pc->order_id);
    2311           0 :   refunds = json_array ();
    2312           0 :   GNUNET_assert (NULL != refunds);
    2313           0 :   for (unsigned int i = 0; i<pc->coins_cnt; i++)
    2314             :   {
    2315           0 :     struct DepositConfirmation *dci = &pc->dc[i];
    2316             :     struct TALER_MerchantSignatureP merchant_sig;
    2317             : 
    2318           0 :     if (dci->matched_in_db)
    2319           0 :       continue;
    2320           0 :     TALER_merchant_refund_sign (&dci->coin_pub,
    2321           0 :                                 &pc->h_contract_terms,
    2322             :                                 0, /* rtransaction id */
    2323           0 :                                 &dci->amount_with_fee,
    2324           0 :                                 &pc->hc->instance->merchant_priv,
    2325             :                                 &merchant_sig);
    2326           0 :     GNUNET_assert (
    2327             :       0 ==
    2328             :       json_array_append_new (
    2329             :         refunds,
    2330             :         GNUNET_JSON_PACK (
    2331             :           GNUNET_JSON_pack_data_auto (
    2332             :             "coin_pub",
    2333             :             &dci->coin_pub),
    2334             :           GNUNET_JSON_pack_data_auto (
    2335             :             "merchant_sig",
    2336             :             &merchant_sig),
    2337             :           TALER_JSON_pack_amount ("amount",
    2338             :                                   &dci->amount_with_fee),
    2339             :           GNUNET_JSON_pack_uint64 ("rtransaction_id",
    2340             :                                    0))));
    2341             :   }
    2342             :   return (MHD_YES ==
    2343           0 :           TALER_MHD_REPLY_JSON_PACK (
    2344             :             pc->connection,
    2345             :             MHD_HTTP_CONFLICT,
    2346             :             TALER_MHD_PACK_EC (
    2347             :               TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_ALREADY_PAID),
    2348             :             GNUNET_JSON_pack_array_steal ("refunds",
    2349             :                                           refunds)))
    2350             :        ? GNUNET_NO
    2351           0 :        : GNUNET_SYSERR;
    2352             : }
    2353             : 
    2354             : 
    2355             : /**
    2356             :  * Check the database state for the given order. * Schedules an error response in the connection on failure.
    2357             :  *
    2358             :  * @param pc context we use to handle the payment
    2359             :  * @return #GNUNET_OK on success,
    2360             :  *         #GNUNET_NO on failure (response was queued with MHD)
    2361             :  *         #GNUNET_SYSERR on hard error (MHD connection must be dropped)
    2362             :  */
    2363             : static enum GNUNET_GenericReturnValue
    2364           0 : check_contract (struct PayContext *pc)
    2365             : {
    2366             :   /* obtain contract terms */
    2367             :   enum GNUNET_DB_QueryStatus qs;
    2368           0 :   json_t *contract_terms = NULL;
    2369           0 :   bool paid = false;
    2370             : 
    2371           0 :   qs = TMH_db->lookup_contract_terms (TMH_db->cls,
    2372           0 :                                       pc->hc->instance->settings.id,
    2373             :                                       pc->order_id,
    2374             :                                       &contract_terms,
    2375             :                                       &pc->order_serial,
    2376             :                                       &paid,
    2377             :                                       NULL);
    2378           0 :   if (0 > qs)
    2379             :   {
    2380             :     /* single, read-only SQL statements should never cause
    2381             :        serialization problems */
    2382           0 :     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
    2383             :     /* Always report on hard error to enable diagnostics */
    2384           0 :     GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
    2385             :     return (MHD_YES ==
    2386           0 :             TALER_MHD_reply_with_error (pc->connection,
    2387             :                                         MHD_HTTP_INTERNAL_SERVER_ERROR,
    2388             :                                         TALER_EC_GENERIC_DB_FETCH_FAILED,
    2389             :                                         "contract terms"))
    2390             :        ? GNUNET_NO
    2391           0 :        : GNUNET_SYSERR;
    2392             :   }
    2393           0 :   if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
    2394             :   {
    2395             :     return (MHD_YES ==
    2396           0 :             TALER_MHD_reply_with_error (pc->connection,
    2397             :                                         MHD_HTTP_NOT_FOUND,
    2398             :                                         TALER_EC_MERCHANT_GENERIC_ORDER_UNKNOWN,
    2399             :                                         pc->order_id))
    2400             :        ? GNUNET_NO
    2401           0 :        : GNUNET_SYSERR;
    2402             :   }
    2403             :   /* hash contract (needed later) */
    2404           0 :   if (GNUNET_OK !=
    2405           0 :       TALER_JSON_contract_hash (contract_terms,
    2406             :                                 &pc->h_contract_terms))
    2407             :   {
    2408           0 :     GNUNET_break (0);
    2409           0 :     json_decref (contract_terms);
    2410             :     return (MHD_YES ==
    2411           0 :             TALER_MHD_reply_with_error (pc->connection,
    2412             :                                         MHD_HTTP_INTERNAL_SERVER_ERROR,
    2413             :                                         TALER_EC_GENERIC_FAILED_COMPUTE_JSON_HASH,
    2414             :                                         NULL))
    2415             :        ? GNUNET_NO
    2416           0 :        : GNUNET_SYSERR;
    2417             :   }
    2418           0 :   if (paid)
    2419             :   {
    2420           0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    2421             :                 "Order `%s' paid, checking for double-payment\n",
    2422             :                 pc->order_id);
    2423           0 :     return handle_contract_paid (pc);
    2424             :   }
    2425           0 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    2426             :               "Handling payment for order `%s' with contract hash `%s'\n",
    2427             :               pc->order_id,
    2428             :               GNUNET_h2s (&pc->h_contract_terms.hash));
    2429             : 
    2430             :   /* basic sanity check on the contract */
    2431           0 :   if (NULL == json_object_get (contract_terms,
    2432             :                                "merchant"))
    2433             :   {
    2434             :     /* invalid contract */
    2435           0 :     GNUNET_break (0);
    2436           0 :     json_decref (contract_terms);
    2437             :     return (MHD_YES ==
    2438           0 :             TALER_MHD_reply_with_error (pc->connection,
    2439             :                                         MHD_HTTP_INTERNAL_SERVER_ERROR,
    2440             :                                         TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_MERCHANT_FIELD_MISSING,
    2441             :                                         NULL))
    2442             :        ? GNUNET_NO
    2443           0 :        : GNUNET_SYSERR;
    2444             :   }
    2445             : 
    2446             :   /* Get details from contract and check fundamentals */
    2447             :   {
    2448           0 :     const char *fulfillment_url = NULL;
    2449             :     struct GNUNET_JSON_Specification espec[] = {
    2450           0 :       TALER_JSON_spec_amount ("amount",
    2451             :                               TMH_currency,
    2452             :                               &pc->amount),
    2453           0 :       GNUNET_JSON_spec_mark_optional (
    2454             :         GNUNET_JSON_spec_string ("fulfillment_url",
    2455             :                                  &fulfillment_url),
    2456             :         NULL),
    2457           0 :       TALER_JSON_spec_amount ("max_fee",
    2458             :                               TMH_currency,
    2459             :                               &pc->max_fee),
    2460           0 :       TALER_JSON_spec_amount ("max_wire_fee",
    2461             :                               TMH_currency,
    2462             :                               &pc->max_wire_fee),
    2463           0 :       GNUNET_JSON_spec_uint32 ("wire_fee_amortization",
    2464             :                                &pc->wire_fee_amortization),
    2465           0 :       GNUNET_JSON_spec_timestamp ("timestamp",
    2466             :                                   &pc->timestamp),
    2467           0 :       GNUNET_JSON_spec_timestamp ("refund_deadline",
    2468             :                                   &pc->refund_deadline),
    2469           0 :       GNUNET_JSON_spec_timestamp ("pay_deadline",
    2470             :                                   &pc->pay_deadline),
    2471           0 :       GNUNET_JSON_spec_timestamp ("wire_transfer_deadline",
    2472             :                                   &pc->wire_transfer_deadline),
    2473           0 :       GNUNET_JSON_spec_fixed_auto ("h_wire",
    2474             :                                    &pc->h_wire),
    2475           0 :       GNUNET_JSON_spec_mark_optional (
    2476             :         GNUNET_JSON_spec_uint32 ("minimum_age",
    2477           0 :                                  &pc->minimum_age),
    2478             :         NULL),
    2479           0 :       GNUNET_JSON_spec_end ()
    2480             :     };
    2481             :     enum GNUNET_GenericReturnValue res;
    2482             : 
    2483           0 :     pc->minimum_age = 0;
    2484           0 :     res = TALER_MHD_parse_internal_json_data (pc->connection,
    2485             :                                               contract_terms,
    2486             :                                               espec);
    2487           0 :     if (NULL != fulfillment_url)
    2488           0 :       pc->fulfillment_url = GNUNET_strdup (fulfillment_url);
    2489           0 :     json_decref (contract_terms);
    2490           0 :     if (GNUNET_YES != res)
    2491             :     {
    2492           0 :       GNUNET_break (0);
    2493           0 :       return res;
    2494             :     }
    2495             :   }
    2496             : 
    2497           0 :   if (GNUNET_TIME_timestamp_cmp (pc->wire_transfer_deadline,
    2498             :                                  <,
    2499             :                                  pc->refund_deadline))
    2500             :   {
    2501             :     /* This should already have been checked when creating the order! */
    2502           0 :     GNUNET_break (0);
    2503           0 :     return TALER_MHD_reply_with_error (pc->connection,
    2504             :                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
    2505             :                                        TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_REFUND_DEADLINE_PAST_WIRE_TRANSFER_DEADLINE,
    2506             :                                        NULL);
    2507             :   }
    2508           0 :   if (GNUNET_TIME_absolute_is_past (pc->pay_deadline.abs_time))
    2509             :   {
    2510             :     /* too late */
    2511             :     return (MHD_YES ==
    2512           0 :             TALER_MHD_reply_with_error (pc->connection,
    2513             :                                         MHD_HTTP_GONE,
    2514             :                                         TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_OFFER_EXPIRED,
    2515             :                                         NULL))
    2516             :        ? GNUNET_NO
    2517           0 :        : GNUNET_SYSERR;
    2518             :   }
    2519             : 
    2520             :   /* Make sure wire method (still) exists for this instance */
    2521             :   {
    2522             :     struct TMH_WireMethod *wm;
    2523             : 
    2524           0 :     wm = pc->hc->instance->wm_head;
    2525           0 :     while (0 != GNUNET_memcmp (&pc->h_wire,
    2526             :                                &wm->h_wire))
    2527           0 :       wm = wm->next;
    2528           0 :     if (NULL == wm)
    2529             :     {
    2530           0 :       GNUNET_break (0);
    2531           0 :       return TALER_MHD_reply_with_error (pc->connection,
    2532             :                                          MHD_HTTP_INTERNAL_SERVER_ERROR,
    2533             :                                          TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_WIRE_HASH_UNKNOWN,
    2534             :                                          NULL);
    2535             :     }
    2536           0 :     pc->wm = wm;
    2537             :   }
    2538             : 
    2539           0 :   return GNUNET_OK;
    2540             : }
    2541             : 
    2542             : 
    2543             : /**
    2544             :  * Handle a timeout for the processing of the pay request.
    2545             :  *
    2546             :  * @param cls our `struct PayContext`
    2547             :  */
    2548             : static void
    2549           0 : handle_pay_timeout (void *cls)
    2550             : {
    2551           0 :   struct PayContext *pc = cls;
    2552             : 
    2553           0 :   pc->timeout_task = NULL;
    2554           0 :   GNUNET_assert (GNUNET_YES == pc->suspended);
    2555           0 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    2556             :               "Resuming pay with error after timeout\n");
    2557           0 :   if (NULL != pc->fo)
    2558             :   {
    2559           0 :     TMH_EXCHANGES_find_exchange_cancel (pc->fo);
    2560           0 :     pc->fo = NULL;
    2561             :   }
    2562           0 :   resume_pay_with_error (pc,
    2563             :                          MHD_HTTP_GATEWAY_TIMEOUT,
    2564             :                          TALER_EC_MERCHANT_GENERIC_EXCHANGE_TIMEOUT,
    2565             :                          NULL);
    2566           0 : }
    2567             : 
    2568             : 
    2569             : MHD_RESULT
    2570           0 : TMH_post_orders_ID_pay (const struct TMH_RequestHandler *rh,
    2571             :                         struct MHD_Connection *connection,
    2572             :                         struct TMH_HandlerContext *hc)
    2573             : {
    2574           0 :   struct PayContext *pc = hc->ctx;
    2575             :   enum GNUNET_GenericReturnValue ret;
    2576             : 
    2577           0 :   GNUNET_assert (NULL != hc->infix);
    2578           0 :   if (NULL == pc)
    2579             :   {
    2580           0 :     pc = GNUNET_new (struct PayContext);
    2581           0 :     GNUNET_CONTAINER_DLL_insert (pc_head,
    2582             :                                  pc_tail,
    2583             :                                  pc);
    2584           0 :     pc->connection = connection;
    2585           0 :     pc->hc = hc;
    2586           0 :     pc->order_id = hc->infix;
    2587           0 :     hc->ctx = pc;
    2588           0 :     hc->cc = &pay_context_cleanup;
    2589           0 :     ret = parse_pay (pc);
    2590           0 :     if (GNUNET_OK != ret)
    2591             :       return (GNUNET_NO == ret)
    2592             :        ? MHD_YES
    2593           0 :        : MHD_NO;
    2594             :   }
    2595           0 :   if (GNUNET_SYSERR == pc->suspended)
    2596           0 :     return MHD_NO; /* during shutdown, we don't generate any more replies */
    2597           0 :   GNUNET_assert (GNUNET_NO == pc->suspended);
    2598           0 :   if (0 != pc->response_code)
    2599             :   {
    2600             :     /* We are *done* processing the request, just queue the response (!) */
    2601           0 :     if (UINT_MAX == pc->response_code)
    2602             :     {
    2603           0 :       GNUNET_break (0);
    2604           0 :       return MHD_NO; /* hard error */
    2605             :     }
    2606           0 :     return MHD_queue_response (connection,
    2607             :                                pc->response_code,
    2608             :                                pc->response);
    2609             :   }
    2610           0 :   ret = check_contract (pc);
    2611           0 :   if (GNUNET_OK != ret)
    2612             :     return (GNUNET_NO == ret)
    2613             :       ? MHD_YES
    2614           0 :       : MHD_NO;
    2615             : 
    2616             :   /* Payment not finished, suspend while we interact with the exchange */
    2617           0 :   MHD_suspend_connection (connection);
    2618           0 :   pc->suspended = GNUNET_YES;
    2619           0 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    2620             :               "Suspending pay handling while working with the exchange\n");
    2621           0 :   GNUNET_assert (NULL == pc->timeout_task);
    2622             :   pc->timeout_task
    2623           0 :     = GNUNET_SCHEDULER_add_delayed (get_pay_timeout (pc->coins_cnt),
    2624             :                                     &handle_pay_timeout,
    2625             :                                     pc);
    2626           0 :   GNUNET_assert (NULL != pc->wm);
    2627           0 :   execute_pay_transaction (pc);
    2628           0 :   return MHD_YES;
    2629             : }
    2630             : 
    2631             : 
    2632             : /* end of taler-merchant-httpd_post-orders-ID-pay.c */

Generated by: LCOV version 1.14