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

Generated by: LCOV version 2.0-1