LCOV - code coverage report
Current view: top level - backend - taler-merchant-httpd_post-orders-ID-pay.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 59.9 % 1455 871
Test Date: 2025-11-28 21:09:21 Functions: 80.0 % 40 32

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

Generated by: LCOV version 2.0-1