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.1 % 1852 1131
Test Date: 2026-09-04 23:42:01 Functions: 83.3 % 48 40

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

Generated by: LCOV version 2.0-1