LCOV - code coverage report
Current view: top level - backend - taler-merchant-httpd_post-orders-ID-pay.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 760 1240 61.3 %
Date: 2025-06-23 16:22:09 Functions: 29 36 80.6 %

          Line data    Source code
       1             : /*
       2             :    This file is part of TALER
       3             :    (C) 2014-2025 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 <gnunet/gnunet_common.h>
      29             : #include <gnunet/gnunet_db_lib.h>
      30             : #include <gnunet/gnunet_json_lib.h>
      31             : #include <gnunet/gnunet_time_lib.h>
      32             : #include <jansson.h>
      33             : #include <microhttpd.h>
      34             : #include <stddef.h>
      35             : #include <stdint.h>
      36             : #include <string.h>
      37             : #include <taler/taler_dbevents.h>
      38             : #include <taler/taler_error_codes.h>
      39             : #include <taler/taler_signatures.h>
      40             : #include <taler/taler_json_lib.h>
      41             : #include <taler/taler_exchange_service.h>
      42             : #include "taler-merchant-httpd.h"
      43             : #include "taler-merchant-httpd_exchanges.h"
      44             : #include "taler-merchant-httpd_helper.h"
      45             : #include "taler-merchant-httpd_post-orders-ID-pay.h"
      46             : #include "taler-merchant-httpd_private-get-orders.h"
      47             : #include "taler_merchant_util.h"
      48             : #include "taler_merchantdb_plugin.h"
      49             : 
      50             : 
      51             : /**
      52             :  * How often do we retry the (complex!) database transaction?
      53             :  */
      54             : #define MAX_RETRIES 5
      55             : 
      56             : /**
      57             :  * Maximum number of coins that we allow per transaction.
      58             :  * Note that the limit for each batch deposit request to
      59             :  * the exchange is lower, so we may break a very large
      60             :  * number of coins up into multiple smaller requests to
      61             :  * the exchange.
      62             :  */
      63             : #define MAX_COIN_ALLOWED_COINS 1024
      64             : 
      65             : /**
      66             :  * Maximum number of tokens that we allow as inputs per transaction
      67             :  */
      68             : #define MAX_TOKEN_ALLOWED_INPUTs 64
      69             : 
      70             : /**
      71             :  * Maximum number of tokens that we allow as outputs per transaction
      72             :  */
      73             : #define MAX_TOKEN_ALLOWED_OUTPUTs 64
      74             : 
      75             : /**
      76             :  * How often do we ask the exchange again about our
      77             :  * KYC status? Very rarely, as if the user actively
      78             :  * changes it, we should usually notice anyway.
      79             :  */
      80             : #define KYC_RETRY_FREQUENCY GNUNET_TIME_UNIT_WEEKS
      81             : 
      82             : /**
      83             :  * Information we keep for an individual call to the pay handler.
      84             :  */
      85             : struct PayContext;
      86             : 
      87             : 
      88             : /**
      89             :  * Different phases of processing the /pay request.
      90             :  */
      91             : enum PayPhase
      92             : {
      93             :   /**
      94             :    * Initial phase where the request is parsed.
      95             :    */
      96             :   PP_PARSE_PAY = 0,
      97             : 
      98             :   /**
      99             :    * Parse wallet data object from the pay request.
     100             :    */
     101             :   PP_PARSE_WALLET_DATA,
     102             : 
     103             :   /**
     104             :    * Check database state for the given order.
     105             :    */
     106             :   PP_CHECK_CONTRACT,
     107             : 
     108             :   /**
     109             :    * Validate provided tokens and token envelopes.
     110             :    */
     111             :   PP_VALIDATE_TOKENS,
     112             : 
     113             :   /**
     114             :    * Check if contract has been paid.
     115             :    */
     116             :   PP_CONTRACT_PAID,
     117             : 
     118             :   /**
     119             :    * Execute payment transaction.
     120             :    */
     121             :   PP_PAY_TRANSACTION,
     122             : 
     123             :   // FIXME: new (optional) phase for DONAU interaction here.
     124             : 
     125             :   /**
     126             :    * Notify other processes about successful payment.
     127             :    */
     128             :   PP_PAYMENT_NOTIFICATION,
     129             : 
     130             :   /**
     131             :    * Create final success response.
     132             :    */
     133             :   PP_SUCCESS_RESPONSE,
     134             : 
     135             :   /**
     136             :    * Perform batch deposits with exchange(s).
     137             :    */
     138             :   PP_BATCH_DEPOSITS,
     139             : 
     140             :   /**
     141             :    * Return response in payment context.
     142             :    */
     143             :   PP_RETURN_RESPONSE,
     144             : 
     145             :   /**
     146             :    * An exchange denied a deposit, fail for
     147             :    * legal reasons.
     148             :    */
     149             :   PP_FAIL_LEGAL_REASONS,
     150             : 
     151             :   /**
     152             :    * Return #MHD_YES to end processing.
     153             :    */
     154             :   PP_END_YES,
     155             : 
     156             :   /**
     157             :    * Return #MHD_NO to end processing.
     158             :    */
     159             :   PP_END_NO
     160             : };
     161             : 
     162             : 
     163             : /**
     164             :  * Information kept during a pay request for each coin.
     165             :  */
     166             : struct DepositConfirmation
     167             : {
     168             : 
     169             :   /**
     170             :    * Reference to the main PayContext
     171             :    */
     172             :   struct PayContext *pc;
     173             : 
     174             :   /**
     175             :    * URL of the exchange that issued this coin.
     176             :    */
     177             :   char *exchange_url;
     178             : 
     179             :   /**
     180             :    * Details about the coin being deposited.
     181             :    */
     182             :   struct TALER_EXCHANGE_CoinDepositDetail cdd;
     183             : 
     184             :   /**
     185             :    * Fee charged by the exchange for the deposit operation of this coin.
     186             :    */
     187             :   struct TALER_Amount deposit_fee;
     188             : 
     189             :   /**
     190             :    * Fee charged by the exchange for the refund operation of this coin.
     191             :    */
     192             :   struct TALER_Amount refund_fee;
     193             : 
     194             :   /**
     195             :    * If a minimum age was required (i. e. pc->minimum_age is large enough),
     196             :    * this is the signature of the minimum age (as a single uint8_t), using the
     197             :    * private key to the corresponding age group.  Might be all zeroes for no
     198             :    * age attestation.
     199             :    */
     200             :   struct TALER_AgeAttestationP minimum_age_sig;
     201             : 
     202             :   /**
     203             :    * If a minimum age was required (i. e. pc->minimum_age is large enough),
     204             :    * this is the age commitment (i. e. age mask and vector of EdDSA public
     205             :    * keys, one per age group) that went into the mining of the coin.  The
     206             :    * SHA256 hash of the mask and the vector of public keys was bound to the
     207             :    * key.
     208             :    */
     209             :   struct TALER_AgeCommitment age_commitment;
     210             : 
     211             :   /**
     212             :    * Age mask in the denomination that defines the age groups.  Only
     213             :    * applicable, if minimum age was required.
     214             :    */
     215             :   struct TALER_AgeMask age_mask;
     216             : 
     217             :   /**
     218             :    * Offset of this coin into the `dc` array of all coins in the
     219             :    * @e pc.
     220             :    */
     221             :   unsigned int index;
     222             : 
     223             :   /**
     224             :    * true, if no field "age_commitment" was found in the JSON blob
     225             :    */
     226             :   bool no_age_commitment;
     227             : 
     228             :   /**
     229             :    * True, if no field "minimum_age_sig" was found in the JSON blob
     230             :    */
     231             :   bool no_minimum_age_sig;
     232             : 
     233             :   /**
     234             :    * true, if no field "h_age_commitment" was found in the JSON blob
     235             :    */
     236             :   bool no_h_age_commitment;
     237             : 
     238             :   /**
     239             :    * true if we found this coin in the database.
     240             :    */
     241             :   bool found_in_db;
     242             : 
     243             :   /**
     244             :    * true if we #deposit_paid_check() matched this coin in the database.
     245             :    */
     246             :   bool matched_in_db;
     247             : 
     248             : };
     249             : 
     250             : struct TokenUseConfirmation
     251             : {
     252             : 
     253             :   /**
     254             :    * Signature on the deposit request made using the token use private key.
     255             :    */
     256             :   struct TALER_TokenUseSignatureP sig;
     257             : 
     258             :   /**
     259             :    * Token use public key. This key was blindly signed by the merchant during
     260             :    * the token issuance process.
     261             :    */
     262             :   struct TALER_TokenUsePublicKeyP pub;
     263             : 
     264             :   /**
     265             :    * Unblinded signature on the token use public key done by the merchant.
     266             :    */
     267             :   struct TALER_TokenIssueSignature unblinded_sig;
     268             : 
     269             :   /**
     270             :    * Hash of the token issue public key associated with this token.
     271             :    * Note this is set in the validate_tokens phase.
     272             :    */
     273             :   struct TALER_TokenIssuePublicKeyHashP h_issue;
     274             : 
     275             :   /**
     276             :    * true if we found this token in the database.
     277             :    */
     278             :   bool found_in_db;
     279             : 
     280             : };
     281             : 
     282             : 
     283             : /**
     284             :  * Information about a token envelope.
     285             :  */
     286             : struct TokenEnvelope
     287             : {
     288             : 
     289             :   /**
     290             :    * Blinded token use public keys waiting to be signed.
     291             :    */
     292             :   struct TALER_TokenEnvelope blinded_token;
     293             : 
     294             : };
     295             : 
     296             : 
     297             : /**
     298             :  * (Blindly) signed token to be returned to the wallet.
     299             :  */
     300             : struct SignedOutputToken
     301             : {
     302             : 
     303             :   /**
     304             :    * Blinded token use public keys waiting to be signed.
     305             :    */
     306             :   struct TALER_BlindedTokenIssueSignature sig;
     307             : 
     308             :   /**
     309             :    * Hash of token issue public key.
     310             :    */
     311             :   struct TALER_TokenIssuePublicKeyHashP h_issue;
     312             : 
     313             : };
     314             : 
     315             : 
     316             : /**
     317             :  * Information kept during a pay request for each exchange.
     318             :  */
     319             : struct ExchangeGroup
     320             : {
     321             : 
     322             :   /**
     323             :    * Payment context this group is part of.
     324             :    */
     325             :   struct PayContext *pc;
     326             : 
     327             :   /**
     328             :    * Handle to the batch deposit operation we are performing for this
     329             :    * exchange, NULL after the operation is done.
     330             :    */
     331             :   struct TALER_EXCHANGE_BatchDepositHandle *bdh;
     332             : 
     333             :   /**
     334             :    * Handle for operation to lookup /keys (and auditors) from
     335             :    * the exchange used for this transaction; NULL if no operation is
     336             :    * pending.
     337             :    */
     338             :   struct TMH_EXCHANGES_KeysOperation *fo;
     339             : 
     340             :   /**
     341             :    * URL of the exchange that issued this coin. Aliases
     342             :    * the exchange URL of one of the coins, do not free!
     343             :    */
     344             :   const char *exchange_url;
     345             : 
     346             :   /**
     347             :    * Total deposit amount in this exchange group.
     348             :    */
     349             :   struct TALER_Amount total;
     350             : 
     351             :   /**
     352             :    * Wire fee that applies to this exchange for the
     353             :    * given payment context's wire method.
     354             :    */
     355             :   struct TALER_Amount wire_fee;
     356             : 
     357             :   /**
     358             :    * true if we already tried a forced /keys download.
     359             :    */
     360             :   bool tried_force_keys;
     361             : 
     362             :   /**
     363             :    * Did this exchange deny the transaction for legal reasons?
     364             :    */
     365             :   bool got_451;
     366             : };
     367             : 
     368             : 
     369             : /**
     370             :  * Information we keep for an individual call to the /pay handler.
     371             :  */
     372             : struct PayContext
     373             : {
     374             : 
     375             :   /**
     376             :    * Stored in a DLL.
     377             :    */
     378             :   struct PayContext *next;
     379             : 
     380             :   /**
     381             :    * Stored in a DLL.
     382             :    */
     383             :   struct PayContext *prev;
     384             : 
     385             :   /**
     386             :    * MHD connection to return to
     387             :    */
     388             :   struct MHD_Connection *connection;
     389             : 
     390             :   /**
     391             :    * Details about the client's request.
     392             :    */
     393             :   struct TMH_HandlerContext *hc;
     394             : 
     395             :   /**
     396             :    * Transaction ID given in @e root.
     397             :    */
     398             :   const char *order_id;
     399             : 
     400             :   /**
     401             :    * Response to return, NULL if we don't have one yet.
     402             :    */
     403             :   struct MHD_Response *response;
     404             : 
     405             :   /**
     406             :    * HTTP status code to use for the reply, i.e 200 for "OK".
     407             :    * Special value UINT_MAX is used to indicate hard errors
     408             :    * (no reply, return #MHD_NO).
     409             :    */
     410             :   unsigned int response_code;
     411             : 
     412             :   /**
     413             :    * Payment processing phase we are in.
     414             :    */
     415             :   enum PayPhase phase;
     416             : 
     417             :   /**
     418             :    * #GNUNET_NO if the @e connection was not suspended,
     419             :    * #GNUNET_YES if the @e connection was suspended,
     420             :    * #GNUNET_SYSERR if @e connection was resumed to as
     421             :    * part of #MH_force_pc_resume during shutdown.
     422             :    */
     423             :   enum GNUNET_GenericReturnValue suspended;
     424             : 
     425             :   /**
     426             :    * Results from the phase_parse_pay()
     427             :    */
     428             :   struct
     429             :   {
     430             : 
     431             :     /**
     432             :      * Array with @e num_exchanges exchanges we are depositing
     433             :      * coins into.
     434             :      */
     435             :     struct ExchangeGroup **egs;
     436             : 
     437             :     /**
     438             :      * Array with @e coins_cnt coins we are despositing.
     439             :      */
     440             :     struct DepositConfirmation *dc;
     441             : 
     442             :     /**
     443             :      * Array with @e tokens_cnt input tokens passed to this request.
     444             :      */
     445             :     struct TokenUseConfirmation *tokens;
     446             : 
     447             :     /**
     448             :      * Optional session id given in @e root.
     449             :      * NULL if not given.
     450             :      */
     451             :     char *session_id;
     452             : 
     453             :     /**
     454             :      * Wallet data json object from the request. Containing additional
     455             :      * wallet data such as the selected choice_index.
     456             :      */
     457             :     const json_t *wallet_data;
     458             : 
     459             :     /**
     460             :      * Number of coins this payment is made of.  Length
     461             :      * of the @e dc array.
     462             :      */
     463             :     size_t coins_cnt;
     464             : 
     465             :     /**
     466             :      * Number of input tokens passed to this request.  Length
     467             :      * of the @e tokens array.
     468             :      */
     469             :     size_t tokens_cnt;
     470             : 
     471             :     /**
     472             :      * Number of exchanges involved in the payment. Length
     473             :      * of the @e eg array.
     474             :      */
     475             :     unsigned int num_exchanges;
     476             : 
     477             :   } parse_pay;
     478             : 
     479             :   /**
     480             :    * Results from the phase_wallet_data()
     481             :    */
     482             :   struct
     483             :   {
     484             : 
     485             :     /**
     486             :      * Array with @e token_envelopes_cnt (blinded) token envelopes.
     487             :      */
     488             :     struct TokenEnvelope *token_envelopes;
     489             : 
     490             :     /**
     491             :      * Index of selected choice in the @e contract_terms choices array.
     492             :      */
     493             :     int16_t choice_index;
     494             : 
     495             :     /**
     496             :      * Number of token envelopes passed to this request.
     497             :      * Length of the @e token_envelopes array.
     498             :      */
     499             :     size_t token_envelopes_cnt;
     500             : 
     501             :     /**
     502             :      * Hash of the canonicalized wallet data json object.
     503             :      */
     504             :     struct GNUNET_HashCode h_wallet_data;
     505             : 
     506             :   } parse_wallet_data;
     507             : 
     508             :   /**
     509             :    * Results from the phase_check_contract()
     510             :    */
     511             :   struct
     512             :   {
     513             : 
     514             :     /**
     515             :      * Hashed @e contract_terms.
     516             :      */
     517             :     struct TALER_PrivateContractHashP h_contract_terms;
     518             : 
     519             :     /**
     520             :      * Our contract (or NULL if not available).
     521             :      */
     522             :     json_t *contract_terms_json;
     523             : 
     524             :     /**
     525             :      * Parsed contract terms, NULL when parsing failed.
     526             :      */
     527             :     struct TALER_MERCHANT_Contract *contract_terms;
     528             : 
     529             :     /**
     530             :      * What wire method (of the @e mi) was selected by the wallet?
     531             :      * Set in #phase_parse_pay().
     532             :      */
     533             :     struct TMH_WireMethod *wm;
     534             : 
     535             :     /**
     536             :      * Set to the POS key, if applicable for this order.
     537             :      */
     538             :     char *pos_key;
     539             : 
     540             :     /**
     541             :      * Serial number of this order in the database (set once we did the lookup).
     542             :      */
     543             :     uint64_t order_serial;
     544             : 
     545             :     /**
     546             :      * Algorithm chosen for generating the confirmation code.
     547             :      */
     548             :     enum TALER_MerchantConfirmationAlgorithm pos_alg;
     549             : 
     550             :   } check_contract;
     551             : 
     552             :   /**
     553             :    * Results from the phase_validate_tokens()
     554             :    */
     555             :   struct
     556             :   {
     557             : 
     558             :     /**
     559             :      * Maximum fee the merchant is willing to pay, from @e root.
     560             :      * Note that IF the total fee of the exchange is higher, that is
     561             :      * acceptable to the merchant if the customer is willing to
     562             :      * pay the difference
     563             :      * (i.e. amount - max_fee <= actual_amount - actual_fee).
     564             :      */
     565             :     struct TALER_Amount max_fee;
     566             : 
     567             :     /**
     568             :      * Amount from @e root.  This is the amount the merchant expects
     569             :      * to make, minus @e max_fee.
     570             :      */
     571             :     struct TALER_Amount brutto;
     572             : 
     573             :     /**
     574             :      * Array with @e output_tokens_len signed tokens returned in
     575             :      * the response to the wallet.
     576             :      */
     577             :     struct SignedOutputToken *output_tokens;
     578             : 
     579             :     /**
     580             :      * Number of output tokens to return in the response.
     581             :      * Length of the @e output_tokens array.
     582             :      */
     583             :     unsigned int output_tokens_len;
     584             : 
     585             :   } validate_tokens;
     586             : 
     587             :   /**
     588             :    * Results from the phase_execute_pay_transaction()
     589             :    */
     590             :   struct
     591             :   {
     592             : 
     593             :     /**
     594             :      * Considering all the coins with the "found_in_db" flag
     595             :      * set, what is the total amount we were so far paid on
     596             :      * this contract?
     597             :      */
     598             :     struct TALER_Amount total_paid;
     599             : 
     600             :     /**
     601             :      * Considering all the coins with the "found_in_db" flag
     602             :      * set, what is the total amount we had to pay in deposit
     603             :      * fees so far on this contract?
     604             :      */
     605             :     struct TALER_Amount total_fees_paid;
     606             : 
     607             :     /**
     608             :      * Considering all the coins with the "found_in_db" flag
     609             :      * set, what is the total amount we already refunded?
     610             :      */
     611             :     struct TALER_Amount total_refunded;
     612             : 
     613             :     /**
     614             :      * Number of coin deposits pending.
     615             :      */
     616             :     unsigned int pending;
     617             : 
     618             :     /**
     619             :      * How often have we retried the 'main' transaction?
     620             :      */
     621             :     unsigned int retry_counter;
     622             : 
     623             :     /**
     624             :      * Set to true if the deposit currency of a coin
     625             :      * does not match the contract currency.
     626             :      */
     627             :     bool deposit_currency_mismatch;
     628             : 
     629             :     /**
     630             :      * Set to true if the database contains a (bogus)
     631             :      * refund for a different currency.
     632             :      */
     633             :     bool refund_currency_mismatch;
     634             : 
     635             :   } pay_transaction;
     636             : 
     637             :   /**
     638             :    * Results from the phase_batch_deposits()
     639             :    */
     640             :   struct
     641             :   {
     642             : 
     643             :     /**
     644             :      * Task called when the (suspended) processing for
     645             :      * the /pay request times out.
     646             :      * Happens when we don't get a response from the exchange.
     647             :      */
     648             :     struct GNUNET_SCHEDULER_Task *timeout_task;
     649             : 
     650             :     /**
     651             :      * Number of batch transactions pending.
     652             :      */
     653             :     unsigned int pending_at_eg;
     654             : 
     655             :     /**
     656             :      * Did any exchange deny a deposit for legal reasons?
     657             :      */
     658             :     bool got_451;
     659             : 
     660             :   } batch_deposits;
     661             : 
     662             : };
     663             : 
     664             : 
     665             : /**
     666             :  * Head of active pay context DLL.
     667             :  */
     668             : static struct PayContext *pc_head;
     669             : 
     670             : /**
     671             :  * Tail of active pay context DLL.
     672             :  */
     673             : static struct PayContext *pc_tail;
     674             : 
     675             : 
     676             : void
     677          14 : TMH_force_pc_resume ()
     678             : {
     679          14 :   for (struct PayContext *pc = pc_head;
     680          14 :        NULL != pc;
     681           0 :        pc = pc->next)
     682             :   {
     683           0 :     if (NULL != pc->batch_deposits.timeout_task)
     684             :     {
     685           0 :       GNUNET_SCHEDULER_cancel (pc->batch_deposits.timeout_task);
     686           0 :       pc->batch_deposits.timeout_task = NULL;
     687             :     }
     688           0 :     if (GNUNET_YES == pc->suspended)
     689             :     {
     690           0 :       pc->suspended = GNUNET_SYSERR;
     691           0 :       MHD_resume_connection (pc->connection);
     692             :     }
     693             :   }
     694          14 : }
     695             : 
     696             : 
     697             : /**
     698             :  * Resume payment processing.
     699             :  *
     700             :  * @param[in,out] pc payment process to resume
     701             :  */
     702             : static void
     703          34 : pay_resume (struct PayContext *pc)
     704             : {
     705          34 :   GNUNET_assert (GNUNET_YES == pc->suspended);
     706          34 :   pc->suspended = GNUNET_NO;
     707          34 :   MHD_resume_connection (pc->connection);
     708          34 :   TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */
     709          34 : }
     710             : 
     711             : 
     712             : /**
     713             :  * Resume the given pay context and send the given response.
     714             :  * Stores the response in the @a pc and signals MHD to resume
     715             :  * the connection.  Also ensures MHD runs immediately.
     716             :  *
     717             :  * @param pc payment context
     718             :  * @param response_code response code to use
     719             :  * @param response response data to send back
     720             :  */
     721             : static void
     722           6 : resume_pay_with_response (struct PayContext *pc,
     723             :                           unsigned int response_code,
     724             :                           struct MHD_Response *response)
     725             : {
     726           6 :   pc->response_code = response_code;
     727           6 :   pc->response = response;
     728           6 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     729             :               "Resuming /pay handling. HTTP status for our reply is %u.\n",
     730             :               response_code);
     731          12 :   for (unsigned int i = 0; i<pc->parse_pay.num_exchanges; i++)
     732             :   {
     733           6 :     struct ExchangeGroup *eg = pc->parse_pay.egs[i];
     734             : 
     735           6 :     if (NULL != eg->fo)
     736             :     {
     737           0 :       TMH_EXCHANGES_keys4exchange_cancel (eg->fo);
     738           0 :       eg->fo = NULL;
     739           0 :       pc->batch_deposits.pending_at_eg--;
     740             :     }
     741           6 :     if (NULL != eg->bdh)
     742             :     {
     743           0 :       TALER_EXCHANGE_batch_deposit_cancel (eg->bdh);
     744           0 :       eg->bdh = NULL;
     745           0 :       pc->batch_deposits.pending_at_eg--;
     746             :     }
     747             :   }
     748           6 :   GNUNET_assert (0 == pc->batch_deposits.pending_at_eg);
     749           6 :   if (NULL != pc->batch_deposits.timeout_task)
     750             :   {
     751           6 :     GNUNET_SCHEDULER_cancel (pc->batch_deposits.timeout_task);
     752           6 :     pc->batch_deposits.timeout_task = NULL;
     753             :   }
     754           6 :   pc->phase = PP_RETURN_RESPONSE;
     755           6 :   pay_resume (pc);
     756           6 : }
     757             : 
     758             : 
     759             : /**
     760             :  * Resume payment processing with an error.
     761             :  *
     762             :  * @param pc operation to resume
     763             :  * @param ec taler error code to return
     764             :  * @param msg human readable error message
     765             :  */
     766             : static void
     767           0 : resume_pay_with_error (struct PayContext *pc,
     768             :                        enum TALER_ErrorCode ec,
     769             :                        const char *msg)
     770             : {
     771           0 :   resume_pay_with_response (
     772             :     pc,
     773             :     TALER_ErrorCode_get_http_status_safe (ec),
     774             :     TALER_MHD_make_error (ec,
     775             :                           msg));
     776           0 : }
     777             : 
     778             : 
     779             : /**
     780             :  * Conclude payment processing for @a pc with the
     781             :  * given @a res MHD status code.
     782             :  *
     783             :  * @param[in,out] pc payment context for final state transition
     784             :  * @param res MHD return code to end with
     785             :  */
     786             : static void
     787          42 : pay_end (struct PayContext *pc,
     788             :          MHD_RESULT res)
     789             : {
     790          42 :   pc->phase = (MHD_YES == res)
     791             :     ? PP_END_YES
     792          42 :     : PP_END_NO;
     793          42 : }
     794             : 
     795             : 
     796             : /**
     797             :  * Return response stored in @a pc.
     798             :  *
     799             :  * @param[in,out] pc payment context we are processing
     800             :  */
     801             : static void
     802           6 : phase_return_response (struct PayContext *pc)
     803             : {
     804           6 :   GNUNET_assert (0 != pc->response_code);
     805             :   /* We are *done* processing the request, just queue the response (!) */
     806           6 :   if (UINT_MAX == pc->response_code)
     807             :   {
     808           0 :     GNUNET_break (0);
     809           0 :     pay_end (pc,
     810             :              MHD_NO); /* hard error */
     811           0 :     return;
     812             :   }
     813           6 :   pay_end (pc,
     814             :            MHD_queue_response (pc->connection,
     815             :                                pc->response_code,
     816             :                                pc->response));
     817             : }
     818             : 
     819             : 
     820             : /**
     821             :  * Return a response indicating failure for legal reasons.
     822             :  *
     823             :  * @param[in,out] pc payment context we are processing
     824             :  */
     825             : static void
     826           0 : phase_fail_for_legal_reasons (struct PayContext *pc)
     827             : {
     828             :   json_t *exchanges;
     829             : 
     830           0 :   GNUNET_assert (0 == pc->pay_transaction.pending);
     831           0 :   GNUNET_assert (pc->batch_deposits.got_451);
     832           0 :   exchanges = json_array ();
     833           0 :   GNUNET_assert (NULL != exchanges);
     834           0 :   for (unsigned int i = 0; i<pc->parse_pay.num_exchanges; i++)
     835             :   {
     836           0 :     struct ExchangeGroup *eg = pc->parse_pay.egs[i];
     837             : 
     838           0 :     GNUNET_assert (NULL == eg->fo);
     839           0 :     GNUNET_assert (NULL == eg->bdh);
     840           0 :     if (! eg->got_451)
     841           0 :       continue;
     842           0 :     GNUNET_assert (
     843             :       0 ==
     844             :       json_array_append_new (
     845             :         exchanges,
     846             :         json_string (eg->exchange_url)));
     847             :   }
     848           0 :   pay_end (pc,
     849           0 :            TALER_MHD_REPLY_JSON_PACK (
     850             :              pc->connection,
     851             :              MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS,
     852             :              GNUNET_JSON_pack_array_steal ("exchange_base_urls",
     853             :                                            exchanges)));
     854           0 : }
     855             : 
     856             : 
     857             : /**
     858             :  * Do database transaction for a completed batch deposit.
     859             :  *
     860             :  * @param eg group that completed
     861             :  * @param dr response from the server
     862             :  * @return transaction status
     863             :  */
     864             : static enum GNUNET_DB_QueryStatus
     865          28 : batch_deposit_transaction (const struct ExchangeGroup *eg,
     866             :                            const struct TALER_EXCHANGE_BatchDepositResult *dr)
     867             : {
     868          28 :   const struct PayContext *pc = eg->pc;
     869             :   enum GNUNET_DB_QueryStatus qs;
     870             :   struct TALER_Amount total_without_fees;
     871             :   uint64_t b_dep_serial;
     872          28 :   uint32_t off = 0;
     873             : 
     874          28 :   GNUNET_assert (GNUNET_OK ==
     875             :                  TALER_amount_set_zero (pc->validate_tokens.brutto.currency,
     876             :                                         &total_without_fees));
     877          62 :   for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++)
     878             :   {
     879          34 :     struct DepositConfirmation *dc = &pc->parse_pay.dc[i];
     880             :     struct TALER_Amount amount_without_fees;
     881             : 
     882             :     /* might want to group deposits by batch more explicitly ... */
     883          34 :     if (0 != strcmp (eg->exchange_url,
     884          34 :                      dc->exchange_url))
     885           0 :       continue;
     886          34 :     if (dc->found_in_db)
     887           0 :       continue;
     888          34 :     GNUNET_assert (0 <=
     889             :                    TALER_amount_subtract (&amount_without_fees,
     890             :                                           &dc->cdd.amount,
     891             :                                           &dc->deposit_fee));
     892          34 :     GNUNET_assert (0 <=
     893             :                    TALER_amount_add (&total_without_fees,
     894             :                                      &total_without_fees,
     895             :                                      &amount_without_fees));
     896             :   }
     897          28 :   qs = TMH_db->insert_deposit_confirmation (
     898          28 :     TMH_db->cls,
     899          28 :     pc->hc->instance->settings.id,
     900             :     dr->details.ok.deposit_timestamp,
     901             :     &pc->check_contract.h_contract_terms,
     902          28 :     eg->exchange_url,
     903          28 :     pc->check_contract.contract_terms->wire_deadline,
     904             :     &total_without_fees,
     905             :     &eg->wire_fee,
     906          28 :     &pc->check_contract.wm->h_wire,
     907          28 :     dr->details.ok.exchange_sig,
     908          28 :     dr->details.ok.exchange_pub,
     909             :     &b_dep_serial);
     910          28 :   if (qs <= 0)
     911           0 :     return qs; /* Entire batch already known or failure, we're done */
     912             : 
     913          62 :   for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++)
     914             :   {
     915          34 :     struct DepositConfirmation *dc = &pc->parse_pay.dc[i];
     916             : 
     917             :     /* might want to group deposits by batch more explicitly ... */
     918          34 :     if (0 != strcmp (eg->exchange_url,
     919          34 :                      dc->exchange_url))
     920           0 :       continue;
     921          34 :     if (dc->found_in_db)
     922           0 :       continue;
     923             :     /* FIXME-#9457: We might want to check if the order was fully paid concurrently
     924             :        by some other wallet here, and if so, issue an auto-refund. Right now,
     925             :        it is possible to over-pay if two wallets literally make a concurrent
     926             :        payment, as the earlier check for 'paid' is not in the same transaction
     927             :        scope as this 'insert' operation. */
     928          34 :     qs = TMH_db->insert_deposit (
     929          34 :       TMH_db->cls,
     930             :       off++, /* might want to group deposits by batch more explicitly ... */
     931             :       b_dep_serial,
     932          34 :       &dc->cdd.coin_pub,
     933          34 :       &dc->cdd.coin_sig,
     934          34 :       &dc->cdd.amount,
     935          34 :       &dc->deposit_fee,
     936          34 :       &dc->refund_fee);
     937          34 :     if (qs < 0)
     938           0 :       return qs;
     939          34 :     GNUNET_break (qs > 0);
     940             :   }
     941          28 :   return qs;
     942             : }
     943             : 
     944             : 
     945             : /**
     946             :  * Handle case where the batch deposit completed
     947             :  * with a status of #MHD_HTTP_OK.
     948             :  *
     949             :  * @param eg group that completed
     950             :  * @param dr response from the server
     951             :  */
     952             : static void
     953          28 : handle_batch_deposit_ok (struct ExchangeGroup *eg,
     954             :                          const struct TALER_EXCHANGE_BatchDepositResult *dr)
     955             : {
     956          28 :   struct PayContext *pc = eg->pc;
     957          28 :   enum GNUNET_DB_QueryStatus qs
     958             :     = GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
     959             : 
     960             :   /* store result to DB */
     961          28 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     962             :               "Storing successful payment %s (%s) at instance `%s'\n",
     963             :               pc->hc->infix,
     964             :               GNUNET_h2s (&pc->check_contract.h_contract_terms.hash),
     965             :               pc->hc->instance->settings.id);
     966          28 :   for (unsigned int r = 0; r<MAX_RETRIES; r++)
     967             :   {
     968          28 :     TMH_db->preflight (TMH_db->cls);
     969          28 :     if (GNUNET_OK !=
     970          28 :         TMH_db->start (TMH_db->cls,
     971             :                        "batch-deposit-insert-confirmation"))
     972             :     {
     973           0 :       resume_pay_with_response (
     974             :         pc,
     975             :         MHD_HTTP_INTERNAL_SERVER_ERROR,
     976           0 :         TALER_MHD_MAKE_JSON_PACK (
     977             :           TALER_JSON_pack_ec (
     978             :             TALER_EC_GENERIC_DB_START_FAILED),
     979             :           TMH_pack_exchange_reply (&dr->hr)));
     980           0 :       return;
     981             :     }
     982          28 :     qs = batch_deposit_transaction (eg,
     983             :                                     dr);
     984          28 :     if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
     985             :     {
     986           0 :       TMH_db->rollback (TMH_db->cls);
     987           0 :       continue;
     988             :     }
     989          28 :     if (GNUNET_DB_STATUS_HARD_ERROR == qs)
     990             :     {
     991           0 :       GNUNET_break (0);
     992           0 :       resume_pay_with_error (pc,
     993             :                              TALER_EC_GENERIC_DB_COMMIT_FAILED,
     994             :                              "batch_deposit_transaction");
     995             :     }
     996          28 :     qs = TMH_db->commit (TMH_db->cls);
     997          28 :     if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
     998             :     {
     999           0 :       TMH_db->rollback (TMH_db->cls);
    1000           0 :       continue;
    1001             :     }
    1002          28 :     if (GNUNET_DB_STATUS_HARD_ERROR == qs)
    1003             :     {
    1004           0 :       GNUNET_break (0);
    1005           0 :       resume_pay_with_error (pc,
    1006             :                              TALER_EC_GENERIC_DB_COMMIT_FAILED,
    1007             :                              "insert_deposit");
    1008             :     }
    1009          28 :     break; /* DB transaction succeeded */
    1010             :   }
    1011          28 :   if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
    1012             :   {
    1013           0 :     resume_pay_with_error (pc,
    1014             :                            TALER_EC_GENERIC_DB_SOFT_FAILURE,
    1015             :                            "insert_deposit");
    1016           0 :     return;
    1017             :   }
    1018             : 
    1019             :   /* Transaction is done, mark affected coins as complete as well. */
    1020          62 :   for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++)
    1021             :   {
    1022          34 :     struct DepositConfirmation *dc = &pc->parse_pay.dc[i];
    1023             : 
    1024          34 :     if (0 != strcmp (eg->exchange_url,
    1025          34 :                      pc->parse_pay.dc[i].exchange_url))
    1026           0 :       continue;
    1027          34 :     if (dc->found_in_db)
    1028           0 :       continue;
    1029          34 :     dc->found_in_db = true;     /* well, at least NOW it'd be true ;-) */
    1030          34 :     pc->pay_transaction.pending--;
    1031             :   }
    1032             : }
    1033             : 
    1034             : 
    1035             : /**
    1036             :  * Notify taler-merchant-kyccheck that we got a KYC
    1037             :  * rule violation notification and should start to
    1038             :  * check our KYC status.
    1039             :  *
    1040             :  * @param eg exchange group we were notified for
    1041             :  */
    1042             : static void
    1043           0 : notify_kyc_required (const struct ExchangeGroup *eg)
    1044             : {
    1045           0 :   struct GNUNET_DB_EventHeaderP es = {
    1046           0 :     .size = htons (sizeof (es)),
    1047           0 :     .type = htons (TALER_DBEVENT_MERCHANT_EXCHANGE_KYC_RULE_TRIGGERED)
    1048             :   };
    1049             :   char *hws;
    1050             :   char *extra;
    1051             : 
    1052           0 :   hws = GNUNET_STRINGS_data_to_string_alloc (
    1053           0 :     &eg->pc->check_contract.contract_terms->h_wire,
    1054             :     sizeof (eg->pc->check_contract.contract_terms->h_wire));
    1055           0 :   GNUNET_asprintf (&extra,
    1056             :                    "%s %s",
    1057             :                    hws,
    1058           0 :                    eg->exchange_url);
    1059           0 :   GNUNET_free (hws);
    1060           0 :   TMH_db->event_notify (TMH_db->cls,
    1061             :                         &es,
    1062             :                         extra,
    1063           0 :                         strlen (extra) + 1);
    1064           0 :   GNUNET_free (extra);
    1065           0 : }
    1066             : 
    1067             : 
    1068             : /**
    1069             :  * Callback to handle a batch deposit permission's response.
    1070             :  *
    1071             :  * @param cls a `struct ExchangeGroup`
    1072             :  * @param dr HTTP response code details
    1073             :  */
    1074             : static void
    1075          34 : batch_deposit_cb (
    1076             :   void *cls,
    1077             :   const struct TALER_EXCHANGE_BatchDepositResult *dr)
    1078             : {
    1079          34 :   struct ExchangeGroup *eg = cls;
    1080          34 :   struct PayContext *pc = eg->pc;
    1081             : 
    1082          34 :   eg->bdh = NULL;
    1083          34 :   pc->batch_deposits.pending_at_eg--;
    1084          34 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1085             :               "Batch deposit completed with status %u\n",
    1086             :               dr->hr.http_status);
    1087          34 :   GNUNET_assert (GNUNET_YES == pc->suspended);
    1088          34 :   switch (dr->hr.http_status)
    1089             :   {
    1090          28 :   case MHD_HTTP_OK:
    1091          28 :     handle_batch_deposit_ok (eg,
    1092             :                              dr);
    1093          28 :     if (0 == pc->batch_deposits.pending_at_eg)
    1094             :     {
    1095          28 :       pc->phase = PP_PAY_TRANSACTION;
    1096          28 :       pay_resume (pc);
    1097             :     }
    1098          28 :     return;
    1099           0 :   case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
    1100           0 :     notify_kyc_required (eg);
    1101           0 :     eg->got_451 = true;
    1102           0 :     pc->batch_deposits.got_451 = true;
    1103             :     /* update pc->pay_transaction.pending */
    1104           0 :     for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++)
    1105             :     {
    1106           0 :       struct DepositConfirmation *dc = &pc->parse_pay.dc[i];
    1107             : 
    1108           0 :       if (0 != strcmp (eg->exchange_url,
    1109           0 :                        pc->parse_pay.dc[i].exchange_url))
    1110           0 :         continue;
    1111           0 :       if (dc->found_in_db)
    1112           0 :         continue;
    1113           0 :       pc->pay_transaction.pending--;
    1114             :     }
    1115           0 :     if (0 == pc->batch_deposits.pending_at_eg)
    1116             :     {
    1117           0 :       pc->phase = PP_PAY_TRANSACTION;
    1118           0 :       pay_resume (pc);
    1119             :     }
    1120           0 :     return;
    1121           6 :   default:
    1122           6 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1123             :                 "Deposit operation failed with HTTP code %u/%d\n",
    1124             :                 dr->hr.http_status,
    1125             :                 (int) dr->hr.ec);
    1126             :     /* Transaction failed */
    1127           6 :     if (5 == dr->hr.http_status / 100)
    1128             :     {
    1129             :       /* internal server error at exchange */
    1130           0 :       resume_pay_with_response (pc,
    1131             :                                 MHD_HTTP_BAD_GATEWAY,
    1132           0 :                                 TALER_MHD_MAKE_JSON_PACK (
    1133             :                                   TALER_JSON_pack_ec (
    1134             :                                     TALER_EC_MERCHANT_GENERIC_EXCHANGE_UNEXPECTED_STATUS),
    1135             :                                   TMH_pack_exchange_reply (&dr->hr)));
    1136           0 :       return;
    1137             :     }
    1138           6 :     if (NULL == dr->hr.reply)
    1139             :     {
    1140             :       /* We can't do anything meaningful here, the exchange did something wrong */
    1141           0 :       resume_pay_with_response (
    1142             :         pc,
    1143             :         MHD_HTTP_BAD_GATEWAY,
    1144           0 :         TALER_MHD_MAKE_JSON_PACK (
    1145             :           TALER_JSON_pack_ec (
    1146             :             TALER_EC_MERCHANT_GENERIC_EXCHANGE_REPLY_MALFORMED),
    1147             :           TMH_pack_exchange_reply (&dr->hr)));
    1148           0 :       return;
    1149             :     }
    1150             : 
    1151             :     /* Forward error, adding the "exchange_url" for which the
    1152             :        error was being generated */
    1153           6 :     if (TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS == dr->hr.ec)
    1154             :     {
    1155           6 :       resume_pay_with_response (
    1156             :         pc,
    1157             :         MHD_HTTP_CONFLICT,
    1158           6 :         TALER_MHD_MAKE_JSON_PACK (
    1159             :           TALER_JSON_pack_ec (
    1160             :             TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_INSUFFICIENT_FUNDS),
    1161             :           TMH_pack_exchange_reply (&dr->hr),
    1162             :           GNUNET_JSON_pack_string ("exchange_url",
    1163             :                                    eg->exchange_url)));
    1164           6 :       return;
    1165             :     }
    1166           0 :     resume_pay_with_response (
    1167             :       pc,
    1168             :       MHD_HTTP_BAD_GATEWAY,
    1169           0 :       TALER_MHD_MAKE_JSON_PACK (
    1170             :         TALER_JSON_pack_ec (
    1171             :           TALER_EC_MERCHANT_GENERIC_EXCHANGE_UNEXPECTED_STATUS),
    1172             :         TMH_pack_exchange_reply (&dr->hr),
    1173             :         GNUNET_JSON_pack_string ("exchange_url",
    1174             :                                  eg->exchange_url)));
    1175           0 :     return;
    1176             :   } /* end switch */
    1177             : }
    1178             : 
    1179             : 
    1180             : /**
    1181             :  * Force re-downloading keys for @a eg.
    1182             :  *
    1183             :  * @param[in,out] eg group to re-download keys for
    1184             :  */
    1185             : static void
    1186             : force_keys (struct ExchangeGroup *eg);
    1187             : 
    1188             : 
    1189             : /**
    1190             :  * Function called with the result of our exchange keys lookup.
    1191             :  *
    1192             :  * @param cls the `struct ExchangeGroup`
    1193             :  * @param keys the keys of the exchange
    1194             :  * @param exchange representation of the exchange
    1195             :  */
    1196             : static void
    1197          34 : process_pay_with_keys (
    1198             :   void *cls,
    1199             :   struct TALER_EXCHANGE_Keys *keys,
    1200             :   struct TMH_Exchange *exchange)
    1201             : {
    1202          34 :   struct ExchangeGroup *eg = cls;
    1203          34 :   struct PayContext *pc = eg->pc;
    1204          34 :   struct TMH_HandlerContext *hc = pc->hc;
    1205             :   unsigned int group_size;
    1206             :   struct TALER_Amount max_amount;
    1207             : 
    1208          34 :   eg->fo = NULL;
    1209          34 :   pc->batch_deposits.pending_at_eg--;
    1210          34 :   GNUNET_SCHEDULER_begin_async_scope (&hc->async_scope_id);
    1211          34 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1212             :               "Processing payment with keys from exchange %s\n",
    1213             :               eg->exchange_url);
    1214          34 :   GNUNET_assert (GNUNET_YES == pc->suspended);
    1215          34 :   if (NULL == keys)
    1216             :   {
    1217           0 :     GNUNET_break_op (0);
    1218           0 :     resume_pay_with_error (
    1219             :       pc,
    1220             :       TALER_EC_MERCHANT_GENERIC_EXCHANGE_TIMEOUT,
    1221             :       NULL);
    1222           0 :     return;
    1223             :   }
    1224          34 :   if (! TMH_EXCHANGES_is_below_limit (keys,
    1225             :                                       TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION,
    1226          34 :                                       &eg->total))
    1227             :   {
    1228           0 :     GNUNET_break_op (0);
    1229           0 :     resume_pay_with_error (
    1230             :       pc,
    1231             :       TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_EXCHANGE_TRANSACTION_LIMIT_VIOLATION,
    1232             :       eg->exchange_url);
    1233           0 :     return;
    1234             :   }
    1235             : 
    1236          34 :   max_amount = eg->total;
    1237          34 :   if (GNUNET_OK !=
    1238          34 :       TMH_exchange_check_debit (
    1239          34 :         pc->hc->instance->settings.id,
    1240             :         exchange,
    1241          34 :         pc->check_contract.wm,
    1242             :         &max_amount))
    1243             :   {
    1244           0 :     if (eg->tried_force_keys)
    1245             :     {
    1246           0 :       GNUNET_break_op (0);
    1247           0 :       resume_pay_with_error (
    1248             :         pc,
    1249             :         TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_WIRE_METHOD_UNSUPPORTED,
    1250             :         NULL);
    1251           0 :       return;
    1252             :     }
    1253           0 :     force_keys (eg);
    1254           0 :     return;
    1255             :   }
    1256          34 :   if (-1 ==
    1257          34 :       TALER_amount_cmp (&max_amount,
    1258          34 :                         &eg->total))
    1259             :   {
    1260             :     /* max_amount < eg->total */
    1261           0 :     GNUNET_break_op (0);
    1262           0 :     resume_pay_with_error (
    1263             :       pc,
    1264             :       TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_EXCHANGE_TRANSACTION_LIMIT_VIOLATION,
    1265             :       eg->exchange_url);
    1266           0 :     return;
    1267             :   }
    1268             : 
    1269          34 :   if (GNUNET_OK !=
    1270          34 :       TMH_EXCHANGES_lookup_wire_fee (exchange,
    1271          34 :                                      pc->check_contract.wm->wire_method,
    1272             :                                      &eg->wire_fee))
    1273             :   {
    1274           0 :     if (eg->tried_force_keys)
    1275             :     {
    1276           0 :       GNUNET_break_op (0);
    1277           0 :       resume_pay_with_error (
    1278             :         pc,
    1279             :         TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_WIRE_METHOD_UNSUPPORTED,
    1280           0 :         pc->check_contract.wm->wire_method);
    1281           0 :       return;
    1282             :     }
    1283           0 :     force_keys (eg);
    1284           0 :     return;
    1285             :   }
    1286          34 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1287             :               "Got wire data for %s\n",
    1288             :               eg->exchange_url);
    1289             : 
    1290             :   /* Initiate /batch-deposit operation for all coins of
    1291             :      the current exchange (!) */
    1292          34 :   group_size = 0;
    1293          76 :   for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++)
    1294             :   {
    1295          42 :     struct DepositConfirmation *dc = &pc->parse_pay.dc[i];
    1296             :     const struct TALER_EXCHANGE_DenomPublicKey *denom_details;
    1297          42 :     bool is_age_restricted_denom = false;
    1298             : 
    1299          42 :     if (0 != strcmp (eg->exchange_url,
    1300          42 :                      pc->parse_pay.dc[i].exchange_url))
    1301           0 :       continue;
    1302          42 :     if (dc->found_in_db)
    1303           0 :       continue;
    1304             : 
    1305             :     denom_details
    1306          42 :       = TALER_EXCHANGE_get_denomination_key_by_hash (keys,
    1307          42 :                                                      &dc->cdd.h_denom_pub);
    1308          42 :     if (NULL == denom_details)
    1309             :     {
    1310           0 :       if (eg->tried_force_keys)
    1311             :       {
    1312           0 :         GNUNET_break_op (0);
    1313           0 :         resume_pay_with_response (
    1314             :           pc,
    1315             :           MHD_HTTP_BAD_REQUEST,
    1316           0 :           TALER_MHD_MAKE_JSON_PACK (
    1317             :             TALER_JSON_pack_ec (
    1318             :               TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_DENOMINATION_KEY_NOT_FOUND),
    1319             :             GNUNET_JSON_pack_data_auto ("h_denom_pub",
    1320             :                                         &dc->cdd.h_denom_pub),
    1321             :             GNUNET_JSON_pack_allow_null (
    1322             :               GNUNET_JSON_pack_object_steal (
    1323             :                 "exchange_keys",
    1324             :                 TALER_EXCHANGE_keys_to_json (keys)))));
    1325           0 :         return;
    1326             :       }
    1327           0 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1328             :                   "Missing denomination %s from exchange %s, updating keys\n",
    1329             :                   GNUNET_h2s (&dc->cdd.h_denom_pub.hash),
    1330             :                   eg->exchange_url);
    1331           0 :       force_keys (eg);
    1332           0 :       return;
    1333             :     }
    1334          42 :     dc->deposit_fee = denom_details->fees.deposit;
    1335          42 :     dc->refund_fee = denom_details->fees.refund;
    1336             : 
    1337          42 :     if (GNUNET_TIME_absolute_is_past (
    1338             :           denom_details->expire_deposit.abs_time))
    1339             :     {
    1340           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1341             :                   "Denomination key offered by client has expired for deposits\n");
    1342           0 :       resume_pay_with_response (
    1343             :         pc,
    1344             :         MHD_HTTP_GONE,
    1345           0 :         TALER_MHD_MAKE_JSON_PACK (
    1346             :           TALER_JSON_pack_ec (
    1347             :             TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_DENOMINATION_DEPOSIT_EXPIRED),
    1348             :           GNUNET_JSON_pack_data_auto ("h_denom_pub",
    1349             :                                       &denom_details->h_key)));
    1350           0 :       return;
    1351             :     }
    1352             : 
    1353             :     /* Now that we have the details about the denomination, we can verify age
    1354             :      * restriction requirements, if applicable. Note that denominations with an
    1355             :      * age_mask equal to zero always pass the age verification.  */
    1356          42 :     is_age_restricted_denom = (0 != denom_details->key.age_mask.bits);
    1357             : 
    1358          42 :     if (is_age_restricted_denom &&
    1359           0 :         (0 < pc->check_contract.contract_terms->minimum_age))
    1360           0 :     {
    1361             :       /* Minimum age given and restricted coin provided: We need to verify the
    1362             :        * minimum age */
    1363           0 :       unsigned int code = 0;
    1364             : 
    1365           0 :       if (dc->no_age_commitment)
    1366             :       {
    1367           0 :         GNUNET_break_op (0);
    1368           0 :         code = TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AGE_COMMITMENT_MISSING;
    1369           0 :         goto AGE_FAIL;
    1370             :       }
    1371           0 :       dc->age_commitment.mask = denom_details->key.age_mask;
    1372           0 :       if (((int) (dc->age_commitment.num + 1)) !=
    1373           0 :           __builtin_popcount (dc->age_commitment.mask.bits))
    1374             :       {
    1375           0 :         GNUNET_break_op (0);
    1376           0 :         code =
    1377             :           TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AGE_COMMITMENT_SIZE_MISMATCH;
    1378           0 :         goto AGE_FAIL;
    1379             :       }
    1380           0 :       if (GNUNET_OK !=
    1381           0 :           TALER_age_commitment_verify (
    1382           0 :             &dc->age_commitment,
    1383           0 :             pc->check_contract.contract_terms->minimum_age,
    1384           0 :             &dc->minimum_age_sig))
    1385           0 :         code = TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AGE_VERIFICATION_FAILED;
    1386           0 : AGE_FAIL:
    1387           0 :       if (0 < code)
    1388             :       {
    1389           0 :         GNUNET_break_op (0);
    1390           0 :         TALER_age_commitment_free (&dc->age_commitment);
    1391           0 :         resume_pay_with_response (
    1392             :           pc,
    1393             :           MHD_HTTP_BAD_REQUEST,
    1394           0 :           TALER_MHD_MAKE_JSON_PACK (
    1395             :             TALER_JSON_pack_ec (code),
    1396             :             GNUNET_JSON_pack_data_auto ("h_denom_pub",
    1397             :                                         &denom_details->h_key)));
    1398           0 :         return;
    1399             :       }
    1400             : 
    1401             :       /* Age restriction successfully verified!
    1402             :        * Calculate the hash of the age commitment. */
    1403           0 :       TALER_age_commitment_hash (&dc->age_commitment,
    1404             :                                  &dc->cdd.h_age_commitment);
    1405           0 :       TALER_age_commitment_free (&dc->age_commitment);
    1406             :     }
    1407          42 :     else if (is_age_restricted_denom &&
    1408           0 :              dc->no_h_age_commitment)
    1409             :     {
    1410             :       /* The contract did not ask for a minimum_age but the client paid
    1411             :        * with a coin that has age restriction enabled.  We lack the hash
    1412             :        * of the age commitment in this case in order to verify the coin
    1413             :        * and to deposit it with the exchange. */
    1414           0 :       GNUNET_break_op (0);
    1415           0 :       resume_pay_with_response (
    1416             :         pc,
    1417             :         MHD_HTTP_BAD_REQUEST,
    1418           0 :         TALER_MHD_MAKE_JSON_PACK (
    1419             :           TALER_JSON_pack_ec (
    1420             :             TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AGE_COMMITMENT_HASH_MISSING),
    1421             :           GNUNET_JSON_pack_data_auto ("h_denom_pub",
    1422             :                                       &denom_details->h_key)));
    1423           0 :       return;
    1424             :     }
    1425          42 :     group_size++;
    1426             :   }
    1427             : 
    1428          34 :   if (0 == group_size)
    1429             :   {
    1430           0 :     GNUNET_break (0);
    1431           0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1432             :                 "Group size zero, %u batch transactions remain pending\n",
    1433             :                 pc->batch_deposits.pending_at_eg);
    1434           0 :     if (0 == pc->batch_deposits.pending_at_eg)
    1435             :     {
    1436           0 :       pc->phase = PP_PAY_TRANSACTION;
    1437           0 :       pay_resume (pc);
    1438           0 :       return;
    1439             :     }
    1440           0 :     return;
    1441             :   }
    1442          34 :   if (group_size > TALER_MAX_COINS)
    1443           0 :     group_size = TALER_MAX_COINS;
    1444          34 :   {
    1445          34 :     struct TALER_EXCHANGE_CoinDepositDetail cdds[group_size];
    1446          34 :     struct TALER_EXCHANGE_DepositContractDetail dcd = {
    1447          34 :       .wire_deadline = pc->check_contract.contract_terms->wire_deadline,
    1448          34 :       .merchant_payto_uri = pc->check_contract.wm->payto_uri,
    1449          34 :       .wire_salt = pc->check_contract.wm->wire_salt,
    1450             :       .h_contract_terms = pc->check_contract.h_contract_terms,
    1451             :       .wallet_data_hash = pc->parse_wallet_data.h_wallet_data,
    1452          34 :       .wallet_timestamp = pc->check_contract.contract_terms->timestamp,
    1453          34 :       .merchant_pub = hc->instance->merchant_pub,
    1454          34 :       .refund_deadline = pc->check_contract.contract_terms->refund_deadline
    1455             :     };
    1456             :     enum TALER_ErrorCode ec;
    1457          34 :     size_t off = 0;
    1458             : 
    1459          34 :     TALER_merchant_contract_sign (&pc->check_contract.h_contract_terms,
    1460          34 :                                   &pc->hc->instance->merchant_priv,
    1461             :                                   &dcd.merchant_sig);
    1462          42 :     for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++)
    1463             :     {
    1464          42 :       struct DepositConfirmation *dc = &pc->parse_pay.dc[i];
    1465             : 
    1466          42 :       if (dc->found_in_db)
    1467           0 :         continue;
    1468          42 :       if (0 != strcmp (dc->exchange_url,
    1469             :                        eg->exchange_url))
    1470           0 :         continue;
    1471          42 :       cdds[off++] = dc->cdd;
    1472          42 :       if (off >= group_size)
    1473          34 :         break;
    1474             :     }
    1475          34 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1476             :                 "Initiating batch deposit with %u coins\n",
    1477             :                 group_size);
    1478             :     /* Note: the coin signatures over the wallet_data_hash are
    1479             :        checked inside of this call */
    1480          34 :     eg->bdh = TALER_EXCHANGE_batch_deposit (
    1481             :       TMH_curl_ctx,
    1482             :       eg->exchange_url,
    1483             :       keys,
    1484             :       &dcd,
    1485             :       group_size,
    1486             :       cdds,
    1487             :       &batch_deposit_cb,
    1488             :       eg,
    1489             :       &ec);
    1490          34 :     if (NULL == eg->bdh)
    1491             :     {
    1492             :       /* Signature was invalid or some other constraint was not satisfied.  If
    1493             :          the exchange was unavailable, we'd get that information in the
    1494             :          callback. */
    1495           0 :       GNUNET_break_op (0);
    1496           0 :       resume_pay_with_response (
    1497             :         pc,
    1498             :         TALER_ErrorCode_get_http_status_safe (ec),
    1499           0 :         TALER_MHD_MAKE_JSON_PACK (
    1500             :           TALER_JSON_pack_ec (ec),
    1501             :           GNUNET_JSON_pack_string ("exchange_url",
    1502             :                                    eg->exchange_url)));
    1503           0 :       return;
    1504             :     }
    1505          34 :     pc->batch_deposits.pending_at_eg++;
    1506          34 :     if (TMH_force_audit)
    1507           8 :       TALER_EXCHANGE_batch_deposit_force_dc (eg->bdh);
    1508             :   }
    1509             : }
    1510             : 
    1511             : 
    1512             : static void
    1513           0 : force_keys (struct ExchangeGroup *eg)
    1514             : {
    1515           0 :   struct PayContext *pc = eg->pc;
    1516             : 
    1517           0 :   eg->tried_force_keys = true;
    1518           0 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1519             :               "Forcing /keys download (once)\n");
    1520           0 :   eg->fo = TMH_EXCHANGES_keys4exchange (
    1521             :     eg->exchange_url,
    1522             :     true,
    1523             :     &process_pay_with_keys,
    1524             :     eg);
    1525           0 :   if (NULL == eg->fo)
    1526             :   {
    1527           0 :     GNUNET_break_op (0);
    1528           0 :     resume_pay_with_error (pc,
    1529             :                            TALER_EC_MERCHANT_GENERIC_EXCHANGE_UNTRUSTED,
    1530             :                            eg->exchange_url);
    1531           0 :     return;
    1532             :   }
    1533           0 :   pc->batch_deposits.pending_at_eg++;
    1534             : }
    1535             : 
    1536             : 
    1537             : /**
    1538             :  * Handle a timeout for the processing of the pay request.
    1539             :  *
    1540             :  * @param cls our `struct PayContext`
    1541             :  */
    1542             : static void
    1543           0 : handle_pay_timeout (void *cls)
    1544             : {
    1545           0 :   struct PayContext *pc = cls;
    1546             : 
    1547           0 :   pc->batch_deposits.timeout_task = NULL;
    1548           0 :   GNUNET_assert (GNUNET_YES == pc->suspended);
    1549           0 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1550             :               "Resuming pay with error after timeout\n");
    1551           0 :   resume_pay_with_error (pc,
    1552             :                          TALER_EC_MERCHANT_GENERIC_EXCHANGE_TIMEOUT,
    1553             :                          NULL);
    1554           0 : }
    1555             : 
    1556             : 
    1557             : /**
    1558             :  * Compute the timeout for a /pay request based on the number of coins
    1559             :  * involved.
    1560             :  *
    1561             :  * @param num_coins number of coins
    1562             :  * @returns timeout for the /pay request
    1563             :  */
    1564             : static struct GNUNET_TIME_Relative
    1565          34 : get_pay_timeout (unsigned int num_coins)
    1566             : {
    1567             :   struct GNUNET_TIME_Relative t;
    1568             : 
    1569             :   /* FIXME-Performance-Optimization: Do some benchmarking to come up with a
    1570             :    * better timeout.  We've increased this value so the wallet integration
    1571             :    * test passes again on my (Florian) machine.
    1572             :    */
    1573          34 :   t = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
    1574          34 :                                      15 * (1 + (num_coins / 5)));
    1575             : 
    1576          34 :   return t;
    1577             : }
    1578             : 
    1579             : 
    1580             : /**
    1581             :  * Start batch deposits for all exchanges involved
    1582             :  * in this payment.
    1583             :  *
    1584             :  * @param[in,out] pc payment context we are processing
    1585             :  */
    1586             : static void
    1587          34 : phase_batch_deposits (struct PayContext *pc)
    1588             : {
    1589          68 :   for (unsigned int i = 0; i<pc->parse_pay.num_exchanges; i++)
    1590             :   {
    1591          34 :     struct ExchangeGroup *eg = pc->parse_pay.egs[i];
    1592          34 :     bool have_coins = false;
    1593             : 
    1594          34 :     for (size_t j = 0; j<pc->parse_pay.coins_cnt; j++)
    1595             :     {
    1596          34 :       struct DepositConfirmation *dc = &pc->parse_pay.dc[j];
    1597             : 
    1598          34 :       if (0 != strcmp (eg->exchange_url,
    1599          34 :                        dc->exchange_url))
    1600           0 :         continue;
    1601          34 :       if (dc->found_in_db)
    1602           0 :         continue;
    1603          34 :       have_coins = true;
    1604          34 :       break;
    1605             :     }
    1606          34 :     if (! have_coins)
    1607           0 :       continue; /* no coins left to deposit at this exchange */
    1608          34 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1609             :                 "Getting /keys for %s\n",
    1610             :                 eg->exchange_url);
    1611          34 :     eg->fo = TMH_EXCHANGES_keys4exchange (
    1612             :       eg->exchange_url,
    1613             :       false,
    1614             :       &process_pay_with_keys,
    1615             :       eg);
    1616          34 :     if (NULL == eg->fo)
    1617             :     {
    1618           0 :       GNUNET_break_op (0);
    1619           0 :       pay_end (pc,
    1620             :                TALER_MHD_reply_with_error (
    1621             :                  pc->connection,
    1622             :                  MHD_HTTP_BAD_REQUEST,
    1623             :                  TALER_EC_MERCHANT_GENERIC_EXCHANGE_UNTRUSTED,
    1624             :                  eg->exchange_url));
    1625           0 :       return;
    1626             :     }
    1627          34 :     pc->batch_deposits.pending_at_eg++;
    1628             :   }
    1629          34 :   if (0 == pc->batch_deposits.pending_at_eg)
    1630             :   {
    1631           0 :     pc->phase = PP_PAY_TRANSACTION;
    1632           0 :     pay_resume (pc);
    1633           0 :     return;
    1634             :   }
    1635             :   /* Suspend while we interact with the exchange */
    1636          34 :   MHD_suspend_connection (pc->connection);
    1637          34 :   pc->suspended = GNUNET_YES;
    1638          34 :   GNUNET_assert (NULL == pc->batch_deposits.timeout_task);
    1639             :   pc->batch_deposits.timeout_task
    1640          34 :     = GNUNET_SCHEDULER_add_delayed (get_pay_timeout (pc->parse_pay.coins_cnt),
    1641             :                                     &handle_pay_timeout,
    1642             :                                     pc);
    1643             : }
    1644             : 
    1645             : 
    1646             : /**
    1647             :  * Build JSON array of blindly signed token envelopes,
    1648             :  * to be used in the response to the wallet.
    1649             :  *
    1650             :  * @param[in,out] pc payment context to use
    1651             :  */
    1652             : static json_t *
    1653           4 : build_token_sigs (struct PayContext *pc)
    1654             : {
    1655           4 :   json_t *token_sigs = json_array ();
    1656             : 
    1657           4 :   GNUNET_assert (NULL != token_sigs);
    1658           8 :   for (unsigned int i = 0; i < pc->validate_tokens.output_tokens_len; i++)
    1659             :   {
    1660           4 :     GNUNET_assert (0 ==
    1661             :                    json_array_append_new (
    1662             :                      token_sigs,
    1663             :                      GNUNET_JSON_PACK (
    1664             :                        GNUNET_JSON_pack_blinded_sig (
    1665             :                          "blind_sig",
    1666             :                          pc->validate_tokens.output_tokens[i].sig.signature)
    1667             :                        )));
    1668             :   }
    1669           4 :   return token_sigs;
    1670             : }
    1671             : 
    1672             : 
    1673             : /**
    1674             :  * Generate response (payment successful)
    1675             :  *
    1676             :  * @param[in,out] pc payment context where the payment was successful
    1677             :  */
    1678             : static void
    1679          30 : phase_success_response (struct PayContext *pc)
    1680             : {
    1681             :   struct TALER_MerchantSignatureP sig;
    1682             :   char *pos_confirmation;
    1683             :   json_t *token_sigs;
    1684             : 
    1685             :   /* Sign on our end (as the payment did go through, even if it may
    1686             :      have been refunded already) */
    1687          30 :   TALER_merchant_pay_sign (&pc->check_contract.h_contract_terms,
    1688          30 :                            &pc->hc->instance->merchant_priv,
    1689             :                            &sig);
    1690             :   /* Build the response */
    1691          60 :   pos_confirmation = (NULL == pc->check_contract.pos_key)
    1692             :     ? NULL
    1693          30 :     : TALER_build_pos_confirmation (pc->check_contract.pos_key,
    1694             :                                     pc->check_contract.pos_alg,
    1695           2 :                                     &pc->validate_tokens.brutto,
    1696           2 :                                     pc->check_contract.contract_terms->timestamp
    1697             :                                     );
    1698          60 :   token_sigs = (0 >= pc->validate_tokens.output_tokens_len)
    1699             :     ? NULL
    1700          30 :     : build_token_sigs (pc);
    1701             :   // FIXME: add signatures obtained from donau to response
    1702          30 :   pay_end (pc,
    1703          30 :            TALER_MHD_REPLY_JSON_PACK (
    1704             :              pc->connection,
    1705             :              MHD_HTTP_OK,
    1706             :              GNUNET_JSON_pack_allow_null (
    1707             :                GNUNET_JSON_pack_string ("pos_confirmation",
    1708             :                                         pos_confirmation)),
    1709             :              GNUNET_JSON_pack_allow_null (
    1710             :                GNUNET_JSON_pack_array_steal ("token_sigs",
    1711             :                                              token_sigs)),
    1712             :              GNUNET_JSON_pack_data_auto ("sig",
    1713             :                                          &sig)));
    1714          30 :   GNUNET_free (pos_confirmation);
    1715          30 : }
    1716             : 
    1717             : 
    1718             : /**
    1719             :  * Use database to notify other clients about the
    1720             :  * payment being completed.
    1721             :  *
    1722             :  * @param[in,out] pc context to trigger notification for
    1723             :  */
    1724             : static void
    1725          28 : phase_payment_notification (struct PayContext *pc)
    1726             : {
    1727             :   {
    1728          28 :     struct TMH_OrderPayEventP pay_eh = {
    1729          28 :       .header.size = htons (sizeof (pay_eh)),
    1730          28 :       .header.type = htons (TALER_DBEVENT_MERCHANT_ORDER_PAID),
    1731          28 :       .merchant_pub = pc->hc->instance->merchant_pub
    1732             :     };
    1733             : 
    1734          28 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1735             :                 "Notifying clients about payment of order %s\n",
    1736             :                 pc->order_id);
    1737          28 :     GNUNET_CRYPTO_hash (pc->order_id,
    1738             :                         strlen (pc->order_id),
    1739             :                         &pay_eh.h_order_id);
    1740          28 :     TMH_db->event_notify (TMH_db->cls,
    1741             :                           &pay_eh.header,
    1742             :                           NULL,
    1743             :                           0);
    1744             :   }
    1745          28 :   if ( (NULL != pc->parse_pay.session_id) &&
    1746          28 :        (NULL != pc->check_contract.contract_terms->fulfillment_url) )
    1747             :   {
    1748          16 :     struct TMH_SessionEventP session_eh = {
    1749          16 :       .header.size = htons (sizeof (session_eh)),
    1750          16 :       .header.type = htons (TALER_DBEVENT_MERCHANT_SESSION_CAPTURED),
    1751          16 :       .merchant_pub = pc->hc->instance->merchant_pub
    1752             :     };
    1753             : 
    1754          16 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1755             :                 "Notifying clients about session change to %s for %s\n",
    1756             :                 pc->parse_pay.session_id,
    1757             :                 pc->check_contract.contract_terms->fulfillment_url);
    1758          16 :     GNUNET_CRYPTO_hash (pc->parse_pay.session_id,
    1759          16 :                         strlen (pc->parse_pay.session_id),
    1760             :                         &session_eh.h_session_id);
    1761          16 :     GNUNET_CRYPTO_hash (pc->check_contract.contract_terms->fulfillment_url,
    1762          16 :                         strlen (pc->check_contract.contract_terms->
    1763             :                                 fulfillment_url),
    1764             :                         &session_eh.h_fulfillment_url);
    1765          16 :     TMH_db->event_notify (TMH_db->cls,
    1766             :                           &session_eh.header,
    1767             :                           NULL,
    1768             :                           0);
    1769             :   }
    1770          28 :   pc->phase = PP_SUCCESS_RESPONSE;
    1771          28 : }
    1772             : 
    1773             : 
    1774             : /**
    1775             :  * Function called with information about a coin that was deposited.
    1776             :  *
    1777             :  * @param cls closure
    1778             :  * @param exchange_url exchange where @a coin_pub was deposited
    1779             :  * @param coin_pub public key of the coin
    1780             :  * @param amount_with_fee amount the exchange will deposit for this coin
    1781             :  * @param deposit_fee fee the exchange will charge for this coin
    1782             :  * @param refund_fee fee the exchange will charge for refunding this coin
    1783             :  */
    1784             : static void
    1785          36 : check_coin_paid (void *cls,
    1786             :                  const char *exchange_url,
    1787             :                  const struct TALER_CoinSpendPublicKeyP *coin_pub,
    1788             :                  const struct TALER_Amount *amount_with_fee,
    1789             :                  const struct TALER_Amount *deposit_fee,
    1790             :                  const struct TALER_Amount *refund_fee)
    1791             : {
    1792          36 :   struct PayContext *pc = cls;
    1793             : 
    1794          84 :   for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++)
    1795             :   {
    1796          48 :     struct DepositConfirmation *dc = &pc->parse_pay.dc[i];
    1797             : 
    1798          48 :     if (dc->found_in_db)
    1799           6 :       continue; /* processed earlier, skip "expensive" memcmp() */
    1800             :     /* Get matching coin from results*/
    1801          42 :     if ( (0 != GNUNET_memcmp (coin_pub,
    1802          34 :                               &dc->cdd.coin_pub)) ||
    1803             :          (0 !=
    1804          34 :           strcmp (exchange_url,
    1805          68 :                   dc->exchange_url)) ||
    1806             :          (GNUNET_OK !=
    1807          34 :           TALER_amount_cmp_currency (amount_with_fee,
    1808          68 :                                      &dc->cdd.amount)) ||
    1809          34 :          (0 != TALER_amount_cmp (amount_with_fee,
    1810          34 :                                  &dc->cdd.amount)) )
    1811           8 :       continue; /* does not match, skip */
    1812          34 :     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    1813             :                 "Deposit of coin `%s' already in our DB.\n",
    1814             :                 TALER_B2S (coin_pub));
    1815          34 :     if ( (GNUNET_OK !=
    1816          34 :           TALER_amount_cmp_currency (&pc->pay_transaction.total_paid,
    1817          34 :                                      amount_with_fee)) ||
    1818             :          (GNUNET_OK !=
    1819          34 :           TALER_amount_cmp_currency (&pc->pay_transaction.total_fees_paid,
    1820             :                                      deposit_fee)) )
    1821             :     {
    1822           0 :       GNUNET_break_op (0);
    1823           0 :       pc->pay_transaction.deposit_currency_mismatch = true;
    1824           0 :       break;
    1825             :     }
    1826          34 :     GNUNET_assert (0 <=
    1827             :                    TALER_amount_add (&pc->pay_transaction.total_paid,
    1828             :                                      &pc->pay_transaction.total_paid,
    1829             :                                      amount_with_fee));
    1830          34 :     GNUNET_assert (0 <=
    1831             :                    TALER_amount_add (&pc->pay_transaction.total_fees_paid,
    1832             :                                      &pc->pay_transaction.total_fees_paid,
    1833             :                                      deposit_fee));
    1834          34 :     dc->deposit_fee = *deposit_fee;
    1835          34 :     dc->refund_fee = *refund_fee;
    1836          34 :     dc->cdd.amount = *amount_with_fee;
    1837          34 :     dc->found_in_db = true;
    1838          34 :     pc->pay_transaction.pending--;
    1839             :   }
    1840          36 : }
    1841             : 
    1842             : 
    1843             : /**
    1844             :  * Function called with information about a refund.  Check if this coin was
    1845             :  * claimed by the wallet for the transaction, and if so add the refunded
    1846             :  * amount to the pc's "total_refunded" amount.
    1847             :  *
    1848             :  * @param cls closure with a `struct PayContext`
    1849             :  * @param coin_pub public coin from which the refund comes from
    1850             :  * @param refund_amount refund amount which is being taken from @a coin_pub
    1851             :  */
    1852             : static void
    1853           0 : check_coin_refunded (void *cls,
    1854             :                      const struct TALER_CoinSpendPublicKeyP *coin_pub,
    1855             :                      const struct TALER_Amount *refund_amount)
    1856             : {
    1857           0 :   struct PayContext *pc = cls;
    1858             : 
    1859             :   /* We look at refunds here that apply to the coins
    1860             :      that the customer is currently trying to pay us with.
    1861             : 
    1862             :      Such refunds are not "normal" refunds, but abort-pay refunds, which are
    1863             :      given in the case that the wallet aborts the payment.
    1864             :      In the case the wallet then decides to complete the payment *after* doing
    1865             :      an abort-pay refund (an unusual but possible case), we need
    1866             :      to make sure that existing refunds are accounted for. */
    1867             : 
    1868           0 :   for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++)
    1869             :   {
    1870           0 :     struct DepositConfirmation *dc = &pc->parse_pay.dc[i];
    1871             : 
    1872             :     /* Get matching coins from results.  */
    1873           0 :     if (0 != GNUNET_memcmp (coin_pub,
    1874             :                             &dc->cdd.coin_pub))
    1875           0 :       continue;
    1876           0 :     if (GNUNET_OK !=
    1877           0 :         TALER_amount_cmp_currency (&pc->pay_transaction.total_refunded,
    1878             :                                    refund_amount))
    1879             :     {
    1880           0 :       GNUNET_break (0);
    1881           0 :       pc->pay_transaction.refund_currency_mismatch = true;
    1882           0 :       break;
    1883             :     }
    1884           0 :     GNUNET_assert (0 <=
    1885             :                    TALER_amount_add (&pc->pay_transaction.total_refunded,
    1886             :                                      &pc->pay_transaction.total_refunded,
    1887             :                                      refund_amount));
    1888           0 :     break;
    1889             :   }
    1890           0 : }
    1891             : 
    1892             : 
    1893             : /**
    1894             :  * Check whether the amount paid is sufficient to cover the price.
    1895             :  *
    1896             :  * @param pc payment context to check
    1897             :  * @return true if the payment is sufficient, false if it is
    1898             :  *         insufficient
    1899             :  */
    1900             : static bool
    1901          30 : check_payment_sufficient (struct PayContext *pc)
    1902             : {
    1903             :   struct TALER_Amount acc_fee;
    1904             :   struct TALER_Amount acc_amount;
    1905             :   struct TALER_Amount final_amount;
    1906             :   struct TALER_Amount total_wire_fee;
    1907             :   struct TALER_Amount total_needed;
    1908             : 
    1909          30 :   if (0 == pc->parse_pay.coins_cnt)
    1910           2 :     return TALER_amount_is_zero (&pc->validate_tokens.brutto);
    1911          28 :   GNUNET_assert (GNUNET_OK ==
    1912             :                  TALER_amount_set_zero (pc->validate_tokens.brutto.currency,
    1913             :                                         &total_wire_fee));
    1914          56 :   for (unsigned int i = 0; i < pc->parse_pay.num_exchanges; i++)
    1915             :   {
    1916          28 :     if (GNUNET_OK !=
    1917          28 :         TALER_amount_cmp_currency (&total_wire_fee,
    1918          28 :                                    &pc->parse_pay.egs[i]->wire_fee))
    1919             :     {
    1920           0 :       GNUNET_break_op (0);
    1921           0 :       pay_end (pc,
    1922             :                TALER_MHD_reply_with_error (pc->connection,
    1923             :                                            MHD_HTTP_BAD_REQUEST,
    1924             :                                            TALER_EC_GENERIC_CURRENCY_MISMATCH,
    1925             :                                            total_wire_fee.currency));
    1926           0 :       return false;
    1927             :     }
    1928          28 :     if (0 >
    1929          28 :         TALER_amount_add (&total_wire_fee,
    1930             :                           &total_wire_fee,
    1931          28 :                           &pc->parse_pay.egs[i]->wire_fee))
    1932             :     {
    1933           0 :       GNUNET_break (0);
    1934           0 :       pay_end (pc,
    1935             :                TALER_MHD_reply_with_error (
    1936             :                  pc->connection,
    1937             :                  MHD_HTTP_INTERNAL_SERVER_ERROR,
    1938             :                  TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_EXCHANGE_WIRE_FEE_ADDITION_FAILED,
    1939             :                  "could not add exchange wire fee to total"));
    1940           0 :       return false;
    1941             :     }
    1942             :   }
    1943             : 
    1944             :   /**
    1945             :    * This loops calculates what are the deposit fee / total
    1946             :    * amount with fee / and wire fee, for all the coins.
    1947             :    */
    1948          28 :   GNUNET_assert (GNUNET_OK ==
    1949             :                  TALER_amount_set_zero (pc->validate_tokens.brutto.currency,
    1950             :                                         &acc_fee));
    1951          28 :   GNUNET_assert (GNUNET_OK ==
    1952             :                  TALER_amount_set_zero (pc->validate_tokens.brutto.currency,
    1953             :                                         &acc_amount));
    1954          62 :   for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++)
    1955             :   {
    1956          34 :     struct DepositConfirmation *dc = &pc->parse_pay.dc[i];
    1957             : 
    1958          34 :     GNUNET_assert (dc->found_in_db);
    1959          34 :     if ( (GNUNET_OK !=
    1960          34 :           TALER_amount_cmp_currency (&acc_fee,
    1961          68 :                                      &dc->deposit_fee)) ||
    1962             :          (GNUNET_OK !=
    1963          34 :           TALER_amount_cmp_currency (&acc_amount,
    1964          34 :                                      &dc->cdd.amount)) )
    1965             :     {
    1966           0 :       GNUNET_break_op (0);
    1967           0 :       pay_end (pc,
    1968             :                TALER_MHD_reply_with_error (
    1969             :                  pc->connection,
    1970             :                  MHD_HTTP_BAD_REQUEST,
    1971             :                  TALER_EC_GENERIC_CURRENCY_MISMATCH,
    1972           0 :                  dc->deposit_fee.currency));
    1973           0 :       return false;
    1974             :     }
    1975          34 :     if ( (0 >
    1976          34 :           TALER_amount_add (&acc_fee,
    1977          34 :                             &dc->deposit_fee,
    1978          34 :                             &acc_fee)) ||
    1979             :          (0 >
    1980          34 :           TALER_amount_add (&acc_amount,
    1981          34 :                             &dc->cdd.amount,
    1982             :                             &acc_amount)) )
    1983             :     {
    1984           0 :       GNUNET_break (0);
    1985             :       /* Overflow in these amounts? Very strange. */
    1986           0 :       pay_end (pc,
    1987             :                TALER_MHD_reply_with_error (
    1988             :                  pc->connection,
    1989             :                  MHD_HTTP_INTERNAL_SERVER_ERROR,
    1990             :                  TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AMOUNT_OVERFLOW,
    1991             :                  "Overflow adding up amounts"));
    1992           0 :       return false;
    1993             :     }
    1994          34 :     if (1 ==
    1995          34 :         TALER_amount_cmp (&dc->deposit_fee,
    1996          34 :                           &dc->cdd.amount))
    1997             :     {
    1998           0 :       GNUNET_break_op (0);
    1999           0 :       pay_end (pc,
    2000             :                TALER_MHD_reply_with_error (
    2001             :                  pc->connection,
    2002             :                  MHD_HTTP_BAD_REQUEST,
    2003             :                  TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_FEES_EXCEED_PAYMENT,
    2004             :                  "Deposit fees exceed coin's contribution"));
    2005           0 :       return false;
    2006             :     }
    2007             :   } /* end deposit loop */
    2008             : 
    2009          28 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    2010             :               "Amount received from wallet: %s\n",
    2011             :               TALER_amount2s (&acc_amount));
    2012          28 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    2013             :               "Deposit fee for all coins: %s\n",
    2014             :               TALER_amount2s (&acc_fee));
    2015          28 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    2016             :               "Total wire fee: %s\n",
    2017             :               TALER_amount2s (&total_wire_fee));
    2018          28 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    2019             :               "Deposit fee limit for merchant: %s\n",
    2020             :               TALER_amount2s (&pc->validate_tokens.max_fee));
    2021          28 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    2022             :               "Total refunded amount: %s\n",
    2023             :               TALER_amount2s (&pc->pay_transaction.total_refunded));
    2024             : 
    2025             :   /* Now compare exchange wire fee compared to what we are willing to pay */
    2026          28 :   if (GNUNET_YES !=
    2027          28 :       TALER_amount_cmp_currency (&total_wire_fee,
    2028             :                                  &acc_fee))
    2029             :   {
    2030           0 :     GNUNET_break (0);
    2031           0 :     pay_end (pc,
    2032             :              TALER_MHD_reply_with_error (
    2033             :                pc->connection,
    2034             :                MHD_HTTP_BAD_REQUEST,
    2035             :                TALER_EC_GENERIC_CURRENCY_MISMATCH,
    2036             :                total_wire_fee.currency));
    2037           0 :     return false;
    2038             :   }
    2039             : 
    2040             :   /* add wire fee to the total fees */
    2041          28 :   if (0 >
    2042          28 :       TALER_amount_add (&acc_fee,
    2043             :                         &acc_fee,
    2044             :                         &total_wire_fee))
    2045             :   {
    2046           0 :     GNUNET_break (0);
    2047           0 :     pay_end (pc,
    2048             :              TALER_MHD_reply_with_error (
    2049             :                pc->connection,
    2050             :                MHD_HTTP_INTERNAL_SERVER_ERROR,
    2051             :                TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AMOUNT_OVERFLOW,
    2052             :                "Overflow adding up amounts"));
    2053           0 :     return false;
    2054             :   }
    2055          28 :   if (-1 == TALER_amount_cmp (&pc->validate_tokens.max_fee,
    2056             :                               &acc_fee))
    2057             :   {
    2058             :     /**
    2059             :      * Sum of fees of *all* the different exchanges of all the coins are
    2060             :      * higher than the fixed limit that the merchant is willing to pay.  The
    2061             :      * difference must be paid by the customer.
    2062             :      */
    2063             :     struct TALER_Amount excess_fee;
    2064             : 
    2065             :     /* compute fee amount to be covered by customer */
    2066           8 :     GNUNET_assert (TALER_AAR_RESULT_POSITIVE ==
    2067             :                    TALER_amount_subtract (&excess_fee,
    2068             :                                           &acc_fee,
    2069             :                                           &pc->validate_tokens.max_fee));
    2070             :     /* add that to the total */
    2071           8 :     if (0 >
    2072           8 :         TALER_amount_add (&total_needed,
    2073             :                           &excess_fee,
    2074           8 :                           &pc->validate_tokens.brutto))
    2075             :     {
    2076           0 :       GNUNET_break (0);
    2077           0 :       pay_end (pc,
    2078             :                TALER_MHD_reply_with_error (
    2079             :                  pc->connection,
    2080             :                  MHD_HTTP_INTERNAL_SERVER_ERROR,
    2081             :                  TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AMOUNT_OVERFLOW,
    2082             :                  "Overflow adding up amounts"));
    2083           0 :       return false;
    2084             :     }
    2085             :   }
    2086             :   else
    2087             :   {
    2088             :     /* Fees are fully covered by the merchant, all we require
    2089             :        is that the total payment is not below the contract's amount */
    2090          20 :     total_needed = pc->validate_tokens.brutto;
    2091             :   }
    2092             : 
    2093             :   /* Do not count refunds towards the payment */
    2094          28 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    2095             :               "Subtracting total refunds from paid amount: %s\n",
    2096             :               TALER_amount2s (&pc->pay_transaction.total_refunded));
    2097          28 :   if (0 >
    2098          28 :       TALER_amount_subtract (&final_amount,
    2099             :                              &acc_amount,
    2100          28 :                              &pc->pay_transaction.total_refunded))
    2101             :   {
    2102           0 :     GNUNET_break (0);
    2103           0 :     pay_end (pc,
    2104             :              TALER_MHD_reply_with_error (
    2105             :                pc->connection,
    2106             :                MHD_HTTP_INTERNAL_SERVER_ERROR,
    2107             :                TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_REFUNDS_EXCEED_PAYMENTS,
    2108             :                "refunded amount exceeds total payments"));
    2109           0 :     return false;
    2110             :   }
    2111             : 
    2112          28 :   if (-1 == TALER_amount_cmp (&final_amount,
    2113             :                               &total_needed))
    2114             :   {
    2115             :     /* acc_amount < total_needed */
    2116           2 :     if (-1 < TALER_amount_cmp (&acc_amount,
    2117             :                                &total_needed))
    2118             :     {
    2119           0 :       GNUNET_break_op (0);
    2120           0 :       pay_end (pc,
    2121             :                TALER_MHD_reply_with_error (
    2122             :                  pc->connection,
    2123             :                  MHD_HTTP_PAYMENT_REQUIRED,
    2124             :                  TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_REFUNDED,
    2125             :                  "contract not paid up due to refunds"));
    2126           0 :       return false;
    2127             :     }
    2128           2 :     if (-1 < TALER_amount_cmp (&acc_amount,
    2129           2 :                                &pc->validate_tokens.brutto))
    2130             :     {
    2131           0 :       GNUNET_break_op (0);
    2132           0 :       pay_end (pc,
    2133             :                TALER_MHD_reply_with_error (
    2134             :                  pc->connection,
    2135             :                  MHD_HTTP_BAD_REQUEST,
    2136             :                  TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_INSUFFICIENT_DUE_TO_FEES,
    2137             :                  "contract not paid up due to fees (client may have calculated them badly)"));
    2138           0 :       return false;
    2139             :     }
    2140           2 :     GNUNET_break_op (0);
    2141           2 :     pay_end (pc,
    2142             :              TALER_MHD_reply_with_error (
    2143             :                pc->connection,
    2144             :                MHD_HTTP_BAD_REQUEST,
    2145             :                TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_PAYMENT_INSUFFICIENT,
    2146             :                "payment insufficient"));
    2147           2 :     return false;
    2148             :   }
    2149          26 :   return true;
    2150             : }
    2151             : 
    2152             : 
    2153             : /**
    2154             :  * Execute the DB transaction.  If required (from
    2155             :  * soft/serialization errors), the transaction can be
    2156             :  * restarted here.
    2157             :  *
    2158             :  * @param[in,out] pc payment context to transact
    2159             :  */
    2160             : static void
    2161          66 : phase_execute_pay_transaction (struct PayContext *pc)
    2162             : {
    2163          66 :   struct TMH_HandlerContext *hc = pc->hc;
    2164          66 :   const char *instance_id = hc->instance->settings.id;
    2165             : 
    2166          66 :   if (pc->batch_deposits.got_451)
    2167             :   {
    2168           0 :     pc->phase = PP_FAIL_LEGAL_REASONS;
    2169           0 :     return;
    2170             :   }
    2171             :   /* Avoid re-trying transactions on soft errors forever! */
    2172          66 :   if (pc->pay_transaction.retry_counter++ > MAX_RETRIES)
    2173             :   {
    2174           0 :     GNUNET_break (0);
    2175           0 :     pay_end (pc,
    2176             :              TALER_MHD_reply_with_error (pc->connection,
    2177             :                                          MHD_HTTP_INTERNAL_SERVER_ERROR,
    2178             :                                          TALER_EC_GENERIC_DB_SOFT_FAILURE,
    2179             :                                          NULL));
    2180           0 :     return;
    2181             :   }
    2182             : 
    2183             :   /* Initialize some amount accumulators
    2184             :      (used in check_coin_paid(), check_coin_refunded()
    2185             :      and check_payment_sufficient()). */
    2186          66 :   GNUNET_break (GNUNET_OK ==
    2187             :                 TALER_amount_set_zero (pc->validate_tokens.brutto.currency,
    2188             :                                        &pc->pay_transaction.total_paid));
    2189          66 :   GNUNET_break (GNUNET_OK ==
    2190             :                 TALER_amount_set_zero (pc->validate_tokens.brutto.currency,
    2191             :                                        &pc->pay_transaction.total_fees_paid));
    2192          66 :   GNUNET_break (GNUNET_OK ==
    2193             :                 TALER_amount_set_zero (pc->validate_tokens.brutto.currency,
    2194             :                                        &pc->pay_transaction.total_refunded));
    2195         142 :   for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++)
    2196          76 :     pc->parse_pay.dc[i].found_in_db = false;
    2197          66 :   pc->pay_transaction.pending = pc->parse_pay.coins_cnt;
    2198             : 
    2199             :   /* First, try to see if we have all we need already done */
    2200          66 :   TMH_db->preflight (TMH_db->cls);
    2201          66 :   if (GNUNET_OK !=
    2202          66 :       TMH_db->start (TMH_db->cls,
    2203             :                      "run pay"))
    2204             :   {
    2205           0 :     GNUNET_break (0);
    2206           0 :     pay_end (pc,
    2207             :              TALER_MHD_reply_with_error (pc->connection,
    2208             :                                          MHD_HTTP_INTERNAL_SERVER_ERROR,
    2209             :                                          TALER_EC_GENERIC_DB_START_FAILED,
    2210             :                                          NULL));
    2211           0 :     return;
    2212             :   }
    2213             : 
    2214          68 :   for (size_t i = 0; i<pc->parse_pay.tokens_cnt; i++)
    2215             :   {
    2216           4 :     struct TokenUseConfirmation *tuc = &pc->parse_pay.tokens[i];
    2217             :     enum GNUNET_DB_QueryStatus qs;
    2218             : 
    2219             :     /* Insert used token into database, the unique constraint will
    2220             :        case an error if this token was used before. */
    2221           4 :     qs = TMH_db->insert_spent_token (TMH_db->cls,
    2222           4 :                                      &pc->check_contract.h_contract_terms,
    2223           4 :                                      &tuc->h_issue,
    2224           4 :                                      &tuc->pub,
    2225           4 :                                      &tuc->sig,
    2226           4 :                                      &tuc->unblinded_sig);
    2227             : 
    2228           4 :     if (0 > qs)
    2229             :     {
    2230           0 :       TMH_db->rollback (TMH_db->cls);
    2231           0 :       if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
    2232           0 :         return; /* do it again */
    2233             :       /* Always report on hard error as well to enable diagnostics */
    2234           0 :       GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
    2235           0 :       pay_end (pc,
    2236             :                TALER_MHD_reply_with_error (pc->connection,
    2237             :                                            MHD_HTTP_INTERNAL_SERVER_ERROR,
    2238             :                                            TALER_EC_GENERIC_DB_STORE_FAILED,
    2239             :                                            "insert used token"));
    2240           0 :       return;
    2241             :     }
    2242           4 :     else if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
    2243             :     {
    2244             :       /* UNIQUE constraint violation, meaning this token was already used. */
    2245           2 :       TMH_db->rollback (TMH_db->cls);
    2246           2 :       pay_end (pc,
    2247             :                TALER_MHD_reply_with_error (pc->connection,
    2248             :                                            MHD_HTTP_CONFLICT,
    2249             :                                            TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_TOKEN_INVALID,
    2250             :                                            NULL));
    2251           2 :       return;
    2252             :     }
    2253             :   }
    2254             : 
    2255             :   {
    2256             :     enum GNUNET_DB_QueryStatus qs;
    2257             : 
    2258             :     /* Check if some of these coins already succeeded for _this_ contract.  */
    2259          64 :     qs = TMH_db->lookup_deposits (TMH_db->cls,
    2260             :                                   instance_id,
    2261          64 :                                   &pc->check_contract.h_contract_terms,
    2262             :                                   &check_coin_paid,
    2263             :                                   pc);
    2264          64 :     if (0 > qs)
    2265             :     {
    2266           0 :       TMH_db->rollback (TMH_db->cls);
    2267           0 :       if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
    2268           0 :         return; /* do it again */
    2269             :       /* Always report on hard error as well to enable diagnostics */
    2270           0 :       GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
    2271           0 :       pay_end (pc,
    2272             :                TALER_MHD_reply_with_error (pc->connection,
    2273             :                                            MHD_HTTP_INTERNAL_SERVER_ERROR,
    2274             :                                            TALER_EC_GENERIC_DB_FETCH_FAILED,
    2275             :                                            "lookup deposits"));
    2276           0 :       return;
    2277             :     }
    2278          64 :     if (pc->pay_transaction.deposit_currency_mismatch)
    2279             :     {
    2280           0 :       TMH_db->rollback (TMH_db->cls);
    2281           0 :       GNUNET_break_op (0);
    2282           0 :       pay_end (pc,
    2283             :                TALER_MHD_reply_with_error (pc->connection,
    2284             :                                            MHD_HTTP_BAD_REQUEST,
    2285             :                                            TALER_EC_MERCHANT_GENERIC_CURRENCY_MISMATCH,
    2286           0 :                                            pc->validate_tokens.brutto.currency))
    2287             :       ;
    2288           0 :       return;
    2289             :     }
    2290             :   }
    2291             : 
    2292             :   {
    2293             :     enum GNUNET_DB_QueryStatus qs;
    2294             : 
    2295             :     /* Check if we refunded some of the coins */
    2296          64 :     qs = TMH_db->lookup_refunds (TMH_db->cls,
    2297             :                                  instance_id,
    2298          64 :                                  &pc->check_contract.h_contract_terms,
    2299             :                                  &check_coin_refunded,
    2300             :                                  pc);
    2301          64 :     if (0 > qs)
    2302             :     {
    2303           0 :       TMH_db->rollback (TMH_db->cls);
    2304           0 :       if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
    2305           0 :         return; /* do it again */
    2306             :       /* Always report on hard error as well to enable diagnostics */
    2307           0 :       GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
    2308           0 :       pay_end (pc,
    2309             :                TALER_MHD_reply_with_error (pc->connection,
    2310             :                                            MHD_HTTP_INTERNAL_SERVER_ERROR,
    2311             :                                            TALER_EC_GENERIC_DB_FETCH_FAILED,
    2312             :                                            "lookup refunds"));
    2313           0 :       return;
    2314             :     }
    2315          64 :     if (pc->pay_transaction.refund_currency_mismatch)
    2316             :     {
    2317           0 :       TMH_db->rollback (TMH_db->cls);
    2318           0 :       pay_end (pc,
    2319             :                TALER_MHD_reply_with_error (pc->connection,
    2320             :                                            MHD_HTTP_INTERNAL_SERVER_ERROR,
    2321             :                                            TALER_EC_GENERIC_DB_FETCH_FAILED,
    2322             :                                            "refund currency in database does not match order currency"));
    2323           0 :       return;
    2324             :     }
    2325             :   }
    2326             : 
    2327             :   /* Check if there are coins that still need to be processed */
    2328          64 :   if (0 != pc->pay_transaction.pending)
    2329             :   {
    2330             :     /* we made no DB changes, so we can just rollback */
    2331          34 :     TMH_db->rollback (TMH_db->cls);
    2332             :     /* Ok, we need to first go to the network to process more coins.
    2333             :        We that interaction in *tiny* transactions (hence the rollback
    2334             :        above). */
    2335          34 :     pc->phase = PP_BATCH_DEPOSITS;
    2336          34 :     return;
    2337             :   }
    2338             : 
    2339             :   /* 0 == pc->pay_transaction.pending: all coins processed, let's see if that was enough */
    2340          30 :   if (! check_payment_sufficient (pc))
    2341             :   {
    2342             :     /* check_payment_sufficient() will have queued an error already.
    2343             :        We need to still abort the transaction. */
    2344           2 :     TMH_db->rollback (TMH_db->cls);
    2345           2 :     return;
    2346             :   }
    2347             :   /* Payment succeeded, save in database */
    2348          28 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    2349             :               "Order `%s' (%s) was fully paid\n",
    2350             :               pc->order_id,
    2351             :               GNUNET_h2s (&pc->check_contract.h_contract_terms.hash));
    2352             :   {
    2353             :     enum GNUNET_DB_QueryStatus qs;
    2354             : 
    2355          28 :     qs = TMH_db->mark_contract_paid (TMH_db->cls,
    2356             :                                      instance_id,
    2357          28 :                                      &pc->check_contract.h_contract_terms,
    2358          28 :                                      pc->parse_pay.session_id,
    2359          28 :                                      pc->parse_wallet_data.choice_index);
    2360          28 :     if (qs < 0)
    2361             :     {
    2362           0 :       TMH_db->rollback (TMH_db->cls);
    2363           0 :       if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
    2364           0 :         return; /* do it again */
    2365           0 :       GNUNET_break (0);
    2366           0 :       pay_end (pc,
    2367             :                TALER_MHD_reply_with_error (pc->connection,
    2368             :                                            MHD_HTTP_INTERNAL_SERVER_ERROR,
    2369             :                                            TALER_EC_GENERIC_DB_STORE_FAILED,
    2370             :                                            "mark contract paid"));
    2371           0 :       return;
    2372             :     }
    2373             :   }
    2374             : 
    2375             :   /* Store signed output tokens in database. */
    2376          32 :   for (size_t i = 0; i<pc->validate_tokens.output_tokens_len; i++)
    2377             :   {
    2378           4 :     struct SignedOutputToken *output = &pc->validate_tokens.output_tokens[i];
    2379             : 
    2380             :     enum GNUNET_DB_QueryStatus qs;
    2381             : 
    2382           4 :     qs = TMH_db->insert_issued_token (TMH_db->cls,
    2383           4 :                                       &pc->check_contract.h_contract_terms,
    2384           4 :                                       &output->h_issue,
    2385           4 :                                       &output->sig);
    2386             : 
    2387           4 :     if (0 >= qs)
    2388             :     {
    2389           0 :       TMH_db->rollback (TMH_db->cls);
    2390           0 :       if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
    2391           0 :         return; /* do it again */
    2392             :       /* Always report on hard error as well to enable diagnostics */
    2393           0 :       GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
    2394           0 :       pay_end (pc,
    2395             :                TALER_MHD_reply_with_error (pc->connection,
    2396             :                                            MHD_HTTP_INTERNAL_SERVER_ERROR,
    2397             :                                            TALER_EC_GENERIC_DB_STORE_FAILED,
    2398             :                                            "insert output token"));
    2399           0 :       return;
    2400             :     }
    2401             :   }
    2402             : 
    2403             :   // FIXME: insert donau blinded inputs (into DB here!),
    2404             :   // idempotency: if already exists, no problem!
    2405             : 
    2406          28 :   TMH_notify_order_change (hc->instance,
    2407             :                            TMH_OSF_CLAIMED | TMH_OSF_PAID,
    2408          28 :                            pc->check_contract.contract_terms->timestamp,
    2409             :                            pc->check_contract.order_serial);
    2410             :   {
    2411             :     enum GNUNET_DB_QueryStatus qs;
    2412             :     json_t *jhook;
    2413             : 
    2414          28 :     jhook = GNUNET_JSON_PACK (
    2415             :       GNUNET_JSON_pack_object_incref ("contract_terms",
    2416             :                                       pc->check_contract.contract_terms_json),
    2417             :       GNUNET_JSON_pack_string ("order_id",
    2418             :                                pc->order_id)
    2419             :       );
    2420          28 :     GNUNET_assert (NULL != jhook);
    2421          28 :     qs = TMH_trigger_webhook (pc->hc->instance->settings.id,
    2422             :                               "pay",
    2423             :                               jhook);
    2424          28 :     json_decref (jhook);
    2425          28 :     if (qs < 0)
    2426             :     {
    2427           0 :       TMH_db->rollback (TMH_db->cls);
    2428           0 :       if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
    2429           0 :         return; /* do it again */
    2430           0 :       GNUNET_break (0);
    2431           0 :       pay_end (pc,
    2432             :                TALER_MHD_reply_with_error (pc->connection,
    2433             :                                            MHD_HTTP_INTERNAL_SERVER_ERROR,
    2434             :                                            TALER_EC_GENERIC_DB_STORE_FAILED,
    2435             :                                            "failed to trigger webhooks"));
    2436           0 :       return;
    2437             :     }
    2438             :   }
    2439             :   {
    2440             :     enum GNUNET_DB_QueryStatus qs;
    2441             : 
    2442             :     /* Now commit! */
    2443          28 :     qs = TMH_db->commit (TMH_db->cls);
    2444          28 :     if (0 > qs)
    2445             :     {
    2446             :       /* commit failed */
    2447           0 :       TMH_db->rollback (TMH_db->cls);
    2448           0 :       if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
    2449           0 :         return; /* do it again */
    2450           0 :       GNUNET_break (0);
    2451           0 :       pay_end (pc,
    2452             :                TALER_MHD_reply_with_error (pc->connection,
    2453             :                                            MHD_HTTP_INTERNAL_SERVER_ERROR,
    2454             :                                            TALER_EC_GENERIC_DB_COMMIT_FAILED,
    2455             :                                            NULL));
    2456           0 :       return;
    2457             :     }
    2458             :   }
    2459             :   // FIXME: if we have donation receipts, do NEW phase
    2460             :   // DONAU interaction here, otherwise skip DONAU phase
    2461             :   // and move to payment notification
    2462          28 :   pc->phase = PP_PAYMENT_NOTIFICATION;
    2463             : }
    2464             : 
    2465             : 
    2466             : /**
    2467             :  * Ensures that the expected number of tokens for a @e key
    2468             :  * are provided as inputs and have valid signatures.
    2469             :  *
    2470             :  * @param[in,out] pc payment context we are processing
    2471             :  * @param family family the tokens should be from
    2472             :  * @param index number of the input we are handling
    2473             :  * @param expected_num number of tokens expected
    2474             :  * @return #GNUNET_YES on success
    2475             :  */
    2476             : static enum GNUNET_GenericReturnValue
    2477           4 : find_valid_input_tokens (
    2478             :   struct PayContext *pc,
    2479             :   const struct TALER_MERCHANT_ContractTokenFamily *family,
    2480             :   unsigned int index,
    2481             :   unsigned int expected_num)
    2482             : {
    2483           4 :   unsigned int num_validated = 0;
    2484             :   struct GNUNET_TIME_Timestamp now
    2485           4 :     = GNUNET_TIME_timestamp_get ();
    2486             : 
    2487           8 :   for (unsigned int j = 0; j < expected_num; j++)
    2488             :   {
    2489           4 :     struct TokenUseConfirmation *tuc = &pc->parse_pay.tokens[index + j];
    2490           4 :     const struct TALER_MERCHANT_ContractTokenFamilyKey *key = NULL;
    2491             : 
    2492           4 :     for (unsigned int i=0; i<family->keys_len; i++)
    2493             :     {
    2494           4 :       const struct TALER_MERCHANT_ContractTokenFamilyKey *ki
    2495           4 :         = &family->keys[i];
    2496             : 
    2497           4 :       if (GNUNET_TIME_timestamp_cmp (ki->valid_after, >, now) ||
    2498           4 :           GNUNET_TIME_timestamp_cmp (ki->valid_before, <, now))
    2499             :       {
    2500           0 :         continue; /* ki currently not valid */
    2501             :       }
    2502           4 :       if (0 ==
    2503           4 :           GNUNET_memcmp (&ki->pub.public_key->pub_key_hash,
    2504             :                          &tuc->h_issue.hash))
    2505             :       {
    2506           4 :         key = ki;
    2507           4 :         break;
    2508             :       }
    2509             :     }
    2510           4 :     if (NULL == key)
    2511             :     {
    2512           0 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    2513             :                   "Input token supplied for public key that is not acceptable\n");
    2514           0 :       GNUNET_break (0);
    2515           0 :       pay_end (pc,
    2516             :                TALER_MHD_reply_with_error (
    2517             :                  pc->connection,
    2518             :                  MHD_HTTP_BAD_REQUEST,
    2519             :                  TALER_EC_MERCHANT_GENERIC_TOKEN_KEY_UNKNOWN,
    2520             :                  NULL));
    2521           0 :       return GNUNET_NO;
    2522             :     }
    2523           4 :     if (GNUNET_OK !=
    2524           4 :         TALER_token_issue_verify (&tuc->pub,
    2525             :                                   &key->pub,
    2526           4 :                                   &tuc->unblinded_sig))
    2527             :     {
    2528           0 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    2529             :                   "Input token for public key with valid_after "
    2530             :                   "`%s' has invalid issue signature\n",
    2531             :                   GNUNET_TIME_timestamp2s (key->valid_after));
    2532           0 :       GNUNET_break (0);
    2533           0 :       pay_end (pc,
    2534             :                TALER_MHD_reply_with_error (
    2535             :                  pc->connection,
    2536             :                  MHD_HTTP_BAD_REQUEST,
    2537             :                  TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_TOKEN_ISSUE_SIG_INVALID,
    2538             :                  NULL));
    2539           0 :       return GNUNET_NO;
    2540             :     }
    2541             : 
    2542           4 :     if (GNUNET_OK !=
    2543           4 :         TALER_wallet_token_use_verify (&pc->check_contract.h_contract_terms,
    2544           4 :                                        &pc->parse_wallet_data.h_wallet_data,
    2545           4 :                                        &tuc->pub,
    2546           4 :                                        &tuc->sig))
    2547             :     {
    2548           0 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    2549             :                   "Input token for public key with valid_before "
    2550             :                   "`%s' has invalid use signature\n",
    2551             :                   GNUNET_TIME_timestamp2s (key->valid_before));
    2552           0 :       GNUNET_break (0);
    2553           0 :       pay_end (pc,
    2554             :                TALER_MHD_reply_with_error (
    2555             :                  pc->connection,
    2556             :                  MHD_HTTP_BAD_REQUEST,
    2557             :                  TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_TOKEN_USE_SIG_INVALID,
    2558             :                  NULL));
    2559           0 :       return GNUNET_NO;
    2560             :     }
    2561             : 
    2562           4 :     num_validated++;
    2563             :   }
    2564             : 
    2565           4 :   if (num_validated != expected_num)
    2566             :   {
    2567           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    2568             :                 "Expected %d tokens for family %s, but found %d\n",
    2569             :                 expected_num,
    2570             :                 family->slug,
    2571             :                 num_validated);
    2572           0 :     GNUNET_break (0);
    2573           0 :     pay_end (pc,
    2574             :              TALER_MHD_reply_with_error (
    2575             :                pc->connection,
    2576             :                MHD_HTTP_BAD_REQUEST,
    2577             :                TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_TOKEN_COUNT_MISMATCH,
    2578             :                NULL));
    2579           0 :     return GNUNET_NO;
    2580             :   }
    2581             : 
    2582           4 :   return GNUNET_YES;
    2583             : }
    2584             : 
    2585             : 
    2586             : /**
    2587             :  * Check if an output token of the given @a tfk is mandatory, or if
    2588             :  * wallets are allowed to simply not support it and still proceed.
    2589             :  *
    2590             :  * @param tfk token family kind to check
    2591             :  * @return true if such outputs are mandatory and wallets must supply
    2592             :  *  the corresponding blinded input
    2593             :  */
    2594             : static bool
    2595           6 : test_tfk_mandatory (enum TALER_MERCHANTDB_TokenFamilyKind tfk)
    2596             : {
    2597           6 :   switch (tfk)
    2598             :   {
    2599           0 :   case TALER_MERCHANTDB_TFK_Discount:
    2600           0 :     return false;
    2601           6 :   case TALER_MERCHANTDB_TFK_Subscription:
    2602           6 :     return true;
    2603             :   }
    2604           0 :   GNUNET_break (0);
    2605           0 :   return false;
    2606             : }
    2607             : 
    2608             : 
    2609             : /**
    2610             :  * Sign the tokens provided by the wallet for a particular @a key.
    2611             :  *
    2612             :  * @param[in,out] payment we are processing
    2613             :  * @param key token family data
    2614             :  * @param priv private key to use to sign with
    2615             :  * @param mandatory true if the token must exist, if false
    2616             :  *        and the client did not provide an envelope, that's OK and
    2617             :  *        we just also skimp on the signature
    2618             :  * @param index offset in the token envelope array (from other families)
    2619             :  * @param expected_num number of tokens of this type that we should create
    2620             :  * @return #GNUNET_NO on failure
    2621             :  *         #GNUNET_OK on success
    2622             :  */
    2623             : static enum GNUNET_GenericReturnValue
    2624           6 : sign_token_envelopes (struct PayContext *pc,
    2625             :                       struct TALER_MERCHANT_ContractTokenFamilyKey *key,
    2626             :                       struct TALER_TokenIssuePrivateKey *priv,
    2627             :                       bool mandatory,
    2628             :                       unsigned int index,
    2629             :                       unsigned int expected_num)
    2630             : {
    2631           6 :   unsigned int num_signed = 0;
    2632             : 
    2633          12 :   for (unsigned int j = 0; j<expected_num; j++)
    2634             :   {
    2635           6 :     unsigned int pos = index + j;
    2636           6 :     const struct TokenEnvelope *env
    2637           6 :       = &pc->parse_wallet_data.token_envelopes[pos];
    2638           6 :     struct SignedOutputToken *output
    2639           6 :       = &pc->validate_tokens.output_tokens[pos];
    2640             : 
    2641           6 :     if ( (pos >= pc->parse_wallet_data.token_envelopes_cnt) ||
    2642           6 :          (pos >= pc->validate_tokens.output_tokens_len) )
    2643             :     {
    2644           0 :       GNUNET_assert (0); /* this should not happen */
    2645             :       return GNUNET_NO;
    2646             :     }
    2647           6 :     if (NULL == env->blinded_token.blinded_pub)
    2648             :     {
    2649           0 :       if (! mandatory)
    2650           0 :         continue;
    2651             : 
    2652             :       /* mandatory token families require a token envelope. */
    2653           0 :       GNUNET_break_op (0);
    2654           0 :       pay_end (pc,
    2655             :                TALER_MHD_reply_with_error (
    2656             :                  pc->connection,
    2657             :                  MHD_HTTP_BAD_REQUEST,
    2658             :                  TALER_EC_GENERIC_PARAMETER_MALFORMED,
    2659             :                  "Token envelope for mandatory token family missing"));
    2660           0 :       return GNUNET_NO;
    2661             :     }
    2662           6 :     TALER_token_issue_sign (priv,
    2663             :                             &env->blinded_token,
    2664             :                             &output->sig);
    2665           6 :     output->h_issue.hash = key->pub.public_key->pub_key_hash;
    2666           6 :     num_signed++;
    2667             :   }
    2668             : 
    2669           6 :   if (num_signed != expected_num)
    2670             :   {
    2671           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    2672             :                 "Expected %d token envelopes for public key with valid_after "
    2673             :                 "'%s', but found %d\n",
    2674             :                 expected_num,
    2675             :                 GNUNET_TIME_timestamp2s (key->valid_after),
    2676             :                 num_signed);
    2677           0 :     GNUNET_break (0);
    2678           0 :     pay_end (pc,
    2679             :              TALER_MHD_reply_with_error (
    2680             :                pc->connection,
    2681             :                MHD_HTTP_BAD_REQUEST,
    2682             :                TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_TOKEN_ENVELOPE_COUNT_MISMATCH,
    2683             :                NULL));
    2684           0 :     return GNUNET_NO;
    2685             :   }
    2686             : 
    2687           6 :   return GNUNET_OK;
    2688             : }
    2689             : 
    2690             : 
    2691             : /**
    2692             :  * Find the family entry for the family of the given @a slug
    2693             :  * in @a pc.
    2694             :  *
    2695             :  * @param[in] pc payment context to search
    2696             :  * @param slug slug to search for
    2697             :  * @return NULL if @a slug was not found
    2698             :  */
    2699             : static const struct TALER_MERCHANT_ContractTokenFamily *
    2700          10 : find_family (const struct PayContext *pc,
    2701             :              const char *slug)
    2702             : {
    2703          10 :   for (unsigned int i = 0;
    2704          10 :        i < pc->check_contract.contract_terms->details.v1.token_authorities_len;
    2705           0 :        i++)
    2706             :   {
    2707          10 :     const struct TALER_MERCHANT_ContractTokenFamily *tfi
    2708          10 :       = &pc->check_contract.contract_terms->details.v1.token_authorities[i];
    2709             : 
    2710          10 :     if (0 == strcmp (tfi->slug,
    2711             :                      slug))
    2712             :     {
    2713          10 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    2714             :                   "Token family %s found with %u keys\n",
    2715             :                   slug,
    2716             :                   tfi->keys_len);
    2717          10 :       return tfi;
    2718             :     }
    2719             :   }
    2720           0 :   return NULL;
    2721             : }
    2722             : 
    2723             : 
    2724             : /**
    2725             :  * Validate tokens and token envelopes. First, we check if all tokens listed
    2726             :  * in the 'inputs' array of the selected choice are present in the 'tokens'
    2727             :  * array of the request. Then, we validate the signatures of each provided
    2728             :  * token.
    2729             :  *
    2730             :  * @param[in,out] pc context we use to handle the payment
    2731             :  */
    2732             : static void
    2733          38 : phase_validate_tokens (struct PayContext *pc)
    2734             : {
    2735          38 :   switch (pc->check_contract.contract_terms->version)
    2736             :   {
    2737          32 :   case TALER_MERCHANT_CONTRACT_VERSION_0:
    2738             :     /* No tokens to validate */
    2739          32 :     pc->phase = PP_PAY_TRANSACTION;
    2740             :     pc->validate_tokens.max_fee
    2741          32 :       = pc->check_contract.contract_terms->details.v0.max_fee;
    2742             :     pc->validate_tokens.brutto
    2743          32 :       = pc->check_contract.contract_terms->details.v0.brutto;
    2744          32 :     break;
    2745           6 :   case TALER_MERCHANT_CONTRACT_VERSION_1:
    2746             :     {
    2747           6 :       const struct TALER_MERCHANT_ContractChoice *selected
    2748           6 :         = &pc->check_contract.contract_terms->details.v1.choices[
    2749           6 :             pc->parse_wallet_data.choice_index];
    2750             : 
    2751           6 :       pc->validate_tokens.max_fee = selected->max_fee;
    2752           6 :       pc->validate_tokens.brutto = selected->amount;
    2753             : 
    2754          10 :       for (unsigned int i = 0; i<selected->inputs_len; i++)
    2755             :       {
    2756           4 :         const struct TALER_MERCHANT_ContractInput *input
    2757           4 :           = &selected->inputs[i];
    2758             :         const struct TALER_MERCHANT_ContractTokenFamily *family;
    2759             : 
    2760           4 :         if (input->type != TALER_MERCHANT_CONTRACT_INPUT_TYPE_TOKEN)
    2761             :         {
    2762             :           /* only validate inputs of type token (for now) */
    2763           0 :           continue;
    2764             :         }
    2765             : 
    2766           4 :         family = find_family (pc,
    2767           4 :                               input->details.token.token_family_slug);
    2768           4 :         if (NULL == family)
    2769             :         {
    2770             :           /* this should never happen, since the choices and
    2771             :              token families are validated on insert. */
    2772           0 :           GNUNET_break (0);
    2773           0 :           pay_end (pc,
    2774             :                    TALER_MHD_reply_with_error (
    2775             :                      pc->connection,
    2776             :                      MHD_HTTP_INTERNAL_SERVER_ERROR,
    2777             :                      TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
    2778             :                      "token family not found in order"));
    2779           0 :           return;
    2780             :         }
    2781           4 :         if (GNUNET_NO ==
    2782           4 :             find_valid_input_tokens (pc,
    2783             :                                      family,
    2784             :                                      i,
    2785           4 :                                      input->details.token.count))
    2786             :         {
    2787             :           /* Error is already scheduled from find_valid_input_token. */
    2788           0 :           return;
    2789             :         }
    2790             :       }
    2791             : 
    2792           6 :       GNUNET_array_grow (pc->validate_tokens.output_tokens,
    2793             :                          pc->validate_tokens.output_tokens_len,
    2794             :                          selected->outputs_len);
    2795             : 
    2796          12 :       for (unsigned int i = 0; i<selected->outputs_len; i++)
    2797             :       {
    2798             :         enum GNUNET_DB_QueryStatus qs;
    2799             :         struct TALER_MERCHANTDB_TokenFamilyKeyDetails details;
    2800           6 :         const struct TALER_MERCHANT_ContractOutput *output
    2801           6 :           = &selected->outputs[i];
    2802             :         const struct TALER_MERCHANT_ContractTokenFamily *family;
    2803             :         struct TALER_MERCHANT_ContractTokenFamilyKey *key;
    2804             : 
    2805             :         // FIXME: check donau outputs are good choices
    2806             :         // (allowed donau, total amount below max, correct year, ...)
    2807             :         // change 'if' to switch...
    2808           6 :         if (output->type != TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_TOKEN)
    2809             :         {
    2810             :           /* only validate outputs of type tokens (for now) */
    2811           0 :           continue;
    2812             :         }
    2813             :         // FIXME: move this into a function for the switch case on token...
    2814           6 :         family = find_family (pc,
    2815           6 :                               output->details.token.token_family_slug);
    2816           6 :         if (NULL == family)
    2817             :         {
    2818             :           /* this should never happen, since the choices and
    2819             :              token families are validated on insert. */
    2820           0 :           GNUNET_break (0);
    2821           0 :           pay_end (pc,
    2822             :                    TALER_MHD_reply_with_error (
    2823             :                      pc->connection,
    2824             :                      MHD_HTTP_INTERNAL_SERVER_ERROR,
    2825             :                      TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
    2826             :                      "token family not found in order"));
    2827           0 :           return;
    2828             :         }
    2829           6 :         if (output->details.token.key_index >= family->keys_len)
    2830             :         {
    2831             :           /* this should never happen, since the choices and
    2832             :              token families are validated on insert. */
    2833           0 :           GNUNET_break (0);
    2834           0 :           pay_end (pc,
    2835             :                    TALER_MHD_reply_with_error (
    2836             :                      pc->connection,
    2837             :                      MHD_HTTP_INTERNAL_SERVER_ERROR,
    2838             :                      TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
    2839             :                      "key index invalid for token family"));
    2840           0 :           return;
    2841             :         }
    2842           6 :         key = &family->keys[output->details.token.key_index];
    2843           6 :         qs = TMH_db->lookup_token_family_key (
    2844           6 :           TMH_db->cls,
    2845           6 :           pc->hc->instance->settings.id,
    2846           6 :           family->slug,
    2847           6 :           pc->check_contract.contract_terms->timestamp,
    2848           6 :           pc->check_contract.contract_terms->pay_deadline,
    2849             :           &details);
    2850           6 :         if (qs <= 0)
    2851             :         {
    2852           0 :           GNUNET_log (
    2853             :             GNUNET_ERROR_TYPE_ERROR,
    2854             :             "Did not find key for %s at [%llu,%llu]\n",
    2855             :             family->slug,
    2856             :             (unsigned long long) pc->check_contract.contract_terms->timestamp.
    2857             :             abs_time.
    2858             :             abs_value_us,
    2859             :             (unsigned long long) pc->check_contract.contract_terms->pay_deadline
    2860             :             .abs_time.
    2861             :             abs_value_us);
    2862           0 :           GNUNET_break (0);
    2863           0 :           pay_end (pc,
    2864             :                    TALER_MHD_reply_with_error (
    2865             :                      pc->connection,
    2866             :                      MHD_HTTP_INTERNAL_SERVER_ERROR,
    2867             :                      TALER_EC_GENERIC_DB_FETCH_FAILED,
    2868             :                      NULL));
    2869           0 :           return;
    2870             :         }
    2871             : 
    2872           6 :         GNUNET_assert (NULL != details.priv.private_key);
    2873           6 :         if (GNUNET_OK !=
    2874           6 :             sign_token_envelopes (
    2875             :               pc,
    2876             :               key,
    2877             :               &details.priv,
    2878           6 :               test_tfk_mandatory (details.token_family.kind),
    2879             :               i,
    2880           6 :               output->details.token.count))
    2881             :         {
    2882             :           /* Error is already scheduled from sign_token_envelopes. */
    2883           0 :           return;
    2884             :         }
    2885             :       }
    2886             :     }
    2887             :   }
    2888             : 
    2889          80 :   for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++)
    2890             :   {
    2891          42 :     const struct DepositConfirmation *dc = &pc->parse_pay.dc[i];
    2892             : 
    2893          42 :     if (GNUNET_OK !=
    2894          42 :         TALER_amount_cmp_currency (&dc->cdd.amount,
    2895          42 :                                    &pc->validate_tokens.brutto))
    2896             :     {
    2897           0 :       GNUNET_break_op (0);
    2898           0 :       fprintf (stderr,
    2899             :                "HERE (%u): %s != %s\n",
    2900           0 :                (unsigned int) pc->check_contract.contract_terms->version,
    2901           0 :                dc->cdd.amount.currency,
    2902           0 :                TALER_amount2s (&pc->validate_tokens.brutto));
    2903           0 :       pay_end (pc,
    2904             :                TALER_MHD_reply_with_error (
    2905             :                  pc->connection,
    2906             :                  MHD_HTTP_CONFLICT,
    2907             :                  TALER_EC_MERCHANT_GENERIC_CURRENCY_MISMATCH,
    2908           0 :                  pc->validate_tokens.brutto.currency));
    2909           0 :       return;
    2910             :     }
    2911             :   }
    2912             : 
    2913          38 :   pc->phase = PP_PAY_TRANSACTION;
    2914             : }
    2915             : 
    2916             : 
    2917             : /**
    2918             :  * Function called with information about a coin that was deposited.
    2919             :  * Checks if this coin is in our list of deposits as well.
    2920             :  *
    2921             :  * @param cls closure with our `struct PayContext *`
    2922             :  * @param deposit_serial which deposit operation is this about
    2923             :  * @param exchange_url URL of the exchange that issued the coin
    2924             :  * @param h_wire hash of merchant's wire details
    2925             :  * @param deposit_timestamp when was the deposit made
    2926             :  * @param amount_with_fee amount the exchange will deposit for this coin
    2927             :  * @param deposit_fee fee the exchange will charge for this coin
    2928             :  * @param coin_pub public key of the coin
    2929             :  */
    2930             : static void
    2931           6 : deposit_paid_check (
    2932             :   void *cls,
    2933             :   uint64_t deposit_serial,
    2934             :   const char *exchange_url,
    2935             :   const struct TALER_MerchantWireHashP *h_wire,
    2936             :   struct GNUNET_TIME_Timestamp deposit_timestamp,
    2937             :   const struct TALER_Amount *amount_with_fee,
    2938             :   const struct TALER_Amount *deposit_fee,
    2939             :   const struct TALER_CoinSpendPublicKeyP *coin_pub)
    2940             : {
    2941           6 :   struct PayContext *pc = cls;
    2942             : 
    2943          14 :   for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++)
    2944             :   {
    2945          10 :     struct DepositConfirmation *dci = &pc->parse_pay.dc[i];
    2946             : 
    2947          10 :     if ( (0 ==
    2948          10 :           GNUNET_memcmp (&dci->cdd.coin_pub,
    2949           2 :                          coin_pub)) &&
    2950             :          (0 ==
    2951           2 :           strcmp (dci->exchange_url,
    2952           2 :                   exchange_url)) &&
    2953             :          (GNUNET_YES ==
    2954           2 :           TALER_amount_cmp_currency (&dci->cdd.amount,
    2955           2 :                                      amount_with_fee)) &&
    2956             :          (0 ==
    2957           2 :           TALER_amount_cmp (&dci->cdd.amount,
    2958             :                             amount_with_fee)) )
    2959             :     {
    2960           2 :       dci->matched_in_db = true;
    2961           2 :       break;
    2962             :     }
    2963             :   }
    2964           6 : }
    2965             : 
    2966             : 
    2967             : static void
    2968           0 : input_tokens_paid_check (
    2969             :   void *cls,
    2970             :   uint64_t spent_token_serial,
    2971             :   const struct TALER_PrivateContractHashP *h_contract_terms,
    2972             :   const struct TALER_TokenIssuePublicKeyHashP *h_issue_pub,
    2973             :   const struct TALER_TokenUsePublicKeyP *use_pub,
    2974             :   const struct TALER_TokenUseSignatureP *use_sig,
    2975             :   const struct TALER_TokenIssueSignature *issue_sig)
    2976             : {
    2977           0 :   struct PayContext *pc = cls;
    2978             : 
    2979           0 :   for (size_t i = 0; i<pc->parse_pay.tokens_cnt; i++)
    2980             :   {
    2981           0 :     struct TokenUseConfirmation *tuc = &pc->parse_pay.tokens[i];
    2982             : 
    2983           0 :     if ( (0 ==
    2984           0 :           GNUNET_memcmp (&tuc->pub, use_pub)) &&
    2985             :          (0 ==
    2986           0 :           GNUNET_memcmp (&tuc->sig, use_sig)) &&
    2987             :          (0 ==
    2988           0 :           GNUNET_memcmp (&tuc->unblinded_sig, issue_sig)) )
    2989             :     {
    2990           0 :       tuc->found_in_db = true;
    2991           0 :       break;
    2992             :     }
    2993             :   }
    2994           0 : }
    2995             : 
    2996             : 
    2997             : /**
    2998             :  * Handle case where contract was already paid. Either decides
    2999             :  * the payment is idempotent, or refunds the excess payment.
    3000             :  *
    3001             :  * @param[in,out] pc context we use to handle the payment
    3002             :  */
    3003             : static void
    3004           4 : phase_contract_paid (struct PayContext *pc)
    3005             : {
    3006             :   json_t *refunds;
    3007           4 :   bool unmatched = false;
    3008             : 
    3009             :   {
    3010             :     enum GNUNET_DB_QueryStatus qs;
    3011             : 
    3012           4 :     qs = TMH_db->lookup_deposits_by_order (TMH_db->cls,
    3013             :                                            pc->check_contract.order_serial,
    3014             :                                            &deposit_paid_check,
    3015             :                                            pc);
    3016             :     /* Since orders with choices can have a price of zero,
    3017             :        0 is also a valid query state */
    3018           4 :     if (qs < 0)
    3019             :     {
    3020           0 :       GNUNET_break (0);
    3021           0 :       pay_end (pc,
    3022             :                TALER_MHD_reply_with_error (
    3023             :                  pc->connection,
    3024             :                  MHD_HTTP_INTERNAL_SERVER_ERROR,
    3025             :                  TALER_EC_GENERIC_DB_FETCH_FAILED,
    3026             :                  "lookup_deposits_by_order"));
    3027           2 :       return;
    3028             :     }
    3029             :   }
    3030           8 :   for (size_t i = 0; i<pc->parse_pay.coins_cnt && ! unmatched; i++)
    3031             :   {
    3032           4 :     struct DepositConfirmation *dci = &pc->parse_pay.dc[i];
    3033             : 
    3034           4 :     if (! dci->matched_in_db)
    3035           2 :       unmatched = true;
    3036             :   }
    3037             :   /* Check if provided input tokens match token in the database */
    3038             :   {
    3039             :     enum GNUNET_DB_QueryStatus qs;
    3040             : 
    3041             :     /* FIXME-Optimization: Maybe use h_contract instead of order_serial here? */
    3042           4 :     qs = TMH_db->lookup_spent_tokens_by_order (TMH_db->cls,
    3043             :                                                pc->check_contract.order_serial,
    3044             :                                                &input_tokens_paid_check,
    3045             :                                                pc);
    3046             : 
    3047           4 :     if (qs < 0)
    3048             :     {
    3049           0 :       GNUNET_break (0);
    3050           0 :       pay_end (pc,
    3051             :                TALER_MHD_reply_with_error (
    3052             :                  pc->connection,
    3053             :                  MHD_HTTP_INTERNAL_SERVER_ERROR,
    3054             :                  TALER_EC_GENERIC_DB_FETCH_FAILED,
    3055             :                  "lookup_spent_tokens_by_order"));
    3056           0 :       return;
    3057             :     }
    3058             :   }
    3059           4 :   for (size_t i = 0; i<pc->parse_pay.tokens_cnt && ! unmatched; i++)
    3060             :   {
    3061           0 :     struct TokenUseConfirmation *tuc = &pc->parse_pay.tokens[i];
    3062             : 
    3063           0 :     if (! tuc->found_in_db)
    3064           0 :       unmatched = true;
    3065             :   }
    3066           4 :   if (! unmatched)
    3067             :   {
    3068             :     /* Everything fine, idempotent request, generate response immediately */
    3069           2 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    3070             :                 "Idempotent pay request for order `%s', signing again\n",
    3071             :                 pc->order_id);
    3072           2 :     pc->phase = PP_SUCCESS_RESPONSE;
    3073           2 :     return;
    3074             :   }
    3075             :   /* Conflict, double-payment detected! */
    3076             :   /* FIXME-#8674: What should we do with input tokens?
    3077             :      Currently there is no refund for tokens. */
    3078           2 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    3079             :               "Client attempted to pay extra for already paid order `%s'\n",
    3080             :               pc->order_id);
    3081           2 :   refunds = json_array ();
    3082           2 :   GNUNET_assert (NULL != refunds);
    3083           6 :   for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++)
    3084             :   {
    3085           4 :     struct DepositConfirmation *dci = &pc->parse_pay.dc[i];
    3086             :     struct TALER_MerchantSignatureP merchant_sig;
    3087             : 
    3088           4 :     if (dci->matched_in_db)
    3089           0 :       continue;
    3090           4 :     TALER_merchant_refund_sign (&dci->cdd.coin_pub,
    3091           4 :                                 &pc->check_contract.h_contract_terms,
    3092             :                                 0, /* rtransaction id */
    3093           4 :                                 &dci->cdd.amount,
    3094           4 :                                 &pc->hc->instance->merchant_priv,
    3095             :                                 &merchant_sig);
    3096           4 :     GNUNET_assert (
    3097             :       0 ==
    3098             :       json_array_append_new (
    3099             :         refunds,
    3100             :         GNUNET_JSON_PACK (
    3101             :           GNUNET_JSON_pack_data_auto (
    3102             :             "coin_pub",
    3103             :             &dci->cdd.coin_pub),
    3104             :           GNUNET_JSON_pack_data_auto (
    3105             :             "merchant_sig",
    3106             :             &merchant_sig),
    3107             :           TALER_JSON_pack_amount ("amount",
    3108             :                                   &dci->cdd.amount),
    3109             :           GNUNET_JSON_pack_uint64 ("rtransaction_id",
    3110             :                                    0))));
    3111             :   }
    3112           2 :   pay_end (pc,
    3113           2 :            TALER_MHD_REPLY_JSON_PACK (
    3114             :              pc->connection,
    3115             :              MHD_HTTP_CONFLICT,
    3116             :              TALER_MHD_PACK_EC (
    3117             :                TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_ALREADY_PAID),
    3118             :              GNUNET_JSON_pack_array_steal ("refunds",
    3119             :                                            refunds)));
    3120             : }
    3121             : 
    3122             : 
    3123             : /**
    3124             :  * Check the database state for the given order.
    3125             :  * Schedules an error response in the connection on failure.
    3126             :  *
    3127             :  * @param[in,out] pc context we use to handle the payment
    3128             :  */
    3129             : static void
    3130          42 : phase_check_contract (struct PayContext *pc)
    3131             : {
    3132             :   /* obtain contract terms */
    3133             :   enum GNUNET_DB_QueryStatus qs;
    3134          42 :   bool paid = false;
    3135             : 
    3136          42 :   if (NULL != pc->check_contract.contract_terms_json)
    3137             :   {
    3138           0 :     json_decref (pc->check_contract.contract_terms_json);
    3139           0 :     pc->check_contract.contract_terms_json = NULL;
    3140             :   }
    3141          42 :   if (NULL != pc->check_contract.contract_terms)
    3142             :   {
    3143           0 :     TALER_MERCHANT_contract_free (pc->check_contract.contract_terms);
    3144           0 :     pc->check_contract.contract_terms = NULL;
    3145             :   }
    3146          42 :   qs = TMH_db->lookup_contract_terms2 (TMH_db->cls,
    3147          42 :                                        pc->hc->instance->settings.id,
    3148             :                                        pc->order_id,
    3149             :                                        &pc->check_contract.contract_terms_json,
    3150             :                                        &pc->check_contract.order_serial,
    3151             :                                        &paid,
    3152             :                                        NULL,
    3153             :                                        &pc->check_contract.pos_key,
    3154             :                                        &pc->check_contract.pos_alg);
    3155          42 :   if (0 > qs)
    3156             :   {
    3157             :     /* single, read-only SQL statements should never cause
    3158             :        serialization problems */
    3159           0 :     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
    3160             :     /* Always report on hard error to enable diagnostics */
    3161           0 :     GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
    3162           0 :     pay_end (pc,
    3163             :              TALER_MHD_reply_with_error (
    3164             :                pc->connection,
    3165             :                MHD_HTTP_INTERNAL_SERVER_ERROR,
    3166             :                TALER_EC_GENERIC_DB_FETCH_FAILED,
    3167             :                "contract terms"));
    3168           4 :     return;
    3169             :   }
    3170          42 :   if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
    3171             :   {
    3172           0 :     pay_end (pc,
    3173             :              TALER_MHD_reply_with_error (
    3174             :                pc->connection,
    3175             :                MHD_HTTP_NOT_FOUND,
    3176             :                TALER_EC_MERCHANT_GENERIC_ORDER_UNKNOWN,
    3177             :                pc->order_id));
    3178           0 :     return;
    3179             :   }
    3180             :   /* hash contract (needed later) */
    3181             : #if DEBUG
    3182             :   json_dumpf (pc->check_contract.contract_terms_json,
    3183             :               stderr,
    3184             :               JSON_INDENT (2));
    3185             : #endif
    3186          42 :   if (GNUNET_OK !=
    3187          42 :       TALER_JSON_contract_hash (pc->check_contract.contract_terms_json,
    3188             :                                 &pc->check_contract.h_contract_terms))
    3189             :   {
    3190           0 :     GNUNET_break (0);
    3191           0 :     pay_end (pc,
    3192             :              TALER_MHD_reply_with_error (
    3193             :                pc->connection,
    3194             :                MHD_HTTP_INTERNAL_SERVER_ERROR,
    3195             :                TALER_EC_GENERIC_FAILED_COMPUTE_JSON_HASH,
    3196             :                NULL));
    3197           0 :     return;
    3198             :   }
    3199          42 :   if (paid)
    3200             :   {
    3201           4 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    3202             :                 "Order `%s' paid, checking for double-payment\n",
    3203             :                 pc->order_id);
    3204           4 :     pc->phase = PP_CONTRACT_PAID;
    3205           4 :     return;
    3206             :   }
    3207          38 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    3208             :               "Handling payment for order `%s' with contract hash `%s'\n",
    3209             :               pc->order_id,
    3210             :               GNUNET_h2s (&pc->check_contract.h_contract_terms.hash));
    3211             : 
    3212          38 :   pc->check_contract.contract_terms = TALER_MERCHANT_contract_parse (
    3213             :     pc->check_contract.contract_terms_json,
    3214             :     true);
    3215             : 
    3216          38 :   if (NULL == pc->check_contract.contract_terms)
    3217             :   {
    3218             :     /* invalid contract */
    3219           0 :     GNUNET_break (0);
    3220           0 :     pay_end (pc,
    3221             :              TALER_MHD_reply_with_error (
    3222             :                pc->connection,
    3223             :                MHD_HTTP_INTERNAL_SERVER_ERROR,
    3224             :                TALER_EC_MERCHANT_GENERIC_DB_CONTRACT_CONTENT_INVALID,
    3225             :                pc->order_id));
    3226           0 :     return;
    3227             :   }
    3228             : 
    3229             :   /* Get details from contract and check fundamentals */
    3230             :   {
    3231          38 :     switch (pc->check_contract.contract_terms->version)
    3232             :     {
    3233          32 :     case TALER_MERCHANT_CONTRACT_VERSION_0:
    3234             :       {
    3235          32 :         if (pc->parse_wallet_data.choice_index > 0)
    3236             :         {
    3237           0 :           GNUNET_break (0);
    3238           0 :           pay_end (pc,
    3239             :                    TALER_MHD_reply_with_error (
    3240             :                      pc->connection,
    3241             :                      MHD_HTTP_BAD_REQUEST,
    3242             :                      TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_CHOICE_INDEX_OUT_OF_BOUNDS,
    3243             :                      "contract terms v0 has no choices"));
    3244           0 :           return;
    3245             :         }
    3246             :       }
    3247          32 :       break;
    3248           6 :     case TALER_MERCHANT_CONTRACT_VERSION_1:
    3249             :       {
    3250           6 :         if (pc->parse_wallet_data.choice_index < 0)
    3251             :         {
    3252           0 :           GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    3253             :                       "Order `%s' has non-empty choices array but"
    3254             :                       "request is missing 'choice_index' field\n",
    3255             :                       pc->order_id);
    3256           0 :           GNUNET_break (0);
    3257           0 :           pay_end (pc,
    3258             :                    TALER_MHD_reply_with_error (
    3259             :                      pc->connection,
    3260             :                      MHD_HTTP_BAD_REQUEST,
    3261             :                      TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_CHOICE_INDEX_MISSING,
    3262             :                      NULL));
    3263           0 :           return;
    3264             :         }
    3265           6 :         if (pc->parse_wallet_data.choice_index >=
    3266           6 :             pc->check_contract.contract_terms->details.v1.choices_len)
    3267             :         {
    3268           0 :           GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    3269             :                       "Order `%s' has choices array with %u elements but "
    3270             :                       "request has 'choice_index' field with value %d\n",
    3271             :                       pc->order_id,
    3272             :                       pc->check_contract.contract_terms->details.v1.choices_len,
    3273             :                       pc->parse_wallet_data.choice_index);
    3274           0 :           GNUNET_break (0);
    3275           0 :           pay_end (pc,
    3276             :                    TALER_MHD_reply_with_error (
    3277             :                      pc->connection,
    3278             :                      MHD_HTTP_BAD_REQUEST,
    3279             :                      TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_CHOICE_INDEX_OUT_OF_BOUNDS,
    3280             :                      NULL));
    3281           0 :           return;
    3282             :         }
    3283             :       }
    3284           6 :       break;
    3285           0 :     default:
    3286           0 :       GNUNET_break (0);
    3287           0 :       pay_end (pc,
    3288             :                TALER_MHD_reply_with_error (
    3289             :                  pc->connection,
    3290             :                  MHD_HTTP_INTERNAL_SERVER_ERROR,
    3291             :                  TALER_EC_GENERIC_DB_FETCH_FAILED,
    3292             :                  "contract 'version' in database not supported by this backend")
    3293             :                );
    3294           0 :       return;
    3295             :     }
    3296             :   }
    3297             : 
    3298          38 :   if (GNUNET_TIME_timestamp_cmp (pc->check_contract.contract_terms->
    3299             :                                  wire_deadline,
    3300             :                                  <,
    3301             :                                  pc->check_contract.contract_terms->
    3302             :                                  refund_deadline))
    3303             :   {
    3304             :     /* This should already have been checked when creating the order! */
    3305           0 :     GNUNET_break (0);
    3306           0 :     pay_end (pc,
    3307             :              TALER_MHD_reply_with_error (
    3308             :                pc->connection,
    3309             :                MHD_HTTP_INTERNAL_SERVER_ERROR,
    3310             :                TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_REFUND_DEADLINE_PAST_WIRE_TRANSFER_DEADLINE,
    3311             :                NULL));
    3312           0 :     return;
    3313             :   }
    3314          38 :   if (GNUNET_TIME_absolute_is_past (pc->check_contract.contract_terms->
    3315             :                                     pay_deadline.abs_time))
    3316             :   {
    3317             :     /* too late */
    3318           0 :     pay_end (pc,
    3319             :              TALER_MHD_reply_with_error (
    3320             :                pc->connection,
    3321             :                MHD_HTTP_GONE,
    3322             :                TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_OFFER_EXPIRED,
    3323             :                NULL));
    3324           0 :     return;
    3325             :   }
    3326             : 
    3327             : /* Make sure wire method (still) exists for this instance */
    3328             :   {
    3329             :     struct TMH_WireMethod *wm;
    3330             : 
    3331          38 :     wm = pc->hc->instance->wm_head;
    3332          39 :     while (0 != GNUNET_memcmp (&pc->check_contract.contract_terms->h_wire,
    3333             :                                &wm->h_wire))
    3334           1 :       wm = wm->next;
    3335          38 :     if (NULL == wm)
    3336             :     {
    3337           0 :       GNUNET_break (0);
    3338           0 :       pay_end (pc,
    3339             :                TALER_MHD_reply_with_error (
    3340             :                  pc->connection,
    3341             :                  MHD_HTTP_INTERNAL_SERVER_ERROR,
    3342             :                  TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_WIRE_HASH_UNKNOWN,
    3343             :                  NULL));
    3344           0 :       return;
    3345             :     }
    3346          38 :     pc->check_contract.wm = wm;
    3347             :   }
    3348          38 :   pc->phase = PP_VALIDATE_TOKENS;
    3349             : }
    3350             : 
    3351             : 
    3352             : /**
    3353             :  * Try to parse the wallet_data object of the pay request into
    3354             :  * the given context. Schedules an error response in the connection
    3355             :  * on failure.
    3356             :  *
    3357             :  * @param[in,out] pc context we use to handle the payment
    3358             :  */
    3359             : static void
    3360          42 : phase_parse_wallet_data (struct PayContext *pc)
    3361             : {
    3362             :   const json_t *tokens_evs;
    3363             :   struct GNUNET_JSON_Specification spec[] = {
    3364          42 :     GNUNET_JSON_spec_mark_optional (
    3365             :       GNUNET_JSON_spec_int16 ("choice_index",
    3366             :                               &pc->parse_wallet_data.choice_index),
    3367             :       NULL),
    3368          42 :     GNUNET_JSON_spec_mark_optional (
    3369             :       GNUNET_JSON_spec_array_const ("tokens_evs",
    3370             :                                     &tokens_evs),
    3371             :       NULL),
    3372             :     // FIXME: extend spec for wallet to submit
    3373             :     // - URL of selected donau
    3374             :     // - year
    3375             :     // - BUDIs with blinded donation receipts (donau-key-hash, blinded value)
    3376             :     // + check in later phase (once we have the contract)
    3377             :     //   that the selected donau was offered and the BUDIs are below the allowed amount
    3378          42 :     GNUNET_JSON_spec_end ()
    3379             :   };
    3380             : 
    3381          42 :   pc->parse_wallet_data.choice_index = -1;
    3382          42 :   if (NULL == pc->parse_pay.wallet_data)
    3383             :   {
    3384          36 :     pc->phase = PP_CHECK_CONTRACT;
    3385          36 :     return;
    3386             :   }
    3387             :   {
    3388             :     enum GNUNET_GenericReturnValue res;
    3389             : 
    3390           6 :     res = TALER_MHD_parse_json_data (pc->connection,
    3391             :                                      pc->parse_pay.wallet_data,
    3392             :                                      spec);
    3393           6 :     if (GNUNET_YES != res)
    3394             :     {
    3395           0 :       GNUNET_break_op (0);
    3396           0 :       pay_end (pc,
    3397             :                (GNUNET_NO == res)
    3398             :              ? MHD_YES
    3399             :              : MHD_NO);
    3400           0 :       return;
    3401             :     }
    3402             :   }
    3403             : 
    3404             :   pc->parse_wallet_data.token_envelopes_cnt
    3405           6 :     = json_array_size (tokens_evs);
    3406           6 :   if (pc->parse_wallet_data.token_envelopes_cnt >
    3407             :       MAX_TOKEN_ALLOWED_OUTPUTs)
    3408             :   {
    3409           0 :     GNUNET_break_op (0);
    3410           0 :     pay_end (pc,
    3411             :              TALER_MHD_reply_with_error (
    3412             :                pc->connection,
    3413             :                MHD_HTTP_BAD_REQUEST,
    3414             :                TALER_EC_GENERIC_PARAMETER_MALFORMED,
    3415             :                "'tokens_evs' array too long"));
    3416           0 :     return;
    3417             :   }
    3418             :   pc->parse_wallet_data.token_envelopes
    3419           6 :     = GNUNET_new_array (pc->parse_wallet_data.token_envelopes_cnt,
    3420             :                         struct TokenEnvelope);
    3421             : 
    3422             :   {
    3423             :     unsigned int tokens_ev_index;
    3424             :     json_t *token_ev;
    3425             : 
    3426          12 :     json_array_foreach (tokens_evs,
    3427             :                         tokens_ev_index,
    3428             :                         token_ev)
    3429             :     {
    3430           6 :       struct TokenEnvelope *ev
    3431           6 :         = &pc->parse_wallet_data.token_envelopes[tokens_ev_index];
    3432             :       struct GNUNET_JSON_Specification ispec[] = {
    3433           6 :         TALER_JSON_spec_token_envelope (NULL,
    3434             :                                         &ev->blinded_token),
    3435           6 :         GNUNET_JSON_spec_end ()
    3436             :       };
    3437             :       enum GNUNET_GenericReturnValue res;
    3438             : 
    3439           6 :       if (json_is_null (token_ev))
    3440           0 :         continue;
    3441           6 :       res = TALER_MHD_parse_json_data (pc->connection,
    3442             :                                        token_ev,
    3443             :                                        ispec);
    3444           6 :       if (GNUNET_YES != res)
    3445             :       {
    3446           0 :         GNUNET_break_op (0);
    3447           0 :         pay_end (pc,
    3448             :                  (GNUNET_NO == res)
    3449             :                  ? MHD_YES
    3450             :                  : MHD_NO);
    3451           0 :         return;
    3452             :       }
    3453             : 
    3454           6 :       for (unsigned int j = 0; j<tokens_ev_index; j++)
    3455             :       {
    3456           0 :         if (0 ==
    3457           0 :             GNUNET_memcmp (ev->blinded_token.blinded_pub,
    3458             :                            pc->parse_wallet_data.token_envelopes[j].
    3459             :                            blinded_token.blinded_pub))
    3460             :         {
    3461           0 :           GNUNET_break_op (0);
    3462           0 :           pay_end (pc,
    3463             :                    TALER_MHD_reply_with_error (
    3464             :                      pc->connection,
    3465             :                      MHD_HTTP_BAD_REQUEST,
    3466             :                      TALER_EC_GENERIC_PARAMETER_MALFORMED,
    3467             :                      "duplicate token envelope in list"));
    3468           0 :           return;
    3469             :         }
    3470             :       }
    3471             :     }
    3472             :   }
    3473             : 
    3474           6 :   TALER_json_hash (pc->parse_pay.wallet_data,
    3475             :                    &pc->parse_wallet_data.h_wallet_data);
    3476             : 
    3477           6 :   pc->phase = PP_CHECK_CONTRACT;
    3478             : }
    3479             : 
    3480             : 
    3481             : /**
    3482             :  * Try to parse the pay request into the given pay context.
    3483             :  * Schedules an error response in the connection on failure.
    3484             :  *
    3485             :  * @param[in,out] pc context we use to handle the payment
    3486             :  */
    3487             : static void
    3488          42 : phase_parse_pay (struct PayContext *pc)
    3489             : {
    3490          42 :   const char *session_id = NULL;
    3491             :   const json_t *coins;
    3492             :   const json_t *tokens;
    3493             :   struct GNUNET_JSON_Specification spec[] = {
    3494          42 :     GNUNET_JSON_spec_array_const ("coins",
    3495             :                                   &coins),
    3496          42 :     GNUNET_JSON_spec_mark_optional (
    3497             :       GNUNET_JSON_spec_string ("session_id",
    3498             :                                &session_id),
    3499             :       NULL),
    3500          42 :     GNUNET_JSON_spec_mark_optional (
    3501             :       GNUNET_JSON_spec_object_const ("wallet_data",
    3502             :                                      &pc->parse_pay.wallet_data),
    3503             :       NULL),
    3504          42 :     GNUNET_JSON_spec_mark_optional (
    3505             :       GNUNET_JSON_spec_array_const ("tokens",
    3506             :                                     &tokens),
    3507             :       NULL),
    3508          42 :     GNUNET_JSON_spec_end ()
    3509             :   };
    3510             : 
    3511          42 :   GNUNET_assert (PP_PARSE_PAY == pc->phase);
    3512             :   {
    3513             :     enum GNUNET_GenericReturnValue res;
    3514             : 
    3515          42 :     res = TALER_MHD_parse_json_data (pc->connection,
    3516          42 :                                      pc->hc->request_body,
    3517             :                                      spec);
    3518          42 :     if (GNUNET_YES != res)
    3519             :     {
    3520           0 :       GNUNET_break_op (0);
    3521           0 :       pay_end (pc,
    3522             :                (GNUNET_NO == res)
    3523             :                ? MHD_YES
    3524             :                : MHD_NO);
    3525           0 :       return;
    3526             :     }
    3527             :   }
    3528             : 
    3529             :   /* copy session ID (if set) */
    3530          42 :   if (NULL != session_id)
    3531             :   {
    3532          16 :     pc->parse_pay.session_id = GNUNET_strdup (session_id);
    3533             :   }
    3534             :   else
    3535             :   {
    3536             :     /* use empty string as default if client didn't specify it */
    3537          26 :     pc->parse_pay.session_id = GNUNET_strdup ("");
    3538             :   }
    3539             : 
    3540          42 :   pc->parse_pay.coins_cnt = json_array_size (coins);
    3541          42 :   if (pc->parse_pay.coins_cnt > MAX_COIN_ALLOWED_COINS)
    3542             :   {
    3543           0 :     GNUNET_break_op (0);
    3544           0 :     pay_end (pc,
    3545             :              TALER_MHD_reply_with_error (
    3546             :                pc->connection,
    3547             :                MHD_HTTP_BAD_REQUEST,
    3548             :                TALER_EC_GENERIC_PARAMETER_MALFORMED,
    3549             :                "'coins' array too long"));
    3550           0 :     return;
    3551             :   }
    3552             :   /* note: 1 coin = 1 deposit confirmation expected */
    3553          42 :   pc->parse_pay.dc = GNUNET_new_array (pc->parse_pay.coins_cnt,
    3554             :                                        struct DepositConfirmation);
    3555             : 
    3556             :   /* This loop populates the array 'dc' in 'pc' */
    3557             :   {
    3558             :     unsigned int coins_index;
    3559             :     json_t *coin;
    3560             : 
    3561          90 :     json_array_foreach (coins, coins_index, coin)
    3562             :     {
    3563          48 :       struct DepositConfirmation *dc = &pc->parse_pay.dc[coins_index];
    3564             :       const char *exchange_url;
    3565             :       struct GNUNET_JSON_Specification ispec[] = {
    3566          48 :         GNUNET_JSON_spec_fixed_auto ("coin_sig",
    3567             :                                      &dc->cdd.coin_sig),
    3568          48 :         GNUNET_JSON_spec_fixed_auto ("coin_pub",
    3569             :                                      &dc->cdd.coin_pub),
    3570          48 :         TALER_JSON_spec_denom_sig ("ub_sig",
    3571             :                                    &dc->cdd.denom_sig),
    3572          48 :         GNUNET_JSON_spec_fixed_auto ("h_denom",
    3573             :                                      &dc->cdd.h_denom_pub),
    3574          48 :         TALER_JSON_spec_amount_any ("contribution",
    3575             :                                     &dc->cdd.amount),
    3576          48 :         TALER_JSON_spec_web_url ("exchange_url",
    3577             :                                  &exchange_url),
    3578             :         /* if a minimum age was required, the minimum_age_sig and
    3579             :          * age_commitment must be provided */
    3580          48 :         GNUNET_JSON_spec_mark_optional (
    3581          48 :           GNUNET_JSON_spec_fixed_auto ("minimum_age_sig",
    3582             :                                        &dc->minimum_age_sig),
    3583             :           &dc->no_minimum_age_sig),
    3584          48 :         GNUNET_JSON_spec_mark_optional (
    3585             :           TALER_JSON_spec_age_commitment ("age_commitment",
    3586             :                                           &dc->age_commitment),
    3587             :           &dc->no_age_commitment),
    3588             :         /* if minimum age was not required, but coin with age restriction set
    3589             :          * was used, h_age_commitment must be provided. */
    3590          48 :         GNUNET_JSON_spec_mark_optional (
    3591          48 :           GNUNET_JSON_spec_fixed_auto ("h_age_commitment",
    3592             :                                        &dc->cdd.h_age_commitment),
    3593             :           &dc->no_h_age_commitment),
    3594          48 :         GNUNET_JSON_spec_end ()
    3595             :       };
    3596             :       enum GNUNET_GenericReturnValue res;
    3597          48 :       struct ExchangeGroup *eg = NULL;
    3598             : 
    3599          48 :       res = TALER_MHD_parse_json_data (pc->connection,
    3600             :                                        coin,
    3601             :                                        ispec);
    3602          48 :       if (GNUNET_YES != res)
    3603             :       {
    3604           0 :         GNUNET_break_op (0);
    3605           0 :         pay_end (pc,
    3606             :                  (GNUNET_NO == res)
    3607             :                  ? MHD_YES
    3608             :                  : MHD_NO);
    3609           0 :         return;
    3610             :       }
    3611          58 :       for (unsigned int j = 0; j<coins_index; j++)
    3612             :       {
    3613          10 :         if (0 ==
    3614          10 :             GNUNET_memcmp (&dc->cdd.coin_pub,
    3615             :                            &pc->parse_pay.dc[j].cdd.coin_pub))
    3616             :         {
    3617           0 :           GNUNET_break_op (0);
    3618           0 :           pay_end (pc,
    3619             :                    TALER_MHD_reply_with_error (pc->connection,
    3620             :                                                MHD_HTTP_BAD_REQUEST,
    3621             :                                                TALER_EC_GENERIC_PARAMETER_MALFORMED,
    3622             :                                                "duplicate coin in list"));
    3623           0 :           return;
    3624             :         }
    3625             :       }
    3626             : 
    3627          48 :       dc->exchange_url = GNUNET_strdup (exchange_url);
    3628          48 :       dc->index = coins_index;
    3629          48 :       dc->pc = pc;
    3630             : 
    3631             :       /* Check the consistency of the (potential) age restriction
    3632             :        * information. */
    3633          48 :       if (dc->no_age_commitment != dc->no_minimum_age_sig)
    3634             :       {
    3635           0 :         GNUNET_break_op (0);
    3636           0 :         pay_end (pc,
    3637             :                  TALER_MHD_reply_with_error (
    3638             :                    pc->connection,
    3639             :                    MHD_HTTP_BAD_REQUEST,
    3640             :                    TALER_EC_GENERIC_PARAMETER_MALFORMED,
    3641             :                    "inconsistent: 'age_commitment' vs. 'minimum_age_sig'"
    3642             :                    ));
    3643           0 :         return;
    3644             :       }
    3645             : 
    3646             :       /* Setup exchange group */
    3647          48 :       for (unsigned int i = 0; i<pc->parse_pay.num_exchanges; i++)
    3648             :       {
    3649          10 :         if (0 ==
    3650          10 :             strcmp (pc->parse_pay.egs[i]->exchange_url,
    3651             :                     exchange_url))
    3652             :         {
    3653          10 :           eg = pc->parse_pay.egs[i];
    3654          10 :           break;
    3655             :         }
    3656             :       }
    3657          48 :       if (NULL == eg)
    3658             :       {
    3659          38 :         eg = GNUNET_new (struct ExchangeGroup);
    3660          38 :         eg->pc = pc;
    3661          38 :         eg->exchange_url = dc->exchange_url;
    3662          38 :         eg->total = dc->cdd.amount;
    3663          38 :         GNUNET_array_append (pc->parse_pay.egs,
    3664             :                              pc->parse_pay.num_exchanges,
    3665             :                              eg);
    3666             :       }
    3667             :       else
    3668             :       {
    3669          10 :         if (0 >
    3670          10 :             TALER_amount_add (&eg->total,
    3671          10 :                               &eg->total,
    3672          10 :                               &dc->cdd.amount))
    3673             :         {
    3674           0 :           GNUNET_break_op (0);
    3675           0 :           pay_end (pc,
    3676             :                    TALER_MHD_reply_with_error (
    3677             :                      pc->connection,
    3678             :                      MHD_HTTP_INTERNAL_SERVER_ERROR,
    3679             :                      TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AMOUNT_OVERFLOW,
    3680             :                      "Overflow adding up amounts"));
    3681           0 :           return;
    3682             :         }
    3683             :       }
    3684             :     }
    3685             :   }
    3686             : 
    3687          42 :   pc->parse_pay.tokens_cnt = json_array_size (tokens);
    3688          42 :   if (pc->parse_pay.tokens_cnt > MAX_TOKEN_ALLOWED_INPUTs)
    3689             :   {
    3690           0 :     GNUNET_break_op (0);
    3691           0 :     pay_end (pc,
    3692             :              TALER_MHD_reply_with_error (
    3693             :                pc->connection,
    3694             :                MHD_HTTP_BAD_REQUEST,
    3695             :                TALER_EC_GENERIC_PARAMETER_MALFORMED,
    3696             :                "'tokens' array too long"));
    3697           0 :     return;
    3698             :   }
    3699             : 
    3700          42 :   pc->parse_pay.tokens = GNUNET_new_array (pc->parse_pay.tokens_cnt,
    3701             :                                            struct TokenUseConfirmation);
    3702             : 
    3703             :   /* This look populates the array 'tokens' in 'pc' */
    3704             :   {
    3705             :     unsigned int tokens_index;
    3706             :     json_t *token;
    3707             : 
    3708          46 :     json_array_foreach (tokens, tokens_index, token)
    3709             :     {
    3710           4 :       struct TokenUseConfirmation *tuc = &pc->parse_pay.tokens[tokens_index];
    3711             :       struct GNUNET_JSON_Specification ispec[] = {
    3712           4 :         GNUNET_JSON_spec_fixed_auto ("token_sig",
    3713             :                                      &tuc->sig),
    3714           4 :         GNUNET_JSON_spec_fixed_auto ("token_pub",
    3715             :                                      &tuc->pub),
    3716           4 :         GNUNET_JSON_spec_fixed_auto ("h_issue",
    3717             :                                      &tuc->h_issue),
    3718           4 :         TALER_JSON_spec_token_issue_sig ("ub_sig",
    3719             :                                          &tuc->unblinded_sig),
    3720           4 :         GNUNET_JSON_spec_end ()
    3721             :       };
    3722             :       enum GNUNET_GenericReturnValue res;
    3723             : 
    3724           4 :       res = TALER_MHD_parse_json_data (pc->connection,
    3725             :                                        token,
    3726             :                                        ispec);
    3727           4 :       if (GNUNET_YES != res)
    3728             :       {
    3729           0 :         GNUNET_break_op (0);
    3730           0 :         pay_end (pc,
    3731             :                  (GNUNET_NO == res)
    3732             :                  ? MHD_YES
    3733             :                  : MHD_NO);
    3734           0 :         return;
    3735             :       }
    3736             : 
    3737           4 :       for (unsigned int j = 0; j<tokens_index; j++)
    3738             :       {
    3739           0 :         if (0 ==
    3740           0 :             GNUNET_memcmp (&tuc->pub,
    3741             :                            &pc->parse_pay.tokens[j].pub))
    3742             :         {
    3743           0 :           GNUNET_break_op (0);
    3744           0 :           pay_end (pc,
    3745             :                    TALER_MHD_reply_with_error (pc->connection,
    3746             :                                                MHD_HTTP_BAD_REQUEST,
    3747             :                                                TALER_EC_GENERIC_PARAMETER_MALFORMED,
    3748             :                                                "duplicate token in list"));
    3749           0 :           return;
    3750             :         }
    3751             :       }
    3752             :     }
    3753             :   }
    3754             : 
    3755          42 :   pc->phase = PP_PARSE_WALLET_DATA;
    3756             : }
    3757             : 
    3758             : 
    3759             : /**
    3760             :  * Custom cleanup routine for a `struct PayContext`.
    3761             :  *
    3762             :  * @param cls the `struct PayContext` to clean up.
    3763             :  */
    3764             : static void
    3765          42 : pay_context_cleanup (void *cls)
    3766             : {
    3767          42 :   struct PayContext *pc = cls;
    3768             : 
    3769          42 :   if (NULL != pc->batch_deposits.timeout_task)
    3770             :   {
    3771          28 :     GNUNET_SCHEDULER_cancel (pc->batch_deposits.timeout_task);
    3772          28 :     pc->batch_deposits.timeout_task = NULL;
    3773             :   }
    3774          42 :   if (NULL != pc->check_contract.contract_terms_json)
    3775             :   {
    3776          42 :     json_decref (pc->check_contract.contract_terms_json);
    3777          42 :     pc->check_contract.contract_terms_json = NULL;
    3778             :   }
    3779          90 :   for (unsigned int i = 0; i<pc->parse_pay.coins_cnt; i++)
    3780             :   {
    3781          48 :     struct DepositConfirmation *dc = &pc->parse_pay.dc[i];
    3782             : 
    3783          48 :     TALER_denom_sig_free (&dc->cdd.denom_sig);
    3784          48 :     GNUNET_free (dc->exchange_url);
    3785             :   }
    3786          42 :   GNUNET_free (pc->parse_pay.dc);
    3787          46 :   for (unsigned int i = 0; i<pc->parse_pay.tokens_cnt; i++)
    3788             :   {
    3789           4 :     struct TokenUseConfirmation *tuc = &pc->parse_pay.tokens[i];
    3790             : 
    3791           4 :     TALER_token_issue_sig_free (&tuc->unblinded_sig);
    3792             :   }
    3793          42 :   GNUNET_free (pc->parse_pay.tokens);
    3794          80 :   for (unsigned int i = 0; i<pc->parse_pay.num_exchanges; i++)
    3795             :   {
    3796          38 :     struct ExchangeGroup *eg = pc->parse_pay.egs[i];
    3797             : 
    3798          38 :     if (NULL != eg->fo)
    3799           0 :       TMH_EXCHANGES_keys4exchange_cancel (eg->fo);
    3800          38 :     GNUNET_free (eg);
    3801             :   }
    3802          42 :   GNUNET_free (pc->parse_pay.egs);
    3803          42 :   if (NULL != pc->check_contract.contract_terms)
    3804             :   {
    3805          38 :     TALER_MERCHANT_contract_free (pc->check_contract.contract_terms);
    3806          38 :     pc->check_contract.contract_terms = NULL;
    3807             :   }
    3808          42 :   if (NULL != pc->response)
    3809             :   {
    3810           6 :     MHD_destroy_response (pc->response);
    3811           6 :     pc->response = NULL;
    3812             :   }
    3813          42 :   GNUNET_free (pc->parse_pay.session_id);
    3814          42 :   GNUNET_CONTAINER_DLL_remove (pc_head,
    3815             :                                pc_tail,
    3816             :                                pc);
    3817          42 :   GNUNET_free (pc->check_contract.pos_key);
    3818          42 :   GNUNET_free (pc);
    3819          42 : }
    3820             : 
    3821             : 
    3822             : MHD_RESULT
    3823          76 : TMH_post_orders_ID_pay (const struct TMH_RequestHandler *rh,
    3824             :                         struct MHD_Connection *connection,
    3825             :                         struct TMH_HandlerContext *hc)
    3826             : {
    3827          76 :   struct PayContext *pc = hc->ctx;
    3828             : 
    3829          76 :   GNUNET_assert (NULL != hc->infix);
    3830          76 :   if (NULL == pc)
    3831             :   {
    3832          42 :     pc = GNUNET_new (struct PayContext);
    3833          42 :     pc->connection = connection;
    3834          42 :     pc->hc = hc;
    3835          42 :     pc->order_id = hc->infix;
    3836          42 :     hc->ctx = pc;
    3837          42 :     hc->cc = &pay_context_cleanup;
    3838          42 :     GNUNET_CONTAINER_DLL_insert (pc_head,
    3839             :                                  pc_tail,
    3840             :                                  pc);
    3841             :   }
    3842             :   while (1)
    3843             :   {
    3844         672 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    3845             :                 "Processing /pay in phase %d\n",
    3846             :                 (int) pc->phase);
    3847         374 :     switch (pc->phase)
    3848             :     {
    3849          42 :     case PP_PARSE_PAY:
    3850          42 :       phase_parse_pay (pc);
    3851          42 :       break;
    3852          42 :     case PP_PARSE_WALLET_DATA:
    3853          42 :       phase_parse_wallet_data (pc);
    3854          42 :       break;
    3855          42 :     case PP_CHECK_CONTRACT:
    3856          42 :       phase_check_contract (pc);
    3857          42 :       break;
    3858          38 :     case PP_VALIDATE_TOKENS:
    3859          38 :       phase_validate_tokens (pc);
    3860          38 :       break;
    3861           4 :     case PP_CONTRACT_PAID:
    3862           4 :       phase_contract_paid (pc);
    3863           4 :       break;
    3864          66 :     case PP_PAY_TRANSACTION:
    3865          66 :       phase_execute_pay_transaction (pc);
    3866          66 :       break;
    3867          28 :     case PP_PAYMENT_NOTIFICATION:
    3868          28 :       phase_payment_notification (pc);
    3869          28 :       break;
    3870             :     // FIXME: donau phase
    3871          30 :     case PP_SUCCESS_RESPONSE:
    3872          30 :       phase_success_response (pc);
    3873          30 :       break;
    3874          34 :     case PP_BATCH_DEPOSITS:
    3875          34 :       phase_batch_deposits (pc);
    3876          34 :       break;
    3877           6 :     case PP_RETURN_RESPONSE:
    3878           6 :       phase_return_response (pc);
    3879           6 :       break;
    3880           0 :     case PP_FAIL_LEGAL_REASONS:
    3881           0 :       phase_fail_for_legal_reasons (pc);
    3882           0 :       break;
    3883          42 :     case PP_END_YES:
    3884          42 :       return MHD_YES;
    3885           0 :     case PP_END_NO:
    3886           0 :       return MHD_NO;
    3887             :     }
    3888         332 :     switch (pc->suspended)
    3889             :     {
    3890           0 :     case GNUNET_SYSERR:
    3891             :       /* during shutdown, we don't generate any more replies */
    3892           0 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    3893             :                   "Processing /pay ends due to shutdown in phase %d\n",
    3894             :                   (int) pc->phase);
    3895           0 :       return MHD_NO;
    3896         298 :     case GNUNET_NO:
    3897             :       /* continue to next phase */
    3898         298 :       break;
    3899          34 :     case GNUNET_YES:
    3900          34 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    3901             :                   "Processing /pay suspended in phase %d\n",
    3902             :                   (int) pc->phase);
    3903          34 :       return MHD_YES;
    3904             :     }
    3905             :   }
    3906             :   /* impossible to get here */
    3907             :   GNUNET_assert (0);
    3908             :   return MHD_YES;
    3909             : }
    3910             : 
    3911             : 
    3912             : /* end of taler-merchant-httpd_post-orders-ID-pay.c */

Generated by: LCOV version 1.16