LCOV - code coverage report
Current view: top level - backend - taler-merchant-httpd_post-orders-ORDER_ID-pay.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 61.0 % 1869 1141
Test Date: 2026-09-11 17:45:24 Functions: 83.7 % 49 41

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

Generated by: LCOV version 2.0-1