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: 58.9 % 1524 898
Test Date: 2025-12-31 20:31:13 Functions: 78.6 % 42 33

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

Generated by: LCOV version 2.0-1