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: 833 1399 59.5 %
Date: 2025-08-28 06:06:54 Functions: 31 39 79.5 %

          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             : #ifdef HAVE_DONAU_DONAU_SERVICE_H
      51             : #include <donau/donau_service.h>
      52             : #include <donau/donau_util.h>
      53             : #include <donau/donau_json_lib.h>
      54             : #endif
      55             : 
      56             : /**
      57             :  * How often do we retry the (complex!) database transaction?
      58             :  */
      59             : #define MAX_RETRIES 5
      60             : 
      61             : /**
      62             :  * Maximum number of coins that we allow per transaction.
      63             :  * Note that the limit for each batch deposit request to
      64             :  * the exchange is lower, so we may break a very large
      65             :  * number of coins up into multiple smaller requests to
      66             :  * the exchange.
      67             :  */
      68             : #define MAX_COIN_ALLOWED_COINS 1024
      69             : 
      70             : /**
      71             :  * Maximum number of tokens that we allow as inputs per transaction
      72             :  */
      73             : #define MAX_TOKEN_ALLOWED_INPUTs 64
      74             : 
      75             : /**
      76             :  * Maximum number of tokens that we allow as outputs per transaction
      77             :  */
      78             : #define MAX_TOKEN_ALLOWED_OUTPUTs 64
      79             : 
      80             : /**
      81             :  * How often do we ask the exchange again about our
      82             :  * KYC status? Very rarely, as if the user actively
      83             :  * changes it, we should usually notice anyway.
      84             :  */
      85             : #define KYC_RETRY_FREQUENCY GNUNET_TIME_UNIT_WEEKS
      86             : 
      87             : /**
      88             :  * Information we keep for an individual call to the pay handler.
      89             :  */
      90             : struct PayContext;
      91             : 
      92             : 
      93             : /**
      94             :  * Different phases of processing the /pay request.
      95             :  */
      96             : enum PayPhase
      97             : {
      98             :   /**
      99             :    * Initial phase where the request is parsed.
     100             :    */
     101             :   PP_PARSE_PAY = 0,
     102             : 
     103             :   /**
     104             :    * Parse wallet data object from the pay request.
     105             :    */
     106             :   PP_PARSE_WALLET_DATA,
     107             : 
     108             :   /**
     109             :    * Check database state for the given order.
     110             :    */
     111             :   PP_CHECK_CONTRACT,
     112             : 
     113             :   /**
     114             :    * Validate provided tokens and token envelopes.
     115             :    */
     116             :   PP_VALIDATE_TOKENS,
     117             : 
     118             :   /**
     119             :    * Check if contract has been paid.
     120             :    */
     121             :   PP_CONTRACT_PAID,
     122             : 
     123             :   /**
     124             :    * Execute payment transaction.
     125             :    */
     126             :   PP_PAY_TRANSACTION,
     127             : 
     128             : #ifdef HAVE_DONAU_DONAU_SERVICE_H
     129             :   /**
     130             :    * Communicate with DONAU to generate a donation receipt from the donor BUDIs.
     131             :    */
     132             :   PP_REQUEST_DONATION_RECEIPT,
     133             : #endif
     134             : 
     135             :   /**
     136             :    * Process the donation receipt response from DONAU (save the donau_sigs to the db).
     137             :    */
     138             :   PP_FINAL_OUTPUT_TOKEN_PROCESSING,
     139             : 
     140             :   /**
     141             :    * Notify other processes about successful payment.
     142             :    */
     143             :   PP_PAYMENT_NOTIFICATION,
     144             : 
     145             :   /**
     146             :    * Create final success response.
     147             :    */
     148             :   PP_SUCCESS_RESPONSE,
     149             : 
     150             :   /**
     151             :    * Perform batch deposits with exchange(s).
     152             :    */
     153             :   PP_BATCH_DEPOSITS,
     154             : 
     155             :   /**
     156             :    * Return response in payment context.
     157             :    */
     158             :   PP_RETURN_RESPONSE,
     159             : 
     160             :   /**
     161             :    * An exchange denied a deposit, fail for
     162             :    * legal reasons.
     163             :    */
     164             :   PP_FAIL_LEGAL_REASONS,
     165             : 
     166             :   /**
     167             :    * Return #MHD_YES to end processing.
     168             :    */
     169             :   PP_END_YES,
     170             : 
     171             :   /**
     172             :    * Return #MHD_NO to end processing.
     173             :    */
     174             :   PP_END_NO
     175             : };
     176             : 
     177             : 
     178             : /**
     179             :  * Information kept during a pay request for each coin.
     180             :  */
     181             : struct DepositConfirmation
     182             : {
     183             : 
     184             :   /**
     185             :    * Reference to the main PayContext
     186             :    */
     187             :   struct PayContext *pc;
     188             : 
     189             :   /**
     190             :    * URL of the exchange that issued this coin.
     191             :    */
     192             :   char *exchange_url;
     193             : 
     194             :   /**
     195             :    * Details about the coin being deposited.
     196             :    */
     197             :   struct TALER_EXCHANGE_CoinDepositDetail cdd;
     198             : 
     199             :   /**
     200             :    * Fee charged by the exchange for the deposit operation of this coin.
     201             :    */
     202             :   struct TALER_Amount deposit_fee;
     203             : 
     204             :   /**
     205             :    * Fee charged by the exchange for the refund operation of this coin.
     206             :    */
     207             :   struct TALER_Amount refund_fee;
     208             : 
     209             :   /**
     210             :    * If a minimum age was required (i. e. pc->minimum_age is large enough),
     211             :    * this is the signature of the minimum age (as a single uint8_t), using the
     212             :    * private key to the corresponding age group.  Might be all zeroes for no
     213             :    * age attestation.
     214             :    */
     215             :   struct TALER_AgeAttestationP minimum_age_sig;
     216             : 
     217             :   /**
     218             :    * If a minimum age was required (i. e. pc->minimum_age is large enough),
     219             :    * this is the age commitment (i. e. age mask and vector of EdDSA public
     220             :    * keys, one per age group) that went into the mining of the coin.  The
     221             :    * SHA256 hash of the mask and the vector of public keys was bound to the
     222             :    * key.
     223             :    */
     224             :   struct TALER_AgeCommitment age_commitment;
     225             : 
     226             :   /**
     227             :    * Age mask in the denomination that defines the age groups.  Only
     228             :    * applicable, if minimum age was required.
     229             :    */
     230             :   struct TALER_AgeMask age_mask;
     231             : 
     232             :   /**
     233             :    * Offset of this coin into the `dc` array of all coins in the
     234             :    * @e pc.
     235             :    */
     236             :   unsigned int index;
     237             : 
     238             :   /**
     239             :    * true, if no field "age_commitment" was found in the JSON blob
     240             :    */
     241             :   bool no_age_commitment;
     242             : 
     243             :   /**
     244             :    * True, if no field "minimum_age_sig" was found in the JSON blob
     245             :    */
     246             :   bool no_minimum_age_sig;
     247             : 
     248             :   /**
     249             :    * true, if no field "h_age_commitment" was found in the JSON blob
     250             :    */
     251             :   bool no_h_age_commitment;
     252             : 
     253             :   /**
     254             :    * true if we found this coin in the database.
     255             :    */
     256             :   bool found_in_db;
     257             : 
     258             :   /**
     259             :    * true if we #deposit_paid_check() matched this coin in the database.
     260             :    */
     261             :   bool matched_in_db;
     262             : 
     263             : };
     264             : 
     265             : struct TokenUseConfirmation
     266             : {
     267             : 
     268             :   /**
     269             :    * Signature on the deposit request made using the token use private key.
     270             :    */
     271             :   struct TALER_TokenUseSignatureP sig;
     272             : 
     273             :   /**
     274             :    * Token use public key. This key was blindly signed by the merchant during
     275             :    * the token issuance process.
     276             :    */
     277             :   struct TALER_TokenUsePublicKeyP pub;
     278             : 
     279             :   /**
     280             :    * Unblinded signature on the token use public key done by the merchant.
     281             :    */
     282             :   struct TALER_TokenIssueSignature unblinded_sig;
     283             : 
     284             :   /**
     285             :    * Hash of the token issue public key associated with this token.
     286             :    * Note this is set in the validate_tokens phase.
     287             :    */
     288             :   struct TALER_TokenIssuePublicKeyHashP h_issue;
     289             : 
     290             :   /**
     291             :    * true if we found this token in the database.
     292             :    */
     293             :   bool found_in_db;
     294             : 
     295             : };
     296             : 
     297             : 
     298             : /**
     299             :  * Information about a token envelope.
     300             :  */
     301             : struct TokenEnvelope
     302             : {
     303             : 
     304             :   /**
     305             :    * Blinded token use public keys waiting to be signed.
     306             :    */
     307             :   struct TALER_TokenEnvelope blinded_token;
     308             : 
     309             : };
     310             : 
     311             : 
     312             : /**
     313             :  * (Blindly) signed token to be returned to the wallet.
     314             :  */
     315             : struct SignedOutputToken
     316             : {
     317             : 
     318             :   /**
     319             :    * Blinded token use public keys waiting to be signed.
     320             :    */
     321             :   struct TALER_BlindedTokenIssueSignature sig;
     322             : 
     323             :   /**
     324             :    * Hash of token issue public key.
     325             :    */
     326             :   struct TALER_TokenIssuePublicKeyHashP h_issue;
     327             : 
     328             : };
     329             : 
     330             : 
     331             : /**
     332             :  * Information kept during a pay request for each exchange.
     333             :  */
     334             : struct ExchangeGroup
     335             : {
     336             : 
     337             :   /**
     338             :    * Payment context this group is part of.
     339             :    */
     340             :   struct PayContext *pc;
     341             : 
     342             :   /**
     343             :    * Handle to the batch deposit operation we are performing for this
     344             :    * exchange, NULL after the operation is done.
     345             :    */
     346             :   struct TALER_EXCHANGE_BatchDepositHandle *bdh;
     347             : 
     348             :   /**
     349             :    * Handle for operation to lookup /keys (and auditors) from
     350             :    * the exchange used for this transaction; NULL if no operation is
     351             :    * pending.
     352             :    */
     353             :   struct TMH_EXCHANGES_KeysOperation *fo;
     354             : 
     355             :   /**
     356             :    * URL of the exchange that issued this coin. Aliases
     357             :    * the exchange URL of one of the coins, do not free!
     358             :    */
     359             :   const char *exchange_url;
     360             : 
     361             :   /**
     362             :    * Total deposit amount in this exchange group.
     363             :    */
     364             :   struct TALER_Amount total;
     365             : 
     366             :   /**
     367             :    * Wire fee that applies to this exchange for the
     368             :    * given payment context's wire method.
     369             :    */
     370             :   struct TALER_Amount wire_fee;
     371             : 
     372             :   /**
     373             :    * true if we already tried a forced /keys download.
     374             :    */
     375             :   bool tried_force_keys;
     376             : 
     377             :   /**
     378             :    * Did this exchange deny the transaction for legal reasons?
     379             :    */
     380             :   bool got_451;
     381             : };
     382             : 
     383             : 
     384             : /**
     385             :  * Information about donau, that can be fetched even
     386             :  * if the merhchant doesn't support donau
     387             :  */
     388             : struct DonauData
     389             : {
     390             :   /**
     391             :    * The user-selected Donau URL.
     392             :    */
     393             :   char *donau_url;
     394             : 
     395             :   /**
     396             :    * The donation year, as parsed from "year".
     397             :    */
     398             :   uint64_t donation_year;
     399             : 
     400             :   /**
     401             :    * The original BUDI key-pairs array from the donor
     402             :    * to be used for the receipt creation.
     403             :    */
     404             :   const json_t *budikeypairs;
     405             : };
     406             : 
     407             : /**
     408             :  * Information we keep for an individual call to the /pay handler.
     409             :  */
     410             : struct PayContext
     411             : {
     412             : 
     413             :   /**
     414             :    * Stored in a DLL.
     415             :    */
     416             :   struct PayContext *next;
     417             : 
     418             :   /**
     419             :    * Stored in a DLL.
     420             :    */
     421             :   struct PayContext *prev;
     422             : 
     423             :   /**
     424             :    * MHD connection to return to
     425             :    */
     426             :   struct MHD_Connection *connection;
     427             : 
     428             :   /**
     429             :    * Details about the client's request.
     430             :    */
     431             :   struct TMH_HandlerContext *hc;
     432             : 
     433             :   /**
     434             :    * Transaction ID given in @e root.
     435             :    */
     436             :   const char *order_id;
     437             : 
     438             :   /**
     439             :    * Response to return, NULL if we don't have one yet.
     440             :    */
     441             :   struct MHD_Response *response;
     442             : 
     443             :   /**
     444             :    * Array with @e output_tokens_len signed tokens returned in
     445             :    * the response to the wallet.
     446             :    */
     447             :   struct SignedOutputToken *output_tokens;
     448             : 
     449             :   /**
     450             :    * Number of output tokens to return in the response.
     451             :    * Length of the @e output_tokens array.
     452             :    */
     453             :   unsigned int output_tokens_len;
     454             : 
     455             :   /**
     456             :    * HTTP status code to use for the reply, i.e 200 for "OK".
     457             :    * Special value UINT_MAX is used to indicate hard errors
     458             :    * (no reply, return #MHD_NO).
     459             :    */
     460             :   unsigned int response_code;
     461             : 
     462             :   /**
     463             :    * Payment processing phase we are in.
     464             :    */
     465             :   enum PayPhase phase;
     466             : 
     467             :   /**
     468             :    * #GNUNET_NO if the @e connection was not suspended,
     469             :    * #GNUNET_YES if the @e connection was suspended,
     470             :    * #GNUNET_SYSERR if @e connection was resumed to as
     471             :    * part of #MH_force_pc_resume during shutdown.
     472             :    */
     473             :   enum GNUNET_GenericReturnValue suspended;
     474             : 
     475             :   /**
     476             :    * Results from the phase_parse_pay()
     477             :    */
     478             :   struct
     479             :   {
     480             : 
     481             :     /**
     482             :      * Array with @e num_exchanges exchanges we are depositing
     483             :      * coins into.
     484             :      */
     485             :     struct ExchangeGroup **egs;
     486             : 
     487             :     /**
     488             :      * Array with @e coins_cnt coins we are despositing.
     489             :      */
     490             :     struct DepositConfirmation *dc;
     491             : 
     492             :     /**
     493             :      * Array with @e tokens_cnt input tokens passed to this request.
     494             :      */
     495             :     struct TokenUseConfirmation *tokens;
     496             : 
     497             :     /**
     498             :      * Optional session id given in @e root.
     499             :      * NULL if not given.
     500             :      */
     501             :     char *session_id;
     502             : 
     503             :     /**
     504             :      * Wallet data json object from the request. Containing additional
     505             :      * wallet data such as the selected choice_index.
     506             :      */
     507             :     const json_t *wallet_data;
     508             : 
     509             :     /**
     510             :      * Number of coins this payment is made of.  Length
     511             :      * of the @e dc array.
     512             :      */
     513             :     size_t coins_cnt;
     514             : 
     515             :     /**
     516             :      * Number of input tokens passed to this request.  Length
     517             :      * of the @e tokens array.
     518             :      */
     519             :     size_t tokens_cnt;
     520             : 
     521             :     /**
     522             :      * Number of exchanges involved in the payment. Length
     523             :      * of the @e eg array.
     524             :      */
     525             :     unsigned int num_exchanges;
     526             : 
     527             :   } parse_pay;
     528             : 
     529             :   /**
     530             :    * Results from the phase_wallet_data()
     531             :    */
     532             :   struct
     533             :   {
     534             : 
     535             :     /**
     536             :      * Array with @e token_envelopes_cnt (blinded) token envelopes.
     537             :      */
     538             :     struct TokenEnvelope *token_envelopes;
     539             : 
     540             :     /**
     541             :      * Index of selected choice in the @e contract_terms choices array.
     542             :      */
     543             :     int16_t choice_index;
     544             : 
     545             :     /**
     546             :      * Number of token envelopes passed to this request.
     547             :      * Length of the @e token_envelopes array.
     548             :      */
     549             :     size_t token_envelopes_cnt;
     550             : 
     551             :     /**
     552             :      * Hash of the canonicalized wallet data json object.
     553             :      */
     554             :     struct GNUNET_HashCode h_wallet_data;
     555             : 
     556             :     /**
     557             :      * Donau related information
     558             :      */
     559             :     struct DonauData donau;
     560             : 
     561             :     /**
     562             :      * Serial from the DB of the donau instance that we are using
     563             :      */
     564             :     uint64_t donau_instance_serial;
     565             : 
     566             : #ifdef  HAVE_DONAU_DONAU_SERVICE_H
     567             :     /**
     568             :      * Number of the blinded key pairs @e bkps
     569             :      */
     570             :     unsigned int num_bkps;
     571             : 
     572             :     /**
     573             :      * Blinded key pairs received from the wallet
     574             :      */
     575             :     struct DONAU_BlindedUniqueDonorIdentifierKeyPair *bkps;
     576             : 
     577             :     /**
     578             :      * The id of the charity as saved on the donau.
     579             :      */
     580             :     uint64_t charity_id;
     581             : 
     582             :     /**
     583             :      * Private key of the charity(related to the private key of the merchant).
     584             :      */
     585             :     struct DONAU_CharityPrivateKeyP charity_priv;
     586             : 
     587             :     /**
     588             :      * Maximum amount of donations that the charity can receive per year.
     589             :      */
     590             :     struct TALER_Amount charity_max_per_year;
     591             : 
     592             :     /**
     593             :      * Amount of donations that the charity has received so far this year.
     594             :      */
     595             :     struct TALER_Amount charity_receipts_to_date;
     596             : 
     597             :     /**
     598             :      * Donau keys, that we are using to get the information about the bkps.
     599             :      */
     600             :     struct DONAU_Keys *donau_keys;
     601             : 
     602             :     /**
     603             :      * Amount from BKPS
     604             :      */
     605             :     struct TALER_Amount donation_amount;
     606             : #endif
     607             : 
     608             :   } parse_wallet_data;
     609             : 
     610             :   /**
     611             :    * Results from the phase_check_contract()
     612             :    */
     613             :   struct
     614             :   {
     615             : 
     616             :     /**
     617             :      * Hashed @e contract_terms.
     618             :      */
     619             :     struct TALER_PrivateContractHashP h_contract_terms;
     620             : 
     621             :     /**
     622             :      * Our contract (or NULL if not available).
     623             :      */
     624             :     json_t *contract_terms_json;
     625             : 
     626             :     /**
     627             :      * Parsed contract terms, NULL when parsing failed.
     628             :      */
     629             :     struct TALER_MERCHANT_Contract *contract_terms;
     630             : 
     631             :     /**
     632             :      * What wire method (of the @e mi) was selected by the wallet?
     633             :      * Set in #phase_parse_pay().
     634             :      */
     635             :     struct TMH_WireMethod *wm;
     636             : 
     637             :     /**
     638             :      * Set to the POS key, if applicable for this order.
     639             :      */
     640             :     char *pos_key;
     641             : 
     642             :     /**
     643             :      * Serial number of this order in the database (set once we did the lookup).
     644             :      */
     645             :     uint64_t order_serial;
     646             : 
     647             :     /**
     648             :      * Algorithm chosen for generating the confirmation code.
     649             :      */
     650             :     enum TALER_MerchantConfirmationAlgorithm pos_alg;
     651             : 
     652             :   } check_contract;
     653             : 
     654             :   /**
     655             :    * Results from the phase_validate_tokens()
     656             :    */
     657             :   struct
     658             :   {
     659             : 
     660             :     /**
     661             :      * Maximum fee the merchant is willing to pay, from @e root.
     662             :      * Note that IF the total fee of the exchange is higher, that is
     663             :      * acceptable to the merchant if the customer is willing to
     664             :      * pay the difference
     665             :      * (i.e. amount - max_fee <= actual_amount - actual_fee).
     666             :      */
     667             :     struct TALER_Amount max_fee;
     668             : 
     669             :     /**
     670             :      * Amount from @e root.  This is the amount the merchant expects
     671             :      * to make, minus @e max_fee.
     672             :      */
     673             :     struct TALER_Amount brutto;
     674             : 
     675             :   } validate_tokens;
     676             : 
     677             :   /**
     678             :    * Results from the phase_execute_pay_transaction()
     679             :    */
     680             :   struct
     681             :   {
     682             : 
     683             :     /**
     684             :      * Considering all the coins with the "found_in_db" flag
     685             :      * set, what is the total amount we were so far paid on
     686             :      * this contract?
     687             :      */
     688             :     struct TALER_Amount total_paid;
     689             : 
     690             :     /**
     691             :      * Considering all the coins with the "found_in_db" flag
     692             :      * set, what is the total amount we had to pay in deposit
     693             :      * fees so far on this contract?
     694             :      */
     695             :     struct TALER_Amount total_fees_paid;
     696             : 
     697             :     /**
     698             :      * Considering all the coins with the "found_in_db" flag
     699             :      * set, what is the total amount we already refunded?
     700             :      */
     701             :     struct TALER_Amount total_refunded;
     702             : 
     703             :     /**
     704             :      * Number of coin deposits pending.
     705             :      */
     706             :     unsigned int pending;
     707             : 
     708             :     /**
     709             :      * How often have we retried the 'main' transaction?
     710             :      */
     711             :     unsigned int retry_counter;
     712             : 
     713             :     /**
     714             :      * Set to true if the deposit currency of a coin
     715             :      * does not match the contract currency.
     716             :      */
     717             :     bool deposit_currency_mismatch;
     718             : 
     719             :     /**
     720             :      * Set to true if the database contains a (bogus)
     721             :      * refund for a different currency.
     722             :      */
     723             :     bool refund_currency_mismatch;
     724             : 
     725             :   } pay_transaction;
     726             : 
     727             :   /**
     728             :    * Results from the phase_batch_deposits()
     729             :    */
     730             :   struct
     731             :   {
     732             : 
     733             :     /**
     734             :      * Task called when the (suspended) processing for
     735             :      * the /pay request times out.
     736             :      * Happens when we don't get a response from the exchange.
     737             :      */
     738             :     struct GNUNET_SCHEDULER_Task *timeout_task;
     739             : 
     740             :     /**
     741             :      * Number of batch transactions pending.
     742             :      */
     743             :     unsigned int pending_at_eg;
     744             : 
     745             :     /**
     746             :      * Did any exchange deny a deposit for legal reasons?
     747             :      */
     748             :     bool got_451;
     749             : 
     750             :   } batch_deposits;
     751             : 
     752             : #ifdef HAVE_DONAU_DONAU_SERVICE_H
     753             :   /**
     754             :    * Struct for #phase_request_donation_receipt()
     755             :    */
     756             :   struct
     757             :   {
     758             :     /**
     759             :      * Handler of the donau request
     760             :      */
     761             :     struct DONAU_BatchIssueReceiptHandle *birh;
     762             : 
     763             :   } donau_receipt;
     764             : #endif
     765             : };
     766             : 
     767             : 
     768             : /**
     769             :  * Head of active pay context DLL.
     770             :  */
     771             : static struct PayContext *pc_head;
     772             : 
     773             : /**
     774             :  * Tail of active pay context DLL.
     775             :  */
     776             : static struct PayContext *pc_tail;
     777             : 
     778             : 
     779             : void
     780          15 : TMH_force_pc_resume ()
     781             : {
     782          15 :   for (struct PayContext *pc = pc_head;
     783          15 :        NULL != pc;
     784           0 :        pc = pc->next)
     785             :   {
     786           0 :     if (NULL != pc->batch_deposits.timeout_task)
     787             :     {
     788           0 :       GNUNET_SCHEDULER_cancel (pc->batch_deposits.timeout_task);
     789           0 :       pc->batch_deposits.timeout_task = NULL;
     790             :     }
     791           0 :     if (GNUNET_YES == pc->suspended)
     792             :     {
     793           0 :       pc->suspended = GNUNET_SYSERR;
     794           0 :       MHD_resume_connection (pc->connection);
     795             :     }
     796             :   }
     797          15 : }
     798             : 
     799             : 
     800             : /**
     801             :  * Resume payment processing.
     802             :  *
     803             :  * @param[in,out] pc payment process to resume
     804             :  */
     805             : static void
     806          35 : pay_resume (struct PayContext *pc)
     807             : {
     808          35 :   GNUNET_assert (GNUNET_YES == pc->suspended);
     809          35 :   pc->suspended = GNUNET_NO;
     810          35 :   MHD_resume_connection (pc->connection);
     811          35 :   TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */
     812          35 : }
     813             : 
     814             : 
     815             : /**
     816             :  * Resume the given pay context and send the given response.
     817             :  * Stores the response in the @a pc and signals MHD to resume
     818             :  * the connection.  Also ensures MHD runs immediately.
     819             :  *
     820             :  * @param pc payment context
     821             :  * @param response_code response code to use
     822             :  * @param response response data to send back
     823             :  */
     824             : static void
     825           6 : resume_pay_with_response (struct PayContext *pc,
     826             :                           unsigned int response_code,
     827             :                           struct MHD_Response *response)
     828             : {
     829           6 :   pc->response_code = response_code;
     830           6 :   pc->response = response;
     831           6 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     832             :               "Resuming /pay handling. HTTP status for our reply is %u.\n",
     833             :               response_code);
     834          12 :   for (unsigned int i = 0; i<pc->parse_pay.num_exchanges; i++)
     835             :   {
     836           6 :     struct ExchangeGroup *eg = pc->parse_pay.egs[i];
     837             : 
     838           6 :     if (NULL != eg->fo)
     839             :     {
     840           0 :       TMH_EXCHANGES_keys4exchange_cancel (eg->fo);
     841           0 :       eg->fo = NULL;
     842           0 :       pc->batch_deposits.pending_at_eg--;
     843             :     }
     844           6 :     if (NULL != eg->bdh)
     845             :     {
     846           0 :       TALER_EXCHANGE_batch_deposit_cancel (eg->bdh);
     847           0 :       eg->bdh = NULL;
     848           0 :       pc->batch_deposits.pending_at_eg--;
     849             :     }
     850             :   }
     851           6 :   GNUNET_assert (0 == pc->batch_deposits.pending_at_eg);
     852           6 :   if (NULL != pc->batch_deposits.timeout_task)
     853             :   {
     854           6 :     GNUNET_SCHEDULER_cancel (pc->batch_deposits.timeout_task);
     855           6 :     pc->batch_deposits.timeout_task = NULL;
     856             :   }
     857           6 :   pc->phase = PP_RETURN_RESPONSE;
     858           6 :   pay_resume (pc);
     859           6 : }
     860             : 
     861             : 
     862             : /**
     863             :  * Resume payment processing with an error.
     864             :  *
     865             :  * @param pc operation to resume
     866             :  * @param ec taler error code to return
     867             :  * @param msg human readable error message
     868             :  */
     869             : static void
     870           0 : resume_pay_with_error (struct PayContext *pc,
     871             :                        enum TALER_ErrorCode ec,
     872             :                        const char *msg)
     873             : {
     874           0 :   resume_pay_with_response (
     875             :     pc,
     876             :     TALER_ErrorCode_get_http_status_safe (ec),
     877             :     TALER_MHD_make_error (ec,
     878             :                           msg));
     879           0 : }
     880             : 
     881             : 
     882             : /**
     883             :  * Conclude payment processing for @a pc with the
     884             :  * given @a res MHD status code.
     885             :  *
     886             :  * @param[in,out] pc payment context for final state transition
     887             :  * @param res MHD return code to end with
     888             :  */
     889             : static void
     890          43 : pay_end (struct PayContext *pc,
     891             :          MHD_RESULT res)
     892             : {
     893          43 :   pc->phase = (MHD_YES == res)
     894             :     ? PP_END_YES
     895          43 :     : PP_END_NO;
     896          43 : }
     897             : 
     898             : 
     899             : /**
     900             :  * Return response stored in @a pc.
     901             :  *
     902             :  * @param[in,out] pc payment context we are processing
     903             :  */
     904             : static void
     905           6 : phase_return_response (struct PayContext *pc)
     906             : {
     907           6 :   GNUNET_assert (0 != pc->response_code);
     908             :   /* We are *done* processing the request, just queue the response (!) */
     909           6 :   if (UINT_MAX == pc->response_code)
     910             :   {
     911           0 :     GNUNET_break (0);
     912           0 :     pay_end (pc,
     913             :              MHD_NO); /* hard error */
     914           0 :     return;
     915             :   }
     916           6 :   pay_end (pc,
     917             :            MHD_queue_response (pc->connection,
     918             :                                pc->response_code,
     919             :                                pc->response));
     920             : }
     921             : 
     922             : 
     923             : /**
     924             :  * Return a response indicating failure for legal reasons.
     925             :  *
     926             :  * @param[in,out] pc payment context we are processing
     927             :  */
     928             : static void
     929           0 : phase_fail_for_legal_reasons (struct PayContext *pc)
     930             : {
     931             :   json_t *exchanges;
     932             : 
     933           0 :   GNUNET_assert (0 == pc->pay_transaction.pending);
     934           0 :   GNUNET_assert (pc->batch_deposits.got_451);
     935           0 :   exchanges = json_array ();
     936           0 :   GNUNET_assert (NULL != exchanges);
     937           0 :   for (unsigned int i = 0; i<pc->parse_pay.num_exchanges; i++)
     938             :   {
     939           0 :     struct ExchangeGroup *eg = pc->parse_pay.egs[i];
     940             : 
     941           0 :     GNUNET_assert (NULL == eg->fo);
     942           0 :     GNUNET_assert (NULL == eg->bdh);
     943           0 :     if (! eg->got_451)
     944           0 :       continue;
     945           0 :     GNUNET_assert (
     946             :       0 ==
     947             :       json_array_append_new (
     948             :         exchanges,
     949             :         json_string (eg->exchange_url)));
     950             :   }
     951           0 :   pay_end (pc,
     952           0 :            TALER_MHD_REPLY_JSON_PACK (
     953             :              pc->connection,
     954             :              MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS,
     955             :              GNUNET_JSON_pack_array_steal ("exchange_base_urls",
     956             :                                            exchanges)));
     957           0 : }
     958             : 
     959             : 
     960             : /**
     961             :  * Do database transaction for a completed batch deposit.
     962             :  *
     963             :  * @param eg group that completed
     964             :  * @param dr response from the server
     965             :  * @return transaction status
     966             :  */
     967             : static enum GNUNET_DB_QueryStatus
     968          29 : batch_deposit_transaction (const struct ExchangeGroup *eg,
     969             :                            const struct TALER_EXCHANGE_BatchDepositResult *dr)
     970             : {
     971          29 :   const struct PayContext *pc = eg->pc;
     972             :   enum GNUNET_DB_QueryStatus qs;
     973             :   struct TALER_Amount total_without_fees;
     974             :   uint64_t b_dep_serial;
     975          29 :   uint32_t off = 0;
     976             : 
     977          29 :   GNUNET_assert (GNUNET_OK ==
     978             :                  TALER_amount_set_zero (pc->validate_tokens.brutto.currency,
     979             :                                         &total_without_fees));
     980          64 :   for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++)
     981             :   {
     982          35 :     struct DepositConfirmation *dc = &pc->parse_pay.dc[i];
     983             :     struct TALER_Amount amount_without_fees;
     984             : 
     985             :     /* might want to group deposits by batch more explicitly ... */
     986          35 :     if (0 != strcmp (eg->exchange_url,
     987          35 :                      dc->exchange_url))
     988           0 :       continue;
     989          35 :     if (dc->found_in_db)
     990           0 :       continue;
     991          35 :     GNUNET_assert (0 <=
     992             :                    TALER_amount_subtract (&amount_without_fees,
     993             :                                           &dc->cdd.amount,
     994             :                                           &dc->deposit_fee));
     995          35 :     GNUNET_assert (0 <=
     996             :                    TALER_amount_add (&total_without_fees,
     997             :                                      &total_without_fees,
     998             :                                      &amount_without_fees));
     999             :   }
    1000          29 :   qs = TMH_db->insert_deposit_confirmation (
    1001          29 :     TMH_db->cls,
    1002          29 :     pc->hc->instance->settings.id,
    1003             :     dr->details.ok.deposit_timestamp,
    1004             :     &pc->check_contract.h_contract_terms,
    1005          29 :     eg->exchange_url,
    1006          29 :     pc->check_contract.contract_terms->wire_deadline,
    1007             :     &total_without_fees,
    1008             :     &eg->wire_fee,
    1009          29 :     &pc->check_contract.wm->h_wire,
    1010          29 :     dr->details.ok.exchange_sig,
    1011          29 :     dr->details.ok.exchange_pub,
    1012             :     &b_dep_serial);
    1013          29 :   if (qs <= 0)
    1014           0 :     return qs; /* Entire batch already known or failure, we're done */
    1015             : 
    1016          64 :   for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++)
    1017             :   {
    1018          35 :     struct DepositConfirmation *dc = &pc->parse_pay.dc[i];
    1019             : 
    1020             :     /* might want to group deposits by batch more explicitly ... */
    1021          35 :     if (0 != strcmp (eg->exchange_url,
    1022          35 :                      dc->exchange_url))
    1023           0 :       continue;
    1024          35 :     if (dc->found_in_db)
    1025           0 :       continue;
    1026             :     /* FIXME-#9457: We might want to check if the order was fully paid concurrently
    1027             :        by some other wallet here, and if so, issue an auto-refund. Right now,
    1028             :        it is possible to over-pay if two wallets literally make a concurrent
    1029             :        payment, as the earlier check for 'paid' is not in the same transaction
    1030             :        scope as this 'insert' operation. */
    1031          35 :     qs = TMH_db->insert_deposit (
    1032          35 :       TMH_db->cls,
    1033             :       off++, /* might want to group deposits by batch more explicitly ... */
    1034             :       b_dep_serial,
    1035          35 :       &dc->cdd.coin_pub,
    1036          35 :       &dc->cdd.coin_sig,
    1037          35 :       &dc->cdd.amount,
    1038          35 :       &dc->deposit_fee,
    1039          35 :       &dc->refund_fee,
    1040             :       GNUNET_TIME_absolute_add (
    1041          35 :         pc->check_contract.contract_terms->wire_deadline.abs_time,
    1042             :         GNUNET_TIME_randomize (GNUNET_TIME_UNIT_MINUTES)));
    1043          35 :     if (qs < 0)
    1044           0 :       return qs;
    1045          35 :     GNUNET_break (qs > 0);
    1046             :   }
    1047          29 :   return qs;
    1048             : }
    1049             : 
    1050             : 
    1051             : /**
    1052             :  * Handle case where the batch deposit completed
    1053             :  * with a status of #MHD_HTTP_OK.
    1054             :  *
    1055             :  * @param eg group that completed
    1056             :  * @param dr response from the server
    1057             :  */
    1058             : static void
    1059          29 : handle_batch_deposit_ok (struct ExchangeGroup *eg,
    1060             :                          const struct TALER_EXCHANGE_BatchDepositResult *dr)
    1061             : {
    1062          29 :   struct PayContext *pc = eg->pc;
    1063          29 :   enum GNUNET_DB_QueryStatus qs
    1064             :     = GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
    1065             : 
    1066             :   /* store result to DB */
    1067          29 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    1068             :               "Storing successful payment %s (%s) at instance `%s'\n",
    1069             :               pc->hc->infix,
    1070             :               GNUNET_h2s (&pc->check_contract.h_contract_terms.hash),
    1071             :               pc->hc->instance->settings.id);
    1072          29 :   for (unsigned int r = 0; r<MAX_RETRIES; r++)
    1073             :   {
    1074          29 :     TMH_db->preflight (TMH_db->cls);
    1075          29 :     if (GNUNET_OK !=
    1076          29 :         TMH_db->start (TMH_db->cls,
    1077             :                        "batch-deposit-insert-confirmation"))
    1078             :     {
    1079           0 :       resume_pay_with_response (
    1080             :         pc,
    1081             :         MHD_HTTP_INTERNAL_SERVER_ERROR,
    1082           0 :         TALER_MHD_MAKE_JSON_PACK (
    1083             :           TALER_JSON_pack_ec (
    1084             :             TALER_EC_GENERIC_DB_START_FAILED),
    1085             :           TMH_pack_exchange_reply (&dr->hr)));
    1086           0 :       return;
    1087             :     }
    1088          29 :     qs = batch_deposit_transaction (eg,
    1089             :                                     dr);
    1090          29 :     if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
    1091             :     {
    1092           0 :       TMH_db->rollback (TMH_db->cls);
    1093           0 :       continue;
    1094             :     }
    1095          29 :     if (GNUNET_DB_STATUS_HARD_ERROR == qs)
    1096             :     {
    1097           0 :       GNUNET_break (0);
    1098           0 :       resume_pay_with_error (pc,
    1099             :                              TALER_EC_GENERIC_DB_COMMIT_FAILED,
    1100             :                              "batch_deposit_transaction");
    1101             :     }
    1102          29 :     qs = TMH_db->commit (TMH_db->cls);
    1103          29 :     if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
    1104             :     {
    1105           0 :       TMH_db->rollback (TMH_db->cls);
    1106           0 :       continue;
    1107             :     }
    1108          29 :     if (GNUNET_DB_STATUS_HARD_ERROR == qs)
    1109             :     {
    1110           0 :       GNUNET_break (0);
    1111           0 :       resume_pay_with_error (pc,
    1112             :                              TALER_EC_GENERIC_DB_COMMIT_FAILED,
    1113             :                              "insert_deposit");
    1114             :     }
    1115          29 :     break; /* DB transaction succeeded */
    1116             :   }
    1117          29 :   if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
    1118             :   {
    1119           0 :     resume_pay_with_error (pc,
    1120             :                            TALER_EC_GENERIC_DB_SOFT_FAILURE,
    1121             :                            "insert_deposit");
    1122           0 :     return;
    1123             :   }
    1124             : 
    1125             :   /* Transaction is done, mark affected coins as complete as well. */
    1126          64 :   for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++)
    1127             :   {
    1128          35 :     struct DepositConfirmation *dc = &pc->parse_pay.dc[i];
    1129             : 
    1130          35 :     if (0 != strcmp (eg->exchange_url,
    1131          35 :                      pc->parse_pay.dc[i].exchange_url))
    1132           0 :       continue;
    1133          35 :     if (dc->found_in_db)
    1134           0 :       continue;
    1135          35 :     dc->found_in_db = true;     /* well, at least NOW it'd be true ;-) */
    1136          35 :     pc->pay_transaction.pending--;
    1137             :   }
    1138             : }
    1139             : 
    1140             : 
    1141             : /**
    1142             :  * Notify taler-merchant-kyccheck that we got a KYC
    1143             :  * rule violation notification and should start to
    1144             :  * check our KYC status.
    1145             :  *
    1146             :  * @param eg exchange group we were notified for
    1147             :  */
    1148             : static void
    1149           0 : notify_kyc_required (const struct ExchangeGroup *eg)
    1150             : {
    1151           0 :   struct GNUNET_DB_EventHeaderP es = {
    1152           0 :     .size = htons (sizeof (es)),
    1153           0 :     .type = htons (TALER_DBEVENT_MERCHANT_EXCHANGE_KYC_RULE_TRIGGERED)
    1154             :   };
    1155             :   char *hws;
    1156             :   char *extra;
    1157             : 
    1158           0 :   hws = GNUNET_STRINGS_data_to_string_alloc (
    1159           0 :     &eg->pc->check_contract.contract_terms->h_wire,
    1160             :     sizeof (eg->pc->check_contract.contract_terms->h_wire));
    1161           0 :   GNUNET_asprintf (&extra,
    1162             :                    "%s %s",
    1163             :                    hws,
    1164           0 :                    eg->exchange_url);
    1165           0 :   GNUNET_free (hws);
    1166           0 :   TMH_db->event_notify (TMH_db->cls,
    1167             :                         &es,
    1168             :                         extra,
    1169           0 :                         strlen (extra) + 1);
    1170           0 :   GNUNET_free (extra);
    1171           0 : }
    1172             : 
    1173             : 
    1174             : /**
    1175             :  * Callback to handle a batch deposit permission's response.
    1176             :  *
    1177             :  * @param cls a `struct ExchangeGroup`
    1178             :  * @param dr HTTP response code details
    1179             :  */
    1180             : static void
    1181          35 : batch_deposit_cb (
    1182             :   void *cls,
    1183             :   const struct TALER_EXCHANGE_BatchDepositResult *dr)
    1184             : {
    1185          35 :   struct ExchangeGroup *eg = cls;
    1186          35 :   struct PayContext *pc = eg->pc;
    1187             : 
    1188          35 :   eg->bdh = NULL;
    1189          35 :   pc->batch_deposits.pending_at_eg--;
    1190          35 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1191             :               "Batch deposit completed with status %u\n",
    1192             :               dr->hr.http_status);
    1193          35 :   GNUNET_assert (GNUNET_YES == pc->suspended);
    1194          35 :   switch (dr->hr.http_status)
    1195             :   {
    1196          29 :   case MHD_HTTP_OK:
    1197          29 :     handle_batch_deposit_ok (eg,
    1198             :                              dr);
    1199          29 :     if (0 == pc->batch_deposits.pending_at_eg)
    1200             :     {
    1201          29 :       pc->phase = PP_PAY_TRANSACTION;
    1202          29 :       pay_resume (pc);
    1203             :     }
    1204          29 :     return;
    1205           0 :   case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
    1206           0 :     notify_kyc_required (eg);
    1207           0 :     eg->got_451 = true;
    1208           0 :     pc->batch_deposits.got_451 = true;
    1209             :     /* update pc->pay_transaction.pending */
    1210           0 :     for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++)
    1211             :     {
    1212           0 :       struct DepositConfirmation *dc = &pc->parse_pay.dc[i];
    1213             : 
    1214           0 :       if (0 != strcmp (eg->exchange_url,
    1215           0 :                        pc->parse_pay.dc[i].exchange_url))
    1216           0 :         continue;
    1217           0 :       if (dc->found_in_db)
    1218           0 :         continue;
    1219           0 :       pc->pay_transaction.pending--;
    1220             :     }
    1221           0 :     if (0 == pc->batch_deposits.pending_at_eg)
    1222             :     {
    1223           0 :       pc->phase = PP_PAY_TRANSACTION;
    1224           0 :       pay_resume (pc);
    1225             :     }
    1226           0 :     return;
    1227           6 :   default:
    1228           6 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1229             :                 "Deposit operation failed with HTTP code %u/%d\n",
    1230             :                 dr->hr.http_status,
    1231             :                 (int) dr->hr.ec);
    1232             :     /* Transaction failed */
    1233           6 :     if (5 == dr->hr.http_status / 100)
    1234             :     {
    1235             :       /* internal server error at exchange */
    1236           0 :       resume_pay_with_response (pc,
    1237             :                                 MHD_HTTP_BAD_GATEWAY,
    1238           0 :                                 TALER_MHD_MAKE_JSON_PACK (
    1239             :                                   TALER_JSON_pack_ec (
    1240             :                                     TALER_EC_MERCHANT_GENERIC_EXCHANGE_UNEXPECTED_STATUS),
    1241             :                                   TMH_pack_exchange_reply (&dr->hr)));
    1242           0 :       return;
    1243             :     }
    1244           6 :     if (NULL == dr->hr.reply)
    1245             :     {
    1246             :       /* We can't do anything meaningful here, the exchange did something wrong */
    1247           0 :       resume_pay_with_response (
    1248             :         pc,
    1249             :         MHD_HTTP_BAD_GATEWAY,
    1250           0 :         TALER_MHD_MAKE_JSON_PACK (
    1251             :           TALER_JSON_pack_ec (
    1252             :             TALER_EC_MERCHANT_GENERIC_EXCHANGE_REPLY_MALFORMED),
    1253             :           TMH_pack_exchange_reply (&dr->hr)));
    1254           0 :       return;
    1255             :     }
    1256             : 
    1257             :     /* Forward error, adding the "exchange_url" for which the
    1258             :        error was being generated */
    1259           6 :     if (TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS == dr->hr.ec)
    1260             :     {
    1261           6 :       resume_pay_with_response (
    1262             :         pc,
    1263             :         MHD_HTTP_CONFLICT,
    1264           6 :         TALER_MHD_MAKE_JSON_PACK (
    1265             :           TALER_JSON_pack_ec (
    1266             :             TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_INSUFFICIENT_FUNDS),
    1267             :           TMH_pack_exchange_reply (&dr->hr),
    1268             :           GNUNET_JSON_pack_string ("exchange_url",
    1269             :                                    eg->exchange_url)));
    1270           6 :       return;
    1271             :     }
    1272           0 :     resume_pay_with_response (
    1273             :       pc,
    1274             :       MHD_HTTP_BAD_GATEWAY,
    1275           0 :       TALER_MHD_MAKE_JSON_PACK (
    1276             :         TALER_JSON_pack_ec (
    1277             :           TALER_EC_MERCHANT_GENERIC_EXCHANGE_UNEXPECTED_STATUS),
    1278             :         TMH_pack_exchange_reply (&dr->hr),
    1279             :         GNUNET_JSON_pack_string ("exchange_url",
    1280             :                                  eg->exchange_url)));
    1281           0 :     return;
    1282             :   } /* end switch */
    1283             : }
    1284             : 
    1285             : 
    1286             : /**
    1287             :  * Force re-downloading keys for @a eg.
    1288             :  *
    1289             :  * @param[in,out] eg group to re-download keys for
    1290             :  */
    1291             : static void
    1292             : force_keys (struct ExchangeGroup *eg);
    1293             : 
    1294             : 
    1295             : /**
    1296             :  * Function called with the result of our exchange keys lookup.
    1297             :  *
    1298             :  * @param cls the `struct ExchangeGroup`
    1299             :  * @param keys the keys of the exchange
    1300             :  * @param exchange representation of the exchange
    1301             :  */
    1302             : static void
    1303          35 : process_pay_with_keys (
    1304             :   void *cls,
    1305             :   struct TALER_EXCHANGE_Keys *keys,
    1306             :   struct TMH_Exchange *exchange)
    1307             : {
    1308          35 :   struct ExchangeGroup *eg = cls;
    1309          35 :   struct PayContext *pc = eg->pc;
    1310          35 :   struct TMH_HandlerContext *hc = pc->hc;
    1311             :   unsigned int group_size;
    1312             :   struct TALER_Amount max_amount;
    1313             :   enum TMH_ExchangeStatus es;
    1314             : 
    1315          35 :   eg->fo = NULL;
    1316          35 :   pc->batch_deposits.pending_at_eg--;
    1317          35 :   GNUNET_SCHEDULER_begin_async_scope (&hc->async_scope_id);
    1318          35 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1319             :               "Processing payment with keys from exchange %s\n",
    1320             :               eg->exchange_url);
    1321          35 :   GNUNET_assert (GNUNET_YES == pc->suspended);
    1322          35 :   if (NULL == keys)
    1323             :   {
    1324           0 :     GNUNET_break_op (0);
    1325           0 :     resume_pay_with_error (
    1326             :       pc,
    1327             :       TALER_EC_MERCHANT_GENERIC_EXCHANGE_TIMEOUT,
    1328             :       NULL);
    1329           0 :     return;
    1330             :   }
    1331          35 :   if (! TMH_EXCHANGES_is_below_limit (keys,
    1332             :                                       TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION,
    1333          35 :                                       &eg->total))
    1334             :   {
    1335           0 :     GNUNET_break_op (0);
    1336           0 :     resume_pay_with_error (
    1337             :       pc,
    1338             :       TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_EXCHANGE_TRANSACTION_LIMIT_VIOLATION,
    1339             :       eg->exchange_url);
    1340           0 :     return;
    1341             :   }
    1342             : 
    1343          35 :   max_amount = eg->total;
    1344          35 :   es = TMH_exchange_check_debit (
    1345          35 :     pc->hc->instance->settings.id,
    1346             :     exchange,
    1347          35 :     pc->check_contract.wm,
    1348             :     &max_amount);
    1349          35 :   if ( (TMH_ES_OK != es) &&
    1350             :        (TMH_ES_RETRY_OK != es) )
    1351             :   {
    1352           0 :     if (eg->tried_force_keys ||
    1353           0 :         (0 == (TMH_ES_RETRY_OK & es)) )
    1354             :     {
    1355           0 :       GNUNET_break_op (0);
    1356           0 :       resume_pay_with_error (
    1357             :         pc,
    1358             :         TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_WIRE_METHOD_UNSUPPORTED,
    1359             :         NULL);
    1360           0 :       return;
    1361             :     }
    1362           0 :     force_keys (eg);
    1363           0 :     return;
    1364             :   }
    1365          35 :   if (-1 ==
    1366          35 :       TALER_amount_cmp (&max_amount,
    1367          35 :                         &eg->total))
    1368             :   {
    1369             :     /* max_amount < eg->total */
    1370           0 :     GNUNET_break_op (0);
    1371           0 :     resume_pay_with_error (
    1372             :       pc,
    1373             :       TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_EXCHANGE_TRANSACTION_LIMIT_VIOLATION,
    1374             :       eg->exchange_url);
    1375           0 :     return;
    1376             :   }
    1377             : 
    1378          35 :   if (GNUNET_OK !=
    1379          35 :       TMH_EXCHANGES_lookup_wire_fee (exchange,
    1380          35 :                                      pc->check_contract.wm->wire_method,
    1381             :                                      &eg->wire_fee))
    1382             :   {
    1383           0 :     if (eg->tried_force_keys)
    1384             :     {
    1385           0 :       GNUNET_break_op (0);
    1386           0 :       resume_pay_with_error (
    1387             :         pc,
    1388             :         TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_WIRE_METHOD_UNSUPPORTED,
    1389           0 :         pc->check_contract.wm->wire_method);
    1390           0 :       return;
    1391             :     }
    1392           0 :     force_keys (eg);
    1393           0 :     return;
    1394             :   }
    1395          35 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1396             :               "Got wire data for %s\n",
    1397             :               eg->exchange_url);
    1398             : 
    1399             :   /* Initiate /batch-deposit operation for all coins of
    1400             :      the current exchange (!) */
    1401          35 :   group_size = 0;
    1402          78 :   for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++)
    1403             :   {
    1404          43 :     struct DepositConfirmation *dc = &pc->parse_pay.dc[i];
    1405             :     const struct TALER_EXCHANGE_DenomPublicKey *denom_details;
    1406          43 :     bool is_age_restricted_denom = false;
    1407             : 
    1408          43 :     if (0 != strcmp (eg->exchange_url,
    1409          43 :                      pc->parse_pay.dc[i].exchange_url))
    1410           0 :       continue;
    1411          43 :     if (dc->found_in_db)
    1412           0 :       continue;
    1413             : 
    1414             :     denom_details
    1415          43 :       = TALER_EXCHANGE_get_denomination_key_by_hash (keys,
    1416          43 :                                                      &dc->cdd.h_denom_pub);
    1417          43 :     if (NULL == denom_details)
    1418             :     {
    1419           0 :       if (eg->tried_force_keys)
    1420             :       {
    1421           0 :         GNUNET_break_op (0);
    1422           0 :         resume_pay_with_response (
    1423             :           pc,
    1424             :           MHD_HTTP_BAD_REQUEST,
    1425           0 :           TALER_MHD_MAKE_JSON_PACK (
    1426             :             TALER_JSON_pack_ec (
    1427             :               TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_DENOMINATION_KEY_NOT_FOUND),
    1428             :             GNUNET_JSON_pack_data_auto ("h_denom_pub",
    1429             :                                         &dc->cdd.h_denom_pub),
    1430             :             GNUNET_JSON_pack_allow_null (
    1431             :               GNUNET_JSON_pack_object_steal (
    1432             :                 "exchange_keys",
    1433             :                 TALER_EXCHANGE_keys_to_json (keys)))));
    1434           0 :         return;
    1435             :       }
    1436           0 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1437             :                   "Missing denomination %s from exchange %s, updating keys\n",
    1438             :                   GNUNET_h2s (&dc->cdd.h_denom_pub.hash),
    1439             :                   eg->exchange_url);
    1440           0 :       force_keys (eg);
    1441           0 :       return;
    1442             :     }
    1443          43 :     dc->deposit_fee = denom_details->fees.deposit;
    1444          43 :     dc->refund_fee = denom_details->fees.refund;
    1445             : 
    1446          43 :     if (GNUNET_TIME_absolute_is_past (
    1447             :           denom_details->expire_deposit.abs_time))
    1448             :     {
    1449           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1450             :                   "Denomination key offered by client has expired for deposits\n");
    1451           0 :       resume_pay_with_response (
    1452             :         pc,
    1453             :         MHD_HTTP_GONE,
    1454           0 :         TALER_MHD_MAKE_JSON_PACK (
    1455             :           TALER_JSON_pack_ec (
    1456             :             TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_DENOMINATION_DEPOSIT_EXPIRED),
    1457             :           GNUNET_JSON_pack_data_auto ("h_denom_pub",
    1458             :                                       &denom_details->h_key)));
    1459           0 :       return;
    1460             :     }
    1461             : 
    1462             :     /* Now that we have the details about the denomination, we can verify age
    1463             :      * restriction requirements, if applicable. Note that denominations with an
    1464             :      * age_mask equal to zero always pass the age verification.  */
    1465          43 :     is_age_restricted_denom = (0 != denom_details->key.age_mask.bits);
    1466             : 
    1467          43 :     if (is_age_restricted_denom &&
    1468           0 :         (0 < pc->check_contract.contract_terms->minimum_age))
    1469           0 :     {
    1470             :       /* Minimum age given and restricted coin provided: We need to verify the
    1471             :        * minimum age */
    1472           0 :       unsigned int code = 0;
    1473             : 
    1474           0 :       if (dc->no_age_commitment)
    1475             :       {
    1476           0 :         GNUNET_break_op (0);
    1477           0 :         code = TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AGE_COMMITMENT_MISSING;
    1478           0 :         goto AGE_FAIL;
    1479             :       }
    1480           0 :       dc->age_commitment.mask = denom_details->key.age_mask;
    1481           0 :       if (((int) (dc->age_commitment.num + 1)) !=
    1482           0 :           __builtin_popcount (dc->age_commitment.mask.bits))
    1483             :       {
    1484           0 :         GNUNET_break_op (0);
    1485           0 :         code =
    1486             :           TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AGE_COMMITMENT_SIZE_MISMATCH;
    1487           0 :         goto AGE_FAIL;
    1488             :       }
    1489           0 :       if (GNUNET_OK !=
    1490           0 :           TALER_age_commitment_verify (
    1491           0 :             &dc->age_commitment,
    1492           0 :             pc->check_contract.contract_terms->minimum_age,
    1493           0 :             &dc->minimum_age_sig))
    1494           0 :         code = TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AGE_VERIFICATION_FAILED;
    1495           0 : AGE_FAIL:
    1496           0 :       if (0 < code)
    1497             :       {
    1498           0 :         GNUNET_break_op (0);
    1499           0 :         TALER_age_commitment_free (&dc->age_commitment);
    1500           0 :         resume_pay_with_response (
    1501             :           pc,
    1502             :           MHD_HTTP_BAD_REQUEST,
    1503           0 :           TALER_MHD_MAKE_JSON_PACK (
    1504             :             TALER_JSON_pack_ec (code),
    1505             :             GNUNET_JSON_pack_data_auto ("h_denom_pub",
    1506             :                                         &denom_details->h_key)));
    1507           0 :         return;
    1508             :       }
    1509             : 
    1510             :       /* Age restriction successfully verified!
    1511             :        * Calculate the hash of the age commitment. */
    1512           0 :       TALER_age_commitment_hash (&dc->age_commitment,
    1513             :                                  &dc->cdd.h_age_commitment);
    1514           0 :       TALER_age_commitment_free (&dc->age_commitment);
    1515             :     }
    1516          43 :     else if (is_age_restricted_denom &&
    1517           0 :              dc->no_h_age_commitment)
    1518             :     {
    1519             :       /* The contract did not ask for a minimum_age but the client paid
    1520             :        * with a coin that has age restriction enabled.  We lack the hash
    1521             :        * of the age commitment in this case in order to verify the coin
    1522             :        * and to deposit it with the exchange. */
    1523           0 :       GNUNET_break_op (0);
    1524           0 :       resume_pay_with_response (
    1525             :         pc,
    1526             :         MHD_HTTP_BAD_REQUEST,
    1527           0 :         TALER_MHD_MAKE_JSON_PACK (
    1528             :           TALER_JSON_pack_ec (
    1529             :             TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AGE_COMMITMENT_HASH_MISSING),
    1530             :           GNUNET_JSON_pack_data_auto ("h_denom_pub",
    1531             :                                       &denom_details->h_key)));
    1532           0 :       return;
    1533             :     }
    1534          43 :     group_size++;
    1535             :   }
    1536             : 
    1537          35 :   if (0 == group_size)
    1538             :   {
    1539           0 :     GNUNET_break (0);
    1540           0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1541             :                 "Group size zero, %u batch transactions remain pending\n",
    1542             :                 pc->batch_deposits.pending_at_eg);
    1543           0 :     if (0 == pc->batch_deposits.pending_at_eg)
    1544             :     {
    1545           0 :       pc->phase = PP_PAY_TRANSACTION;
    1546           0 :       pay_resume (pc);
    1547           0 :       return;
    1548             :     }
    1549           0 :     return;
    1550             :   }
    1551          35 :   if (group_size > TALER_MAX_COINS)
    1552           0 :     group_size = TALER_MAX_COINS;
    1553          35 :   {
    1554          35 :     struct TALER_EXCHANGE_CoinDepositDetail cdds[group_size];
    1555          35 :     struct TALER_EXCHANGE_DepositContractDetail dcd = {
    1556          35 :       .wire_deadline = pc->check_contract.contract_terms->wire_deadline,
    1557          35 :       .merchant_payto_uri = pc->check_contract.wm->payto_uri,
    1558          35 :       .wire_salt = pc->check_contract.wm->wire_salt,
    1559             :       .h_contract_terms = pc->check_contract.h_contract_terms,
    1560             :       .wallet_data_hash = pc->parse_wallet_data.h_wallet_data,
    1561          35 :       .wallet_timestamp = pc->check_contract.contract_terms->timestamp,
    1562          35 :       .merchant_pub = hc->instance->merchant_pub,
    1563          35 :       .refund_deadline = pc->check_contract.contract_terms->refund_deadline
    1564             :     };
    1565             :     enum TALER_ErrorCode ec;
    1566          35 :     size_t off = 0;
    1567             : 
    1568          35 :     TALER_merchant_contract_sign (&pc->check_contract.h_contract_terms,
    1569          35 :                                   &pc->hc->instance->merchant_priv,
    1570             :                                   &dcd.merchant_sig);
    1571          43 :     for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++)
    1572             :     {
    1573          43 :       struct DepositConfirmation *dc = &pc->parse_pay.dc[i];
    1574             : 
    1575          43 :       if (dc->found_in_db)
    1576           0 :         continue;
    1577          43 :       if (0 != strcmp (dc->exchange_url,
    1578             :                        eg->exchange_url))
    1579           0 :         continue;
    1580          43 :       cdds[off++] = dc->cdd;
    1581          43 :       if (off >= group_size)
    1582          35 :         break;
    1583             :     }
    1584          35 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1585             :                 "Initiating batch deposit with %u coins\n",
    1586             :                 group_size);
    1587             :     /* Note: the coin signatures over the wallet_data_hash are
    1588             :        checked inside of this call */
    1589          35 :     eg->bdh = TALER_EXCHANGE_batch_deposit (
    1590             :       TMH_curl_ctx,
    1591             :       eg->exchange_url,
    1592             :       keys,
    1593             :       &dcd,
    1594             :       group_size,
    1595             :       cdds,
    1596             :       &batch_deposit_cb,
    1597             :       eg,
    1598             :       &ec);
    1599          35 :     if (NULL == eg->bdh)
    1600             :     {
    1601             :       /* Signature was invalid or some other constraint was not satisfied.  If
    1602             :          the exchange was unavailable, we'd get that information in the
    1603             :          callback. */
    1604           0 :       GNUNET_break_op (0);
    1605           0 :       resume_pay_with_response (
    1606             :         pc,
    1607             :         TALER_ErrorCode_get_http_status_safe (ec),
    1608           0 :         TALER_MHD_MAKE_JSON_PACK (
    1609             :           TALER_JSON_pack_ec (ec),
    1610             :           GNUNET_JSON_pack_string ("exchange_url",
    1611             :                                    eg->exchange_url)));
    1612           0 :       return;
    1613             :     }
    1614          35 :     pc->batch_deposits.pending_at_eg++;
    1615          35 :     if (TMH_force_audit)
    1616           8 :       TALER_EXCHANGE_batch_deposit_force_dc (eg->bdh);
    1617             :   }
    1618             : }
    1619             : 
    1620             : 
    1621             : static void
    1622           0 : force_keys (struct ExchangeGroup *eg)
    1623             : {
    1624           0 :   struct PayContext *pc = eg->pc;
    1625             : 
    1626           0 :   eg->tried_force_keys = true;
    1627           0 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1628             :               "Forcing /keys download (once)\n");
    1629           0 :   eg->fo = TMH_EXCHANGES_keys4exchange (
    1630             :     eg->exchange_url,
    1631             :     true,
    1632             :     &process_pay_with_keys,
    1633             :     eg);
    1634           0 :   if (NULL == eg->fo)
    1635             :   {
    1636           0 :     GNUNET_break_op (0);
    1637           0 :     resume_pay_with_error (pc,
    1638             :                            TALER_EC_MERCHANT_GENERIC_EXCHANGE_UNTRUSTED,
    1639             :                            eg->exchange_url);
    1640           0 :     return;
    1641             :   }
    1642           0 :   pc->batch_deposits.pending_at_eg++;
    1643             : }
    1644             : 
    1645             : 
    1646             : /**
    1647             :  * Handle a timeout for the processing of the pay request.
    1648             :  *
    1649             :  * @param cls our `struct PayContext`
    1650             :  */
    1651             : static void
    1652           0 : handle_pay_timeout (void *cls)
    1653             : {
    1654           0 :   struct PayContext *pc = cls;
    1655             : 
    1656           0 :   pc->batch_deposits.timeout_task = NULL;
    1657           0 :   GNUNET_assert (GNUNET_YES == pc->suspended);
    1658           0 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1659             :               "Resuming pay with error after timeout\n");
    1660           0 :   resume_pay_with_error (pc,
    1661             :                          TALER_EC_MERCHANT_GENERIC_EXCHANGE_TIMEOUT,
    1662             :                          NULL);
    1663           0 : }
    1664             : 
    1665             : 
    1666             : /**
    1667             :  * Compute the timeout for a /pay request based on the number of coins
    1668             :  * involved.
    1669             :  *
    1670             :  * @param num_coins number of coins
    1671             :  * @returns timeout for the /pay request
    1672             :  */
    1673             : static struct GNUNET_TIME_Relative
    1674          35 : get_pay_timeout (unsigned int num_coins)
    1675             : {
    1676             :   struct GNUNET_TIME_Relative t;
    1677             : 
    1678             :   /* FIXME-Performance-Optimization: Do some benchmarking to come up with a
    1679             :    * better timeout.  We've increased this value so the wallet integration
    1680             :    * test passes again on my (Florian) machine.
    1681             :    */
    1682          35 :   t = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
    1683          35 :                                      15 * (1 + (num_coins / 5)));
    1684             : 
    1685          35 :   return t;
    1686             : }
    1687             : 
    1688             : 
    1689             : /**
    1690             :  * Start batch deposits for all exchanges involved
    1691             :  * in this payment.
    1692             :  *
    1693             :  * @param[in,out] pc payment context we are processing
    1694             :  */
    1695             : static void
    1696          35 : phase_batch_deposits (struct PayContext *pc)
    1697             : {
    1698          70 :   for (unsigned int i = 0; i<pc->parse_pay.num_exchanges; i++)
    1699             :   {
    1700          35 :     struct ExchangeGroup *eg = pc->parse_pay.egs[i];
    1701          35 :     bool have_coins = false;
    1702             : 
    1703          35 :     for (size_t j = 0; j<pc->parse_pay.coins_cnt; j++)
    1704             :     {
    1705          35 :       struct DepositConfirmation *dc = &pc->parse_pay.dc[j];
    1706             : 
    1707          35 :       if (0 != strcmp (eg->exchange_url,
    1708          35 :                        dc->exchange_url))
    1709           0 :         continue;
    1710          35 :       if (dc->found_in_db)
    1711           0 :         continue;
    1712          35 :       have_coins = true;
    1713          35 :       break;
    1714             :     }
    1715          35 :     if (! have_coins)
    1716           0 :       continue; /* no coins left to deposit at this exchange */
    1717          35 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1718             :                 "Getting /keys for %s\n",
    1719             :                 eg->exchange_url);
    1720          35 :     eg->fo = TMH_EXCHANGES_keys4exchange (
    1721             :       eg->exchange_url,
    1722             :       false,
    1723             :       &process_pay_with_keys,
    1724             :       eg);
    1725          35 :     if (NULL == eg->fo)
    1726             :     {
    1727           0 :       GNUNET_break_op (0);
    1728           0 :       pay_end (pc,
    1729             :                TALER_MHD_reply_with_error (
    1730             :                  pc->connection,
    1731             :                  MHD_HTTP_BAD_REQUEST,
    1732             :                  TALER_EC_MERCHANT_GENERIC_EXCHANGE_UNTRUSTED,
    1733             :                  eg->exchange_url));
    1734           0 :       return;
    1735             :     }
    1736          35 :     pc->batch_deposits.pending_at_eg++;
    1737             :   }
    1738          35 :   if (0 == pc->batch_deposits.pending_at_eg)
    1739             :   {
    1740           0 :     pc->phase = PP_PAY_TRANSACTION;
    1741           0 :     pay_resume (pc);
    1742           0 :     return;
    1743             :   }
    1744             :   /* Suspend while we interact with the exchange */
    1745          35 :   MHD_suspend_connection (pc->connection);
    1746          35 :   pc->suspended = GNUNET_YES;
    1747          35 :   GNUNET_assert (NULL == pc->batch_deposits.timeout_task);
    1748             :   pc->batch_deposits.timeout_task
    1749          35 :     = GNUNET_SCHEDULER_add_delayed (get_pay_timeout (pc->parse_pay.coins_cnt),
    1750             :                                     &handle_pay_timeout,
    1751             :                                     pc);
    1752             : }
    1753             : 
    1754             : 
    1755             : /**
    1756             :  * Build JSON array of blindly signed token envelopes,
    1757             :  * to be used in the response to the wallet.
    1758             :  *
    1759             :  * @param[in,out] pc payment context to use
    1760             :  */
    1761             : static json_t *
    1762          31 : build_token_sigs (struct PayContext *pc)
    1763             : {
    1764             :   json_t *token_sigs;
    1765             : 
    1766          31 :   if (0 == pc->output_tokens_len)
    1767          27 :     return NULL;
    1768           4 :   token_sigs = json_array ();
    1769           4 :   GNUNET_assert (NULL != token_sigs);
    1770           8 :   for (unsigned int i = 0; i < pc->output_tokens_len; i++)
    1771             :   {
    1772           4 :     GNUNET_assert (0 ==
    1773             :                    json_array_append_new (
    1774             :                      token_sigs,
    1775             :                      GNUNET_JSON_PACK (
    1776             :                        GNUNET_JSON_pack_blinded_sig (
    1777             :                          "blind_sig",
    1778             :                          pc->output_tokens[i].sig.signature)
    1779             :                        )));
    1780             :   }
    1781           4 :   return token_sigs;
    1782             : }
    1783             : 
    1784             : 
    1785             : /**
    1786             :  * Generate response (payment successful)
    1787             :  *
    1788             :  * @param[in,out] pc payment context where the payment was successful
    1789             :  */
    1790             : static void
    1791          31 : phase_success_response (struct PayContext *pc)
    1792             : {
    1793             :   struct TALER_MerchantSignatureP sig;
    1794             :   char *pos_confirmation;
    1795             : 
    1796             :   /* Sign on our end (as the payment did go through, even if it may
    1797             :      have been refunded already) */
    1798          31 :   TALER_merchant_pay_sign (&pc->check_contract.h_contract_terms,
    1799          31 :                            &pc->hc->instance->merchant_priv,
    1800             :                            &sig);
    1801             :   /* Build the response */
    1802          62 :   pos_confirmation = (NULL == pc->check_contract.pos_key)
    1803             :     ? NULL
    1804          31 :     : TALER_build_pos_confirmation (pc->check_contract.pos_key,
    1805             :                                     pc->check_contract.pos_alg,
    1806           2 :                                     &pc->validate_tokens.brutto,
    1807           2 :                                     pc->check_contract.contract_terms->timestamp
    1808             :                                     );
    1809          31 :   pay_end (pc,
    1810          31 :            TALER_MHD_REPLY_JSON_PACK (
    1811             :              pc->connection,
    1812             :              MHD_HTTP_OK,
    1813             :              GNUNET_JSON_pack_allow_null (
    1814             :                GNUNET_JSON_pack_string ("pos_confirmation",
    1815             :                                         pos_confirmation)),
    1816             :              GNUNET_JSON_pack_allow_null (
    1817             :                GNUNET_JSON_pack_array_steal ("token_sigs",
    1818             :                                              build_token_sigs (pc))),
    1819             :              GNUNET_JSON_pack_data_auto ("sig",
    1820             :                                          &sig)));
    1821          31 :   GNUNET_free (pos_confirmation);
    1822          31 : }
    1823             : 
    1824             : 
    1825             : /**
    1826             :  * Use database to notify other clients about the
    1827             :  * payment being completed.
    1828             :  *
    1829             :  * @param[in,out] pc context to trigger notification for
    1830             :  */
    1831             : static void
    1832          29 : phase_payment_notification (struct PayContext *pc)
    1833             : {
    1834             :   {
    1835          29 :     struct TMH_OrderPayEventP pay_eh = {
    1836          29 :       .header.size = htons (sizeof (pay_eh)),
    1837          29 :       .header.type = htons (TALER_DBEVENT_MERCHANT_ORDER_PAID),
    1838          29 :       .merchant_pub = pc->hc->instance->merchant_pub
    1839             :     };
    1840             : 
    1841          29 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1842             :                 "Notifying clients about payment of order %s\n",
    1843             :                 pc->order_id);
    1844          29 :     GNUNET_CRYPTO_hash (pc->order_id,
    1845             :                         strlen (pc->order_id),
    1846             :                         &pay_eh.h_order_id);
    1847          29 :     TMH_db->event_notify (TMH_db->cls,
    1848             :                           &pay_eh.header,
    1849             :                           NULL,
    1850             :                           0);
    1851             :   }
    1852          29 :   if ( (NULL != pc->parse_pay.session_id) &&
    1853          29 :        (NULL != pc->check_contract.contract_terms->fulfillment_url) )
    1854             :   {
    1855          17 :     struct TMH_SessionEventP session_eh = {
    1856          17 :       .header.size = htons (sizeof (session_eh)),
    1857          17 :       .header.type = htons (TALER_DBEVENT_MERCHANT_SESSION_CAPTURED),
    1858          17 :       .merchant_pub = pc->hc->instance->merchant_pub
    1859             :     };
    1860             : 
    1861          17 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1862             :                 "Notifying clients about session change to %s for %s\n",
    1863             :                 pc->parse_pay.session_id,
    1864             :                 pc->check_contract.contract_terms->fulfillment_url);
    1865          17 :     GNUNET_CRYPTO_hash (pc->parse_pay.session_id,
    1866          17 :                         strlen (pc->parse_pay.session_id),
    1867             :                         &session_eh.h_session_id);
    1868          17 :     GNUNET_CRYPTO_hash (pc->check_contract.contract_terms->fulfillment_url,
    1869          17 :                         strlen (pc->check_contract.contract_terms->
    1870             :                                 fulfillment_url),
    1871             :                         &session_eh.h_fulfillment_url);
    1872          17 :     TMH_db->event_notify (TMH_db->cls,
    1873             :                           &session_eh.header,
    1874             :                           NULL,
    1875             :                           0);
    1876             :   }
    1877          29 :   pc->phase = PP_SUCCESS_RESPONSE;
    1878          29 : }
    1879             : 
    1880             : 
    1881             : /**
    1882             :  * Phase to write all outputs to our database so we do
    1883             :  * not re-request them in case the client re-plays the
    1884             :  * request.
    1885             :  *
    1886             :  * @param[in,out] pc payment context
    1887             :  */
    1888             : static void
    1889          29 : phase_final_output_token_processing (struct PayContext *pc)
    1890             : {
    1891          29 :   if (0 == pc->output_tokens_len)
    1892             :   {
    1893          25 :     pc->phase++;
    1894          25 :     return;
    1895             :   }
    1896           4 :   for (unsigned int retry = 0; retry < MAX_RETRIES; retry++)
    1897             :   {
    1898             :     enum GNUNET_DB_QueryStatus qs;
    1899             : 
    1900           4 :     TMH_db->preflight (TMH_db->cls);
    1901           4 :     if (GNUNET_OK !=
    1902           4 :         TMH_db->start (TMH_db->cls,
    1903             :                        "insert_order_blinded_sigs"))
    1904             :     {
    1905           0 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1906             :                   "start insert_order_blinded_sigs_failed");
    1907           0 :       pc->phase++;
    1908           0 :       return;
    1909             :     }
    1910             : #ifdef HAVE_DONAU_DONAU_SERVICE_H
    1911             :     if (pc->parse_wallet_data.num_bkps > 0)
    1912             :     {
    1913             :       qs = TMH_db->update_donau_instance_receipts_amount (
    1914             :         TMH_db->cls,
    1915             :         &pc->parse_wallet_data.donau_instance_serial,
    1916             :         &pc->parse_wallet_data.charity_receipts_to_date);
    1917             :       switch (qs)
    1918             :       {
    1919             :       case GNUNET_DB_STATUS_HARD_ERROR:
    1920             :         TMH_db->rollback (TMH_db->cls);
    1921             :         GNUNET_break (0);
    1922             :         return;
    1923             :       case GNUNET_DB_STATUS_SOFT_ERROR:
    1924             :         TMH_db->rollback (TMH_db->cls);
    1925             :         continue;
    1926             :       case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
    1927             :         /* weird for an update */
    1928             :         GNUNET_break (0);
    1929             :         break;
    1930             :       case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
    1931             :         break;
    1932             :       }
    1933             :     }
    1934             : #endif
    1935           4 :     for (unsigned int i = 0;
    1936           8 :          i < pc->output_tokens_len;
    1937           4 :          i++)
    1938             :     {
    1939           4 :       qs = TMH_db->insert_order_blinded_sigs (
    1940           4 :         TMH_db->cls,
    1941             :         pc->order_id,
    1942             :         i,
    1943           4 :         &pc->output_tokens[i].h_issue.hash,
    1944           4 :         pc->output_tokens[i].sig.signature);
    1945             : 
    1946           4 :       switch (qs)
    1947             :       {
    1948           0 :       case GNUNET_DB_STATUS_HARD_ERROR:
    1949           0 :         TMH_db->rollback (TMH_db->cls);
    1950           0 :         pc->phase++;
    1951           0 :         return;
    1952           0 :       case GNUNET_DB_STATUS_SOFT_ERROR:
    1953           0 :         TMH_db->rollback (TMH_db->cls);
    1954           0 :         goto OUTER;
    1955           0 :       case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
    1956             :         /* weird for an update */
    1957           0 :         GNUNET_break (0);
    1958           0 :         break;
    1959           4 :       case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
    1960           4 :         break;
    1961             :       }
    1962             :     } /* for i */
    1963           4 :     qs = TMH_db->commit (TMH_db->cls);
    1964           4 :     switch (qs)
    1965             :     {
    1966           0 :     case GNUNET_DB_STATUS_HARD_ERROR:
    1967           0 :       TMH_db->rollback (TMH_db->cls);
    1968           0 :       pc->phase++;
    1969           0 :       return;
    1970           0 :     case GNUNET_DB_STATUS_SOFT_ERROR:
    1971           0 :       TMH_db->rollback (TMH_db->cls);
    1972           0 :       continue;
    1973           4 :     case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
    1974           4 :       pc->phase++;
    1975           4 :       return; /* success */
    1976           0 :     case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
    1977           0 :       pc->phase++;
    1978           0 :       return; /* success */
    1979             :     }
    1980           0 :     GNUNET_break (0);
    1981           0 :     pc->phase++;
    1982           0 :     return; /* strange */
    1983           0 : OUTER:
    1984             :   } /* for retry */
    1985           0 :   TMH_db->rollback (TMH_db->cls);
    1986           0 :   pc->phase++;
    1987             :   /* We continue anyway, as there is not much we can
    1988             :      do here: the Donau *did* issue us the receipts;
    1989             :      also, we'll eventually ask the Donau for the
    1990             :      balance and get the correct one. Plus, we were
    1991             :      paid by the client, so it's technically all still
    1992             :      OK. If the request fails anyway, the wallet will
    1993             :      most likely replay the request and then hopefully
    1994             :      we will succeed the next time */
    1995             : }
    1996             : 
    1997             : 
    1998             : #ifdef HAVE_DONAU_DONAU_SERVICE_H
    1999             : 
    2000             : /**
    2001             :  * Add donation receipt outputs to the output_tokens.
    2002             :  *
    2003             :  * Note that under the current (odd, bad) libdonau
    2004             :  * API *we* are responsible for freeing blinded_sigs,
    2005             :  * so we truly own that array!
    2006             :  *
    2007             :  * @param[in,out] pc payment context
    2008             :  * @param num_blinded_sigs number of signatures received
    2009             :  * @param blinded_sigs blinded signatures from Donau
    2010             :  * @return #GNUNET_OK on success,
    2011             :  *         #GNUNET_SYSERR on failure (state machine was
    2012             :  *          in that case already advanced)
    2013             :  */
    2014             : static enum GNUNET_GenericReturnValue
    2015             : add_donation_receipt_outputs (
    2016             :   struct PayContext *pc,
    2017             :   size_t num_blinded_sigs,
    2018             :   struct DONAU_BlindedDonationUnitSignature *blinded_sigs)
    2019             : {
    2020             :   const struct TALER_MERCHANT_ContractChoice *choice
    2021             :     = &pc->check_contract.contract_terms->details.v1.choices[
    2022             :         pc->parse_wallet_data.choice_index];
    2023             :   unsigned int off = 0;
    2024             : 
    2025             :   GNUNET_assert (pc->parse_wallet_data.num_bkps ==
    2026             :                  num_blinded_sigs);
    2027             : 
    2028             :   for (unsigned int i = 0; i < choice->outputs_len; i++)
    2029             :   {
    2030             :     const struct TALER_MERCHANT_ContractOutput *output
    2031             :       = &choice->outputs[i];
    2032             : 
    2033             :     switch (output->type)
    2034             :     {
    2035             :     case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_INVALID:
    2036             :       GNUNET_assert (0);
    2037             :       break;
    2038             :     case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_TOKEN:
    2039             :       GNUNET_assert (off + output->details.token.count >= off);
    2040             :       off += output->details.token.count;
    2041             :       continue;
    2042             :     case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_DONATION_RECEIPT:
    2043             :       break;
    2044             : #if FUTURE
    2045             :     case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_COIN:
    2046             :       GNUNET_break (0);
    2047             :       pay_end (pc,
    2048             :                TALER_MHD_reply_with_error (
    2049             :                  pc->connection,
    2050             :                  MHD_HTTP_NOT_IMPLEMENTED,
    2051             :                  TALER_EC_MERCHANT_GENERIC_FEATURE_NOT_AVAILABLE,
    2052             :                  "token type not yet supported"));
    2053             :       return GNUNET_SYSERR;
    2054             : #endif
    2055             :     }
    2056             :     /* must have been the donau case we care about */
    2057             :     break;
    2058             :   }
    2059             : 
    2060             :   GNUNET_assert (off + num_blinded_sigs >= off);
    2061             :   GNUNET_assert (off + num_blinded_sigs <= pc->output_tokens_len);
    2062             :   for (unsigned int i = 0; i<pc->output_tokens_len; i++)
    2063             :   {
    2064             :     struct SignedOutputToken *sot
    2065             :       = &pc->output_tokens[off + i];
    2066             : 
    2067             :     // FIXME: in the future, use incref here once
    2068             :     // we change libdonau to do decref!
    2069             :     sot->sig.signature = blinded_sigs[i].blinded_sig;
    2070             :     sot->h_issue.hash = pc->parse_wallet_data.bkps[i].h_donation_unit_pub.hash;
    2071             :   }
    2072             :   // FIXME: do this in libdonau in the future!
    2073             :   GNUNET_free (blinded_sigs);
    2074             :   return GNUNET_OK;
    2075             : }
    2076             : 
    2077             : 
    2078             : /**
    2079             :  * Callback to handle the result of a batch issue request.
    2080             :  *
    2081             :  * @param cls our `struct PayContext`
    2082             :  * @param resp the response from Donau
    2083             :  */
    2084             : static void
    2085             : merchant_donau_issue_receipt_cb (
    2086             :   void *cls,
    2087             :   const struct DONAU_BatchIssueResponse *resp)
    2088             : {
    2089             :   struct PayContext *pc = cls;
    2090             :   /* Donau replies asynchronously, so we expect the PayContext
    2091             :    * to be suspended. */
    2092             :   GNUNET_assert (GNUNET_YES == pc->suspended);
    2093             :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    2094             :               "Donau responded with status=%u, ec=%u",
    2095             :               resp->hr.http_status,
    2096             :               resp->hr.ec);
    2097             :   switch (resp->hr.http_status)
    2098             :   {
    2099             :   case 0:
    2100             :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    2101             :                 "Donau batch issue request from merchant-httpd failed (http_status==0)");
    2102             :     resume_pay_with_error (pc,
    2103             :                            resp->hr.ec,
    2104             :                            "Donau batch issue request failed");
    2105             :     return;
    2106             : 
    2107             :   case MHD_HTTP_OK:
    2108             :   case MHD_HTTP_CREATED:
    2109             :     if (TALER_EC_NONE != resp->hr.ec)
    2110             :     {
    2111             :       /* Most probably, it is just some small flaw from
    2112             :        * donau so no point in failing, yet we have to display it */
    2113             :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    2114             :                   "Donau signalled error %u despite HTTP %u",
    2115             :                   resp->hr.ec,
    2116             :                   resp->hr.http_status);
    2117             :     }
    2118             :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    2119             :                 "Donau accepted donation receipts with total_issued=%s",
    2120             :                 TALER_amount2s (&resp->details.ok.issued_amount));
    2121             :     if (GNUNET_OK !=
    2122             :         add_donation_receipt_outputs (pc,
    2123             :                                       resp->details.ok.num_blinded_sigs,
    2124             :                                       resp->details.ok.blinded_sigs))
    2125             :       return; /* state machine was already advanced */
    2126             :     pc->phase = PP_FINAL_OUTPUT_TOKEN_PROCESSING;
    2127             :     pay_resume (pc);
    2128             :     return;
    2129             : 
    2130             :   case MHD_HTTP_BAD_REQUEST:
    2131             :   case MHD_HTTP_FORBIDDEN:
    2132             :   case MHD_HTTP_NOT_FOUND:
    2133             :   case MHD_HTTP_INTERNAL_SERVER_ERROR:
    2134             :   default: /* make sure that everything except 200/201 will end up here*/
    2135             :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    2136             :                 "Donau replied with HTTP %u (ec=%u)",
    2137             :                 resp->hr.http_status,
    2138             :                 resp->hr.ec);
    2139             :     resume_pay_with_error (pc,
    2140             :                            resp->hr.ec,
    2141             :                            "Donau HTTP error");
    2142             :     return;
    2143             :   }
    2144             : }
    2145             : 
    2146             : 
    2147             : /**
    2148             :  * Parse a bkp encoded in JSON.
    2149             :  *
    2150             :  * @param[out] bkp where to return the result
    2151             :  * @param bkp_key_obj json to parse
    2152             :  * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if @a bkp_key_obj
    2153             :  * is malformed.
    2154             :  */
    2155             : static enum GNUNET_GenericReturnValue
    2156             : merchant_parse_json_bkp (struct DONAU_BlindedUniqueDonorIdentifierKeyPair *bkp,
    2157             :                          const json_t *bkp_key_obj)
    2158             : {
    2159             :   struct GNUNET_JSON_Specification spec[] = {
    2160             :     GNUNET_JSON_spec_fixed_auto ("h_donation_unit_pub",
    2161             :                                  &bkp->h_donation_unit_pub),
    2162             :     DONAU_JSON_spec_blinded_donation_identifier ("blinded_udi",
    2163             :                                                  &bkp->blinded_udi),
    2164             :     GNUNET_JSON_spec_end ()
    2165             :   };
    2166             : 
    2167             :   if (GNUNET_OK !=
    2168             :       GNUNET_JSON_parse (bkp_key_obj,
    2169             :                          spec,
    2170             :                          NULL,
    2171             :                          NULL))
    2172             :   {
    2173             :     GNUNET_break_op (0);
    2174             :     return GNUNET_SYSERR;
    2175             :   }
    2176             :   return GNUNET_OK;
    2177             : }
    2178             : 
    2179             : 
    2180             : /**
    2181             :  * Generate a donation signature for the bkp and charity.
    2182             :  *
    2183             :  * @param[in,out] pc payment context containing the charity and bkps
    2184             :  */
    2185             : static void
    2186             : phase_request_donation_receipt (struct PayContext *pc)
    2187             : {
    2188             :   if ( (NULL == pc->parse_wallet_data.donau.donau_url) ||
    2189             :        (0 == pc->parse_wallet_data.num_bkps) )
    2190             :   {
    2191             :     pc->phase++;
    2192             :     return;
    2193             :   }
    2194             :   pc->donau_receipt.birh =
    2195             :     DONAU_charity_issue_receipt (
    2196             :       TMH_curl_ctx,
    2197             :       pc->parse_wallet_data.donau.donau_url,
    2198             :       &pc->parse_wallet_data.charity_priv,
    2199             :       pc->parse_wallet_data.charity_id,
    2200             :       pc->parse_wallet_data.donau.donation_year,
    2201             :       pc->parse_wallet_data.num_bkps,
    2202             :       pc->parse_wallet_data.bkps,
    2203             :       &merchant_donau_issue_receipt_cb,
    2204             :       pc);
    2205             :   if (NULL == pc->donau_receipt.birh)
    2206             :   {
    2207             :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    2208             :                 "Failed to create Donau receipt request");
    2209             :     pay_end (pc,
    2210             :              TALER_MHD_reply_with_error (pc->connection,
    2211             :                                          MHD_HTTP_INTERNAL_SERVER_ERROR,
    2212             :                                          TALER_EC_GENERIC_CLIENT_INTERNAL_ERROR,
    2213             :                                          "Donau request creation error"));
    2214             :     return;
    2215             :   }
    2216             :   MHD_suspend_connection (pc->connection);
    2217             :   pc->suspended = GNUNET_YES;
    2218             : }
    2219             : 
    2220             : 
    2221             : #endif
    2222             : 
    2223             : 
    2224             : /**
    2225             :  * Function called with information about a coin that was deposited.
    2226             :  *
    2227             :  * @param cls closure
    2228             :  * @param exchange_url exchange where @a coin_pub was deposited
    2229             :  * @param coin_pub public key of the coin
    2230             :  * @param amount_with_fee amount the exchange will deposit for this coin
    2231             :  * @param deposit_fee fee the exchange will charge for this coin
    2232             :  * @param refund_fee fee the exchange will charge for refunding this coin
    2233             :  */
    2234             : static void
    2235          37 : check_coin_paid (void *cls,
    2236             :                  const char *exchange_url,
    2237             :                  const struct TALER_CoinSpendPublicKeyP *coin_pub,
    2238             :                  const struct TALER_Amount *amount_with_fee,
    2239             :                  const struct TALER_Amount *deposit_fee,
    2240             :                  const struct TALER_Amount *refund_fee)
    2241             : {
    2242          37 :   struct PayContext *pc = cls;
    2243             : 
    2244          86 :   for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++)
    2245             :   {
    2246          49 :     struct DepositConfirmation *dc = &pc->parse_pay.dc[i];
    2247             : 
    2248          49 :     if (dc->found_in_db)
    2249           6 :       continue; /* processed earlier, skip "expensive" memcmp() */
    2250             :     /* Get matching coin from results*/
    2251          43 :     if ( (0 != GNUNET_memcmp (coin_pub,
    2252          35 :                               &dc->cdd.coin_pub)) ||
    2253             :          (0 !=
    2254          35 :           strcmp (exchange_url,
    2255          70 :                   dc->exchange_url)) ||
    2256             :          (GNUNET_OK !=
    2257          35 :           TALER_amount_cmp_currency (amount_with_fee,
    2258          70 :                                      &dc->cdd.amount)) ||
    2259          35 :          (0 != TALER_amount_cmp (amount_with_fee,
    2260          35 :                                  &dc->cdd.amount)) )
    2261           8 :       continue; /* does not match, skip */
    2262          35 :     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    2263             :                 "Deposit of coin `%s' already in our DB.\n",
    2264             :                 TALER_B2S (coin_pub));
    2265          35 :     if ( (GNUNET_OK !=
    2266          35 :           TALER_amount_cmp_currency (&pc->pay_transaction.total_paid,
    2267          35 :                                      amount_with_fee)) ||
    2268             :          (GNUNET_OK !=
    2269          35 :           TALER_amount_cmp_currency (&pc->pay_transaction.total_fees_paid,
    2270             :                                      deposit_fee)) )
    2271             :     {
    2272           0 :       GNUNET_break_op (0);
    2273           0 :       pc->pay_transaction.deposit_currency_mismatch = true;
    2274           0 :       break;
    2275             :     }
    2276          35 :     GNUNET_assert (0 <=
    2277             :                    TALER_amount_add (&pc->pay_transaction.total_paid,
    2278             :                                      &pc->pay_transaction.total_paid,
    2279             :                                      amount_with_fee));
    2280          35 :     GNUNET_assert (0 <=
    2281             :                    TALER_amount_add (&pc->pay_transaction.total_fees_paid,
    2282             :                                      &pc->pay_transaction.total_fees_paid,
    2283             :                                      deposit_fee));
    2284          35 :     dc->deposit_fee = *deposit_fee;
    2285          35 :     dc->refund_fee = *refund_fee;
    2286          35 :     dc->cdd.amount = *amount_with_fee;
    2287          35 :     dc->found_in_db = true;
    2288          35 :     pc->pay_transaction.pending--;
    2289             :   }
    2290          37 : }
    2291             : 
    2292             : 
    2293             : /**
    2294             :  * Function called with information about a refund.  Check if this coin was
    2295             :  * claimed by the wallet for the transaction, and if so add the refunded
    2296             :  * amount to the pc's "total_refunded" amount.
    2297             :  *
    2298             :  * @param cls closure with a `struct PayContext`
    2299             :  * @param coin_pub public coin from which the refund comes from
    2300             :  * @param refund_amount refund amount which is being taken from @a coin_pub
    2301             :  */
    2302             : static void
    2303           0 : check_coin_refunded (void *cls,
    2304             :                      const struct TALER_CoinSpendPublicKeyP *coin_pub,
    2305             :                      const struct TALER_Amount *refund_amount)
    2306             : {
    2307           0 :   struct PayContext *pc = cls;
    2308             : 
    2309             :   /* We look at refunds here that apply to the coins
    2310             :      that the customer is currently trying to pay us with.
    2311             : 
    2312             :      Such refunds are not "normal" refunds, but abort-pay refunds, which are
    2313             :      given in the case that the wallet aborts the payment.
    2314             :      In the case the wallet then decides to complete the payment *after* doing
    2315             :      an abort-pay refund (an unusual but possible case), we need
    2316             :      to make sure that existing refunds are accounted for. */
    2317             : 
    2318           0 :   for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++)
    2319             :   {
    2320           0 :     struct DepositConfirmation *dc = &pc->parse_pay.dc[i];
    2321             : 
    2322             :     /* Get matching coins from results.  */
    2323           0 :     if (0 != GNUNET_memcmp (coin_pub,
    2324             :                             &dc->cdd.coin_pub))
    2325           0 :       continue;
    2326           0 :     if (GNUNET_OK !=
    2327           0 :         TALER_amount_cmp_currency (&pc->pay_transaction.total_refunded,
    2328             :                                    refund_amount))
    2329             :     {
    2330           0 :       GNUNET_break (0);
    2331           0 :       pc->pay_transaction.refund_currency_mismatch = true;
    2332           0 :       break;
    2333             :     }
    2334           0 :     GNUNET_assert (0 <=
    2335             :                    TALER_amount_add (&pc->pay_transaction.total_refunded,
    2336             :                                      &pc->pay_transaction.total_refunded,
    2337             :                                      refund_amount));
    2338           0 :     break;
    2339             :   }
    2340           0 : }
    2341             : 
    2342             : 
    2343             : /**
    2344             :  * Check whether the amount paid is sufficient to cover the price.
    2345             :  *
    2346             :  * @param pc payment context to check
    2347             :  * @return true if the payment is sufficient, false if it is
    2348             :  *         insufficient
    2349             :  */
    2350             : static bool
    2351          31 : check_payment_sufficient (struct PayContext *pc)
    2352             : {
    2353             :   struct TALER_Amount acc_fee;
    2354             :   struct TALER_Amount acc_amount;
    2355             :   struct TALER_Amount final_amount;
    2356             :   struct TALER_Amount total_wire_fee;
    2357             :   struct TALER_Amount total_needed;
    2358             : 
    2359          31 :   if (0 == pc->parse_pay.coins_cnt)
    2360           2 :     return TALER_amount_is_zero (&pc->validate_tokens.brutto);
    2361          29 :   GNUNET_assert (GNUNET_OK ==
    2362             :                  TALER_amount_set_zero (pc->validate_tokens.brutto.currency,
    2363             :                                         &total_wire_fee));
    2364          58 :   for (unsigned int i = 0; i < pc->parse_pay.num_exchanges; i++)
    2365             :   {
    2366          29 :     if (GNUNET_OK !=
    2367          29 :         TALER_amount_cmp_currency (&total_wire_fee,
    2368          29 :                                    &pc->parse_pay.egs[i]->wire_fee))
    2369             :     {
    2370           0 :       GNUNET_break_op (0);
    2371           0 :       pay_end (pc,
    2372             :                TALER_MHD_reply_with_error (pc->connection,
    2373             :                                            MHD_HTTP_BAD_REQUEST,
    2374             :                                            TALER_EC_GENERIC_CURRENCY_MISMATCH,
    2375             :                                            total_wire_fee.currency));
    2376           0 :       return false;
    2377             :     }
    2378          29 :     if (0 >
    2379          29 :         TALER_amount_add (&total_wire_fee,
    2380             :                           &total_wire_fee,
    2381          29 :                           &pc->parse_pay.egs[i]->wire_fee))
    2382             :     {
    2383           0 :       GNUNET_break (0);
    2384           0 :       pay_end (pc,
    2385             :                TALER_MHD_reply_with_error (
    2386             :                  pc->connection,
    2387             :                  MHD_HTTP_INTERNAL_SERVER_ERROR,
    2388             :                  TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_EXCHANGE_WIRE_FEE_ADDITION_FAILED,
    2389             :                  "could not add exchange wire fee to total"));
    2390           0 :       return false;
    2391             :     }
    2392             :   }
    2393             : 
    2394             :   /**
    2395             :    * This loops calculates what are the deposit fee / total
    2396             :    * amount with fee / and wire fee, for all the coins.
    2397             :    */
    2398          29 :   GNUNET_assert (GNUNET_OK ==
    2399             :                  TALER_amount_set_zero (pc->validate_tokens.brutto.currency,
    2400             :                                         &acc_fee));
    2401          29 :   GNUNET_assert (GNUNET_OK ==
    2402             :                  TALER_amount_set_zero (pc->validate_tokens.brutto.currency,
    2403             :                                         &acc_amount));
    2404          64 :   for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++)
    2405             :   {
    2406          35 :     struct DepositConfirmation *dc = &pc->parse_pay.dc[i];
    2407             : 
    2408          35 :     GNUNET_assert (dc->found_in_db);
    2409          35 :     if ( (GNUNET_OK !=
    2410          35 :           TALER_amount_cmp_currency (&acc_fee,
    2411          70 :                                      &dc->deposit_fee)) ||
    2412             :          (GNUNET_OK !=
    2413          35 :           TALER_amount_cmp_currency (&acc_amount,
    2414          35 :                                      &dc->cdd.amount)) )
    2415             :     {
    2416           0 :       GNUNET_break_op (0);
    2417           0 :       pay_end (pc,
    2418             :                TALER_MHD_reply_with_error (
    2419             :                  pc->connection,
    2420             :                  MHD_HTTP_BAD_REQUEST,
    2421             :                  TALER_EC_GENERIC_CURRENCY_MISMATCH,
    2422           0 :                  dc->deposit_fee.currency));
    2423           0 :       return false;
    2424             :     }
    2425          35 :     if ( (0 >
    2426          35 :           TALER_amount_add (&acc_fee,
    2427          35 :                             &dc->deposit_fee,
    2428          35 :                             &acc_fee)) ||
    2429             :          (0 >
    2430          35 :           TALER_amount_add (&acc_amount,
    2431          35 :                             &dc->cdd.amount,
    2432             :                             &acc_amount)) )
    2433             :     {
    2434           0 :       GNUNET_break (0);
    2435             :       /* Overflow in these amounts? Very strange. */
    2436           0 :       pay_end (pc,
    2437             :                TALER_MHD_reply_with_error (
    2438             :                  pc->connection,
    2439             :                  MHD_HTTP_INTERNAL_SERVER_ERROR,
    2440             :                  TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AMOUNT_OVERFLOW,
    2441             :                  "Overflow adding up amounts"));
    2442           0 :       return false;
    2443             :     }
    2444          35 :     if (1 ==
    2445          35 :         TALER_amount_cmp (&dc->deposit_fee,
    2446          35 :                           &dc->cdd.amount))
    2447             :     {
    2448           0 :       GNUNET_break_op (0);
    2449           0 :       pay_end (pc,
    2450             :                TALER_MHD_reply_with_error (
    2451             :                  pc->connection,
    2452             :                  MHD_HTTP_BAD_REQUEST,
    2453             :                  TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_FEES_EXCEED_PAYMENT,
    2454             :                  "Deposit fees exceed coin's contribution"));
    2455           0 :       return false;
    2456             :     }
    2457             :   } /* end deposit loop */
    2458             : 
    2459          29 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    2460             :               "Amount received from wallet: %s\n",
    2461             :               TALER_amount2s (&acc_amount));
    2462          29 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    2463             :               "Deposit fee for all coins: %s\n",
    2464             :               TALER_amount2s (&acc_fee));
    2465          29 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    2466             :               "Total wire fee: %s\n",
    2467             :               TALER_amount2s (&total_wire_fee));
    2468          29 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    2469             :               "Deposit fee limit for merchant: %s\n",
    2470             :               TALER_amount2s (&pc->validate_tokens.max_fee));
    2471          29 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    2472             :               "Total refunded amount: %s\n",
    2473             :               TALER_amount2s (&pc->pay_transaction.total_refunded));
    2474             : 
    2475             :   /* Now compare exchange wire fee compared to what we are willing to pay */
    2476          29 :   if (GNUNET_YES !=
    2477          29 :       TALER_amount_cmp_currency (&total_wire_fee,
    2478             :                                  &acc_fee))
    2479             :   {
    2480           0 :     GNUNET_break (0);
    2481           0 :     pay_end (pc,
    2482             :              TALER_MHD_reply_with_error (
    2483             :                pc->connection,
    2484             :                MHD_HTTP_BAD_REQUEST,
    2485             :                TALER_EC_GENERIC_CURRENCY_MISMATCH,
    2486             :                total_wire_fee.currency));
    2487           0 :     return false;
    2488             :   }
    2489             : 
    2490             :   /* add wire fee to the total fees */
    2491          29 :   if (0 >
    2492          29 :       TALER_amount_add (&acc_fee,
    2493             :                         &acc_fee,
    2494             :                         &total_wire_fee))
    2495             :   {
    2496           0 :     GNUNET_break (0);
    2497           0 :     pay_end (pc,
    2498             :              TALER_MHD_reply_with_error (
    2499             :                pc->connection,
    2500             :                MHD_HTTP_INTERNAL_SERVER_ERROR,
    2501             :                TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AMOUNT_OVERFLOW,
    2502             :                "Overflow adding up amounts"));
    2503           0 :     return false;
    2504             :   }
    2505          29 :   if (-1 == TALER_amount_cmp (&pc->validate_tokens.max_fee,
    2506             :                               &acc_fee))
    2507             :   {
    2508             :     /**
    2509             :      * Sum of fees of *all* the different exchanges of all the coins are
    2510             :      * higher than the fixed limit that the merchant is willing to pay.  The
    2511             :      * difference must be paid by the customer.
    2512             :      */
    2513             :     struct TALER_Amount excess_fee;
    2514             : 
    2515             :     /* compute fee amount to be covered by customer */
    2516           8 :     GNUNET_assert (TALER_AAR_RESULT_POSITIVE ==
    2517             :                    TALER_amount_subtract (&excess_fee,
    2518             :                                           &acc_fee,
    2519             :                                           &pc->validate_tokens.max_fee));
    2520             :     /* add that to the total */
    2521           8 :     if (0 >
    2522           8 :         TALER_amount_add (&total_needed,
    2523             :                           &excess_fee,
    2524           8 :                           &pc->validate_tokens.brutto))
    2525             :     {
    2526           0 :       GNUNET_break (0);
    2527           0 :       pay_end (pc,
    2528             :                TALER_MHD_reply_with_error (
    2529             :                  pc->connection,
    2530             :                  MHD_HTTP_INTERNAL_SERVER_ERROR,
    2531             :                  TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AMOUNT_OVERFLOW,
    2532             :                  "Overflow adding up amounts"));
    2533           0 :       return false;
    2534             :     }
    2535             :   }
    2536             :   else
    2537             :   {
    2538             :     /* Fees are fully covered by the merchant, all we require
    2539             :        is that the total payment is not below the contract's amount */
    2540          21 :     total_needed = pc->validate_tokens.brutto;
    2541             :   }
    2542             : 
    2543             :   /* Do not count refunds towards the payment */
    2544          29 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    2545             :               "Subtracting total refunds from paid amount: %s\n",
    2546             :               TALER_amount2s (&pc->pay_transaction.total_refunded));
    2547          29 :   if (0 >
    2548          29 :       TALER_amount_subtract (&final_amount,
    2549             :                              &acc_amount,
    2550          29 :                              &pc->pay_transaction.total_refunded))
    2551             :   {
    2552           0 :     GNUNET_break (0);
    2553           0 :     pay_end (pc,
    2554             :              TALER_MHD_reply_with_error (
    2555             :                pc->connection,
    2556             :                MHD_HTTP_INTERNAL_SERVER_ERROR,
    2557             :                TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_REFUNDS_EXCEED_PAYMENTS,
    2558             :                "refunded amount exceeds total payments"));
    2559           0 :     return false;
    2560             :   }
    2561             : 
    2562          29 :   if (-1 == TALER_amount_cmp (&final_amount,
    2563             :                               &total_needed))
    2564             :   {
    2565             :     /* acc_amount < total_needed */
    2566           2 :     if (-1 < TALER_amount_cmp (&acc_amount,
    2567             :                                &total_needed))
    2568             :     {
    2569           0 :       GNUNET_break_op (0);
    2570           0 :       pay_end (pc,
    2571             :                TALER_MHD_reply_with_error (
    2572             :                  pc->connection,
    2573             :                  MHD_HTTP_PAYMENT_REQUIRED,
    2574             :                  TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_REFUNDED,
    2575             :                  "contract not paid up due to refunds"));
    2576           0 :       return false;
    2577             :     }
    2578           2 :     if (-1 < TALER_amount_cmp (&acc_amount,
    2579           2 :                                &pc->validate_tokens.brutto))
    2580             :     {
    2581           0 :       GNUNET_break_op (0);
    2582           0 :       pay_end (pc,
    2583             :                TALER_MHD_reply_with_error (
    2584             :                  pc->connection,
    2585             :                  MHD_HTTP_BAD_REQUEST,
    2586             :                  TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_INSUFFICIENT_DUE_TO_FEES,
    2587             :                  "contract not paid up due to fees (client may have calculated them badly)"));
    2588           0 :       return false;
    2589             :     }
    2590           2 :     GNUNET_break_op (0);
    2591           2 :     pay_end (pc,
    2592             :              TALER_MHD_reply_with_error (
    2593             :                pc->connection,
    2594             :                MHD_HTTP_BAD_REQUEST,
    2595             :                TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_PAYMENT_INSUFFICIENT,
    2596             :                "payment insufficient"));
    2597           2 :     return false;
    2598             :   }
    2599          27 :   return true;
    2600             : }
    2601             : 
    2602             : 
    2603             : /**
    2604             :  * Execute the DB transaction.  If required (from
    2605             :  * soft/serialization errors), the transaction can be
    2606             :  * restarted here.
    2607             :  *
    2608             :  * @param[in,out] pc payment context to transact
    2609             :  */
    2610             : static void
    2611          68 : phase_execute_pay_transaction (struct PayContext *pc)
    2612             : {
    2613          68 :   struct TMH_HandlerContext *hc = pc->hc;
    2614          68 :   const char *instance_id = hc->instance->settings.id;
    2615             : 
    2616          68 :   if (pc->batch_deposits.got_451)
    2617             :   {
    2618           0 :     pc->phase = PP_FAIL_LEGAL_REASONS;
    2619           0 :     return;
    2620             :   }
    2621             :   /* Avoid re-trying transactions on soft errors forever! */
    2622          68 :   if (pc->pay_transaction.retry_counter++ > MAX_RETRIES)
    2623             :   {
    2624           0 :     GNUNET_break (0);
    2625           0 :     pay_end (pc,
    2626             :              TALER_MHD_reply_with_error (pc->connection,
    2627             :                                          MHD_HTTP_INTERNAL_SERVER_ERROR,
    2628             :                                          TALER_EC_GENERIC_DB_SOFT_FAILURE,
    2629             :                                          NULL));
    2630           0 :     return;
    2631             :   }
    2632             : 
    2633             :   /* Initialize some amount accumulators
    2634             :      (used in check_coin_paid(), check_coin_refunded()
    2635             :      and check_payment_sufficient()). */
    2636          68 :   GNUNET_break (GNUNET_OK ==
    2637             :                 TALER_amount_set_zero (pc->validate_tokens.brutto.currency,
    2638             :                                        &pc->pay_transaction.total_paid));
    2639          68 :   GNUNET_break (GNUNET_OK ==
    2640             :                 TALER_amount_set_zero (pc->validate_tokens.brutto.currency,
    2641             :                                        &pc->pay_transaction.total_fees_paid));
    2642          68 :   GNUNET_break (GNUNET_OK ==
    2643             :                 TALER_amount_set_zero (pc->validate_tokens.brutto.currency,
    2644             :                                        &pc->pay_transaction.total_refunded));
    2645         146 :   for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++)
    2646          78 :     pc->parse_pay.dc[i].found_in_db = false;
    2647          68 :   pc->pay_transaction.pending = pc->parse_pay.coins_cnt;
    2648             : 
    2649             :   /* First, try to see if we have all we need already done */
    2650          68 :   TMH_db->preflight (TMH_db->cls);
    2651          68 :   if (GNUNET_OK !=
    2652          68 :       TMH_db->start (TMH_db->cls,
    2653             :                      "run pay"))
    2654             :   {
    2655           0 :     GNUNET_break (0);
    2656           0 :     pay_end (pc,
    2657             :              TALER_MHD_reply_with_error (pc->connection,
    2658             :                                          MHD_HTTP_INTERNAL_SERVER_ERROR,
    2659             :                                          TALER_EC_GENERIC_DB_START_FAILED,
    2660             :                                          NULL));
    2661           0 :     return;
    2662             :   }
    2663             : 
    2664          70 :   for (size_t i = 0; i<pc->parse_pay.tokens_cnt; i++)
    2665             :   {
    2666           4 :     struct TokenUseConfirmation *tuc = &pc->parse_pay.tokens[i];
    2667             :     enum GNUNET_DB_QueryStatus qs;
    2668             : 
    2669             :     /* Insert used token into database, the unique constraint will
    2670             :        case an error if this token was used before. */
    2671           4 :     qs = TMH_db->insert_spent_token (TMH_db->cls,
    2672           4 :                                      &pc->check_contract.h_contract_terms,
    2673           4 :                                      &tuc->h_issue,
    2674           4 :                                      &tuc->pub,
    2675           4 :                                      &tuc->sig,
    2676           4 :                                      &tuc->unblinded_sig);
    2677             : 
    2678           4 :     switch (qs)
    2679             :     {
    2680           0 :     case GNUNET_DB_STATUS_SOFT_ERROR:
    2681           0 :       TMH_db->rollback (TMH_db->cls);
    2682           0 :       return; /* do it again */
    2683           0 :     case GNUNET_DB_STATUS_HARD_ERROR:
    2684             :       /* Always report on hard error as well to enable diagnostics */
    2685           0 :       TMH_db->rollback (TMH_db->cls);
    2686           0 :       pay_end (pc,
    2687             :                TALER_MHD_reply_with_error (pc->connection,
    2688             :                                            MHD_HTTP_INTERNAL_SERVER_ERROR,
    2689             :                                            TALER_EC_GENERIC_DB_STORE_FAILED,
    2690             :                                            "insert used token"));
    2691           0 :       return;
    2692           2 :     case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
    2693             :       /* UNIQUE constraint violation, meaning this token was already used. */
    2694           2 :       TMH_db->rollback (TMH_db->cls);
    2695           2 :       pay_end (pc,
    2696             :                TALER_MHD_reply_with_error (pc->connection,
    2697             :                                            MHD_HTTP_CONFLICT,
    2698             :                                            TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_TOKEN_INVALID,
    2699             :                                            NULL));
    2700           2 :       return;
    2701           2 :     case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
    2702             :       /* Good, proceed! */
    2703           2 :       break;
    2704             :     }
    2705             :   } /* for all tokens */
    2706             : 
    2707             :   {
    2708             :     enum GNUNET_DB_QueryStatus qs;
    2709             : 
    2710             :     /* Check if some of these coins already succeeded for _this_ contract.  */
    2711          66 :     qs = TMH_db->lookup_deposits (TMH_db->cls,
    2712             :                                   instance_id,
    2713          66 :                                   &pc->check_contract.h_contract_terms,
    2714             :                                   &check_coin_paid,
    2715             :                                   pc);
    2716          66 :     if (0 > qs)
    2717             :     {
    2718           0 :       TMH_db->rollback (TMH_db->cls);
    2719           0 :       if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
    2720           0 :         return; /* do it again */
    2721             :       /* Always report on hard error as well to enable diagnostics */
    2722           0 :       GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
    2723           0 :       pay_end (pc,
    2724             :                TALER_MHD_reply_with_error (pc->connection,
    2725             :                                            MHD_HTTP_INTERNAL_SERVER_ERROR,
    2726             :                                            TALER_EC_GENERIC_DB_FETCH_FAILED,
    2727             :                                            "lookup deposits"));
    2728           0 :       return;
    2729             :     }
    2730          66 :     if (pc->pay_transaction.deposit_currency_mismatch)
    2731             :     {
    2732           0 :       TMH_db->rollback (TMH_db->cls);
    2733           0 :       GNUNET_break_op (0);
    2734           0 :       pay_end (pc,
    2735             :                TALER_MHD_reply_with_error (pc->connection,
    2736             :                                            MHD_HTTP_BAD_REQUEST,
    2737             :                                            TALER_EC_MERCHANT_GENERIC_CURRENCY_MISMATCH,
    2738           0 :                                            pc->validate_tokens.brutto.currency))
    2739             :       ;
    2740           0 :       return;
    2741             :     }
    2742             :   }
    2743             : 
    2744             :   {
    2745             :     enum GNUNET_DB_QueryStatus qs;
    2746             : 
    2747             :     /* Check if we refunded some of the coins */
    2748          66 :     qs = TMH_db->lookup_refunds (TMH_db->cls,
    2749             :                                  instance_id,
    2750          66 :                                  &pc->check_contract.h_contract_terms,
    2751             :                                  &check_coin_refunded,
    2752             :                                  pc);
    2753          66 :     if (0 > qs)
    2754             :     {
    2755           0 :       TMH_db->rollback (TMH_db->cls);
    2756           0 :       if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
    2757           0 :         return; /* do it again */
    2758             :       /* Always report on hard error as well to enable diagnostics */
    2759           0 :       GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
    2760           0 :       pay_end (pc,
    2761             :                TALER_MHD_reply_with_error (pc->connection,
    2762             :                                            MHD_HTTP_INTERNAL_SERVER_ERROR,
    2763             :                                            TALER_EC_GENERIC_DB_FETCH_FAILED,
    2764             :                                            "lookup refunds"));
    2765           0 :       return;
    2766             :     }
    2767          66 :     if (pc->pay_transaction.refund_currency_mismatch)
    2768             :     {
    2769           0 :       TMH_db->rollback (TMH_db->cls);
    2770           0 :       pay_end (pc,
    2771             :                TALER_MHD_reply_with_error (pc->connection,
    2772             :                                            MHD_HTTP_INTERNAL_SERVER_ERROR,
    2773             :                                            TALER_EC_GENERIC_DB_FETCH_FAILED,
    2774             :                                            "refund currency in database does not match order currency"));
    2775           0 :       return;
    2776             :     }
    2777             :   }
    2778             : 
    2779             :   /* Check if there are coins that still need to be processed */
    2780          66 :   if (0 != pc->pay_transaction.pending)
    2781             :   {
    2782             :     /* we made no DB changes, so we can just rollback */
    2783          35 :     TMH_db->rollback (TMH_db->cls);
    2784             :     /* Ok, we need to first go to the network to process more coins.
    2785             :        We that interaction in *tiny* transactions (hence the rollback
    2786             :        above). */
    2787          35 :     pc->phase = PP_BATCH_DEPOSITS;
    2788          35 :     return;
    2789             :   }
    2790             : 
    2791             :   /* 0 == pc->pay_transaction.pending: all coins processed, let's see if that was enough */
    2792          31 :   if (! check_payment_sufficient (pc))
    2793             :   {
    2794             :     /* check_payment_sufficient() will have queued an error already.
    2795             :        We need to still abort the transaction. */
    2796           2 :     TMH_db->rollback (TMH_db->cls);
    2797           2 :     return;
    2798             :   }
    2799             :   /* Payment succeeded, save in database */
    2800          29 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    2801             :               "Order `%s' (%s) was fully paid\n",
    2802             :               pc->order_id,
    2803             :               GNUNET_h2s (&pc->check_contract.h_contract_terms.hash));
    2804             :   {
    2805             :     enum GNUNET_DB_QueryStatus qs;
    2806             : 
    2807          29 :     qs = TMH_db->mark_contract_paid (TMH_db->cls,
    2808             :                                      instance_id,
    2809          29 :                                      &pc->check_contract.h_contract_terms,
    2810          29 :                                      pc->parse_pay.session_id,
    2811          29 :                                      pc->parse_wallet_data.choice_index);
    2812          29 :     if (qs < 0)
    2813             :     {
    2814           0 :       TMH_db->rollback (TMH_db->cls);
    2815           0 :       if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
    2816           0 :         return; /* do it again */
    2817           0 :       GNUNET_break (0);
    2818           0 :       pay_end (pc,
    2819             :                TALER_MHD_reply_with_error (pc->connection,
    2820             :                                            MHD_HTTP_INTERNAL_SERVER_ERROR,
    2821             :                                            TALER_EC_GENERIC_DB_STORE_FAILED,
    2822             :                                            "mark contract paid"));
    2823           0 :       return;
    2824             :     }
    2825             :   }
    2826             : 
    2827             : 
    2828             :   {
    2829          29 :     const struct TALER_MERCHANT_ContractChoice *choice =
    2830          29 :       &pc->check_contract.contract_terms->details.v1
    2831          29 :       .choices[pc->parse_wallet_data.choice_index];
    2832             : 
    2833          33 :     for (size_t i = 0; i<pc->output_tokens_len; i++)
    2834             :     {
    2835           4 :       switch (choice->outputs[i].type)
    2836             :       {
    2837           0 :       case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_INVALID:
    2838             :         /* Well, good luck getting here */
    2839           0 :         GNUNET_break (0);
    2840           0 :         pay_end (pc,
    2841             :                  TALER_MHD_reply_with_error (pc->connection,
    2842             :                                              MHD_HTTP_INTERNAL_SERVER_ERROR,
    2843             :                                              TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
    2844             :                                              "invalid output type"));
    2845           0 :         break;
    2846           0 :       case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_DONATION_RECEIPT:
    2847             :         /* We skip outputs of donation receipts here, as they are handled in the
    2848             :          * phase_final_output_token_processing() callback from donau */
    2849           0 :         break;
    2850           4 :       case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_TOKEN:
    2851           4 :         struct SignedOutputToken *output =
    2852           4 :           &pc->output_tokens[i];
    2853             :         enum GNUNET_DB_QueryStatus qs;
    2854             : 
    2855           4 :         qs = TMH_db->insert_issued_token (TMH_db->cls,
    2856           4 :                                           &pc->check_contract.h_contract_terms,
    2857           4 :                                           &output->h_issue,
    2858           4 :                                           &output->sig);
    2859             :         switch (qs)
    2860             :         {
    2861           0 :         case GNUNET_DB_STATUS_HARD_ERROR:
    2862           0 :           TMH_db->rollback (TMH_db->cls);
    2863           0 :           GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
    2864           0 :           pay_end (pc,
    2865             :                    TALER_MHD_reply_with_error (pc->connection,
    2866             :                                                MHD_HTTP_INTERNAL_SERVER_ERROR,
    2867             :                                                TALER_EC_GENERIC_DB_STORE_FAILED,
    2868             :                                                "insert output token"));
    2869           0 :           return;
    2870           0 :         case GNUNET_DB_STATUS_SOFT_ERROR:
    2871             :           /* Serialization failure, retry */
    2872           0 :           TMH_db->rollback (TMH_db->cls);
    2873           0 :           return;
    2874           0 :         case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
    2875             :           /* UNIQUE constraint violation, meaning this token was already used. */
    2876           0 :           TMH_db->rollback (TMH_db->cls);
    2877           0 :           pay_end (pc,
    2878             :                    TALER_MHD_reply_with_error (pc->connection,
    2879             :                                                MHD_HTTP_INTERNAL_SERVER_ERROR,
    2880             :                                                TALER_EC_GENERIC_DB_STORE_FAILED,
    2881             :                                                "duplicate output token"));
    2882           0 :           return;
    2883           4 :         case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
    2884           4 :           break;
    2885             :         }
    2886           4 :         break;
    2887             :       }
    2888             :     }
    2889             :   }
    2890             : 
    2891          29 :   TMH_notify_order_change (hc->instance,
    2892             :                            TMH_OSF_CLAIMED | TMH_OSF_PAID,
    2893          29 :                            pc->check_contract.contract_terms->timestamp,
    2894             :                            pc->check_contract.order_serial);
    2895             :   {
    2896             :     enum GNUNET_DB_QueryStatus qs;
    2897             :     json_t *jhook;
    2898             : 
    2899          29 :     jhook = GNUNET_JSON_PACK (
    2900             :       GNUNET_JSON_pack_object_incref ("contract_terms",
    2901             :                                       pc->check_contract.contract_terms_json),
    2902             :       GNUNET_JSON_pack_string ("order_id",
    2903             :                                pc->order_id)
    2904             :       );
    2905          29 :     GNUNET_assert (NULL != jhook);
    2906          29 :     qs = TMH_trigger_webhook (pc->hc->instance->settings.id,
    2907             :                               "pay",
    2908             :                               jhook);
    2909          29 :     json_decref (jhook);
    2910          29 :     if (qs < 0)
    2911             :     {
    2912           0 :       TMH_db->rollback (TMH_db->cls);
    2913           0 :       if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
    2914           0 :         return; /* do it again */
    2915           0 :       GNUNET_break (0);
    2916           0 :       pay_end (pc,
    2917             :                TALER_MHD_reply_with_error (pc->connection,
    2918             :                                            MHD_HTTP_INTERNAL_SERVER_ERROR,
    2919             :                                            TALER_EC_GENERIC_DB_STORE_FAILED,
    2920             :                                            "failed to trigger webhooks"));
    2921           0 :       return;
    2922             :     }
    2923             :   }
    2924             :   {
    2925             :     enum GNUNET_DB_QueryStatus qs;
    2926             : 
    2927             :     /* Now commit! */
    2928          29 :     qs = TMH_db->commit (TMH_db->cls);
    2929          29 :     if (0 > qs)
    2930             :     {
    2931             :       /* commit failed */
    2932           0 :       TMH_db->rollback (TMH_db->cls);
    2933           0 :       if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
    2934           0 :         return; /* do it again */
    2935           0 :       GNUNET_break (0);
    2936           0 :       pay_end (pc,
    2937             :                TALER_MHD_reply_with_error (pc->connection,
    2938             :                                            MHD_HTTP_INTERNAL_SERVER_ERROR,
    2939             :                                            TALER_EC_GENERIC_DB_COMMIT_FAILED,
    2940             :                                            NULL));
    2941           0 :       return;
    2942             :     }
    2943             :   }
    2944          29 :   pc->phase++;
    2945             : }
    2946             : 
    2947             : 
    2948             : /**
    2949             :  * Ensures that the expected number of tokens for a @e key
    2950             :  * are provided as inputs and have valid signatures.
    2951             :  *
    2952             :  * @param[in,out] pc payment context we are processing
    2953             :  * @param family family the tokens should be from
    2954             :  * @param index number of the input we are handling
    2955             :  * @param expected_num number of tokens expected
    2956             :  * @return #GNUNET_YES on success
    2957             :  */
    2958             : static enum GNUNET_GenericReturnValue
    2959           4 : find_valid_input_tokens (
    2960             :   struct PayContext *pc,
    2961             :   const struct TALER_MERCHANT_ContractTokenFamily *family,
    2962             :   unsigned int index,
    2963             :   unsigned int expected_num)
    2964             : {
    2965           4 :   unsigned int num_validated = 0;
    2966             :   struct GNUNET_TIME_Timestamp now
    2967           4 :     = GNUNET_TIME_timestamp_get ();
    2968           4 :   const struct TALER_MERCHANT_ContractTokenFamilyKey *kig = NULL;
    2969             : 
    2970           8 :   for (unsigned int j = 0; j < expected_num; j++)
    2971             :   {
    2972           4 :     struct TokenUseConfirmation *tuc
    2973           4 :       = &pc->parse_pay.tokens[index + j];
    2974           4 :     const struct TALER_MERCHANT_ContractTokenFamilyKey *key = NULL;
    2975             : 
    2976           4 :     for (unsigned int i = 0; i<family->keys_len; i++)
    2977             :     {
    2978           4 :       const struct TALER_MERCHANT_ContractTokenFamilyKey *ki
    2979           4 :         = &family->keys[i];
    2980             : 
    2981           4 :       if (0 ==
    2982           4 :           GNUNET_memcmp (&ki->pub.public_key->pub_key_hash,
    2983             :                          &tuc->h_issue.hash))
    2984             :       {
    2985           4 :         if (GNUNET_TIME_timestamp_cmp (ki->valid_after,
    2986             :                                        >,
    2987           4 :                                        now) ||
    2988           4 :             GNUNET_TIME_timestamp_cmp (ki->valid_before,
    2989             :                                        <=,
    2990             :                                        now))
    2991             :         {
    2992             :           /* We have a match, but not in the current validity period */
    2993           0 :           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    2994             :                       "Public key %s currently not valid\n",
    2995             :                       GNUNET_h2s (&ki->pub.public_key->pub_key_hash));
    2996           0 :           kig = ki;
    2997           0 :           continue;
    2998             :         }
    2999           4 :         key = ki;
    3000           4 :         break;
    3001             :       }
    3002             :     }
    3003           4 :     if (NULL == key)
    3004             :     {
    3005           0 :       if (NULL != kig)
    3006             :       {
    3007             :         char start_str[128];
    3008             :         char end_str[128];
    3009             :         char emsg[350];
    3010             : 
    3011           0 :         GNUNET_snprintf (start_str,
    3012             :                          sizeof (start_str),
    3013             :                          "%s",
    3014             :                          GNUNET_STRINGS_timestamp_to_string (kig->valid_after));
    3015           0 :         GNUNET_snprintf (end_str,
    3016             :                          sizeof (end_str),
    3017             :                          "%s",
    3018             :                          GNUNET_STRINGS_timestamp_to_string (kig->valid_before))
    3019             :         ;
    3020             :         /* FIXME: use more specific EC */
    3021           0 :         GNUNET_snprintf (emsg,
    3022             :                          sizeof (emsg),
    3023             :                          "Token is only valid from %s to %s",
    3024             :                          start_str,
    3025             :                          end_str);
    3026           0 :         pay_end (pc,
    3027             :                  TALER_MHD_reply_with_error (
    3028             :                    pc->connection,
    3029             :                    MHD_HTTP_GONE,
    3030             :                    TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_OFFER_EXPIRED,
    3031             :                    emsg));
    3032           0 :         return GNUNET_NO;
    3033             :       }
    3034           0 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    3035             :                   "Input token supplied for public key %s that is not acceptable\n",
    3036             :                   GNUNET_h2s (&tuc->h_issue.hash));
    3037           0 :       GNUNET_break_op (0);
    3038           0 :       pay_end (pc,
    3039             :                TALER_MHD_reply_with_error (
    3040             :                  pc->connection,
    3041             :                  MHD_HTTP_BAD_REQUEST,
    3042             :                  TALER_EC_MERCHANT_GENERIC_TOKEN_KEY_UNKNOWN,
    3043             :                  NULL));
    3044           0 :       return GNUNET_NO;
    3045             :     }
    3046           4 :     if (GNUNET_OK !=
    3047           4 :         TALER_token_issue_verify (&tuc->pub,
    3048             :                                   &key->pub,
    3049           4 :                                   &tuc->unblinded_sig))
    3050             :     {
    3051           0 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    3052             :                   "Input token for public key with valid_after "
    3053             :                   "`%s' has invalid issue signature\n",
    3054             :                   GNUNET_TIME_timestamp2s (key->valid_after));
    3055           0 :       GNUNET_break (0);
    3056           0 :       pay_end (pc,
    3057             :                TALER_MHD_reply_with_error (
    3058             :                  pc->connection,
    3059             :                  MHD_HTTP_BAD_REQUEST,
    3060             :                  TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_TOKEN_ISSUE_SIG_INVALID,
    3061             :                  NULL));
    3062           0 :       return GNUNET_NO;
    3063             :     }
    3064             : 
    3065           4 :     if (GNUNET_OK !=
    3066           4 :         TALER_wallet_token_use_verify (&pc->check_contract.h_contract_terms,
    3067           4 :                                        &pc->parse_wallet_data.h_wallet_data,
    3068           4 :                                        &tuc->pub,
    3069           4 :                                        &tuc->sig))
    3070             :     {
    3071           0 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    3072             :                   "Input token for public key with valid_before "
    3073             :                   "`%s' has invalid use signature\n",
    3074             :                   GNUNET_TIME_timestamp2s (key->valid_before));
    3075           0 :       GNUNET_break (0);
    3076           0 :       pay_end (pc,
    3077             :                TALER_MHD_reply_with_error (
    3078             :                  pc->connection,
    3079             :                  MHD_HTTP_BAD_REQUEST,
    3080             :                  TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_TOKEN_USE_SIG_INVALID,
    3081             :                  NULL));
    3082           0 :       return GNUNET_NO;
    3083             :     }
    3084             : 
    3085           4 :     num_validated++;
    3086             :   }
    3087             : 
    3088           4 :   if (num_validated != expected_num)
    3089             :   {
    3090           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    3091             :                 "Expected %d tokens for family %s, but found %d\n",
    3092             :                 expected_num,
    3093             :                 family->slug,
    3094             :                 num_validated);
    3095           0 :     GNUNET_break (0);
    3096           0 :     pay_end (pc,
    3097             :              TALER_MHD_reply_with_error (
    3098             :                pc->connection,
    3099             :                MHD_HTTP_BAD_REQUEST,
    3100             :                TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_TOKEN_COUNT_MISMATCH,
    3101             :                NULL));
    3102           0 :     return GNUNET_NO;
    3103             :   }
    3104           4 :   return GNUNET_YES;
    3105             : }
    3106             : 
    3107             : 
    3108             : /**
    3109             :  * Check if an output token of the given @a tfk is mandatory, or if
    3110             :  * wallets are allowed to simply not support it and still proceed.
    3111             :  *
    3112             :  * @param tfk token family kind to check
    3113             :  * @return true if such outputs are mandatory and wallets must supply
    3114             :  *  the corresponding blinded input
    3115             :  */
    3116             : /* FIXME: this function belongs into a lower-level lib! */
    3117             : static bool
    3118           6 : test_tfk_mandatory (enum TALER_MERCHANTDB_TokenFamilyKind tfk)
    3119             : {
    3120           6 :   switch (tfk)
    3121             :   {
    3122           0 :   case TALER_MERCHANTDB_TFK_Discount:
    3123           0 :     return false;
    3124           6 :   case TALER_MERCHANTDB_TFK_Subscription:
    3125           6 :     return true;
    3126             :   }
    3127           0 :   GNUNET_break (0);
    3128           0 :   return false;
    3129             : }
    3130             : 
    3131             : 
    3132             : /**
    3133             :  * Sign the tokens provided by the wallet for a particular @a key.
    3134             :  *
    3135             :  * @param[in,out] pc reference for payment we are processing
    3136             :  * @param key token family data
    3137             :  * @param priv private key to use to sign with
    3138             :  * @param mandatory true if the token must exist, if false
    3139             :  *        and the client did not provide an envelope, that's OK and
    3140             :  *        we just also skimp on the signature
    3141             :  * @param index offset in the token envelope array (from other families)
    3142             :  * @param expected_num number of tokens of this type that we should create
    3143             :  * @return #GNUNET_NO on failure
    3144             :  *         #GNUNET_OK on success
    3145             :  */
    3146             : static enum GNUNET_GenericReturnValue
    3147           6 : sign_token_envelopes (
    3148             :   struct PayContext *pc,
    3149             :   const struct TALER_MERCHANT_ContractTokenFamilyKey *key,
    3150             :   const struct TALER_TokenIssuePrivateKey *priv,
    3151             :   bool mandatory,
    3152             :   unsigned int index,
    3153             :   unsigned int expected_num)
    3154             : {
    3155           6 :   unsigned int num_signed = 0;
    3156             : 
    3157          12 :   for (unsigned int j = 0; j<expected_num; j++)
    3158             :   {
    3159           6 :     unsigned int pos = index + j;
    3160           6 :     const struct TokenEnvelope *env
    3161           6 :       = &pc->parse_wallet_data.token_envelopes[pos];
    3162           6 :     struct SignedOutputToken *output
    3163           6 :       = &pc->output_tokens[pos];
    3164             : 
    3165           6 :     if ( (pos >= pc->parse_wallet_data.token_envelopes_cnt) ||
    3166           6 :          (pos >= pc->output_tokens_len) )
    3167             :     {
    3168           0 :       GNUNET_assert (0); /* this should not happen */
    3169             :       return GNUNET_NO;
    3170             :     }
    3171           6 :     if (NULL == env->blinded_token.blinded_pub)
    3172             :     {
    3173           0 :       if (! mandatory)
    3174           0 :         continue;
    3175             : 
    3176             :       /* mandatory token families require a token envelope. */
    3177           0 :       GNUNET_break_op (0);
    3178           0 :       pay_end (pc,
    3179             :                TALER_MHD_reply_with_error (
    3180             :                  pc->connection,
    3181             :                  MHD_HTTP_BAD_REQUEST,
    3182             :                  TALER_EC_GENERIC_PARAMETER_MALFORMED,
    3183             :                  "Token envelope for mandatory token family missing"));
    3184           0 :       return GNUNET_NO;
    3185             :     }
    3186           6 :     TALER_token_issue_sign (priv,
    3187             :                             &env->blinded_token,
    3188             :                             &output->sig);
    3189             :     output->h_issue.hash
    3190           6 :       = key->pub.public_key->pub_key_hash;
    3191           6 :     num_signed++;
    3192             :   }
    3193             : 
    3194           6 :   if (mandatory &&
    3195             :       (num_signed != expected_num) )
    3196             :   {
    3197           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    3198             :                 "Expected %d token envelopes for public key with valid_after "
    3199             :                 "'%s', but found %d\n",
    3200             :                 expected_num,
    3201             :                 GNUNET_TIME_timestamp2s (key->valid_after),
    3202             :                 num_signed);
    3203           0 :     GNUNET_break (0);
    3204           0 :     pay_end (pc,
    3205             :              TALER_MHD_reply_with_error (
    3206             :                pc->connection,
    3207             :                MHD_HTTP_BAD_REQUEST,
    3208             :                TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_TOKEN_ENVELOPE_COUNT_MISMATCH,
    3209             :                NULL));
    3210           0 :     return GNUNET_NO;
    3211             :   }
    3212             : 
    3213           6 :   return GNUNET_OK;
    3214             : }
    3215             : 
    3216             : 
    3217             : /**
    3218             :  * Find the family entry for the family of the given @a slug
    3219             :  * in @a pc.
    3220             :  *
    3221             :  * @param[in] pc payment context to search
    3222             :  * @param slug slug to search for
    3223             :  * @return NULL if @a slug was not found
    3224             :  */
    3225             : static const struct TALER_MERCHANT_ContractTokenFamily *
    3226          10 : find_family (const struct PayContext *pc,
    3227             :              const char *slug)
    3228             : {
    3229          10 :   for (unsigned int i = 0;
    3230          10 :        i < pc->check_contract.contract_terms->details.v1.token_authorities_len;
    3231           0 :        i++)
    3232             :   {
    3233          10 :     const struct TALER_MERCHANT_ContractTokenFamily *tfi
    3234          10 :       = &pc->check_contract.contract_terms->details.v1.token_authorities[i];
    3235             : 
    3236          10 :     if (0 == strcmp (tfi->slug,
    3237             :                      slug))
    3238             :     {
    3239          10 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    3240             :                   "Token family %s found with %u keys\n",
    3241             :                   slug,
    3242             :                   tfi->keys_len);
    3243          10 :       return tfi;
    3244             :     }
    3245             :   }
    3246           0 :   return NULL;
    3247             : }
    3248             : 
    3249             : 
    3250             : /**
    3251             :  * Handle contract output of type TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_TOKEN.
    3252             :  * Looks up the token family, loads the matching private key,
    3253             :  * and signs the corresponding token envelopes from the wallet.
    3254             :  *
    3255             :  * @param pc context for the pay request
    3256             :  * @param output contract output we need to process
    3257             :  * @param output_index index of this output in the contract's outputs array
    3258             :  * @return #GNUNET_OK on success, #GNUNET_NO if an error was encountered
    3259             :  */
    3260             : static enum GNUNET_GenericReturnValue
    3261           6 : handle_output_token (struct PayContext *pc,
    3262             :                      const struct TALER_MERCHANT_ContractOutput *output,
    3263             :                      unsigned int output_index)
    3264             : {
    3265             :   const struct TALER_MERCHANT_ContractTokenFamily *family;
    3266             :   struct TALER_MERCHANT_ContractTokenFamilyKey *key;
    3267             :   struct TALER_MERCHANTDB_TokenFamilyKeyDetails details;
    3268             :   enum GNUNET_DB_QueryStatus qs;
    3269             :   bool mandatory;
    3270             : 
    3271             :   /* Locate token family in the contract.
    3272             :      This should ever fail as this invariant should
    3273             :      have been checked when the contract was created. */
    3274           6 :   family = find_family (pc,
    3275           6 :                         output->details.token.token_family_slug);
    3276           6 :   if (NULL == family)
    3277             :   {
    3278             :     /* This "should never happen", so treat it as an internal error */
    3279           0 :     GNUNET_break (0);
    3280           0 :     pay_end (pc,
    3281             :              TALER_MHD_reply_with_error (
    3282             :                pc->connection,
    3283             :                MHD_HTTP_INTERNAL_SERVER_ERROR,
    3284             :                TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
    3285             :                "token family not found in order"));
    3286           0 :     return GNUNET_SYSERR;
    3287             :   }
    3288             : 
    3289             :   /* Check the key_index field from the output. */
    3290           6 :   if (output->details.token.key_index >= family->keys_len)
    3291             :   {
    3292             :     /* Also "should never happen", contract was presumably validated on insert */
    3293           0 :     GNUNET_break (0);
    3294           0 :     pay_end (pc,
    3295             :              TALER_MHD_reply_with_error (
    3296             :                pc->connection,
    3297             :                MHD_HTTP_INTERNAL_SERVER_ERROR,
    3298             :                TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
    3299             :                "key index invalid for token family"));
    3300           0 :     return GNUNET_SYSERR;
    3301             :   }
    3302             : 
    3303             :   /* Pick the correct key inside that family. */
    3304           6 :   key = &family->keys[output->details.token.key_index];
    3305             : 
    3306             :   /* Fetch the private key from the DB for the merchant instance and
    3307             :    * this particular family/time interval. */
    3308           6 :   qs = TMH_db->lookup_token_family_key (
    3309           6 :     TMH_db->cls,
    3310           6 :     pc->hc->instance->settings.id,
    3311           6 :     family->slug,
    3312           6 :     pc->check_contract.contract_terms->timestamp,
    3313           6 :     pc->check_contract.contract_terms->pay_deadline,
    3314             :     &details);
    3315           6 :   switch (qs)
    3316             :   {
    3317           0 :   case GNUNET_DB_STATUS_HARD_ERROR:
    3318             :   case GNUNET_DB_STATUS_SOFT_ERROR:
    3319           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    3320             :                 "Database error looking up token-family key for %s\n",
    3321             :                 family->slug);
    3322           0 :     GNUNET_break (0);
    3323           0 :     pay_end (pc,
    3324             :              TALER_MHD_reply_with_error (
    3325             :                pc->connection,
    3326             :                MHD_HTTP_INTERNAL_SERVER_ERROR,
    3327             :                TALER_EC_GENERIC_DB_FETCH_FAILED,
    3328             :                NULL));
    3329           0 :     return GNUNET_NO;
    3330           0 :   case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
    3331           0 :     GNUNET_log (
    3332             :       GNUNET_ERROR_TYPE_ERROR,
    3333             :       "Token-family key for %s not found at [%llu,%llu]\n",
    3334             :       family->slug,
    3335             :       (unsigned long long)
    3336             :       pc->check_contract.contract_terms->timestamp.abs_time.abs_value_us,
    3337             :       (unsigned long long)
    3338             :       pc->check_contract.contract_terms->pay_deadline.abs_time.abs_value_us
    3339             :       );
    3340           0 :     GNUNET_break (0);
    3341           0 :     pay_end (pc,
    3342             :              TALER_MHD_reply_with_error (
    3343             :                pc->connection,
    3344             :                MHD_HTTP_NOT_FOUND,
    3345             :                TALER_EC_GENERIC_DB_FETCH_FAILED,
    3346             :                NULL));
    3347           0 :     return GNUNET_NO;
    3348             : 
    3349           6 :   case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
    3350           6 :     break;
    3351             :   }
    3352           6 :   GNUNET_assert (NULL != details.priv.private_key);
    3353             : 
    3354             :   /* Depending on the token family, decide if the token envelope
    3355             :    * is mandatory or optional.  (Simplified logic here: adapt as needed.) */
    3356           6 :   mandatory = test_tfk_mandatory (details.token_family.kind);
    3357             : 
    3358             :   /* Actually sign the number of token envelopes specified in 'count'.
    3359             :    * 'output_index' is the offset into the parse_wallet_data arrays.  */
    3360           6 :   if (GNUNET_OK !=
    3361           6 :       sign_token_envelopes (pc,
    3362             :                             key,
    3363             :                             &details.priv,
    3364             :                             mandatory,
    3365             :                             output_index,
    3366           6 :                             output->details.token.count))
    3367             :   {
    3368             :     /* sign_token_envelopes() already queued up an error via pay_end() */
    3369           0 :     GNUNET_break_op (0);
    3370           0 :     return GNUNET_NO;
    3371             :   }
    3372           6 :   return GNUNET_OK;
    3373             : }
    3374             : 
    3375             : 
    3376             : #ifdef HAVE_DONAU_DONAU_SERVICE_H
    3377             : /**
    3378             :  * Handle checks for contract output of type TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_DONATION_RECEIPT.
    3379             :  * For now, this does nothing and simply returns #GNUNET_OK.
    3380             :  *
    3381             :  * @param pc context for the pay request
    3382             :  * @param output the contract output describing the donation receipt requirement
    3383             :  * @return #GNUNET_OK unconditionally (placeholder)
    3384             :  */
    3385             : static enum GNUNET_GenericReturnValue
    3386             : handle_output_donation_receipt (
    3387             :   struct PayContext *pc,
    3388             :   const struct TALER_MERCHANT_ContractOutput *output)
    3389             : {
    3390             :   if (GNUNET_OK !=
    3391             :       DONAU_get_donation_amount_from_bkps (
    3392             :         pc->parse_wallet_data.donau_keys,
    3393             :         pc->parse_wallet_data.bkps,
    3394             :         pc->parse_wallet_data.num_bkps,
    3395             :         pc->parse_wallet_data.donau.donation_year,
    3396             :         &pc->parse_wallet_data.donation_amount) )
    3397             :   {
    3398             :     GNUNET_break_op (0);
    3399             :     pay_end (pc,
    3400             :              TALER_MHD_reply_with_error (
    3401             :                pc->connection,
    3402             :                MHD_HTTP_BAD_REQUEST,
    3403             :                TALER_EC_GENERIC_PARAMETER_MALFORMED,
    3404             :                "inconsistent bkps / donau keys"));
    3405             :     return GNUNET_NO;
    3406             :   }
    3407             : 
    3408             :   if (GNUNET_OK !=
    3409             :       TALER_amount_cmp_currency (&pc->parse_wallet_data.donation_amount,
    3410             :                                  &output->details.donation_receipt.amount))
    3411             :   {
    3412             :     GNUNET_break_op (0);
    3413             :     pay_end (pc,
    3414             :              TALER_MHD_reply_with_error (
    3415             :                pc->connection,
    3416             :                MHD_HTTP_BAD_REQUEST,
    3417             :                TALER_EC_GENERIC_CURRENCY_MISMATCH,
    3418             :                output->details.donation_receipt.amount.currency));
    3419             :     return GNUNET_NO;
    3420             :   }
    3421             : 
    3422             :   if (0 !=
    3423             :       TALER_amount_cmp (&pc->parse_wallet_data.donation_amount,
    3424             :                         &output->details.donation_receipt.amount))
    3425             :   {
    3426             :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    3427             :                 "Wallet amount: %s\n",
    3428             :                 TALER_amount2s (&pc->parse_wallet_data.donation_amount));
    3429             :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    3430             :                 "Donation receipt amount: %s\n",
    3431             :                 TALER_amount2s (&output->details.donation_receipt.amount));
    3432             :     GNUNET_break_op (0);
    3433             :     pay_end (pc,
    3434             :              TALER_MHD_reply_with_error (
    3435             :                pc->connection,
    3436             :                MHD_HTTP_CONFLICT,
    3437             :                TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_DONATION_AMOUNT_MISMATCH,
    3438             :                "donation amount mismatch"));
    3439             :     return GNUNET_NO;
    3440             :   }
    3441             :   {
    3442             :     struct TALER_Amount receipts_to_date;
    3443             : 
    3444             :     if (0 >
    3445             :         TALER_amount_add (&receipts_to_date,
    3446             :                           &pc->parse_wallet_data.charity_receipts_to_date,
    3447             :                           &pc->parse_wallet_data.donation_amount))
    3448             :     {
    3449             :       GNUNET_break (0);
    3450             :       pay_end (pc,
    3451             :                TALER_MHD_reply_with_error (pc->connection,
    3452             :                                            MHD_HTTP_INTERNAL_SERVER_ERROR,
    3453             :                                            TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AMOUNT_OVERFLOW,
    3454             :                                            "adding donation amount"));
    3455             :       return GNUNET_NO;
    3456             :     }
    3457             : 
    3458             :     if (1 ==
    3459             :         TALER_amount_cmp (&receipts_to_date,
    3460             :                           &pc->parse_wallet_data.charity_max_per_year))
    3461             :     {
    3462             :       GNUNET_break_op (0);
    3463             :       pay_end (pc,
    3464             :                TALER_MHD_reply_with_error (pc->connection,
    3465             :                                            MHD_HTTP_CONFLICT,
    3466             :                                            TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_DONATION_AMOUNT_MISMATCH,
    3467             :                                            "donation limit exceeded"));
    3468             :       return GNUNET_NO;
    3469             :     }
    3470             :     pc->parse_wallet_data.charity_receipts_to_date = receipts_to_date;
    3471             :   }
    3472             :   return GNUNET_OK;
    3473             : }
    3474             : 
    3475             : 
    3476             : #endif /* HAVE_DONAU_DONAU_SERVICE_H */
    3477             : 
    3478             : 
    3479             : /**
    3480             :  * Validate tokens and token envelopes. First, we check if all tokens listed
    3481             :  * in the 'inputs' array of the selected choice are present in the 'tokens'
    3482             :  * array of the request. Then, we validate the signatures of each provided
    3483             :  * token.
    3484             :  *
    3485             :  * @param[in,out] pc context we use to handle the payment
    3486             :  */
    3487             : static void
    3488          39 : phase_validate_tokens (struct PayContext *pc)
    3489             : {
    3490          39 :   switch (pc->check_contract.contract_terms->version)
    3491             :   {
    3492          33 :   case TALER_MERCHANT_CONTRACT_VERSION_0:
    3493             :     /* No tokens to validate */
    3494          33 :     pc->phase = PP_PAY_TRANSACTION;
    3495             :     pc->validate_tokens.max_fee
    3496          33 :       = pc->check_contract.contract_terms->details.v0.max_fee;
    3497             :     pc->validate_tokens.brutto
    3498          33 :       = pc->check_contract.contract_terms->details.v0.brutto;
    3499          33 :     break;
    3500           6 :   case TALER_MERCHANT_CONTRACT_VERSION_1:
    3501             :     {
    3502           6 :       const struct TALER_MERCHANT_ContractChoice *selected
    3503           6 :         = &pc->check_contract.contract_terms->details.v1.choices[
    3504           6 :             pc->parse_wallet_data.choice_index];
    3505             :       unsigned int output_off;
    3506             :       unsigned int cnt;
    3507           6 :       bool donau_seen = false;
    3508             : 
    3509           6 :       pc->validate_tokens.max_fee = selected->max_fee;
    3510           6 :       pc->validate_tokens.brutto = selected->amount;
    3511             : 
    3512          10 :       for (unsigned int i = 0; i<selected->inputs_len; i++)
    3513             :       {
    3514           4 :         const struct TALER_MERCHANT_ContractInput *input
    3515           4 :           = &selected->inputs[i];
    3516             :         const struct TALER_MERCHANT_ContractTokenFamily *family;
    3517             : 
    3518           4 :         switch (input->type)
    3519             :         {
    3520           0 :         case TALER_MERCHANT_CONTRACT_INPUT_TYPE_INVALID:
    3521           0 :           GNUNET_break (0);
    3522           0 :           pay_end (pc,
    3523             :                    TALER_MHD_reply_with_error (
    3524             :                      pc->connection,
    3525             :                      MHD_HTTP_BAD_REQUEST,
    3526             :                      TALER_EC_GENERIC_PARAMETER_MALFORMED,
    3527             :                      "input token type not valid"));
    3528           0 :           return;
    3529             : #if FUTURE
    3530             :         case TALER_MERCHANT_CONTRACT_INPUT_TYPE_COIN:
    3531             :           GNUNET_break (0);
    3532             :           pay_end (pc,
    3533             :                    TALER_MHD_reply_with_error (
    3534             :                      pc->connection,
    3535             :                      MHD_HTTP_NOT_IMPLEMENTED,
    3536             :                      TALER_EC_MERCHANT_GENERIC_FEATURE_NOT_AVAILABLE,
    3537             :                      "token type not yet supported"));
    3538             :           return;
    3539             : #endif
    3540           4 :         case TALER_MERCHANT_CONTRACT_INPUT_TYPE_TOKEN:
    3541           4 :           family = find_family (pc,
    3542           4 :                                 input->details.token.token_family_slug);
    3543           4 :           if (NULL == family)
    3544             :           {
    3545             :             /* this should never happen, since the choices and
    3546             :                token families are validated on insert. */
    3547           0 :             GNUNET_break (0);
    3548           0 :             pay_end (pc,
    3549             :                      TALER_MHD_reply_with_error (
    3550             :                        pc->connection,
    3551             :                        MHD_HTTP_INTERNAL_SERVER_ERROR,
    3552             :                        TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
    3553             :                        "token family not found in order"));
    3554           0 :             return;
    3555             :           }
    3556           4 :           if (GNUNET_NO ==
    3557           4 :               find_valid_input_tokens (pc,
    3558             :                                        family,
    3559             :                                        i,
    3560           4 :                                        input->details.token.count))
    3561             :           {
    3562             :             /* Error is already scheduled from find_valid_input_token. */
    3563           0 :             return;
    3564             :           }
    3565             :         }
    3566             :       }
    3567             : 
    3568             :       /* calculate pc->output_tokens_len */
    3569           6 :       output_off = 0;
    3570          12 :       for (unsigned int i = 0; i<selected->outputs_len; i++)
    3571             :       {
    3572           6 :         const struct TALER_MERCHANT_ContractOutput *output
    3573           6 :           = &selected->outputs[i];
    3574             : 
    3575           6 :         switch (output->type)
    3576             :         {
    3577           0 :         case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_INVALID:
    3578           0 :           GNUNET_assert (0);
    3579             :           break;
    3580           6 :         case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_TOKEN:
    3581           6 :           cnt = output->details.token.count;
    3582           6 :           if (output_off + cnt < output_off)
    3583             :           {
    3584           0 :             GNUNET_break_op (0);
    3585           0 :             pay_end (pc,
    3586             :                      TALER_MHD_reply_with_error (
    3587             :                        pc->connection,
    3588             :                        MHD_HTTP_BAD_REQUEST,
    3589             :                        TALER_EC_GENERIC_PARAMETER_MALFORMED,
    3590             :                        "output token counter overflow"));
    3591           0 :             return;
    3592             :           }
    3593           6 :           output_off += cnt;
    3594           6 :           break;
    3595           0 :         case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_DONATION_RECEIPT:
    3596             :           /* check that this output type appears at most once */
    3597           0 :           if (donau_seen)
    3598             :           {
    3599             :             /* This should have been prevented when the
    3600             :                contract was initially created */
    3601           0 :             GNUNET_break (0);
    3602           0 :             pay_end (pc,
    3603             :                      TALER_MHD_reply_with_error (
    3604             :                        pc->connection,
    3605             :                        MHD_HTTP_INTERNAL_SERVER_ERROR,
    3606             :                        TALER_EC_GENERIC_DB_INVARIANT_FAILURE,
    3607             :                        "two donau output sets in same contract"));
    3608           0 :             return;
    3609             :           }
    3610           0 :           donau_seen = true;
    3611             : #ifdef HAVE_DONAU_DONAU_SERVICE_H
    3612             :           if (output_off + pc->parse_wallet_data.num_bkps < output_off)
    3613             :           {
    3614             :             GNUNET_break_op (0);
    3615             :             pay_end (pc,
    3616             :                      TALER_MHD_reply_with_error (
    3617             :                        pc->connection,
    3618             :                        MHD_HTTP_BAD_REQUEST,
    3619             :                        TALER_EC_GENERIC_PARAMETER_MALFORMED,
    3620             :                        "output token counter overflow"));
    3621             :             return;
    3622             :           }
    3623             :           output_off += pc->parse_wallet_data.num_bkps;
    3624             : #endif
    3625           0 :           break;
    3626             :         }
    3627             :       }
    3628             : 
    3629           6 :       pc->output_tokens_len = output_off;
    3630             :       pc->output_tokens
    3631           6 :         = GNUNET_new_array (pc->output_tokens_len,
    3632             :                             struct SignedOutputToken);
    3633             : 
    3634             :       /* compute non-donau outputs */
    3635           6 :       output_off = 0;
    3636          12 :       for (unsigned int i = 0; i<selected->outputs_len; i++)
    3637             :       {
    3638           6 :         const struct TALER_MERCHANT_ContractOutput *output
    3639           6 :           = &selected->outputs[i];
    3640             : 
    3641           6 :         switch (output->type)
    3642             :         {
    3643           0 :         case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_INVALID:
    3644           0 :           GNUNET_assert (0);
    3645             :           break;
    3646           6 :         case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_TOKEN:
    3647           6 :           cnt = output->details.token.count;
    3648           6 :           GNUNET_assert (output_off + cnt
    3649             :                          <= pc->output_tokens_len);
    3650           6 :           if (GNUNET_OK !=
    3651           6 :               handle_output_token (pc,
    3652             :                                    output,
    3653             :                                    output_off))
    3654             :           {
    3655             :             /* Error is already scheduled from handle_output_token. */
    3656           0 :             return;
    3657             :           }
    3658           6 :           output_off += cnt;
    3659           6 :           break;
    3660           0 :         case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_DONATION_RECEIPT:
    3661             : #ifndef HAVE_DONAU_DONAU_SERVICE_H
    3662             :           /* We checked at parse time, and
    3663             :              wallet didn't want donau, so OK! */
    3664           0 :           return;
    3665             : #else
    3666             :           if (GNUNET_OK !=
    3667             :               handle_output_donation_receipt (pc,
    3668             :                                               output))
    3669             :           {
    3670             :             /* Error is already scheduled from handle_output_donation_receipt. */
    3671             :             return;
    3672             :           }
    3673             :           output_off += pc->parse_wallet_data.num_bkps;
    3674             :           continue;
    3675             : #endif
    3676             :         } /* switch on output token */
    3677             :       } /* for all output token types */
    3678             :     } /* case contract v1 */
    3679           6 :     break;
    3680             :   } /* switch on contract type */
    3681             : 
    3682          82 :   for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++)
    3683             :   {
    3684          43 :     const struct DepositConfirmation *dc = &pc->parse_pay.dc[i];
    3685             : 
    3686          43 :     if (GNUNET_OK !=
    3687          43 :         TALER_amount_cmp_currency (&dc->cdd.amount,
    3688          43 :                                    &pc->validate_tokens.brutto))
    3689             :     {
    3690           0 :       GNUNET_break_op (0);
    3691           0 :       pay_end (pc,
    3692             :                TALER_MHD_reply_with_error (
    3693             :                  pc->connection,
    3694             :                  MHD_HTTP_CONFLICT,
    3695             :                  TALER_EC_MERCHANT_GENERIC_CURRENCY_MISMATCH,
    3696           0 :                  pc->validate_tokens.brutto.currency));
    3697           0 :       return;
    3698             :     }
    3699             :   }
    3700             : 
    3701          39 :   pc->phase = PP_PAY_TRANSACTION;
    3702             : }
    3703             : 
    3704             : 
    3705             : /**
    3706             :  * Function called with information about a coin that was deposited.
    3707             :  * Checks if this coin is in our list of deposits as well.
    3708             :  *
    3709             :  * @param cls closure with our `struct PayContext *`
    3710             :  * @param deposit_serial which deposit operation is this about
    3711             :  * @param exchange_url URL of the exchange that issued the coin
    3712             :  * @param h_wire hash of merchant's wire details
    3713             :  * @param deposit_timestamp when was the deposit made
    3714             :  * @param amount_with_fee amount the exchange will deposit for this coin
    3715             :  * @param deposit_fee fee the exchange will charge for this coin
    3716             :  * @param coin_pub public key of the coin
    3717             :  */
    3718             : static void
    3719           6 : deposit_paid_check (
    3720             :   void *cls,
    3721             :   uint64_t deposit_serial,
    3722             :   const char *exchange_url,
    3723             :   const struct TALER_MerchantWireHashP *h_wire,
    3724             :   struct GNUNET_TIME_Timestamp deposit_timestamp,
    3725             :   const struct TALER_Amount *amount_with_fee,
    3726             :   const struct TALER_Amount *deposit_fee,
    3727             :   const struct TALER_CoinSpendPublicKeyP *coin_pub)
    3728             : {
    3729           6 :   struct PayContext *pc = cls;
    3730             : 
    3731          14 :   for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++)
    3732             :   {
    3733          10 :     struct DepositConfirmation *dci = &pc->parse_pay.dc[i];
    3734             : 
    3735          10 :     if ( (0 ==
    3736          10 :           GNUNET_memcmp (&dci->cdd.coin_pub,
    3737           2 :                          coin_pub)) &&
    3738             :          (0 ==
    3739           2 :           strcmp (dci->exchange_url,
    3740           2 :                   exchange_url)) &&
    3741             :          (GNUNET_YES ==
    3742           2 :           TALER_amount_cmp_currency (&dci->cdd.amount,
    3743           2 :                                      amount_with_fee)) &&
    3744             :          (0 ==
    3745           2 :           TALER_amount_cmp (&dci->cdd.amount,
    3746             :                             amount_with_fee)) )
    3747             :     {
    3748           2 :       dci->matched_in_db = true;
    3749           2 :       break;
    3750             :     }
    3751             :   }
    3752           6 : }
    3753             : 
    3754             : 
    3755             : /**
    3756             :  * Function called with information about a token that was spent.
    3757             :  * FIXME: Replace this with a more specific function for this cb
    3758             :  *
    3759             :  * @param cls closure with `struct PayContext *`
    3760             :  * @param spent_token_serial "serial" of the spent token unused
    3761             :  * @param h_contract_terms hash of the contract terms unused
    3762             :  * @param h_issue_pub hash of the token issue public key unused
    3763             :  * @param use_pub public key of the token
    3764             :  * @param use_sig signature of the token
    3765             :  * @param issue_sig signature of the token issue
    3766             :  */
    3767             : static void
    3768           0 : input_tokens_paid_check (
    3769             :   void *cls,
    3770             :   uint64_t spent_token_serial,
    3771             :   const struct TALER_PrivateContractHashP *h_contract_terms,
    3772             :   const struct TALER_TokenIssuePublicKeyHashP *h_issue_pub,
    3773             :   const struct TALER_TokenUsePublicKeyP *use_pub,
    3774             :   const struct TALER_TokenUseSignatureP *use_sig,
    3775             :   const struct TALER_TokenIssueSignature *issue_sig)
    3776             : {
    3777           0 :   struct PayContext *pc = cls;
    3778             : 
    3779           0 :   for (size_t i = 0; i<pc->parse_pay.tokens_cnt; i++)
    3780             :   {
    3781           0 :     struct TokenUseConfirmation *tuc = &pc->parse_pay.tokens[i];
    3782             : 
    3783           0 :     if ( (0 ==
    3784           0 :           GNUNET_memcmp (&tuc->pub,
    3785           0 :                          use_pub)) &&
    3786             :          (0 ==
    3787           0 :           GNUNET_memcmp (&tuc->sig,
    3788           0 :                          use_sig)) &&
    3789             :          (0 ==
    3790           0 :           GNUNET_memcmp (&tuc->unblinded_sig,
    3791             :                          issue_sig)) )
    3792             :     {
    3793           0 :       tuc->found_in_db = true;
    3794           0 :       break;
    3795             :     }
    3796             :   }
    3797           0 : }
    3798             : 
    3799             : 
    3800             : /**
    3801             :  * Small helper function to append an output token signature from db
    3802             :  *
    3803             :  * @param cls closure with `struct PayContext *`
    3804             :  * @param h_issue hash of the token
    3805             :  * @param sig signature of the token
    3806             :  */
    3807             : static void
    3808           0 : append_output_token_sig (void *cls,
    3809             :                          struct GNUNET_HashCode *h_issue,
    3810             :                          struct GNUNET_CRYPTO_BlindedSignature *sig)
    3811             : {
    3812           0 :   struct PayContext *pc = cls;
    3813             :   struct SignedOutputToken out;
    3814             : 
    3815           0 :   out.h_issue.hash = *h_issue;
    3816           0 :   out.sig.signature = sig;
    3817           0 :   GNUNET_array_append (pc->output_tokens,
    3818             :                        pc->output_tokens_len,
    3819             :                        out);
    3820           0 : }
    3821             : 
    3822             : 
    3823             : /**
    3824             :  * Handle case where contract was already paid. Either decides
    3825             :  * the payment is idempotent, or refunds the excess payment.
    3826             :  *
    3827             :  * @param[in,out] pc context we use to handle the payment
    3828             :  */
    3829             : static void
    3830           4 : phase_contract_paid (struct PayContext *pc)
    3831             : {
    3832             :   json_t *refunds;
    3833           4 :   bool unmatched = false;
    3834             : 
    3835             :   {
    3836             :     enum GNUNET_DB_QueryStatus qs;
    3837             : 
    3838           4 :     qs = TMH_db->lookup_deposits_by_order (TMH_db->cls,
    3839             :                                            pc->check_contract.order_serial,
    3840             :                                            &deposit_paid_check,
    3841             :                                            pc);
    3842             :     /* Since orders with choices can have a price of zero,
    3843             :        0 is also a valid query state */
    3844           4 :     if (qs < 0)
    3845             :     {
    3846           0 :       GNUNET_break (0);
    3847           0 :       pay_end (pc,
    3848             :                TALER_MHD_reply_with_error (
    3849             :                  pc->connection,
    3850             :                  MHD_HTTP_INTERNAL_SERVER_ERROR,
    3851             :                  TALER_EC_GENERIC_DB_FETCH_FAILED,
    3852             :                  "lookup_deposits_by_order"));
    3853           2 :       return;
    3854             :     }
    3855             :   }
    3856           4 :   for (size_t i = 0;
    3857           8 :        i<pc->parse_pay.coins_cnt && ! unmatched;
    3858           4 :        i++)
    3859             :   {
    3860           4 :     struct DepositConfirmation *dci = &pc->parse_pay.dc[i];
    3861             : 
    3862           4 :     if (! dci->matched_in_db)
    3863           2 :       unmatched = true;
    3864             :   }
    3865             :   /* Check if provided input tokens match token in the database */
    3866             :   {
    3867             :     enum GNUNET_DB_QueryStatus qs;
    3868             : 
    3869             :     /* FIXME-Optimization: Maybe use h_contract instead of order_serial here? */
    3870           4 :     qs = TMH_db->lookup_spent_tokens_by_order (TMH_db->cls,
    3871             :                                                pc->check_contract.order_serial,
    3872             :                                                &input_tokens_paid_check,
    3873             :                                                pc);
    3874             : 
    3875           4 :     if (qs < 0)
    3876             :     {
    3877           0 :       GNUNET_break (0);
    3878           0 :       pay_end (pc,
    3879             :                TALER_MHD_reply_with_error (
    3880             :                  pc->connection,
    3881             :                  MHD_HTTP_INTERNAL_SERVER_ERROR,
    3882             :                  TALER_EC_GENERIC_DB_FETCH_FAILED,
    3883             :                  "lookup_spent_tokens_by_order"));
    3884           0 :       return;
    3885             :     }
    3886             :   }
    3887           4 :   for (size_t i = 0; i<pc->parse_pay.tokens_cnt && ! unmatched; i++)
    3888             :   {
    3889           0 :     struct TokenUseConfirmation *tuc = &pc->parse_pay.tokens[i];
    3890             : 
    3891           0 :     if (! tuc->found_in_db)
    3892           0 :       unmatched = true;
    3893             :   }
    3894             : 
    3895             :   /* In this part we are fetching token_sigs related output */
    3896           4 :   if (! unmatched)
    3897             :   {
    3898             :     /* Everything fine, idempotent request, generate response immediately */
    3899             :     enum GNUNET_DB_QueryStatus qs;
    3900             : 
    3901           2 :     qs = TMH_db->select_order_blinded_sigs (
    3902           2 :       TMH_db->cls,
    3903             :       pc->order_id,
    3904             :       &append_output_token_sig,
    3905             :       pc);
    3906           2 :     if (0 > qs)
    3907             :     {
    3908           0 :       GNUNET_break (0);
    3909           0 :       pay_end (pc,
    3910             :                TALER_MHD_reply_with_error (
    3911             :                  pc->connection,
    3912             :                  MHD_HTTP_INTERNAL_SERVER_ERROR,
    3913             :                  TALER_EC_GENERIC_DB_FETCH_FAILED,
    3914             :                  "select_order_blinded_sigs"));
    3915           0 :       return;
    3916             :     }
    3917             : 
    3918           2 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    3919             :                 "Idempotent pay request for order `%s', signing again\n",
    3920             :                 pc->order_id);
    3921           2 :     pc->phase = PP_SUCCESS_RESPONSE;
    3922           2 :     return;
    3923             :   }
    3924             :   /* Conflict, double-payment detected! */
    3925             :   /* FIXME-#8674: What should we do with input tokens?
    3926             :      Currently there is no refund for tokens. */
    3927           2 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    3928             :               "Client attempted to pay extra for already paid order `%s'\n",
    3929             :               pc->order_id);
    3930           2 :   refunds = json_array ();
    3931           2 :   GNUNET_assert (NULL != refunds);
    3932           6 :   for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++)
    3933             :   {
    3934           4 :     struct DepositConfirmation *dci = &pc->parse_pay.dc[i];
    3935             :     struct TALER_MerchantSignatureP merchant_sig;
    3936             : 
    3937           4 :     if (dci->matched_in_db)
    3938           0 :       continue;
    3939           4 :     TALER_merchant_refund_sign (&dci->cdd.coin_pub,
    3940           4 :                                 &pc->check_contract.h_contract_terms,
    3941             :                                 0, /* rtransaction id */
    3942           4 :                                 &dci->cdd.amount,
    3943           4 :                                 &pc->hc->instance->merchant_priv,
    3944             :                                 &merchant_sig);
    3945           4 :     GNUNET_assert (
    3946             :       0 ==
    3947             :       json_array_append_new (
    3948             :         refunds,
    3949             :         GNUNET_JSON_PACK (
    3950             :           GNUNET_JSON_pack_data_auto (
    3951             :             "coin_pub",
    3952             :             &dci->cdd.coin_pub),
    3953             :           GNUNET_JSON_pack_data_auto (
    3954             :             "merchant_sig",
    3955             :             &merchant_sig),
    3956             :           TALER_JSON_pack_amount ("amount",
    3957             :                                   &dci->cdd.amount),
    3958             :           GNUNET_JSON_pack_uint64 ("rtransaction_id",
    3959             :                                    0))));
    3960             :   }
    3961           2 :   pay_end (pc,
    3962           2 :            TALER_MHD_REPLY_JSON_PACK (
    3963             :              pc->connection,
    3964             :              MHD_HTTP_CONFLICT,
    3965             :              TALER_MHD_PACK_EC (
    3966             :                TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_ALREADY_PAID),
    3967             :              GNUNET_JSON_pack_array_steal ("refunds",
    3968             :                                            refunds)));
    3969             : }
    3970             : 
    3971             : 
    3972             : /**
    3973             :  * Check the database state for the given order.
    3974             :  * Schedules an error response in the connection on failure.
    3975             :  *
    3976             :  * @param[in,out] pc context we use to handle the payment
    3977             :  */
    3978             : static void
    3979          43 : phase_check_contract (struct PayContext *pc)
    3980             : {
    3981             :   /* obtain contract terms */
    3982             :   enum GNUNET_DB_QueryStatus qs;
    3983          43 :   bool paid = false;
    3984             : 
    3985          43 :   if (NULL != pc->check_contract.contract_terms_json)
    3986             :   {
    3987           0 :     json_decref (pc->check_contract.contract_terms_json);
    3988           0 :     pc->check_contract.contract_terms_json = NULL;
    3989             :   }
    3990          43 :   if (NULL != pc->check_contract.contract_terms)
    3991             :   {
    3992           0 :     TALER_MERCHANT_contract_free (pc->check_contract.contract_terms);
    3993           0 :     pc->check_contract.contract_terms = NULL;
    3994             :   }
    3995          43 :   qs = TMH_db->lookup_contract_terms2 (TMH_db->cls,
    3996          43 :                                        pc->hc->instance->settings.id,
    3997             :                                        pc->order_id,
    3998             :                                        &pc->check_contract.contract_terms_json,
    3999             :                                        &pc->check_contract.order_serial,
    4000             :                                        &paid,
    4001             :                                        NULL,
    4002             :                                        &pc->check_contract.pos_key,
    4003             :                                        &pc->check_contract.pos_alg);
    4004          43 :   if (0 > qs)
    4005             :   {
    4006             :     /* single, read-only SQL statements should never cause
    4007             :        serialization problems */
    4008           0 :     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
    4009             :     /* Always report on hard error to enable diagnostics */
    4010           0 :     GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
    4011           0 :     pay_end (pc,
    4012             :              TALER_MHD_reply_with_error (
    4013             :                pc->connection,
    4014             :                MHD_HTTP_INTERNAL_SERVER_ERROR,
    4015             :                TALER_EC_GENERIC_DB_FETCH_FAILED,
    4016             :                "contract terms"));
    4017           4 :     return;
    4018             :   }
    4019          43 :   if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
    4020             :   {
    4021           0 :     pay_end (pc,
    4022             :              TALER_MHD_reply_with_error (
    4023             :                pc->connection,
    4024             :                MHD_HTTP_NOT_FOUND,
    4025             :                TALER_EC_MERCHANT_GENERIC_ORDER_UNKNOWN,
    4026             :                pc->order_id));
    4027           0 :     return;
    4028             :   }
    4029             :   /* hash contract (needed later) */
    4030             : #if DEBUG
    4031             :   json_dumpf (pc->check_contract.contract_terms_json,
    4032             :               stderr,
    4033             :               JSON_INDENT (2));
    4034             : #endif
    4035          43 :   if (GNUNET_OK !=
    4036          43 :       TALER_JSON_contract_hash (pc->check_contract.contract_terms_json,
    4037             :                                 &pc->check_contract.h_contract_terms))
    4038             :   {
    4039           0 :     GNUNET_break (0);
    4040           0 :     pay_end (pc,
    4041             :              TALER_MHD_reply_with_error (
    4042             :                pc->connection,
    4043             :                MHD_HTTP_INTERNAL_SERVER_ERROR,
    4044             :                TALER_EC_GENERIC_FAILED_COMPUTE_JSON_HASH,
    4045             :                NULL));
    4046           0 :     return;
    4047             :   }
    4048          43 :   if (paid)
    4049             :   {
    4050           4 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    4051             :                 "Order `%s' paid, checking for double-payment\n",
    4052             :                 pc->order_id);
    4053           4 :     pc->phase = PP_CONTRACT_PAID;
    4054           4 :     return;
    4055             :   }
    4056          39 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    4057             :               "Handling payment for order `%s' with contract hash `%s'\n",
    4058             :               pc->order_id,
    4059             :               GNUNET_h2s (&pc->check_contract.h_contract_terms.hash));
    4060             : 
    4061          39 :   pc->check_contract.contract_terms = TALER_MERCHANT_contract_parse (
    4062             :     pc->check_contract.contract_terms_json,
    4063             :     true);
    4064             : 
    4065          39 :   if (NULL == pc->check_contract.contract_terms)
    4066             :   {
    4067             :     /* invalid contract */
    4068           0 :     GNUNET_break (0);
    4069           0 :     pay_end (pc,
    4070             :              TALER_MHD_reply_with_error (
    4071             :                pc->connection,
    4072             :                MHD_HTTP_INTERNAL_SERVER_ERROR,
    4073             :                TALER_EC_MERCHANT_GENERIC_DB_CONTRACT_CONTENT_INVALID,
    4074             :                pc->order_id));
    4075           0 :     return;
    4076             :   }
    4077             : 
    4078             :   /* Get details from contract and check fundamentals */
    4079             :   {
    4080          39 :     switch (pc->check_contract.contract_terms->version)
    4081             :     {
    4082          33 :     case TALER_MERCHANT_CONTRACT_VERSION_0:
    4083             :       {
    4084          33 :         if (pc->parse_wallet_data.choice_index > 0)
    4085             :         {
    4086           0 :           GNUNET_break (0);
    4087           0 :           pay_end (pc,
    4088             :                    TALER_MHD_reply_with_error (
    4089             :                      pc->connection,
    4090             :                      MHD_HTTP_BAD_REQUEST,
    4091             :                      TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_CHOICE_INDEX_OUT_OF_BOUNDS,
    4092             :                      "contract terms v0 has no choices"));
    4093           0 :           return;
    4094             :         }
    4095             :       }
    4096          33 :       break;
    4097           6 :     case TALER_MERCHANT_CONTRACT_VERSION_1:
    4098             :       {
    4099           6 :         if (pc->parse_wallet_data.choice_index < 0)
    4100             :         {
    4101           0 :           GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    4102             :                       "Order `%s' has non-empty choices array but"
    4103             :                       "request is missing 'choice_index' field\n",
    4104             :                       pc->order_id);
    4105           0 :           GNUNET_break (0);
    4106           0 :           pay_end (pc,
    4107             :                    TALER_MHD_reply_with_error (
    4108             :                      pc->connection,
    4109             :                      MHD_HTTP_BAD_REQUEST,
    4110             :                      TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_CHOICE_INDEX_MISSING,
    4111             :                      NULL));
    4112           0 :           return;
    4113             :         }
    4114           6 :         if (pc->parse_wallet_data.choice_index >=
    4115           6 :             pc->check_contract.contract_terms->details.v1.choices_len)
    4116             :         {
    4117           0 :           GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    4118             :                       "Order `%s' has choices array with %u elements but "
    4119             :                       "request has 'choice_index' field with value %d\n",
    4120             :                       pc->order_id,
    4121             :                       pc->check_contract.contract_terms->details.v1.choices_len,
    4122             :                       pc->parse_wallet_data.choice_index);
    4123           0 :           GNUNET_break (0);
    4124           0 :           pay_end (pc,
    4125             :                    TALER_MHD_reply_with_error (
    4126             :                      pc->connection,
    4127             :                      MHD_HTTP_BAD_REQUEST,
    4128             :                      TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_CHOICE_INDEX_OUT_OF_BOUNDS,
    4129             :                      NULL));
    4130           0 :           return;
    4131             :         }
    4132             :       }
    4133           6 :       break;
    4134           0 :     default:
    4135           0 :       GNUNET_break (0);
    4136           0 :       pay_end (pc,
    4137             :                TALER_MHD_reply_with_error (
    4138             :                  pc->connection,
    4139             :                  MHD_HTTP_INTERNAL_SERVER_ERROR,
    4140             :                  TALER_EC_GENERIC_DB_FETCH_FAILED,
    4141             :                  "contract 'version' in database not supported by this backend")
    4142             :                );
    4143           0 :       return;
    4144             :     }
    4145             :   }
    4146             : 
    4147          39 :   if (GNUNET_TIME_timestamp_cmp (pc->check_contract.contract_terms->
    4148             :                                  wire_deadline,
    4149             :                                  <,
    4150             :                                  pc->check_contract.contract_terms->
    4151             :                                  refund_deadline))
    4152             :   {
    4153             :     /* This should already have been checked when creating the order! */
    4154           0 :     GNUNET_break (0);
    4155           0 :     pay_end (pc,
    4156             :              TALER_MHD_reply_with_error (
    4157             :                pc->connection,
    4158             :                MHD_HTTP_INTERNAL_SERVER_ERROR,
    4159             :                TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_REFUND_DEADLINE_PAST_WIRE_TRANSFER_DEADLINE,
    4160             :                NULL));
    4161           0 :     return;
    4162             :   }
    4163          39 :   if (GNUNET_TIME_absolute_is_past (pc->check_contract.contract_terms->
    4164             :                                     pay_deadline.abs_time))
    4165             :   {
    4166             :     /* too late */
    4167           0 :     pay_end (pc,
    4168             :              TALER_MHD_reply_with_error (
    4169             :                pc->connection,
    4170             :                MHD_HTTP_GONE,
    4171             :                TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_OFFER_EXPIRED,
    4172             :                NULL));
    4173           0 :     return;
    4174             :   }
    4175             : 
    4176             : /* Make sure wire method (still) exists for this instance */
    4177             :   {
    4178             :     struct TMH_WireMethod *wm;
    4179             : 
    4180          39 :     wm = pc->hc->instance->wm_head;
    4181          40 :     while (0 != GNUNET_memcmp (&pc->check_contract.contract_terms->h_wire,
    4182             :                                &wm->h_wire))
    4183           1 :       wm = wm->next;
    4184          39 :     if (NULL == wm)
    4185             :     {
    4186           0 :       GNUNET_break (0);
    4187           0 :       pay_end (pc,
    4188             :                TALER_MHD_reply_with_error (
    4189             :                  pc->connection,
    4190             :                  MHD_HTTP_INTERNAL_SERVER_ERROR,
    4191             :                  TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_WIRE_HASH_UNKNOWN,
    4192             :                  NULL));
    4193           0 :       return;
    4194             :     }
    4195          39 :     pc->check_contract.wm = wm;
    4196             :   }
    4197          39 :   pc->phase = PP_VALIDATE_TOKENS;
    4198             : }
    4199             : 
    4200             : 
    4201             : /**
    4202             :  * Try to parse the wallet_data object of the pay request into
    4203             :  * the given context. Schedules an error response in the connection
    4204             :  * on failure.
    4205             :  *
    4206             :  * @param[in,out] pc context we use to handle the payment
    4207             :  */
    4208             : static void
    4209          43 : phase_parse_wallet_data (struct PayContext *pc)
    4210             : {
    4211             :   const json_t *tokens_evs;
    4212             :   const json_t *donau_obj;
    4213             : 
    4214             :   struct GNUNET_JSON_Specification spec[] = {
    4215          43 :     GNUNET_JSON_spec_mark_optional (
    4216             :       GNUNET_JSON_spec_int16 ("choice_index",
    4217             :                               &pc->parse_wallet_data.choice_index),
    4218             :       NULL),
    4219          43 :     GNUNET_JSON_spec_mark_optional (
    4220             :       GNUNET_JSON_spec_array_const ("tokens_evs",
    4221             :                                     &tokens_evs),
    4222             :       NULL),
    4223          43 :     GNUNET_JSON_spec_mark_optional (
    4224             :       GNUNET_JSON_spec_object_const ("donau",
    4225             :                                      &donau_obj),
    4226             :       NULL),
    4227          43 :     GNUNET_JSON_spec_end ()
    4228             :   };
    4229             : 
    4230          43 :   pc->parse_wallet_data.choice_index = -1;
    4231          43 :   if (NULL == pc->parse_pay.wallet_data)
    4232             :   {
    4233          37 :     pc->phase = PP_CHECK_CONTRACT;
    4234          37 :     return;
    4235             :   }
    4236             :   {
    4237             :     enum GNUNET_GenericReturnValue res;
    4238             : 
    4239           6 :     res = TALER_MHD_parse_json_data (pc->connection,
    4240             :                                      pc->parse_pay.wallet_data,
    4241             :                                      spec);
    4242           6 :     if (GNUNET_YES != res)
    4243             :     {
    4244           0 :       GNUNET_break_op (0);
    4245           0 :       pay_end (pc,
    4246             :                (GNUNET_NO == res)
    4247             :              ? MHD_YES
    4248             :              : MHD_NO);
    4249           0 :       return;
    4250             :     }
    4251             :   }
    4252             : 
    4253             :   pc->parse_wallet_data.token_envelopes_cnt
    4254           6 :     = json_array_size (tokens_evs);
    4255           6 :   if (pc->parse_wallet_data.token_envelopes_cnt >
    4256             :       MAX_TOKEN_ALLOWED_OUTPUTs)
    4257             :   {
    4258           0 :     GNUNET_break_op (0);
    4259           0 :     pay_end (pc,
    4260             :              TALER_MHD_reply_with_error (
    4261             :                pc->connection,
    4262             :                MHD_HTTP_BAD_REQUEST,
    4263             :                TALER_EC_GENERIC_PARAMETER_MALFORMED,
    4264             :                "'tokens_evs' array too long"));
    4265           0 :     return;
    4266             :   }
    4267             :   pc->parse_wallet_data.token_envelopes
    4268           6 :     = GNUNET_new_array (pc->parse_wallet_data.token_envelopes_cnt,
    4269             :                         struct TokenEnvelope);
    4270             : 
    4271             :   {
    4272             :     unsigned int tokens_ev_index;
    4273             :     json_t *token_ev;
    4274             : 
    4275          12 :     json_array_foreach (tokens_evs,
    4276             :                         tokens_ev_index,
    4277             :                         token_ev)
    4278             :     {
    4279           6 :       struct TokenEnvelope *ev
    4280           6 :         = &pc->parse_wallet_data.token_envelopes[tokens_ev_index];
    4281             :       struct GNUNET_JSON_Specification ispec[] = {
    4282           6 :         TALER_JSON_spec_token_envelope (NULL,
    4283             :                                         &ev->blinded_token),
    4284           6 :         GNUNET_JSON_spec_end ()
    4285             :       };
    4286             :       enum GNUNET_GenericReturnValue res;
    4287             : 
    4288           6 :       if (json_is_null (token_ev))
    4289           0 :         continue;
    4290           6 :       res = TALER_MHD_parse_json_data (pc->connection,
    4291             :                                        token_ev,
    4292             :                                        ispec);
    4293           6 :       if (GNUNET_YES != res)
    4294             :       {
    4295           0 :         GNUNET_break_op (0);
    4296           0 :         pay_end (pc,
    4297             :                  (GNUNET_NO == res)
    4298             :                  ? MHD_YES
    4299             :                  : MHD_NO);
    4300           0 :         return;
    4301             :       }
    4302             : 
    4303           6 :       for (unsigned int j = 0; j<tokens_ev_index; j++)
    4304             :       {
    4305           0 :         if (0 ==
    4306           0 :             GNUNET_memcmp (ev->blinded_token.blinded_pub,
    4307             :                            pc->parse_wallet_data.token_envelopes[j].
    4308             :                            blinded_token.blinded_pub))
    4309             :         {
    4310           0 :           GNUNET_break_op (0);
    4311           0 :           pay_end (pc,
    4312             :                    TALER_MHD_reply_with_error (
    4313             :                      pc->connection,
    4314             :                      MHD_HTTP_BAD_REQUEST,
    4315             :                      TALER_EC_GENERIC_PARAMETER_MALFORMED,
    4316             :                      "duplicate token envelope in list"));
    4317           0 :           return;
    4318             :         }
    4319             :       }
    4320             :     }
    4321             :   }
    4322             : 
    4323             : #ifdef HAVE_DONAU_DONAU_SERVICE_H
    4324             :   if (NULL != donau_obj)
    4325             :   {
    4326             :     const char *donau_url_tmp;
    4327             :     const json_t *budikeypairs;
    4328             :     json_t *donau_keys_json;
    4329             : 
    4330             :     /* Fetching and checking that all 3 are present in some way */
    4331             :     struct GNUNET_JSON_Specification dspec[] = {
    4332             :       GNUNET_JSON_spec_string      ("url",
    4333             :                                     &donau_url_tmp),
    4334             :       GNUNET_JSON_spec_uint64      ("year",
    4335             :                                     &pc->parse_wallet_data.donau.donation_year),
    4336             :       GNUNET_JSON_spec_array_const ("budikeypairs",
    4337             :                                     &budikeypairs),
    4338             :       GNUNET_JSON_spec_end ()
    4339             :     };
    4340             :     enum GNUNET_GenericReturnValue res;
    4341             : 
    4342             :     res = TALER_MHD_parse_json_data (pc->connection,
    4343             :                                      donau_obj,
    4344             :                                      dspec);
    4345             :     if (GNUNET_YES != res)
    4346             :     {
    4347             :       GNUNET_break_op (0);
    4348             :       pay_end (pc,
    4349             :                (GNUNET_NO == res)
    4350             :                ? MHD_YES
    4351             :                : MHD_NO);
    4352             :       return;
    4353             :     }
    4354             : 
    4355             :     if (0 == json_array_size (budikeypairs))
    4356             :     {
    4357             :       GNUNET_break_op (0);
    4358             :       resume_pay_with_error (pc,
    4359             :                              TALER_EC_GENERIC_PARAMETER_MALFORMED,
    4360             :                              "Empty 'budikeypairs' array");
    4361             :       return;
    4362             :     }
    4363             : 
    4364             :     /* Check if the needed data is present for the given donau URL */
    4365             :     {
    4366             :       enum GNUNET_DB_QueryStatus qs;
    4367             :       qs = TMH_db->lookup_order_charity (
    4368             :         TMH_db->cls,
    4369             :         pc->hc->instance->settings.id,
    4370             :         donau_url_tmp,
    4371             :         &pc->parse_wallet_data.charity_id,
    4372             :         &pc->parse_wallet_data.charity_priv,
    4373             :         &pc->parse_wallet_data.charity_max_per_year,
    4374             :         &pc->parse_wallet_data.charity_receipts_to_date,
    4375             :         &donau_keys_json,
    4376             :         &pc->parse_wallet_data.donau_instance_serial);
    4377             : 
    4378             :       switch (qs)
    4379             :       {
    4380             :       case GNUNET_DB_STATUS_HARD_ERROR:
    4381             :       case GNUNET_DB_STATUS_SOFT_ERROR:
    4382             :         TMH_db->rollback (TMH_db->cls);
    4383             :         pay_end (pc,
    4384             :                  TALER_MHD_reply_with_error (
    4385             :                    pc->connection,
    4386             :                    MHD_HTTP_INTERNAL_SERVER_ERROR,
    4387             :                    TALER_EC_GENERIC_DB_FETCH_FAILED,
    4388             :                    "lookup_order_charity"));
    4389             :         return;
    4390             :       case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
    4391             :         TMH_db->rollback (TMH_db->cls);
    4392             :         pay_end (pc,
    4393             :                  TALER_MHD_reply_with_error (
    4394             :                    pc->connection,
    4395             :                    MHD_HTTP_NOT_FOUND,
    4396             :                    TALER_EC_GENERIC_PARAMETER_MALFORMED,
    4397             :                    "No matching Donau charity found for the given URL"));
    4398             :         return;
    4399             :       case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
    4400             :         pc->parse_wallet_data.donau.donau_url =
    4401             :           GNUNET_strdup (donau_url_tmp);
    4402             :         break;
    4403             :       }
    4404             :     }
    4405             : 
    4406             :     {
    4407             :       pc->parse_wallet_data.donau_keys =
    4408             :         DONAU_keys_from_json (donau_keys_json);
    4409             :       json_decref (donau_keys_json);
    4410             :       if (! pc->parse_wallet_data.donau_keys)
    4411             :       {
    4412             :         GNUNET_break_op (0);
    4413             :         resume_pay_with_error (pc,
    4414             :                                TALER_EC_GENERIC_PARAMETER_MALFORMED,
    4415             :                                "Invalid donau_keys");
    4416             :         return;
    4417             :       }
    4418             :     }
    4419             : 
    4420             :     /* Stage to parse the budikeypairs from json to struct */
    4421             :     {
    4422             :       size_t num_bkps = json_array_size (budikeypairs);
    4423             :       struct DONAU_BlindedUniqueDonorIdentifierKeyPair *bkps =
    4424             :         GNUNET_new_array (num_bkps,
    4425             :                           struct DONAU_BlindedUniqueDonorIdentifierKeyPair);
    4426             : 
    4427             :       /* Change to json for each*/
    4428             :       for (size_t i = 0; i < num_bkps; i++)
    4429             :       {
    4430             :         const json_t *bkp_obj = json_array_get (budikeypairs,
    4431             :                                                 i);
    4432             :         if (GNUNET_SYSERR == merchant_parse_json_bkp (&bkps[i],
    4433             :                                                       bkp_obj))
    4434             :         {
    4435             :           GNUNET_break_op (0);
    4436             :           GNUNET_free (bkps);
    4437             :           resume_pay_with_error (pc,
    4438             :                                  TALER_EC_GENERIC_PARAMETER_MALFORMED,
    4439             :                                  "Failed to parse budikeypairs");
    4440             :           return;
    4441             :         }
    4442             :       }
    4443             : 
    4444             :       pc->parse_wallet_data.num_bkps = num_bkps;
    4445             :       pc->parse_wallet_data.bkps = bkps;
    4446             :     }
    4447             :   }
    4448             : #else
    4449             :   /* Donau not compiled in: reject request if a donau object was given. */
    4450           6 :   if (NULL != donau_obj)
    4451             :   {
    4452           0 :     pay_end (pc,
    4453             :              TALER_MHD_reply_with_error (pc->connection,
    4454             :                                          MHD_HTTP_NOT_IMPLEMENTED,
    4455             :                                          TALER_EC_MERCHANT_GENERIC_DONAU_NOT_CONFIGURED,
    4456             :                                          "donau support disabled"));
    4457           0 :     return;
    4458             :   }
    4459             : #endif /* HAVE_DONAU_DONAU_SERVICE_H */
    4460             : 
    4461           6 :   TALER_json_hash (pc->parse_pay.wallet_data,
    4462             :                    &pc->parse_wallet_data.h_wallet_data);
    4463             : 
    4464           6 :   pc->phase = PP_CHECK_CONTRACT;
    4465             : }
    4466             : 
    4467             : 
    4468             : /**
    4469             :  * Try to parse the pay request into the given pay context.
    4470             :  * Schedules an error response in the connection on failure.
    4471             :  *
    4472             :  * @param[in,out] pc context we use to handle the payment
    4473             :  */
    4474             : static void
    4475          43 : phase_parse_pay (struct PayContext *pc)
    4476             : {
    4477          43 :   const char *session_id = NULL;
    4478             :   const json_t *coins;
    4479             :   const json_t *tokens;
    4480             :   struct GNUNET_JSON_Specification spec[] = {
    4481          43 :     GNUNET_JSON_spec_array_const ("coins",
    4482             :                                   &coins),
    4483          43 :     GNUNET_JSON_spec_mark_optional (
    4484             :       GNUNET_JSON_spec_string ("session_id",
    4485             :                                &session_id),
    4486             :       NULL),
    4487          43 :     GNUNET_JSON_spec_mark_optional (
    4488             :       GNUNET_JSON_spec_object_const ("wallet_data",
    4489             :                                      &pc->parse_pay.wallet_data),
    4490             :       NULL),
    4491          43 :     GNUNET_JSON_spec_mark_optional (
    4492             :       GNUNET_JSON_spec_array_const ("tokens",
    4493             :                                     &tokens),
    4494             :       NULL),
    4495          43 :     GNUNET_JSON_spec_end ()
    4496             :   };
    4497             : 
    4498             : #if DEBUG
    4499             :   {
    4500             :     char *dump = json_dumps (pc->hc->request_body,
    4501             :                              JSON_INDENT (2)
    4502             :                              | JSON_ENCODE_ANY
    4503             :                              | JSON_SORT_KEYS);
    4504             : 
    4505             :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    4506             :                 "POST /orders/%s/pay – request body follows:\n%s\n",
    4507             :                 pc->order_id,
    4508             :                 dump);
    4509             : 
    4510             :     free (dump);
    4511             : 
    4512             :   }
    4513             : #endif /* DEBUG */
    4514             : 
    4515          43 :   GNUNET_assert (PP_PARSE_PAY == pc->phase);
    4516             :   {
    4517             :     enum GNUNET_GenericReturnValue res;
    4518             : 
    4519          43 :     res = TALER_MHD_parse_json_data (pc->connection,
    4520          43 :                                      pc->hc->request_body,
    4521             :                                      spec);
    4522          43 :     if (GNUNET_YES != res)
    4523             :     {
    4524           0 :       GNUNET_break_op (0);
    4525           0 :       pay_end (pc,
    4526             :                (GNUNET_NO == res)
    4527             :                ? MHD_YES
    4528             :                : MHD_NO);
    4529           0 :       return;
    4530             :     }
    4531             :   }
    4532             : 
    4533             :   /* copy session ID (if set) */
    4534          43 :   if (NULL != session_id)
    4535             :   {
    4536          17 :     pc->parse_pay.session_id = GNUNET_strdup (session_id);
    4537             :   }
    4538             :   else
    4539             :   {
    4540             :     /* use empty string as default if client didn't specify it */
    4541          26 :     pc->parse_pay.session_id = GNUNET_strdup ("");
    4542             :   }
    4543             : 
    4544          43 :   pc->parse_pay.coins_cnt = json_array_size (coins);
    4545          43 :   if (pc->parse_pay.coins_cnt > MAX_COIN_ALLOWED_COINS)
    4546             :   {
    4547           0 :     GNUNET_break_op (0);
    4548           0 :     pay_end (pc,
    4549             :              TALER_MHD_reply_with_error (
    4550             :                pc->connection,
    4551             :                MHD_HTTP_BAD_REQUEST,
    4552             :                TALER_EC_GENERIC_PARAMETER_MALFORMED,
    4553             :                "'coins' array too long"));
    4554           0 :     return;
    4555             :   }
    4556             :   /* note: 1 coin = 1 deposit confirmation expected */
    4557          43 :   pc->parse_pay.dc = GNUNET_new_array (pc->parse_pay.coins_cnt,
    4558             :                                        struct DepositConfirmation);
    4559             : 
    4560             :   /* This loop populates the array 'dc' in 'pc' */
    4561             :   {
    4562             :     unsigned int coins_index;
    4563             :     json_t *coin;
    4564             : 
    4565          92 :     json_array_foreach (coins, coins_index, coin)
    4566             :     {
    4567          49 :       struct DepositConfirmation *dc = &pc->parse_pay.dc[coins_index];
    4568             :       const char *exchange_url;
    4569             :       struct GNUNET_JSON_Specification ispec[] = {
    4570          49 :         GNUNET_JSON_spec_fixed_auto ("coin_sig",
    4571             :                                      &dc->cdd.coin_sig),
    4572          49 :         GNUNET_JSON_spec_fixed_auto ("coin_pub",
    4573             :                                      &dc->cdd.coin_pub),
    4574          49 :         TALER_JSON_spec_denom_sig ("ub_sig",
    4575             :                                    &dc->cdd.denom_sig),
    4576          49 :         GNUNET_JSON_spec_fixed_auto ("h_denom",
    4577             :                                      &dc->cdd.h_denom_pub),
    4578          49 :         TALER_JSON_spec_amount_any ("contribution",
    4579             :                                     &dc->cdd.amount),
    4580          49 :         TALER_JSON_spec_web_url ("exchange_url",
    4581             :                                  &exchange_url),
    4582             :         /* if a minimum age was required, the minimum_age_sig and
    4583             :          * age_commitment must be provided */
    4584          49 :         GNUNET_JSON_spec_mark_optional (
    4585          49 :           GNUNET_JSON_spec_fixed_auto ("minimum_age_sig",
    4586             :                                        &dc->minimum_age_sig),
    4587             :           &dc->no_minimum_age_sig),
    4588          49 :         GNUNET_JSON_spec_mark_optional (
    4589             :           TALER_JSON_spec_age_commitment ("age_commitment",
    4590             :                                           &dc->age_commitment),
    4591             :           &dc->no_age_commitment),
    4592             :         /* if minimum age was not required, but coin with age restriction set
    4593             :          * was used, h_age_commitment must be provided. */
    4594          49 :         GNUNET_JSON_spec_mark_optional (
    4595          49 :           GNUNET_JSON_spec_fixed_auto ("h_age_commitment",
    4596             :                                        &dc->cdd.h_age_commitment),
    4597             :           &dc->no_h_age_commitment),
    4598          49 :         GNUNET_JSON_spec_end ()
    4599             :       };
    4600             :       enum GNUNET_GenericReturnValue res;
    4601          49 :       struct ExchangeGroup *eg = NULL;
    4602             : 
    4603          49 :       res = TALER_MHD_parse_json_data (pc->connection,
    4604             :                                        coin,
    4605             :                                        ispec);
    4606          49 :       if (GNUNET_YES != res)
    4607             :       {
    4608           0 :         GNUNET_break_op (0);
    4609           0 :         pay_end (pc,
    4610             :                  (GNUNET_NO == res)
    4611             :                  ? MHD_YES
    4612             :                  : MHD_NO);
    4613           0 :         return;
    4614             :       }
    4615          59 :       for (unsigned int j = 0; j<coins_index; j++)
    4616             :       {
    4617          10 :         if (0 ==
    4618          10 :             GNUNET_memcmp (&dc->cdd.coin_pub,
    4619             :                            &pc->parse_pay.dc[j].cdd.coin_pub))
    4620             :         {
    4621           0 :           GNUNET_break_op (0);
    4622           0 :           pay_end (pc,
    4623             :                    TALER_MHD_reply_with_error (pc->connection,
    4624             :                                                MHD_HTTP_BAD_REQUEST,
    4625             :                                                TALER_EC_GENERIC_PARAMETER_MALFORMED,
    4626             :                                                "duplicate coin in list"));
    4627           0 :           return;
    4628             :         }
    4629             :       }
    4630             : 
    4631          49 :       dc->exchange_url = GNUNET_strdup (exchange_url);
    4632          49 :       dc->index = coins_index;
    4633          49 :       dc->pc = pc;
    4634             : 
    4635             :       /* Check the consistency of the (potential) age restriction
    4636             :        * information. */
    4637          49 :       if (dc->no_age_commitment != dc->no_minimum_age_sig)
    4638             :       {
    4639           0 :         GNUNET_break_op (0);
    4640           0 :         pay_end (pc,
    4641             :                  TALER_MHD_reply_with_error (
    4642             :                    pc->connection,
    4643             :                    MHD_HTTP_BAD_REQUEST,
    4644             :                    TALER_EC_GENERIC_PARAMETER_MALFORMED,
    4645             :                    "inconsistent: 'age_commitment' vs. 'minimum_age_sig'"
    4646             :                    ));
    4647           0 :         return;
    4648             :       }
    4649             : 
    4650             :       /* Setup exchange group */
    4651          49 :       for (unsigned int i = 0; i<pc->parse_pay.num_exchanges; i++)
    4652             :       {
    4653          10 :         if (0 ==
    4654          10 :             strcmp (pc->parse_pay.egs[i]->exchange_url,
    4655             :                     exchange_url))
    4656             :         {
    4657          10 :           eg = pc->parse_pay.egs[i];
    4658          10 :           break;
    4659             :         }
    4660             :       }
    4661          49 :       if (NULL == eg)
    4662             :       {
    4663          39 :         eg = GNUNET_new (struct ExchangeGroup);
    4664          39 :         eg->pc = pc;
    4665          39 :         eg->exchange_url = dc->exchange_url;
    4666          39 :         eg->total = dc->cdd.amount;
    4667          39 :         GNUNET_array_append (pc->parse_pay.egs,
    4668             :                              pc->parse_pay.num_exchanges,
    4669             :                              eg);
    4670             :       }
    4671             :       else
    4672             :       {
    4673          10 :         if (0 >
    4674          10 :             TALER_amount_add (&eg->total,
    4675          10 :                               &eg->total,
    4676          10 :                               &dc->cdd.amount))
    4677             :         {
    4678           0 :           GNUNET_break_op (0);
    4679           0 :           pay_end (pc,
    4680             :                    TALER_MHD_reply_with_error (
    4681             :                      pc->connection,
    4682             :                      MHD_HTTP_INTERNAL_SERVER_ERROR,
    4683             :                      TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AMOUNT_OVERFLOW,
    4684             :                      "Overflow adding up amounts"));
    4685           0 :           return;
    4686             :         }
    4687             :       }
    4688             :     }
    4689             :   }
    4690             : 
    4691          43 :   pc->parse_pay.tokens_cnt = json_array_size (tokens);
    4692          43 :   if (pc->parse_pay.tokens_cnt > MAX_TOKEN_ALLOWED_INPUTs)
    4693             :   {
    4694           0 :     GNUNET_break_op (0);
    4695           0 :     pay_end (pc,
    4696             :              TALER_MHD_reply_with_error (
    4697             :                pc->connection,
    4698             :                MHD_HTTP_BAD_REQUEST,
    4699             :                TALER_EC_GENERIC_PARAMETER_MALFORMED,
    4700             :                "'tokens' array too long"));
    4701           0 :     return;
    4702             :   }
    4703             : 
    4704          43 :   pc->parse_pay.tokens = GNUNET_new_array (pc->parse_pay.tokens_cnt,
    4705             :                                            struct TokenUseConfirmation);
    4706             : 
    4707             :   /* This look populates the array 'tokens' in 'pc' */
    4708             :   {
    4709             :     unsigned int tokens_index;
    4710             :     json_t *token;
    4711             : 
    4712          47 :     json_array_foreach (tokens, tokens_index, token)
    4713             :     {
    4714           4 :       struct TokenUseConfirmation *tuc = &pc->parse_pay.tokens[tokens_index];
    4715             :       struct GNUNET_JSON_Specification ispec[] = {
    4716           4 :         GNUNET_JSON_spec_fixed_auto ("token_sig",
    4717             :                                      &tuc->sig),
    4718           4 :         GNUNET_JSON_spec_fixed_auto ("token_pub",
    4719             :                                      &tuc->pub),
    4720           4 :         GNUNET_JSON_spec_fixed_auto ("h_issue",
    4721             :                                      &tuc->h_issue),
    4722           4 :         TALER_JSON_spec_token_issue_sig ("ub_sig",
    4723             :                                          &tuc->unblinded_sig),
    4724           4 :         GNUNET_JSON_spec_end ()
    4725             :       };
    4726             :       enum GNUNET_GenericReturnValue res;
    4727             : 
    4728           4 :       res = TALER_MHD_parse_json_data (pc->connection,
    4729             :                                        token,
    4730             :                                        ispec);
    4731           4 :       if (GNUNET_YES != res)
    4732             :       {
    4733           0 :         GNUNET_break_op (0);
    4734           0 :         pay_end (pc,
    4735             :                  (GNUNET_NO == res)
    4736             :                  ? MHD_YES
    4737             :                  : MHD_NO);
    4738           0 :         return;
    4739             :       }
    4740             : 
    4741           4 :       for (unsigned int j = 0; j<tokens_index; j++)
    4742             :       {
    4743           0 :         if (0 ==
    4744           0 :             GNUNET_memcmp (&tuc->pub,
    4745             :                            &pc->parse_pay.tokens[j].pub))
    4746             :         {
    4747           0 :           GNUNET_break_op (0);
    4748           0 :           pay_end (pc,
    4749             :                    TALER_MHD_reply_with_error (pc->connection,
    4750             :                                                MHD_HTTP_BAD_REQUEST,
    4751             :                                                TALER_EC_GENERIC_PARAMETER_MALFORMED,
    4752             :                                                "duplicate token in list"));
    4753           0 :           return;
    4754             :         }
    4755             :       }
    4756             :     }
    4757             :   }
    4758             : 
    4759          43 :   pc->phase = PP_PARSE_WALLET_DATA;
    4760             : }
    4761             : 
    4762             : 
    4763             : /**
    4764             :  * Custom cleanup routine for a `struct PayContext`.
    4765             :  *
    4766             :  * @param cls the `struct PayContext` to clean up.
    4767             :  */
    4768             : static void
    4769          43 : pay_context_cleanup (void *cls)
    4770             : {
    4771          43 :   struct PayContext *pc = cls;
    4772             : 
    4773          43 :   if (NULL != pc->batch_deposits.timeout_task)
    4774             :   {
    4775          29 :     GNUNET_SCHEDULER_cancel (pc->batch_deposits.timeout_task);
    4776          29 :     pc->batch_deposits.timeout_task = NULL;
    4777             :   }
    4778          43 :   if (NULL != pc->check_contract.contract_terms_json)
    4779             :   {
    4780          43 :     json_decref (pc->check_contract.contract_terms_json);
    4781          43 :     pc->check_contract.contract_terms_json = NULL;
    4782             :   }
    4783          92 :   for (unsigned int i = 0; i<pc->parse_pay.coins_cnt; i++)
    4784             :   {
    4785          49 :     struct DepositConfirmation *dc = &pc->parse_pay.dc[i];
    4786             : 
    4787          49 :     TALER_denom_sig_free (&dc->cdd.denom_sig);
    4788          49 :     GNUNET_free (dc->exchange_url);
    4789             :   }
    4790          43 :   GNUNET_free (pc->parse_pay.dc);
    4791          47 :   for (unsigned int i = 0; i<pc->parse_pay.tokens_cnt; i++)
    4792             :   {
    4793           4 :     struct TokenUseConfirmation *tuc = &pc->parse_pay.tokens[i];
    4794             : 
    4795           4 :     TALER_token_issue_sig_free (&tuc->unblinded_sig);
    4796             :   }
    4797          43 :   GNUNET_free (pc->parse_pay.tokens);
    4798          82 :   for (unsigned int i = 0; i<pc->parse_pay.num_exchanges; i++)
    4799             :   {
    4800          39 :     struct ExchangeGroup *eg = pc->parse_pay.egs[i];
    4801             : 
    4802          39 :     if (NULL != eg->fo)
    4803           0 :       TMH_EXCHANGES_keys4exchange_cancel (eg->fo);
    4804          39 :     GNUNET_free (eg);
    4805             :   }
    4806          43 :   GNUNET_free (pc->parse_pay.egs);
    4807          43 :   if (NULL != pc->check_contract.contract_terms)
    4808             :   {
    4809          39 :     TALER_MERCHANT_contract_free (pc->check_contract.contract_terms);
    4810          39 :     pc->check_contract.contract_terms = NULL;
    4811             :   }
    4812          43 :   if (NULL != pc->response)
    4813             :   {
    4814           6 :     MHD_destroy_response (pc->response);
    4815           6 :     pc->response = NULL;
    4816             :   }
    4817          43 :   GNUNET_free (pc->parse_pay.session_id);
    4818          43 :   GNUNET_CONTAINER_DLL_remove (pc_head,
    4819             :                                pc_tail,
    4820             :                                pc);
    4821          43 :   GNUNET_free (pc->check_contract.pos_key);
    4822             : #ifdef HAVE_DONAU_DONAU_SERVICE_H
    4823             :   if (NULL != pc->parse_wallet_data.bkps)
    4824             :   {
    4825             :     GNUNET_free (pc->parse_wallet_data.bkps);
    4826             :     pc->parse_wallet_data.bkps = NULL;
    4827             :     pc->parse_wallet_data.num_bkps = 0;
    4828             :   }
    4829             :   if (NULL != pc->parse_wallet_data.donau_keys)
    4830             :   {
    4831             :     DONAU_keys_decref (pc->parse_wallet_data.donau_keys);
    4832             :     pc->parse_wallet_data.donau_keys = NULL;
    4833             :   }
    4834             : #endif
    4835          43 :   GNUNET_free (pc);
    4836          43 : }
    4837             : 
    4838             : 
    4839             : MHD_RESULT
    4840          78 : TMH_post_orders_ID_pay (const struct TMH_RequestHandler *rh,
    4841             :                         struct MHD_Connection *connection,
    4842             :                         struct TMH_HandlerContext *hc)
    4843             : {
    4844          78 :   struct PayContext *pc = hc->ctx;
    4845             : 
    4846          78 :   GNUNET_assert (NULL != hc->infix);
    4847          78 :   if (NULL == pc)
    4848             :   {
    4849          43 :     pc = GNUNET_new (struct PayContext);
    4850          43 :     pc->connection = connection;
    4851          43 :     pc->hc = hc;
    4852          43 :     pc->order_id = hc->infix;
    4853          43 :     hc->ctx = pc;
    4854          43 :     hc->cc = &pay_context_cleanup;
    4855          43 :     GNUNET_CONTAINER_DLL_insert (pc_head,
    4856             :                                  pc_tail,
    4857             :                                  pc);
    4858             :   }
    4859             :   while (1)
    4860             :   {
    4861         748 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    4862             :                 "Processing /pay in phase %d\n",
    4863             :                 (int) pc->phase);
    4864         413 :     switch (pc->phase)
    4865             :     {
    4866          43 :     case PP_PARSE_PAY:
    4867          43 :       phase_parse_pay (pc);
    4868          43 :       break;
    4869          43 :     case PP_PARSE_WALLET_DATA:
    4870          43 :       phase_parse_wallet_data (pc);
    4871          43 :       break;
    4872          43 :     case PP_CHECK_CONTRACT:
    4873          43 :       phase_check_contract (pc);
    4874          43 :       break;
    4875          39 :     case PP_VALIDATE_TOKENS:
    4876          39 :       phase_validate_tokens (pc);
    4877          39 :       break;
    4878           4 :     case PP_CONTRACT_PAID:
    4879           4 :       phase_contract_paid (pc);
    4880           4 :       break;
    4881          68 :     case PP_PAY_TRANSACTION:
    4882          68 :       phase_execute_pay_transaction (pc);
    4883          68 :       break;
    4884             : #ifdef HAVE_DONAU_DONAU_SERVICE_H
    4885             :     case PP_REQUEST_DONATION_RECEIPT:
    4886             :       phase_request_donation_receipt (pc);
    4887             :       break;
    4888             : #endif
    4889          29 :     case PP_FINAL_OUTPUT_TOKEN_PROCESSING:
    4890          29 :       phase_final_output_token_processing (pc);
    4891          29 :       break;
    4892          29 :     case PP_PAYMENT_NOTIFICATION:
    4893          29 :       phase_payment_notification (pc);
    4894          29 :       break;
    4895          31 :     case PP_SUCCESS_RESPONSE:
    4896          31 :       phase_success_response (pc);
    4897          31 :       break;
    4898          35 :     case PP_BATCH_DEPOSITS:
    4899          35 :       phase_batch_deposits (pc);
    4900          35 :       break;
    4901           6 :     case PP_RETURN_RESPONSE:
    4902           6 :       phase_return_response (pc);
    4903           6 :       break;
    4904           0 :     case PP_FAIL_LEGAL_REASONS:
    4905           0 :       phase_fail_for_legal_reasons (pc);
    4906           0 :       break;
    4907          43 :     case PP_END_YES:
    4908          43 :       return MHD_YES;
    4909           0 :     case PP_END_NO:
    4910           0 :       return MHD_NO;
    4911             :     }
    4912         370 :     switch (pc->suspended)
    4913             :     {
    4914           0 :     case GNUNET_SYSERR:
    4915             :       /* during shutdown, we don't generate any more replies */
    4916           0 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    4917             :                   "Processing /pay ends due to shutdown in phase %d\n",
    4918             :                   (int) pc->phase);
    4919           0 :       return MHD_NO;
    4920         335 :     case GNUNET_NO:
    4921             :       /* continue to next phase */
    4922         335 :       break;
    4923          35 :     case GNUNET_YES:
    4924          35 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    4925             :                   "Processing /pay suspended in phase %d\n",
    4926             :                   (int) pc->phase);
    4927          35 :       return MHD_YES;
    4928             :     }
    4929             :   }
    4930             :   /* impossible to get here */
    4931             :   GNUNET_assert (0);
    4932             :   return MHD_YES;
    4933             : }
    4934             : 
    4935             : 
    4936             : /* end of taler-merchant-httpd_post-orders-ID-pay.c */

Generated by: LCOV version 1.16