merchant

Merchant backend to process payments, run by merchants
Log | Files | Refs | Submodules | README | LICENSE

taler-merchant-httpd_post-private-orders.c (146036B)


      1 /*
      2   This file is part of TALER
      3   (C) 2014-2025 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify
      6   it under the terms of the GNU Affero General Public License as
      7   published by the Free Software Foundation; either version 3,
      8   or (at your option) any later version.
      9 
     10   TALER is distributed in the hope that it will be useful, but
     11   WITHOUT ANY WARRANTY; without even the implied warranty of
     12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13   GNU General Public License for more details.
     14 
     15   You should have received a copy of the GNU General Public
     16   License along with TALER; see the file COPYING.  If not,
     17   see <http://www.gnu.org/licenses/>
     18 */
     19 
     20 /**
     21  * @file taler-merchant-httpd_post-private-orders.c
     22  * @brief the POST /orders handler
     23  * @author Christian Grothoff
     24  * @author Marcello Stanisci
     25  * @author Christian Blättler
     26  */
     27 #include "taler/platform.h"
     28 #include <gnunet/gnunet_common.h>
     29 #include <gnunet/gnunet_db_lib.h>
     30 #include <gnunet/gnunet_json_lib.h>
     31 #include <gnunet/gnunet_time_lib.h>
     32 #include <jansson.h>
     33 #include <microhttpd.h>
     34 #include <string.h>
     35 #include <taler/taler_error_codes.h>
     36 #include <taler/taler_signatures.h>
     37 #include <taler/taler_json_lib.h>
     38 #include <taler/taler_dbevents.h>
     39 #include <taler/taler_util.h>
     40 #include <taler/taler_merchant_util.h>
     41 #include <time.h>
     42 #include "taler-merchant-httpd.h"
     43 #include "taler-merchant-httpd_exchanges.h"
     44 #include "taler-merchant-httpd_post-private-orders.h"
     45 #include "taler-merchant-httpd_get-exchanges.h"
     46 #include "taler-merchant-httpd_contract.h"
     47 #include "taler-merchant-httpd_helper.h"
     48 #include "taler-merchant-httpd_get-private-orders.h"
     49 
     50 #include "taler/taler_merchantdb_plugin.h"
     51 
     52 
     53 /**
     54  * How often do we retry the simple INSERT database transaction?
     55  */
     56 #define MAX_RETRIES 3
     57 
     58 /**
     59  * Maximum number of inventory products per order.
     60  */
     61 #define MAX_PRODUCTS 1024
     62 
     63 /**
     64  * What is the label under which we find/place the merchant's
     65  * jurisdiction in the locations list by default?
     66  */
     67 #define STANDARD_LABEL_MERCHANT_JURISDICTION "_mj"
     68 
     69 /**
     70  * What is the label under which we find/place the merchant's
     71  * address in the locations list by default?
     72  */
     73 #define STANDARD_LABEL_MERCHANT_ADDRESS "_ma"
     74 
     75 /**
     76  * How long do we wait at most for /keys from the exchange(s)?
     77  * Ensures that we do not block forever just because some exchange
     78  * fails to respond *or* because our taler-merchant-keyscheck
     79  * refuses a forced download.
     80  */
     81 #define MAX_KEYS_WAIT \
     82         GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 2500)
     83 
     84 /**
     85  * Generate the base URL for the given merchant instance.
     86  *
     87  * @param connection the MHD connection
     88  * @param instance_id the merchant instance ID
     89  * @returns the merchant instance's base URL
     90  */
     91 static char *
     92 make_merchant_base_url (struct MHD_Connection *connection,
     93                         const char *instance_id)
     94 {
     95   struct GNUNET_Buffer buf;
     96 
     97   if (GNUNET_OK !=
     98       TMH_base_url_by_connection (connection,
     99                                   instance_id,
    100                                   &buf))
    101     return NULL;
    102   GNUNET_buffer_write_path (&buf,
    103                             "");
    104   return GNUNET_buffer_reap_str (&buf);
    105 }
    106 
    107 
    108 /**
    109  * Information about a product we are supposed to add to the order
    110  * based on what we know it from our inventory.
    111  */
    112 struct InventoryProduct
    113 {
    114   /**
    115    * Identifier of the product in the inventory.
    116    */
    117   const char *product_id;
    118 
    119   /**
    120    * Number of units of the product to add to the order (integer part).
    121    */
    122   uint64_t quantity;
    123 
    124   /**
    125    * Fractional part of the quantity in units of 1/1000000 of the base value.
    126    */
    127   uint32_t quantity_frac;
    128 
    129   /**
    130    * True if the integer quantity field was missing in the request.
    131    */
    132   bool quantity_missing;
    133 
    134   /**
    135    * String representation of the quantity, if supplied.
    136    */
    137   const char *unit_quantity;
    138 
    139   /**
    140    * True if the string quantity field was missing in the request.
    141    */
    142   bool unit_quantity_missing;
    143 
    144   /**
    145    * Money pot associated with the product. 0 for none.
    146    */
    147   uint64_t product_money_pot;
    148 
    149 };
    150 
    151 
    152 /**
    153  * Handle for a rekey operation where we (re)request
    154  * the /keys from the exchange.
    155  */
    156 struct RekeyExchange
    157 {
    158   /**
    159    * Kept in a DLL.
    160    */
    161   struct RekeyExchange *prev;
    162 
    163   /**
    164    * Kept in a DLL.
    165    */
    166   struct RekeyExchange *next;
    167 
    168   /**
    169    * order this is for.
    170    */
    171   struct OrderContext *oc;
    172 
    173   /**
    174    * Base URL of the exchange.
    175    */
    176   char *url;
    177 
    178   /**
    179    * Request for keys.
    180    */
    181   struct TMH_EXCHANGES_KeysOperation *fo;
    182 
    183 };
    184 
    185 
    186 /**
    187  * Data structure where we evaluate the viability of a given
    188  * wire method for this order.
    189  */
    190 struct WireMethodCandidate
    191 {
    192   /**
    193    * Kept in a DLL.
    194    */
    195   struct WireMethodCandidate *next;
    196 
    197   /**
    198    * Kept in a DLL.
    199    */
    200   struct WireMethodCandidate *prev;
    201 
    202   /**
    203    * The wire method we are evaluating.
    204    */
    205   const struct TMH_WireMethod *wm;
    206 
    207   /**
    208    * List of exchanges to use when we use this wire method.
    209    */
    210   json_t *exchanges;
    211 
    212   /**
    213    * Set of maximum amounts that could be paid over all available exchanges
    214    * for this @a wm. Used to determine if this order creation requests exceeds
    215    * legal limits.
    216    */
    217   struct TALER_AmountSet total_exchange_limits;
    218 
    219 };
    220 
    221 
    222 /**
    223  * Information we keep per order we are processing.
    224  */
    225 struct OrderContext
    226 {
    227   /**
    228    * Information set in the #ORDER_PHASE_PARSE_REQUEST phase.
    229    */
    230   struct
    231   {
    232     /**
    233      * Order field of the request
    234      */
    235     json_t *order;
    236 
    237     /**
    238      * Set to how long refunds will be allowed.
    239      */
    240     struct GNUNET_TIME_Relative refund_delay;
    241 
    242     /**
    243      * RFC8905 payment target type to find a matching merchant account
    244      */
    245     const char *payment_target;
    246 
    247     /**
    248      * Shared key to use with @e pos_algorithm.
    249      */
    250     char *pos_key;
    251 
    252     /**
    253      * Selected algorithm (by template) when we are to
    254      * generate an OTP code for payment confirmation.
    255      */
    256     enum TALER_MerchantConfirmationAlgorithm pos_algorithm;
    257 
    258     /**
    259      * Hash of the POST request data, used to detect
    260      * idempotent requests.
    261      */
    262     struct TALER_MerchantPostDataHashP h_post_data;
    263 
    264     /**
    265      * Length of the @e inventory_products array.
    266      */
    267     unsigned int inventory_products_length;
    268 
    269     /**
    270      * Specifies that some products are to be included in the
    271      * order from the inventory. For these inventory management
    272      * is performed (so the products must be in stock).
    273      */
    274     struct InventoryProduct *inventory_products;
    275 
    276     /**
    277      * Length of the @e uuids array.
    278      */
    279     unsigned int uuids_length;
    280 
    281     /**
    282      * array of UUIDs used to reserve products from @a inventory_products.
    283      */
    284     struct GNUNET_Uuid *uuids;
    285 
    286     /**
    287      * Claim token for the request.
    288      */
    289     struct TALER_ClaimTokenP claim_token;
    290 
    291     /**
    292      * Session ID (optional) to use for the order.
    293      */
    294     const char *session_id;
    295 
    296   } parse_request;
    297 
    298   /**
    299    * Information set in the #ORDER_PHASE_PARSE_ORDER phase.
    300    */
    301   struct
    302   {
    303 
    304     /**
    305      * Our order ID.
    306      */
    307     char *order_id;
    308 
    309     /**
    310      * Summary of the contract.
    311      */
    312     const char *summary;
    313 
    314     /**
    315      * Internationalized summary.
    316      */
    317     const json_t *summary_i18n;
    318 
    319     /**
    320      * URL that will show that the contract was successful
    321      * after it has been paid for.
    322      */
    323     const char *fulfillment_url;
    324 
    325     /**
    326     * Message shown to the customer after paying for the contract.
    327     * Either fulfillment_url or fulfillment_message must be specified.
    328     */
    329     const char *fulfillment_message;
    330 
    331     /**
    332      * Map from IETF BCP 47 language tags to localized fulfillment messages.
    333      */
    334     const json_t *fulfillment_message_i18n;
    335 
    336     /**
    337      * Length of the @e products array.
    338      */
    339     size_t products_len;
    340 
    341     /**
    342      * Array of products that are being sold.
    343      */
    344     struct TALER_MERCHANT_ProductSold *products;
    345 
    346     /**
    347      * URL where the same contract could be ordered again (if available).
    348      */
    349     const char *public_reorder_url;
    350 
    351     /**
    352      * Merchant base URL.
    353      */
    354     char *merchant_base_url;
    355 
    356     /**
    357      * Timestamp of the order.
    358      */
    359     struct GNUNET_TIME_Timestamp timestamp;
    360 
    361     /**
    362      * Deadline for refunds.
    363      */
    364     struct GNUNET_TIME_Timestamp refund_deadline;
    365 
    366     /**
    367      * Payment deadline.
    368      */
    369     struct GNUNET_TIME_Timestamp pay_deadline;
    370 
    371     /**
    372      * Wire transfer deadline.
    373      */
    374     struct GNUNET_TIME_Timestamp wire_deadline;
    375 
    376     /**
    377      * Wire transfer round-up interval to apply.
    378      */
    379     enum GNUNET_TIME_RounderInterval wire_deadline_rounder;
    380 
    381     /**
    382      * Delivery date.
    383      */
    384     struct GNUNET_TIME_Timestamp delivery_date;
    385 
    386     /**
    387      * Delivery location.
    388      */
    389     const json_t *delivery_location;
    390 
    391     /**
    392      * Specifies for how long the wallet should try to get an
    393      * automatic refund for the purchase.
    394      */
    395     struct GNUNET_TIME_Relative auto_refund;
    396 
    397     /**
    398      * Nonce generated by the wallet and echoed by the merchant
    399      * in this field when the proposal is generated.
    400      */
    401     const char *nonce;
    402 
    403     /**
    404      * Extra data that is only interpreted by the merchant frontend.
    405      */
    406     const json_t *extra;
    407 
    408     /**
    409      * Minimum age required by the order.
    410      */
    411     uint32_t minimum_age;
    412 
    413     /**
    414      * Money pot to increment for whatever order payment amount
    415      * is not yet assigned to a pot via the Product.
    416      */
    417     uint64_t order_default_money_pot;
    418 
    419     /**
    420      * Version of the contract terms.
    421      */
    422     enum TALER_MERCHANT_ContractVersion version;
    423 
    424     /**
    425      * Details present depending on @e version.
    426      */
    427     union
    428     {
    429       /**
    430        * Details only present for v0.
    431        */
    432       struct
    433       {
    434         /**
    435          * Gross amount value of the contract. Used to
    436          * compute @e max_stefan_fee.
    437          */
    438         struct TALER_Amount brutto;
    439 
    440         /**
    441          * Tip included by the customer (part of the total amount).
    442          */
    443         struct TALER_Amount tip;
    444 
    445         /**
    446          * True if @e tip was not provided.
    447          */
    448         bool no_tip;
    449 
    450         /**
    451          * Maximum fee as given by the client request.
    452          */
    453         struct TALER_Amount max_fee;
    454       } v0;
    455 
    456       /**
    457        * Details only present for v1.
    458        */
    459       struct
    460       {
    461         /**
    462          * Array of contract choices. Is null for v0 contracts.
    463          */
    464         const json_t *choices;
    465       } v1;
    466     } details;
    467 
    468   } parse_order;
    469 
    470   /**
    471    * Information set in the #ORDER_PHASE_PARSE_CHOICES phase.
    472    */
    473   struct
    474   {
    475     /**
    476      * Array of possible specific contracts the wallet/customer may choose
    477      * from by selecting the respective index when signing the deposit
    478      * confirmation.
    479      */
    480     struct TALER_MERCHANT_ContractChoice *choices;
    481 
    482     /**
    483      * Length of the @e choices array.
    484      */
    485     unsigned int choices_len;
    486 
    487     /**
    488      * Array of token families referenced in the contract.
    489      */
    490     struct TALER_MERCHANT_ContractTokenFamily *token_families;
    491 
    492     /**
    493      * Length of the @e token_families array.
    494      */
    495     unsigned int token_families_len;
    496   } parse_choices;
    497 
    498   /**
    499    * Information set in the #ORDER_PHASE_MERGE_INVENTORY phase.
    500    */
    501   struct
    502   {
    503     /**
    504      * Merged array of products in the @e order.
    505      */
    506     json_t *products;
    507   } merge_inventory;
    508 
    509   /**
    510    * Information set in the #ORDER_PHASE_ADD_PAYMENT_DETAILS phase.
    511    */
    512   struct
    513   {
    514 
    515     /**
    516      * DLL of wire methods under evaluation.
    517      */
    518     struct WireMethodCandidate *wmc_head;
    519 
    520     /**
    521      * DLL of wire methods under evaluation.
    522      */
    523     struct WireMethodCandidate *wmc_tail;
    524 
    525     /**
    526      * Array of maximum amounts that appear in the contract choices
    527      * per currency.
    528      * Determines the maximum amounts that a client could pay for this
    529      * order and which we must thus make sure is acceptable for the
    530      * selected wire method/account if possible.
    531      */
    532     struct TALER_Amount *max_choice_limits;
    533 
    534     /**
    535      * Length of the @e max_choice_limits array.
    536      */
    537     unsigned int num_max_choice_limits;
    538 
    539     /**
    540      * Set to true if we may need an exchange. True if any amount is non-zero.
    541      */
    542     bool need_exchange;
    543 
    544   } add_payment_details;
    545 
    546   /**
    547    * Information set in the #ORDER_PHASE_SELECT_WIRE_METHOD phase.
    548    */
    549   struct
    550   {
    551 
    552     /**
    553      * Array of exchanges we find acceptable for this order and wire method.
    554      */
    555     json_t *exchanges;
    556 
    557     /**
    558      * Wire method (and our bank account) we have selected
    559      * to be included for this order.
    560      */
    561     const struct TMH_WireMethod *wm;
    562 
    563   } select_wire_method;
    564 
    565   /**
    566    * Information set in the #ORDER_PHASE_SET_EXCHANGES phase.
    567    */
    568   struct
    569   {
    570 
    571     /**
    572      * Forced requests to /keys to update our exchange
    573      * information.
    574      */
    575     struct RekeyExchange *pending_reload_head;
    576 
    577     /**
    578      * Forced requests to /keys to update our exchange
    579      * information.
    580      */
    581     struct RekeyExchange *pending_reload_tail;
    582 
    583     /**
    584      * How long do we wait at most until giving up on getting keys?
    585      */
    586     struct GNUNET_TIME_Absolute keys_timeout;
    587 
    588     /**
    589      * Task to wake us up on @e keys_timeout.
    590      */
    591     struct GNUNET_SCHEDULER_Task *wakeup_task;
    592 
    593     /**
    594      * Array of reasons why a particular exchange may be
    595      * limited or not be eligible.
    596      */
    597     json_t *exchange_rejections;
    598 
    599     /**
    600      * Did we previously force reloading of /keys from
    601      * all exchanges? Set to 'true' to prevent us from
    602      * doing it again (and again...).
    603      */
    604     bool forced_reload;
    605 
    606     /**
    607      * Did we find a working exchange?
    608      */
    609     bool exchange_ok;
    610 
    611     /**
    612      * Did we find an exchange that justifies
    613      * reloading keys?
    614      */
    615     bool promising_exchange;
    616 
    617     /**
    618      * Set to true once we have attempted to load exchanges
    619      * for the first time.
    620      */
    621     bool exchanges_tried;
    622 
    623     /**
    624      * Details depending on the contract version.
    625      */
    626     union
    627     {
    628 
    629       /**
    630        * Details for contract v0.
    631        */
    632       struct
    633       {
    634         /**
    635          * Maximum fee for @e order based on STEFAN curves.
    636          * Used to set @e max_fee if not provided as part of
    637          * @e order.
    638          */
    639         struct TALER_Amount max_stefan_fee;
    640 
    641       } v0;
    642 
    643       /**
    644        * Details for contract v1.
    645        */
    646       struct
    647       {
    648         /**
    649          * Maximum fee for @e order based on STEFAN curves by
    650          * contract choice.
    651          * Used to set @e max_fee if not provided as part of
    652          * @e order.
    653          */
    654         struct TALER_Amount *max_stefan_fees;
    655 
    656       } v1;
    657 
    658     } details;
    659 
    660   } set_exchanges;
    661 
    662   /**
    663    * Information set in the #ORDER_PHASE_SET_MAX_FEE phase.
    664    */
    665   struct
    666   {
    667 
    668     /**
    669      * Details depending on the contract version.
    670      */
    671     union
    672     {
    673 
    674       /**
    675        * Details for contract v0.
    676        */
    677       struct
    678       {
    679         /**
    680          * Maximum fee
    681          */
    682         struct TALER_Amount max_fee;
    683       } v0;
    684 
    685       /**
    686        * Details for contract v1.
    687        */
    688       struct
    689       {
    690         /**
    691          * Maximum fees by contract choice.
    692          */
    693         struct TALER_Amount *max_fees;
    694 
    695       } v1;
    696 
    697     } details;
    698   } set_max_fee;
    699 
    700   /**
    701    * Information set in the #ORDER_PHASE_EXECUTE_ORDER phase.
    702    */
    703   struct
    704   {
    705     /**
    706      * Which product (by offset) is out of stock, UINT_MAX if all were in-stock.
    707      */
    708     unsigned int out_of_stock_index;
    709 
    710     /**
    711      * Set to a previous claim token *if* @e idempotent
    712      * is also true.
    713      */
    714     struct TALER_ClaimTokenP token;
    715 
    716     /**
    717      * Set to true if the order was idempotent and there
    718      * was an equivalent one before.
    719      */
    720     bool idempotent;
    721 
    722     /**
    723      * Set to true if the order is in conflict with a
    724      * previous order with the same order ID.
    725      */
    726     bool conflict;
    727   } execute_order;
    728 
    729   struct
    730   {
    731     /**
    732      * Contract terms to store in the database.
    733      */
    734     json_t *contract;
    735   } serialize_order;
    736 
    737   /**
    738    * Connection of the request.
    739    */
    740   struct MHD_Connection *connection;
    741 
    742   /**
    743    * Kept in a DLL while suspended.
    744    */
    745   struct OrderContext *next;
    746 
    747   /**
    748    * Kept in a DLL while suspended.
    749    */
    750   struct OrderContext *prev;
    751 
    752   /**
    753    * Handler context for the request.
    754    */
    755   struct TMH_HandlerContext *hc;
    756 
    757   /**
    758    * #GNUNET_YES if suspended.
    759    */
    760   enum GNUNET_GenericReturnValue suspended;
    761 
    762   /**
    763    * Current phase of setting up the order.
    764    */
    765   enum
    766   {
    767     ORDER_PHASE_PARSE_REQUEST,
    768     ORDER_PHASE_PARSE_ORDER,
    769     ORDER_PHASE_PARSE_CHOICES,
    770     ORDER_PHASE_MERGE_INVENTORY,
    771     ORDER_PHASE_ADD_PAYMENT_DETAILS,
    772     ORDER_PHASE_SET_EXCHANGES,
    773     ORDER_PHASE_SELECT_WIRE_METHOD,
    774     ORDER_PHASE_SET_MAX_FEE,
    775     ORDER_PHASE_SERIALIZE_ORDER,
    776     ORDER_PHASE_SALT_FORGETTABLE,
    777     ORDER_PHASE_CHECK_CONTRACT,
    778     ORDER_PHASE_EXECUTE_ORDER,
    779 
    780     /**
    781      * Processing is done, we should return #MHD_YES.
    782      */
    783     ORDER_PHASE_FINISHED_MHD_YES,
    784 
    785     /**
    786      * Processing is done, we should return #MHD_NO.
    787      */
    788     ORDER_PHASE_FINISHED_MHD_NO
    789   } phase;
    790 
    791 
    792 };
    793 
    794 
    795 /**
    796  * Kept in a DLL while suspended.
    797  */
    798 static struct OrderContext *oc_head;
    799 
    800 /**
    801  * Kept in a DLL while suspended.
    802  */
    803 static struct OrderContext *oc_tail;
    804 
    805 
    806 void
    807 TMH_force_orders_resume ()
    808 {
    809   struct OrderContext *oc;
    810 
    811   while (NULL != (oc = oc_head))
    812   {
    813     GNUNET_CONTAINER_DLL_remove (oc_head,
    814                                  oc_tail,
    815                                  oc);
    816     oc->suspended = GNUNET_SYSERR;
    817     MHD_resume_connection (oc->connection);
    818   }
    819 }
    820 
    821 
    822 /**
    823  * Update the phase of @a oc based on @a mret.
    824  *
    825  * @param[in,out] oc order to update phase for
    826  * @param mret #MHD_NO to close with #MHD_NO
    827  *             #MHD_YES to close with #MHD_YES
    828  */
    829 static void
    830 finalize_order (struct OrderContext *oc,
    831                 MHD_RESULT mret)
    832 {
    833   oc->phase = (MHD_YES == mret)
    834     ? ORDER_PHASE_FINISHED_MHD_YES
    835     : ORDER_PHASE_FINISHED_MHD_NO;
    836 }
    837 
    838 
    839 /**
    840  * Update the phase of @a oc based on @a ret.
    841  *
    842  * @param[in,out] oc order to update phase for
    843  * @param ret #GNUNET_SYSERR to close with #MHD_NO
    844  *            #GNUNET_NO to close with #MHD_YES
    845  *            #GNUNET_OK is not allowed!
    846  */
    847 static void
    848 finalize_order2 (struct OrderContext *oc,
    849                  enum GNUNET_GenericReturnValue ret)
    850 {
    851   GNUNET_assert (GNUNET_OK != ret);
    852   oc->phase = (GNUNET_NO == ret)
    853     ? ORDER_PHASE_FINISHED_MHD_YES
    854     : ORDER_PHASE_FINISHED_MHD_NO;
    855 }
    856 
    857 
    858 /**
    859  * Generate an error response for @a oc.
    860  *
    861  * @param[in,out] oc order context to respond to
    862  * @param http_status HTTP status code to set
    863  * @param ec error code to set
    864  * @param detail error message detail to set
    865  */
    866 static void
    867 reply_with_error (struct OrderContext *oc,
    868                   unsigned int http_status,
    869                   enum TALER_ErrorCode ec,
    870                   const char *detail)
    871 {
    872   MHD_RESULT mret;
    873 
    874   mret = TALER_MHD_reply_with_error (oc->connection,
    875                                      http_status,
    876                                      ec,
    877                                      detail);
    878   finalize_order (oc,
    879                   mret);
    880 }
    881 
    882 
    883 /**
    884  * Clean up memory used by @a wmc.
    885  *
    886  * @param[in,out] oc order context the WMC is part of
    887  * @param[in] wmc wire method candidate to free
    888  */
    889 static void
    890 free_wmc (struct OrderContext *oc,
    891           struct WireMethodCandidate *wmc)
    892 {
    893   GNUNET_CONTAINER_DLL_remove (oc->add_payment_details.wmc_head,
    894                                oc->add_payment_details.wmc_tail,
    895                                wmc);
    896   TALER_amount_set_free (&wmc->total_exchange_limits);
    897   json_decref (wmc->exchanges);
    898   GNUNET_free (wmc);
    899 }
    900 
    901 
    902 /**
    903  * Clean up memory used by @a cls.
    904  *
    905  * @param[in] cls the `struct OrderContext` to clean up
    906  */
    907 static void
    908 clean_order (void *cls)
    909 {
    910   struct OrderContext *oc = cls;
    911   struct RekeyExchange *rx;
    912 
    913   while (NULL != oc->add_payment_details.wmc_head)
    914     free_wmc (oc,
    915               oc->add_payment_details.wmc_head);
    916   while (NULL != (rx = oc->set_exchanges.pending_reload_head))
    917   {
    918     GNUNET_CONTAINER_DLL_remove (oc->set_exchanges.pending_reload_head,
    919                                  oc->set_exchanges.pending_reload_tail,
    920                                  rx);
    921     TMH_EXCHANGES_keys4exchange_cancel (rx->fo);
    922     GNUNET_free (rx->url);
    923     GNUNET_free (rx);
    924   }
    925   GNUNET_array_grow (oc->add_payment_details.max_choice_limits,
    926                      oc->add_payment_details.num_max_choice_limits,
    927                      0);
    928   if (NULL != oc->set_exchanges.wakeup_task)
    929   {
    930     GNUNET_SCHEDULER_cancel (oc->set_exchanges.wakeup_task);
    931     oc->set_exchanges.wakeup_task = NULL;
    932   }
    933   if (NULL != oc->select_wire_method.exchanges)
    934   {
    935     json_decref (oc->select_wire_method.exchanges);
    936     oc->select_wire_method.exchanges = NULL;
    937   }
    938   if (NULL != oc->set_exchanges.exchange_rejections)
    939   {
    940     json_decref (oc->set_exchanges.exchange_rejections);
    941     oc->set_exchanges.exchange_rejections = NULL;
    942   }
    943   switch (oc->parse_order.version)
    944   {
    945   case TALER_MERCHANT_CONTRACT_VERSION_0:
    946     break;
    947   case TALER_MERCHANT_CONTRACT_VERSION_1:
    948     GNUNET_free (oc->set_max_fee.details.v1.max_fees);
    949     GNUNET_free (oc->set_exchanges.details.v1.max_stefan_fees);
    950     break;
    951   }
    952   if (NULL != oc->merge_inventory.products)
    953   {
    954     json_decref (oc->merge_inventory.products);
    955     oc->merge_inventory.products = NULL;
    956   }
    957   for (unsigned int i = 0; i<oc->parse_choices.choices_len; i++)
    958   {
    959     TALER_MERCHANT_contract_choice_free (&oc->parse_choices.choices[i]);
    960   }
    961   GNUNET_array_grow (oc->parse_choices.choices,
    962                      oc->parse_choices.choices_len,
    963                      0);
    964   for (size_t i = 0; i<oc->parse_order.products_len; i++)
    965   {
    966     TALER_MERCHANT_product_sold_free (&oc->parse_order.products[i]);
    967   }
    968   GNUNET_free (oc->parse_order.products);
    969   oc->parse_order.products_len = 0;
    970   for (unsigned int i = 0; i<oc->parse_choices.token_families_len; i++)
    971   {
    972     struct TALER_MERCHANT_ContractTokenFamily *mctf
    973       = &oc->parse_choices.token_families[i];
    974 
    975     GNUNET_free (mctf->slug);
    976     GNUNET_free (mctf->name);
    977     GNUNET_free (mctf->description);
    978     json_decref (mctf->description_i18n);
    979     switch (mctf->kind)
    980     {
    981     case TALER_MERCHANT_CONTRACT_TOKEN_KIND_INVALID:
    982       GNUNET_break (0);
    983       break;
    984     case TALER_MERCHANT_CONTRACT_TOKEN_KIND_SUBSCRIPTION:
    985       for (size_t j = 0; j<mctf->details.subscription.trusted_domains_len; j++)
    986         GNUNET_free (mctf->details.subscription.trusted_domains[j]);
    987       GNUNET_free (mctf->details.subscription.trusted_domains);
    988       break;
    989     case TALER_MERCHANT_CONTRACT_TOKEN_KIND_DISCOUNT:
    990       for (size_t j = 0; j<mctf->details.discount.expected_domains_len; j++)
    991         GNUNET_free (mctf->details.discount.expected_domains[j]);
    992       GNUNET_free (mctf->details.discount.expected_domains);
    993       break;
    994     }
    995     for (unsigned int j = 0; j<mctf->keys_len; j++)
    996     {
    997       GNUNET_CRYPTO_blind_sign_pub_decref (mctf->keys[j].pub.public_key);
    998     }
    999     GNUNET_array_grow (mctf->keys,
   1000                        mctf->keys_len,
   1001                        0);
   1002   }
   1003   GNUNET_array_grow (oc->parse_choices.token_families,
   1004                      oc->parse_choices.token_families_len,
   1005                      0);
   1006   GNUNET_array_grow (oc->parse_request.inventory_products,
   1007                      oc->parse_request.inventory_products_length,
   1008                      0);
   1009   GNUNET_array_grow (oc->parse_request.uuids,
   1010                      oc->parse_request.uuids_length,
   1011                      0);
   1012   GNUNET_free (oc->parse_request.pos_key);
   1013   json_decref (oc->parse_request.order);
   1014   json_decref (oc->serialize_order.contract);
   1015   GNUNET_free (oc->parse_order.order_id);
   1016   GNUNET_free (oc->parse_order.merchant_base_url);
   1017   GNUNET_free (oc);
   1018 }
   1019 
   1020 
   1021 /* ***************** ORDER_PHASE_EXECUTE_ORDER **************** */
   1022 
   1023 /**
   1024  * Compute remaining stock (integer and fractional parts) for a product.
   1025  *
   1026  * @param pd product details with current totals/sold/lost
   1027  * @param[out] available_value remaining whole units (normalized, non-negative)
   1028  * @param[out] available_frac remaining fractional units (0..TALER_MERCHANT_UNIT_FRAC_BASE-1)
   1029  */
   1030 static void
   1031 compute_available_quantity (const struct TALER_MERCHANTDB_ProductDetails *pd,
   1032                             uint64_t *available_value,
   1033                             uint32_t *available_frac)
   1034 {
   1035   int64_t value;
   1036   int64_t frac;
   1037 
   1038   GNUNET_assert (NULL != available_value);
   1039   GNUNET_assert (NULL != available_frac);
   1040 
   1041   if ( (INT64_MAX == pd->total_stock) &&
   1042        (INT32_MAX == pd->total_stock_frac) )
   1043   {
   1044     *available_value = pd->total_stock;
   1045     *available_frac = pd->total_stock_frac;
   1046     return;
   1047   }
   1048 
   1049   value = (int64_t) pd->total_stock
   1050           - (int64_t) pd->total_sold
   1051           - (int64_t) pd->total_lost;
   1052   frac = (int64_t) pd->total_stock_frac
   1053          - (int64_t) pd->total_sold_frac
   1054          - (int64_t) pd->total_lost_frac;
   1055 
   1056   if (frac < 0)
   1057   {
   1058     int64_t borrow = ((-frac) + TALER_MERCHANT_UNIT_FRAC_BASE - 1)
   1059                      / TALER_MERCHANT_UNIT_FRAC_BASE;
   1060     value -= borrow;
   1061     frac += borrow * (int64_t) TALER_MERCHANT_UNIT_FRAC_BASE;
   1062   }
   1063   else if (frac >= TALER_MERCHANT_UNIT_FRAC_BASE)
   1064   {
   1065     int64_t carry = frac / TALER_MERCHANT_UNIT_FRAC_BASE;
   1066     value += carry;
   1067     frac -= carry * (int64_t) TALER_MERCHANT_UNIT_FRAC_BASE;
   1068   }
   1069 
   1070   if (value < 0)
   1071   {
   1072     value = 0;
   1073     frac = 0;
   1074   }
   1075 
   1076   *available_value = (uint64_t) value;
   1077   *available_frac = (uint32_t) frac;
   1078 }
   1079 
   1080 
   1081 /**
   1082  * Execute the database transaction to setup the order.
   1083  *
   1084  * @param[in,out] oc order context
   1085  * @return transaction status, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if @a uuids were insufficient to reserve required inventory
   1086  */
   1087 static enum GNUNET_DB_QueryStatus
   1088 execute_transaction (struct OrderContext *oc)
   1089 {
   1090   enum GNUNET_DB_QueryStatus qs;
   1091   struct GNUNET_TIME_Timestamp timestamp;
   1092   uint64_t order_serial;
   1093 
   1094   if (GNUNET_OK !=
   1095       TMH_db->start (TMH_db->cls,
   1096                      "insert_order"))
   1097   {
   1098     GNUNET_break (0);
   1099     return GNUNET_DB_STATUS_HARD_ERROR;
   1100   }
   1101 
   1102   /* Test if we already have an order with this id */
   1103   {
   1104     json_t *contract_terms;
   1105     struct TALER_MerchantPostDataHashP orig_post;
   1106 
   1107     qs = TMH_db->lookup_order (TMH_db->cls,
   1108                                oc->hc->instance->settings.id,
   1109                                oc->parse_order.order_id,
   1110                                &oc->execute_order.token,
   1111                                &orig_post,
   1112                                &contract_terms);
   1113     /* If yes, check for idempotency */
   1114     if (0 > qs)
   1115     {
   1116       GNUNET_break (0);
   1117       TMH_db->rollback (TMH_db->cls);
   1118       return qs;
   1119     }
   1120     if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
   1121     {
   1122       TMH_db->rollback (TMH_db->cls);
   1123       json_decref (contract_terms);
   1124       /* Comparing the contract terms is sufficient because all the other
   1125          params get added to it at some point. */
   1126       if (0 == GNUNET_memcmp (&orig_post,
   1127                               &oc->parse_request.h_post_data))
   1128       {
   1129         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1130                     "Order creation idempotent\n");
   1131         oc->execute_order.idempotent = true;
   1132         return qs;
   1133       }
   1134       GNUNET_break_op (0);
   1135       oc->execute_order.conflict = true;
   1136       return qs;
   1137     }
   1138   }
   1139 
   1140   /* Setup order */
   1141   qs = TMH_db->insert_order (TMH_db->cls,
   1142                              oc->hc->instance->settings.id,
   1143                              oc->parse_order.order_id,
   1144                              oc->parse_request.session_id,
   1145                              &oc->parse_request.h_post_data,
   1146                              oc->parse_order.pay_deadline,
   1147                              &oc->parse_request.claim_token,
   1148                              oc->serialize_order.contract,  /* called 'contract terms' at database. */
   1149                              oc->parse_request.pos_key,
   1150                              oc->parse_request.pos_algorithm);
   1151   if (qs <= 0)
   1152   {
   1153     /* qs == 0: probably instance does not exist (anymore) */
   1154     TMH_db->rollback (TMH_db->cls);
   1155     return qs;
   1156   }
   1157   /* Migrate locks from UUIDs to new order: first release old locks */
   1158   for (unsigned int i = 0; i<oc->parse_request.uuids_length; i++)
   1159   {
   1160     qs = TMH_db->unlock_inventory (TMH_db->cls,
   1161                                    &oc->parse_request.uuids[i]);
   1162     if (qs < 0)
   1163     {
   1164       TMH_db->rollback (TMH_db->cls);
   1165       return qs;
   1166     }
   1167     /* qs == 0 is OK here, that just means we did not HAVE any lock under this
   1168        UUID */
   1169   }
   1170   /* Migrate locks from UUIDs to new order: acquire new locks
   1171      (note: this can basically ONLY fail on serializability OR
   1172      because the UUID locks were insufficient for the desired
   1173      quantities). */
   1174   for (unsigned int i = 0; i<oc->parse_request.inventory_products_length; i++)
   1175   {
   1176     qs = TMH_db->insert_order_lock (
   1177       TMH_db->cls,
   1178       oc->hc->instance->settings.id,
   1179       oc->parse_order.order_id,
   1180       oc->parse_request.inventory_products[i].product_id,
   1181       oc->parse_request.inventory_products[i].quantity,
   1182       oc->parse_request.inventory_products[i].quantity_frac);
   1183     if (qs < 0)
   1184     {
   1185       TMH_db->rollback (TMH_db->cls);
   1186       return qs;
   1187     }
   1188     if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
   1189     {
   1190       /* qs == 0: lock acquisition failed due to insufficient stocks */
   1191       TMH_db->rollback (TMH_db->cls);
   1192       oc->execute_order.out_of_stock_index = i; /* indicate which product is causing the issue */
   1193       return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
   1194     }
   1195   }
   1196   oc->execute_order.out_of_stock_index = UINT_MAX;
   1197 
   1198   /* Get the order serial and timestamp for the order we just created to
   1199      update long-poll clients. */
   1200   qs = TMH_db->lookup_order_summary (TMH_db->cls,
   1201                                      oc->hc->instance->settings.id,
   1202                                      oc->parse_order.order_id,
   1203                                      &timestamp,
   1204                                      &order_serial);
   1205   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
   1206   {
   1207     TMH_db->rollback (TMH_db->cls);
   1208     return qs;
   1209   }
   1210 
   1211   {
   1212     json_t *jhook;
   1213 
   1214     jhook = GNUNET_JSON_PACK (
   1215       GNUNET_JSON_pack_string ("order_id",
   1216                                oc->parse_order.order_id),
   1217       GNUNET_JSON_pack_object_incref ("contract",
   1218                                       oc->serialize_order.contract),
   1219       GNUNET_JSON_pack_string ("instance_id",
   1220                                oc->hc->instance->settings.id)
   1221       );
   1222     GNUNET_assert (NULL != jhook);
   1223     qs = TMH_trigger_webhook (oc->hc->instance->settings.id,
   1224                               "order_created",
   1225                               jhook);
   1226     json_decref (jhook);
   1227     if (0 > qs)
   1228     {
   1229       TMH_db->rollback (TMH_db->cls);
   1230       if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
   1231         return qs;
   1232       GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
   1233       reply_with_error (oc,
   1234                         MHD_HTTP_INTERNAL_SERVER_ERROR,
   1235                         TALER_EC_GENERIC_DB_STORE_FAILED,
   1236                         "failed to trigger webhooks");
   1237       return qs;
   1238     }
   1239   }
   1240 
   1241   TMH_notify_order_change (oc->hc->instance,
   1242                            TMH_OSF_NONE,
   1243                            timestamp,
   1244                            order_serial);
   1245   /* finally, commit transaction (note: if it fails, we ALSO re-acquire
   1246      the UUID locks, which is exactly what we want) */
   1247   qs = TMH_db->commit (TMH_db->cls);
   1248   if (0 > qs)
   1249     return qs;
   1250   return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;   /* 1 == success! */
   1251 }
   1252 
   1253 
   1254 /**
   1255  * The request was successful, generate the #MHD_HTTP_OK response.
   1256  *
   1257  * @param[in,out] oc context to update
   1258  * @param claim_token claim token to use, NULL if none
   1259  */
   1260 static void
   1261 yield_success_response (struct OrderContext *oc,
   1262                         const struct TALER_ClaimTokenP *claim_token)
   1263 {
   1264   MHD_RESULT ret;
   1265 
   1266   ret = TALER_MHD_REPLY_JSON_PACK (
   1267     oc->connection,
   1268     MHD_HTTP_OK,
   1269     GNUNET_JSON_pack_string ("order_id",
   1270                              oc->parse_order.order_id),
   1271     GNUNET_JSON_pack_timestamp ("pay_deadline",
   1272                                 oc->parse_order.pay_deadline),
   1273     GNUNET_JSON_pack_allow_null (
   1274       GNUNET_JSON_pack_data_auto (
   1275         "token",
   1276         claim_token)));
   1277   finalize_order (oc,
   1278                   ret);
   1279 }
   1280 
   1281 
   1282 /**
   1283  * Transform an order into a proposal and store it in the
   1284  * database. Write the resulting proposal or an error message
   1285  * of a MHD connection.
   1286  *
   1287  * @param[in,out] oc order context
   1288  */
   1289 static void
   1290 phase_execute_order (struct OrderContext *oc)
   1291 {
   1292   const struct TALER_MERCHANTDB_InstanceSettings *settings =
   1293     &oc->hc->instance->settings;
   1294   enum GNUNET_DB_QueryStatus qs;
   1295 
   1296   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   1297               "Executing database transaction to create order '%s' for instance '%s'\n",
   1298               oc->parse_order.order_id,
   1299               settings->id);
   1300   for (unsigned int i = 0; i<MAX_RETRIES; i++)
   1301   {
   1302     TMH_db->preflight (TMH_db->cls);
   1303     qs = execute_transaction (oc);
   1304     if (GNUNET_DB_STATUS_SOFT_ERROR != qs)
   1305       break;
   1306   }
   1307   if (0 >= qs)
   1308   {
   1309     /* Special report if retries insufficient */
   1310     if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
   1311     {
   1312       GNUNET_break (0);
   1313       reply_with_error (oc,
   1314                         MHD_HTTP_INTERNAL_SERVER_ERROR,
   1315                         TALER_EC_GENERIC_DB_SOFT_FAILURE,
   1316                         NULL);
   1317       return;
   1318     }
   1319     if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
   1320     {
   1321       /* should be: contract (!) with same order ID
   1322          already exists */
   1323       reply_with_error (
   1324         oc,
   1325         MHD_HTTP_CONFLICT,
   1326         TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_ALREADY_EXISTS,
   1327         oc->parse_order.order_id);
   1328       return;
   1329     }
   1330     /* Other hard transaction error (disk full, etc.) */
   1331     GNUNET_break (0);
   1332     reply_with_error (
   1333       oc,
   1334       MHD_HTTP_INTERNAL_SERVER_ERROR,
   1335       TALER_EC_GENERIC_DB_COMMIT_FAILED,
   1336       NULL);
   1337     return;
   1338   }
   1339 
   1340   /* DB transaction succeeded, check for idempotent */
   1341   if (oc->execute_order.idempotent)
   1342   {
   1343     yield_success_response (oc,
   1344                             GNUNET_is_zero (&oc->execute_order.token)
   1345                             ? NULL
   1346                             : &oc->execute_order.token);
   1347     return;
   1348   }
   1349   if (oc->execute_order.conflict)
   1350   {
   1351     reply_with_error (
   1352       oc,
   1353       MHD_HTTP_CONFLICT,
   1354       TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_ALREADY_EXISTS,
   1355       oc->parse_order.order_id);
   1356     return;
   1357   }
   1358 
   1359   /* DB transaction succeeded, check for out-of-stock */
   1360   if (oc->execute_order.out_of_stock_index < UINT_MAX)
   1361   {
   1362     /* We had a product that has insufficient quantities,
   1363        generate the details for the response. */
   1364     struct TALER_MERCHANTDB_ProductDetails pd;
   1365     MHD_RESULT ret;
   1366     const struct InventoryProduct *ip;
   1367     size_t num_categories = 0;
   1368     uint64_t *categories = NULL;
   1369     uint64_t available_quantity;
   1370     uint32_t available_quantity_frac;
   1371     char requested_quantity_buf[64];
   1372     char available_quantity_buf[64];
   1373 
   1374     ip = &oc->parse_request.inventory_products[
   1375       oc->execute_order.out_of_stock_index];
   1376     memset (&pd,
   1377             0,
   1378             sizeof (pd));
   1379     qs = TMH_db->lookup_product (
   1380       TMH_db->cls,
   1381       oc->hc->instance->settings.id,
   1382       ip->product_id,
   1383       &pd,
   1384       &num_categories,
   1385       &categories);
   1386     switch (qs)
   1387     {
   1388     case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
   1389       GNUNET_free (categories);
   1390       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1391                   "Order creation failed: product out of stock\n");
   1392 
   1393       compute_available_quantity (&pd,
   1394                                   &available_quantity,
   1395                                   &available_quantity_frac);
   1396       TALER_MERCHANT_vk_format_fractional_string (
   1397         TALER_MERCHANT_VK_QUANTITY,
   1398         ip->quantity,
   1399         ip->quantity_frac,
   1400         sizeof (requested_quantity_buf),
   1401         requested_quantity_buf);
   1402       TALER_MERCHANT_vk_format_fractional_string (
   1403         TALER_MERCHANT_VK_QUANTITY,
   1404         available_quantity,
   1405         available_quantity_frac,
   1406         sizeof (available_quantity_buf),
   1407         available_quantity_buf);
   1408       ret = TALER_MHD_REPLY_JSON_PACK (
   1409         oc->connection,
   1410         MHD_HTTP_GONE,
   1411         GNUNET_JSON_pack_string (
   1412           "product_id",
   1413           ip->product_id),
   1414         GNUNET_JSON_pack_uint64 (
   1415           "requested_quantity",
   1416           ip->quantity),
   1417         GNUNET_JSON_pack_string (
   1418           "unit_requested_quantity",
   1419           requested_quantity_buf),
   1420         GNUNET_JSON_pack_uint64 (
   1421           "available_quantity",
   1422           available_quantity),
   1423         GNUNET_JSON_pack_string (
   1424           "unit_available_quantity",
   1425           available_quantity_buf),
   1426         GNUNET_JSON_pack_allow_null (
   1427           GNUNET_JSON_pack_timestamp (
   1428             "restock_expected",
   1429             pd.next_restock)));
   1430       TALER_MERCHANTDB_product_details_free (&pd);
   1431       finalize_order (oc,
   1432                       ret);
   1433       return;
   1434     case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
   1435       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1436                   "Order creation failed: unknown product out of stock\n");
   1437       finalize_order (oc,
   1438                       TALER_MHD_REPLY_JSON_PACK (
   1439                         oc->connection,
   1440                         MHD_HTTP_GONE,
   1441                         GNUNET_JSON_pack_string (
   1442                           "product_id",
   1443                           ip->product_id),
   1444                         GNUNET_JSON_pack_uint64 (
   1445                           "requested_quantity",
   1446                           ip->quantity),
   1447                         GNUNET_JSON_pack_uint64 (
   1448                           "available_quantity",
   1449                           0)));
   1450       return;
   1451     case GNUNET_DB_STATUS_SOFT_ERROR:
   1452       GNUNET_break (0);
   1453       reply_with_error (
   1454         oc,
   1455         MHD_HTTP_INTERNAL_SERVER_ERROR,
   1456         TALER_EC_GENERIC_DB_SOFT_FAILURE,
   1457         NULL);
   1458       return;
   1459     case GNUNET_DB_STATUS_HARD_ERROR:
   1460       GNUNET_break (0);
   1461       reply_with_error (
   1462         oc,
   1463         MHD_HTTP_INTERNAL_SERVER_ERROR,
   1464         TALER_EC_GENERIC_DB_FETCH_FAILED,
   1465         NULL);
   1466       return;
   1467     }
   1468     GNUNET_break (0);
   1469     oc->phase = ORDER_PHASE_FINISHED_MHD_NO;
   1470     return;
   1471   } /* end 'out of stock' case */
   1472 
   1473   /* Everything in-stock, generate positive response */
   1474   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1475               "Order creation succeeded\n");
   1476   yield_success_response (oc,
   1477                           GNUNET_is_zero (&oc->parse_request.claim_token)
   1478                           ? NULL
   1479                           : &oc->parse_request.claim_token);
   1480 }
   1481 
   1482 
   1483 /* ***************** ORDER_PHASE_CHECK_CONTRACT **************** */
   1484 
   1485 
   1486 /**
   1487  * Check that the contract is now well-formed. Upon success, continue
   1488  * processing with execute_order().
   1489  *
   1490  * @param[in,out] oc order context
   1491  */
   1492 static void
   1493 phase_check_contract (struct OrderContext *oc)
   1494 {
   1495   struct TALER_PrivateContractHashP h_control;
   1496 
   1497   switch (TALER_JSON_contract_hash (oc->serialize_order.contract,
   1498                                     &h_control))
   1499   {
   1500   case GNUNET_SYSERR:
   1501     GNUNET_break (0);
   1502     reply_with_error (
   1503       oc,
   1504       MHD_HTTP_INTERNAL_SERVER_ERROR,
   1505       TALER_EC_GENERIC_FAILED_COMPUTE_JSON_HASH,
   1506       "could not compute hash of serialized order");
   1507     return;
   1508   case GNUNET_NO:
   1509     GNUNET_break_op (0);
   1510     reply_with_error (
   1511       oc,
   1512       MHD_HTTP_BAD_REQUEST,
   1513       TALER_EC_GENERIC_FAILED_COMPUTE_JSON_HASH,
   1514       "order contained unallowed values");
   1515     return;
   1516   case GNUNET_OK:
   1517     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1518                 "Contract hash is %s\n",
   1519                 GNUNET_h2s (&h_control.hash));
   1520     oc->phase++;
   1521     return;
   1522   }
   1523   GNUNET_assert (0);
   1524 }
   1525 
   1526 
   1527 /* ***************** ORDER_PHASE_SALT_FORGETTABLE **************** */
   1528 
   1529 
   1530 /**
   1531  * Modify the final contract terms adding salts for
   1532  * items that are forgettable.
   1533  *
   1534  * @param[in,out] oc order context
   1535  */
   1536 static void
   1537 phase_salt_forgettable (struct OrderContext *oc)
   1538 {
   1539   if (GNUNET_OK !=
   1540       TALER_JSON_contract_seed_forgettable (oc->parse_request.order,
   1541                                             oc->serialize_order.contract))
   1542   {
   1543     GNUNET_break_op (0);
   1544     reply_with_error (
   1545       oc,
   1546       MHD_HTTP_BAD_REQUEST,
   1547       TALER_EC_GENERIC_JSON_INVALID,
   1548       "could not compute hash of order due to bogus forgettable fields");
   1549     return;
   1550   }
   1551   oc->phase++;
   1552 }
   1553 
   1554 
   1555 /* ***************** ORDER_PHASE_SERIALIZE_ORDER **************** */
   1556 
   1557 /**
   1558  * Get rounded time interval. @a start is calculated by rounding
   1559  * @a ts down to the nearest multiple of @a precision.
   1560  *
   1561  * @param precision rounding precision.
   1562  *        year, month, day, hour, minute are supported.
   1563  * @param ts timestamp to round
   1564  * @param[out] start start of the interval
   1565  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
   1566  */
   1567 static enum GNUNET_GenericReturnValue
   1568 get_rounded_time_interval_down (struct GNUNET_TIME_Relative precision,
   1569                                 struct GNUNET_TIME_Timestamp ts,
   1570                                 struct GNUNET_TIME_Timestamp *start)
   1571 {
   1572   enum GNUNET_TIME_RounderInterval ri;
   1573 
   1574   ri = GNUNET_TIME_relative_to_round_interval (precision);
   1575   if ( (GNUNET_TIME_RI_NONE == ri) &&
   1576        (! GNUNET_TIME_relative_is_zero (precision)) )
   1577   {
   1578     *start = ts;
   1579     return GNUNET_SYSERR;
   1580   }
   1581   *start = GNUNET_TIME_absolute_to_timestamp (
   1582     GNUNET_TIME_round_down (ts.abs_time,
   1583                             ri));
   1584   return GNUNET_OK;
   1585 }
   1586 
   1587 
   1588 /**
   1589  * Get rounded time interval. @a start is calculated by rounding
   1590  * @a ts up to the nearest multiple of @a precision.
   1591  *
   1592  * @param precision rounding precision.
   1593  *        year, month, day, hour, minute are supported.
   1594  * @param ts timestamp to round
   1595  * @param[out] start start of the interval
   1596  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
   1597  */
   1598 static enum GNUNET_GenericReturnValue
   1599 get_rounded_time_interval_up (struct GNUNET_TIME_Relative precision,
   1600                               struct GNUNET_TIME_Timestamp ts,
   1601                               struct GNUNET_TIME_Timestamp *start)
   1602 {
   1603   enum GNUNET_TIME_RounderInterval ri;
   1604 
   1605   ri = GNUNET_TIME_relative_to_round_interval (precision);
   1606   if ( (GNUNET_TIME_RI_NONE == ri) &&
   1607        (! GNUNET_TIME_relative_is_zero (precision)) )
   1608   {
   1609     *start = ts;
   1610     return GNUNET_SYSERR;
   1611   }
   1612   *start = GNUNET_TIME_absolute_to_timestamp (
   1613     GNUNET_TIME_round_up (ts.abs_time,
   1614                           ri));
   1615   return GNUNET_OK;
   1616 }
   1617 
   1618 
   1619 /**
   1620  * Find the family entry for the family of the given @a slug
   1621  * in @a oc.
   1622  *
   1623  * @param[in] oc order context to search
   1624  * @param slug slug to search for
   1625  * @return NULL if @a slug was not found
   1626  */
   1627 static struct TALER_MERCHANT_ContractTokenFamily *
   1628 find_family (const struct OrderContext *oc,
   1629              const char *slug)
   1630 {
   1631   for (unsigned int i = 0; i<oc->parse_choices.token_families_len; i++)
   1632   {
   1633     if (0 == strcmp (oc->parse_choices.token_families[i].slug,
   1634                      slug))
   1635     {
   1636       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1637                   "Token family %s already in order\n",
   1638                   slug);
   1639       return &oc->parse_choices.token_families[i];
   1640     }
   1641   }
   1642   return NULL;
   1643 }
   1644 
   1645 
   1646 /**
   1647  * Function called with each applicable family key that should
   1648  * be added to the respective token family of the order.
   1649  *
   1650  * @param cls a `struct OrderContext *` to expand
   1651  * @param tfkd token family key details to add to the contract
   1652  */
   1653 static void
   1654 add_family_key (void *cls,
   1655                 const struct TALER_MERCHANTDB_TokenFamilyKeyDetails *tfkd)
   1656 {
   1657   struct OrderContext *oc = cls;
   1658   const struct TALER_MERCHANTDB_TokenFamilyDetails *tf = &tfkd->token_family;
   1659   struct TALER_MERCHANT_ContractTokenFamily *family;
   1660 
   1661   family = find_family (oc,
   1662                         tf->slug);
   1663   if (NULL == family)
   1664   {
   1665     /* Family not yet in our contract terms, create new entry */
   1666     struct TALER_MERCHANT_ContractTokenFamily new_family = {
   1667       .slug = GNUNET_strdup (tf->slug),
   1668       .name = GNUNET_strdup (tf->name),
   1669       .description = GNUNET_strdup (tf->description),
   1670       .description_i18n = json_incref (tf->description_i18n),
   1671     };
   1672 
   1673     switch (tf->kind)
   1674     {
   1675     case TALER_MERCHANTDB_TFK_Subscription:
   1676       {
   1677         json_t *tdomains = json_object_get (tf->extra_data,
   1678                                             "trusted_domains");
   1679         json_t *dom;
   1680         size_t i;
   1681 
   1682         new_family.kind = TALER_MERCHANT_CONTRACT_TOKEN_KIND_SUBSCRIPTION;
   1683         new_family.critical = true;
   1684         new_family.details.subscription.trusted_domains_len
   1685           = json_array_size (tdomains);
   1686         GNUNET_assert (new_family.details.subscription.trusted_domains_len
   1687                        < UINT_MAX);
   1688         new_family.details.subscription.trusted_domains
   1689           = GNUNET_new_array (
   1690               new_family.details.subscription.trusted_domains_len,
   1691               char *);
   1692         json_array_foreach (tdomains, i, dom)
   1693         {
   1694           const char *val;
   1695 
   1696           val = json_string_value (dom);
   1697           GNUNET_break (NULL != val);
   1698           if (NULL != val)
   1699             new_family.details.subscription.trusted_domains[i]
   1700               = GNUNET_strdup (val);
   1701         }
   1702         break;
   1703       }
   1704     case TALER_MERCHANTDB_TFK_Discount:
   1705       {
   1706         json_t *edomains = json_object_get (tf->extra_data,
   1707                                             "expected_domains");
   1708         json_t *dom;
   1709         size_t i;
   1710 
   1711         new_family.kind = TALER_MERCHANT_CONTRACT_TOKEN_KIND_DISCOUNT;
   1712         new_family.critical = false;
   1713         new_family.details.discount.expected_domains_len
   1714           = json_array_size (edomains);
   1715         GNUNET_assert (new_family.details.discount.expected_domains_len
   1716                        < UINT_MAX);
   1717         new_family.details.discount.expected_domains
   1718           = GNUNET_new_array (
   1719               new_family.details.discount.expected_domains_len,
   1720               char *);
   1721         json_array_foreach (edomains, i, dom)
   1722         {
   1723           const char *val;
   1724 
   1725           val = json_string_value (dom);
   1726           GNUNET_break (NULL != val);
   1727           if (NULL != val)
   1728             new_family.details.discount.expected_domains[i]
   1729               = GNUNET_strdup (val);
   1730         }
   1731         break;
   1732       }
   1733     }
   1734     GNUNET_array_append (oc->parse_choices.token_families,
   1735                          oc->parse_choices.token_families_len,
   1736                          new_family);
   1737     family = &oc->parse_choices.token_families[
   1738       oc->parse_choices.token_families_len - 1];
   1739   }
   1740   if (NULL == tfkd->pub.public_key)
   1741     return;
   1742   for (unsigned int i = 0; i<family->keys_len; i++)
   1743   {
   1744     if (TALER_token_issue_pub_cmp (&family->keys[i].pub,
   1745                                    &tfkd->pub))
   1746     {
   1747       /* A matching key is already in the list. */
   1748       return;
   1749     }
   1750   }
   1751 
   1752   {
   1753     struct TALER_MERCHANT_ContractTokenFamilyKey key;
   1754 
   1755     TALER_token_issue_pub_copy (&key.pub,
   1756                                 &tfkd->pub);
   1757     key.valid_after = tfkd->signature_validity_start;
   1758     key.valid_before = tfkd->signature_validity_end;
   1759     GNUNET_array_append (family->keys,
   1760                          family->keys_len,
   1761                          key);
   1762   }
   1763 }
   1764 
   1765 
   1766 /**
   1767  * Check if the token family with the given @a slug is already present in the
   1768  * list of token families for this order. If not, fetch its details and add it
   1769  * to the list.
   1770  *
   1771  * @param[in,out] oc order context
   1772  * @param slug slug of the token family
   1773  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
   1774  */
   1775 static enum GNUNET_GenericReturnValue
   1776 add_input_token_family (struct OrderContext *oc,
   1777                         const char *slug)
   1778 {
   1779   struct GNUNET_TIME_Timestamp now = GNUNET_TIME_timestamp_get ();
   1780   struct GNUNET_TIME_Timestamp end = oc->parse_order.pay_deadline;
   1781   enum GNUNET_DB_QueryStatus qs;
   1782   enum TALER_ErrorCode ec = TALER_EC_INVALID; /* make compiler happy */
   1783   unsigned int http_status = 0; /* make compiler happy */
   1784 
   1785   qs = TMH_db->lookup_token_family_keys (TMH_db->cls,
   1786                                          oc->hc->instance->settings.id,
   1787                                          slug,
   1788                                          now,
   1789                                          end,
   1790                                          &add_family_key,
   1791                                          oc);
   1792   switch (qs)
   1793   {
   1794   case GNUNET_DB_STATUS_HARD_ERROR:
   1795     GNUNET_break (0);
   1796     http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;
   1797     ec = TALER_EC_GENERIC_DB_FETCH_FAILED;
   1798     break;
   1799   case GNUNET_DB_STATUS_SOFT_ERROR:
   1800     GNUNET_break (0);
   1801     http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;
   1802     ec = TALER_EC_GENERIC_DB_SOFT_FAILURE;
   1803     break;
   1804   case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
   1805     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   1806                 "Input token family slug %s unknown\n",
   1807                 slug);
   1808     http_status = MHD_HTTP_NOT_FOUND;
   1809     ec = TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_TOKEN_FAMILY_SLUG_UNKNOWN;
   1810     break;
   1811   case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
   1812     return GNUNET_OK;
   1813   }
   1814   reply_with_error (oc,
   1815                     http_status,
   1816                     ec,
   1817                     slug);
   1818   return GNUNET_SYSERR;
   1819 }
   1820 
   1821 
   1822 /**
   1823  * Find the index of a key in the @a family that is valid at
   1824  * the time @a valid_at.
   1825  *
   1826  * @param family to search
   1827  * @param valid_at time when the key must be valid
   1828  * @param[out] key_index index to initialize
   1829  * @return #GNUNET_OK if a matching key was found
   1830  */
   1831 static enum GNUNET_GenericReturnValue
   1832 find_key_index (struct TALER_MERCHANT_ContractTokenFamily *family,
   1833                 struct GNUNET_TIME_Timestamp valid_at,
   1834                 unsigned int *key_index)
   1835 {
   1836   for (unsigned int i = 0; i<family->keys_len; i++)
   1837   {
   1838     if ( (GNUNET_TIME_timestamp_cmp (family->keys[i].valid_after,
   1839                                      <=,
   1840                                      valid_at)) &&
   1841          (GNUNET_TIME_timestamp_cmp (family->keys[i].valid_before,
   1842                                      >=,
   1843                                      valid_at)) )
   1844     {
   1845       /* The token family and a matching key already exist. */
   1846       *key_index = i;
   1847       return GNUNET_OK;
   1848     }
   1849   }
   1850   return GNUNET_NO;
   1851 }
   1852 
   1853 
   1854 /**
   1855  * Create fresh key pair based on @a cipher_spec.
   1856  *
   1857  * @param cipher_spec which kind of key pair should we generate
   1858  * @param[out] priv set to new private key
   1859  * @param[out] pub set to new public key
   1860  * @return #GNUNET_OK on success
   1861  */
   1862 static enum GNUNET_GenericReturnValue
   1863 create_key (const char *cipher_spec,
   1864             struct TALER_TokenIssuePrivateKey *priv,
   1865             struct TALER_TokenIssuePublicKey *pub)
   1866 {
   1867   unsigned int len;
   1868   char dummy;
   1869 
   1870   if (0 == strcmp ("cs",
   1871                    cipher_spec))
   1872   {
   1873     GNUNET_CRYPTO_blind_sign_keys_create (
   1874       &priv->private_key,
   1875       &pub->public_key,
   1876       GNUNET_CRYPTO_BSA_CS);
   1877     return GNUNET_OK;
   1878   }
   1879   if (1 ==
   1880       sscanf (cipher_spec,
   1881               "rsa(%u)%c",
   1882               &len,
   1883               &dummy))
   1884   {
   1885     GNUNET_CRYPTO_blind_sign_keys_create (
   1886       &priv->private_key,
   1887       &pub->public_key,
   1888       GNUNET_CRYPTO_BSA_RSA,
   1889       len);
   1890     return GNUNET_OK;
   1891   }
   1892   return GNUNET_SYSERR;
   1893 }
   1894 
   1895 
   1896 /**
   1897  * Check if the token family with the given @a slug is already present in the
   1898  * list of token families for this order. If not, fetch its details and add it
   1899  * to the list. Also checks if there is a public key with that expires after
   1900  * the payment deadline.  If not, generates a new key pair and stores it in
   1901  * the database.
   1902  *
   1903  * @param[in,out] oc order context
   1904  * @param slug slug of the token family
   1905  * @param valid_at time when the token returned must be valid
   1906  * @param[out] key_index set to the index of the respective public
   1907  *    key in the @a slug's token family keys array.
   1908  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
   1909  */
   1910 static enum GNUNET_GenericReturnValue
   1911 add_output_token_family (struct OrderContext *oc,
   1912                          const char *slug,
   1913                          struct GNUNET_TIME_Timestamp valid_at,
   1914                          unsigned int *key_index)
   1915 {
   1916   struct TALER_MERCHANTDB_TokenFamilyKeyDetails key_details;
   1917   struct TALER_MERCHANT_ContractTokenFamily *family;
   1918   enum GNUNET_DB_QueryStatus qs;
   1919 
   1920   family = find_family (oc,
   1921                         slug);
   1922   if ( (NULL != family) &&
   1923        (GNUNET_OK ==
   1924         find_key_index (family,
   1925                         valid_at,
   1926                         key_index)) )
   1927     return GNUNET_OK;
   1928   qs = TMH_db->lookup_token_family_key (TMH_db->cls,
   1929                                         oc->hc->instance->settings.id,
   1930                                         slug,
   1931                                         valid_at,
   1932                                         oc->parse_order.pay_deadline,
   1933                                         &key_details);
   1934   switch (qs)
   1935   {
   1936   case GNUNET_DB_STATUS_HARD_ERROR:
   1937     GNUNET_break (0);
   1938     reply_with_error (oc,
   1939                       MHD_HTTP_INTERNAL_SERVER_ERROR,
   1940                       TALER_EC_GENERIC_DB_FETCH_FAILED,
   1941                       "lookup_token_family_key");
   1942     return GNUNET_SYSERR;
   1943   case GNUNET_DB_STATUS_SOFT_ERROR:
   1944     /* Single-statement transaction shouldn't possibly cause serialization errors.
   1945        Thus treating like a hard error. */
   1946     GNUNET_break (0);
   1947     reply_with_error (oc,
   1948                       MHD_HTTP_INTERNAL_SERVER_ERROR,
   1949                       TALER_EC_GENERIC_DB_SOFT_FAILURE,
   1950                       "lookup_token_family_key");
   1951     return GNUNET_SYSERR;
   1952   case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
   1953     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   1954                 "Output token family slug %s unknown\n",
   1955                 slug);
   1956     reply_with_error (oc,
   1957                       MHD_HTTP_NOT_FOUND,
   1958                       TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_TOKEN_FAMILY_SLUG_UNKNOWN,
   1959                       slug);
   1960     return GNUNET_SYSERR;
   1961   case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
   1962     break;
   1963   }
   1964 
   1965   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1966               "Lookup of token family %s at %llu yielded %s\n",
   1967               slug,
   1968               (unsigned long long) valid_at.abs_time.abs_value_us,
   1969               NULL == key_details.pub.public_key ? "no key" : "a key");
   1970 
   1971   if (NULL == family)
   1972   {
   1973     add_family_key (oc,
   1974                     &key_details);
   1975     family = find_family (oc,
   1976                           slug);
   1977     GNUNET_assert (NULL != family);
   1978   }
   1979   /* we don't need the full family details anymore */
   1980   GNUNET_free (key_details.token_family.slug);
   1981   GNUNET_free (key_details.token_family.name);
   1982   GNUNET_free (key_details.token_family.description);
   1983   json_decref (key_details.token_family.description_i18n);
   1984   json_decref (key_details.token_family.extra_data);
   1985 
   1986   if (NULL != key_details.pub.public_key)
   1987   {
   1988     /* lookup_token_family_key must have found a matching key,
   1989        and it must have been added. Find and use the index. */
   1990     GNUNET_CRYPTO_blind_sign_pub_decref (key_details.pub.public_key);
   1991     GNUNET_CRYPTO_blind_sign_priv_decref (key_details.priv.private_key);
   1992     GNUNET_free (key_details.token_family.cipher_spec);
   1993     GNUNET_assert (GNUNET_OK ==
   1994                    find_key_index (family,
   1995                                    valid_at,
   1996                                    key_index));
   1997     return GNUNET_OK;
   1998   }
   1999 
   2000   /* No suitable key exists, create one! */
   2001   {
   2002     struct TALER_MERCHANT_ContractTokenFamilyKey key;
   2003     enum GNUNET_DB_QueryStatus iqs;
   2004     struct TALER_TokenIssuePrivateKey token_priv;
   2005     struct GNUNET_TIME_Timestamp key_expires;
   2006     struct GNUNET_TIME_Timestamp round_start;
   2007 
   2008     if (GNUNET_OK !=
   2009         get_rounded_time_interval_down (
   2010           key_details.token_family.validity_granularity,
   2011           valid_at,
   2012           &round_start))
   2013     {
   2014       GNUNET_break (0);
   2015       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   2016                   "Unsupported validity granularity interval %s found in database for token family %s!\n",
   2017                   GNUNET_TIME_relative2s (
   2018                     key_details.token_family.validity_granularity,
   2019                     false),
   2020                   slug);
   2021       GNUNET_free (key_details.token_family.cipher_spec);
   2022       reply_with_error (oc,
   2023                         MHD_HTTP_INTERNAL_SERVER_ERROR,
   2024                         TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
   2025                         "get_rounded_time_interval_down failed");
   2026       return GNUNET_SYSERR;
   2027     }
   2028     if (GNUNET_TIME_relative_cmp (
   2029           key_details.token_family.duration,
   2030           <,
   2031           GNUNET_TIME_relative_add (
   2032             key_details.token_family.validity_granularity,
   2033             key_details.token_family.start_offset)))
   2034     {
   2035       GNUNET_break (0);
   2036       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   2037                   "Inconsistent duration %s found in database for token family %s (below validity granularity plus start_offset)!\n",
   2038                   GNUNET_TIME_relative2s (key_details.token_family.duration,
   2039                                           false),
   2040                   slug);
   2041       GNUNET_free (key_details.token_family.cipher_spec);
   2042       reply_with_error (oc,
   2043                         MHD_HTTP_INTERNAL_SERVER_ERROR,
   2044                         TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
   2045                         "duration, validty_granularity and start_offset inconsistent for token family");
   2046       return GNUNET_SYSERR;
   2047     }
   2048     key.valid_after
   2049       = GNUNET_TIME_timestamp_max (
   2050           GNUNET_TIME_absolute_to_timestamp (
   2051             GNUNET_TIME_absolute_subtract (
   2052               round_start.abs_time,
   2053               key_details.token_family.start_offset)),
   2054           key_details.token_family.valid_after);
   2055     key.valid_before
   2056       = GNUNET_TIME_timestamp_min (
   2057           GNUNET_TIME_absolute_to_timestamp (
   2058             GNUNET_TIME_absolute_add (
   2059               key.valid_after.abs_time,
   2060               key_details.token_family.duration)),
   2061           key_details.token_family.valid_before);
   2062     GNUNET_assert (GNUNET_OK ==
   2063                    get_rounded_time_interval_down (
   2064                      key_details.token_family.validity_granularity,
   2065                      key.valid_before,
   2066                      &key_expires));
   2067     if (GNUNET_TIME_timestamp_cmp (
   2068           key_expires,
   2069           ==,
   2070           round_start))
   2071     {
   2072       /* valid_before does not actually end after the
   2073          next rounded validity period would start;
   2074          determine next rounded validity period
   2075          start point and extend valid_before to cover
   2076          the full validity period */
   2077       GNUNET_assert (
   2078         GNUNET_OK ==
   2079         get_rounded_time_interval_up (
   2080           key_details.token_family.validity_granularity,
   2081           key.valid_before,
   2082           &key_expires));
   2083       /* This should basically always end up being key_expires */
   2084       key.valid_before = GNUNET_TIME_timestamp_max (key.valid_before,
   2085                                                     key_expires);
   2086     }
   2087     if (GNUNET_OK !=
   2088         create_key (key_details.token_family.cipher_spec,
   2089                     &token_priv,
   2090                     &key.pub))
   2091     {
   2092       GNUNET_break (0);
   2093       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   2094                   "Unsupported cipher family %s found in database for token family %s!\n",
   2095                   key_details.token_family.cipher_spec,
   2096                   slug);
   2097       GNUNET_free (key_details.token_family.cipher_spec);
   2098       reply_with_error (oc,
   2099                         MHD_HTTP_INTERNAL_SERVER_ERROR,
   2100                         TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
   2101                         "invalid cipher stored in local database for token family");
   2102       return GNUNET_SYSERR;
   2103     }
   2104     GNUNET_free (key_details.token_family.cipher_spec);
   2105     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2106                 "Storing new key for slug %s of %s\n",
   2107                 slug,
   2108                 oc->hc->instance->settings.id);
   2109     iqs = TMH_db->insert_token_family_key (TMH_db->cls,
   2110                                            oc->hc->instance->settings.id,
   2111                                            slug,
   2112                                            &key.pub,
   2113                                            &token_priv,
   2114                                            key_expires,
   2115                                            key.valid_after,
   2116                                            key.valid_before);
   2117     GNUNET_CRYPTO_blind_sign_priv_decref (token_priv.private_key);
   2118     switch (iqs)
   2119     {
   2120     case GNUNET_DB_STATUS_HARD_ERROR:
   2121       GNUNET_break (0);
   2122       reply_with_error (oc,
   2123                         MHD_HTTP_INTERNAL_SERVER_ERROR,
   2124                         TALER_EC_GENERIC_DB_STORE_FAILED,
   2125                         NULL);
   2126       return GNUNET_SYSERR;
   2127     case GNUNET_DB_STATUS_SOFT_ERROR:
   2128       /* Single-statement transaction shouldn't possibly cause serialization errors.
   2129          Thus treating like a hard error. */
   2130       GNUNET_break (0);
   2131       reply_with_error (oc,
   2132                         MHD_HTTP_INTERNAL_SERVER_ERROR,
   2133                         TALER_EC_GENERIC_DB_SOFT_FAILURE,
   2134                         NULL);
   2135       return GNUNET_SYSERR;
   2136     case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
   2137       GNUNET_break (0);
   2138       reply_with_error (oc,
   2139                         MHD_HTTP_INTERNAL_SERVER_ERROR,
   2140                         TALER_EC_GENERIC_DB_STORE_FAILED,
   2141                         NULL);
   2142       return GNUNET_SYSERR;
   2143     case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
   2144       break;
   2145     }
   2146     *key_index = family->keys_len;
   2147     GNUNET_array_append (family->keys,
   2148                          family->keys_len,
   2149                          key);
   2150   }
   2151   return GNUNET_OK;
   2152 }
   2153 
   2154 
   2155 /**
   2156  * Build JSON array that represents all of the token families
   2157  * in the contract.
   2158  *
   2159  * @param[in] oc v1-style order context
   2160  * @return JSON array with token families for the contract
   2161  */
   2162 static json_t *
   2163 output_token_families (struct OrderContext *oc)
   2164 {
   2165   json_t *token_families = json_object ();
   2166 
   2167   GNUNET_assert (NULL != token_families);
   2168   for (unsigned int i = 0; i<oc->parse_choices.token_families_len; i++)
   2169   {
   2170     const struct TALER_MERCHANT_ContractTokenFamily *family
   2171       = &oc->parse_choices.token_families[i];
   2172     json_t *jfamily;
   2173 
   2174     jfamily = TALER_MERCHANT_json_from_token_family (family);
   2175 
   2176     GNUNET_assert (jfamily != NULL);
   2177 
   2178     GNUNET_assert (0 ==
   2179                    json_object_set_new (token_families,
   2180                                         family->slug,
   2181                                         jfamily));
   2182   }
   2183   return token_families;
   2184 }
   2185 
   2186 
   2187 /**
   2188  * Build JSON array that represents all of the contract choices
   2189  * in the contract.
   2190  *
   2191  * @param[in] oc v1-style order context
   2192  * @return JSON array with token families for the contract
   2193  */
   2194 static json_t *
   2195 output_contract_choices (struct OrderContext *oc)
   2196 {
   2197   json_t *choices = json_array ();
   2198 
   2199   GNUNET_assert (NULL != choices);
   2200   for (unsigned int i = 0; i<oc->parse_choices.choices_len; i++)
   2201   {
   2202     oc->parse_choices.choices[i].max_fee =
   2203       oc->set_max_fee.details.v1.max_fees[i];
   2204     GNUNET_assert (0 == json_array_append_new (
   2205                      choices,
   2206                      TALER_MERCHANT_json_from_contract_choice (
   2207                        &oc->parse_choices.choices[i],
   2208                        false)));
   2209   }
   2210 
   2211   return choices;
   2212 }
   2213 
   2214 
   2215 /**
   2216  * Serialize order into @a oc->serialize_order.contract,
   2217  * ready to be stored in the database. Upon success, continue
   2218  * processing with check_contract().
   2219  *
   2220  * @param[in,out] oc order context
   2221  */
   2222 static void
   2223 phase_serialize_order (struct OrderContext *oc)
   2224 {
   2225   const struct TALER_MERCHANTDB_InstanceSettings *settings =
   2226     &oc->hc->instance->settings;
   2227   json_t *merchant;
   2228 
   2229   merchant = GNUNET_JSON_PACK (
   2230     GNUNET_JSON_pack_string ("name",
   2231                              settings->name),
   2232     GNUNET_JSON_pack_allow_null (
   2233       GNUNET_JSON_pack_string ("website",
   2234                                settings->website)),
   2235     GNUNET_JSON_pack_allow_null (
   2236       GNUNET_JSON_pack_string ("email",
   2237                                settings->email)),
   2238     GNUNET_JSON_pack_allow_null (
   2239       GNUNET_JSON_pack_string ("logo",
   2240                                settings->logo)));
   2241   GNUNET_assert (NULL != merchant);
   2242   {
   2243     json_t *loca;
   2244 
   2245     /* Handle merchant address */
   2246     loca = settings->address;
   2247     if (NULL != loca)
   2248     {
   2249       loca = json_deep_copy (loca);
   2250       GNUNET_assert (NULL != loca);
   2251       GNUNET_assert (0 ==
   2252                      json_object_set_new (merchant,
   2253                                           "address",
   2254                                           loca));
   2255     }
   2256   }
   2257   {
   2258     json_t *juri;
   2259 
   2260     /* Handle merchant jurisdiction */
   2261     juri = settings->jurisdiction;
   2262     if (NULL != juri)
   2263     {
   2264       juri = json_deep_copy (juri);
   2265       GNUNET_assert (NULL != juri);
   2266       GNUNET_assert (0 ==
   2267                      json_object_set_new (merchant,
   2268                                           "jurisdiction",
   2269                                           juri));
   2270     }
   2271   }
   2272 
   2273   oc->serialize_order.contract = GNUNET_JSON_PACK (
   2274     GNUNET_JSON_pack_int64 ("version",
   2275                             oc->parse_order.version),
   2276     GNUNET_JSON_pack_string ("summary",
   2277                              oc->parse_order.summary),
   2278     GNUNET_JSON_pack_allow_null (
   2279       GNUNET_JSON_pack_object_incref (
   2280         "summary_i18n",
   2281         (json_t *) oc->parse_order.summary_i18n)),
   2282     GNUNET_JSON_pack_allow_null (
   2283       GNUNET_JSON_pack_string ("public_reorder_url",
   2284                                oc->parse_order.public_reorder_url)),
   2285     GNUNET_JSON_pack_allow_null (
   2286       GNUNET_JSON_pack_string ("fulfillment_message",
   2287                                oc->parse_order.fulfillment_message)),
   2288     GNUNET_JSON_pack_allow_null (
   2289       GNUNET_JSON_pack_object_incref (
   2290         "fulfillment_message_i18n",
   2291         (json_t *) oc->parse_order.fulfillment_message_i18n)),
   2292     GNUNET_JSON_pack_allow_null (
   2293       GNUNET_JSON_pack_string ("fulfillment_url",
   2294                                oc->parse_order.fulfillment_url)),
   2295     GNUNET_JSON_pack_allow_null (
   2296       GNUNET_JSON_pack_uint64 ("minimum_age",
   2297                                oc->parse_order.minimum_age)),
   2298     GNUNET_JSON_pack_allow_null (
   2299       GNUNET_JSON_pack_uint64 ("default_money_pot",
   2300                                oc->parse_order.order_default_money_pot)),
   2301     GNUNET_JSON_pack_array_incref ("products",
   2302                                    oc->merge_inventory.products),
   2303     GNUNET_JSON_pack_data_auto ("h_wire",
   2304                                 &oc->select_wire_method.wm->h_wire),
   2305     GNUNET_JSON_pack_string ("wire_method",
   2306                              oc->select_wire_method.wm->wire_method),
   2307     GNUNET_JSON_pack_string ("order_id",
   2308                              oc->parse_order.order_id),
   2309     GNUNET_JSON_pack_timestamp ("timestamp",
   2310                                 oc->parse_order.timestamp),
   2311     GNUNET_JSON_pack_timestamp ("pay_deadline",
   2312                                 oc->parse_order.pay_deadline),
   2313     GNUNET_JSON_pack_timestamp ("wire_transfer_deadline",
   2314                                 oc->parse_order.wire_deadline),
   2315     GNUNET_JSON_pack_allow_null (
   2316       GNUNET_JSON_pack_timestamp ("delivery_date",
   2317                                   oc->parse_order.delivery_date)),
   2318     GNUNET_JSON_pack_allow_null (
   2319       GNUNET_JSON_pack_object_incref (
   2320         "delivery_location",
   2321         (json_t *) oc->parse_order.delivery_location)),
   2322     GNUNET_JSON_pack_string ("merchant_base_url",
   2323                              oc->parse_order.merchant_base_url),
   2324     GNUNET_JSON_pack_object_steal ("merchant",
   2325                                    merchant),
   2326     GNUNET_JSON_pack_data_auto ("merchant_pub",
   2327                                 &oc->hc->instance->merchant_pub),
   2328     GNUNET_JSON_pack_array_incref ("exchanges",
   2329                                    oc->select_wire_method.exchanges),
   2330     GNUNET_JSON_pack_allow_null (
   2331       GNUNET_JSON_pack_object_incref ("extra",
   2332                                       (json_t *) oc->parse_order.extra))
   2333     );
   2334 
   2335   {
   2336     json_t *xtra;
   2337 
   2338     switch (oc->parse_order.version)
   2339     {
   2340     case TALER_MERCHANT_CONTRACT_VERSION_0:
   2341       xtra = GNUNET_JSON_PACK (
   2342         TALER_JSON_pack_amount ("max_fee",
   2343                                 &oc->set_max_fee.details.v0.max_fee),
   2344         GNUNET_JSON_pack_allow_null (
   2345           TALER_JSON_pack_amount ("tip",
   2346                                   oc->parse_order.details.v0.no_tip
   2347                                   ? NULL
   2348                                   : &oc->parse_order.details.v0.tip)),
   2349         TALER_JSON_pack_amount ("amount",
   2350                                 &oc->parse_order.details.v0.brutto));
   2351       break;
   2352     case TALER_MERCHANT_CONTRACT_VERSION_1:
   2353       {
   2354         json_t *token_families = output_token_families (oc);
   2355         json_t *choices = output_contract_choices (oc);
   2356 
   2357         if ( (NULL == token_families) ||
   2358              (NULL == choices) )
   2359         {
   2360           GNUNET_break (0);
   2361           return;
   2362         }
   2363         xtra = GNUNET_JSON_PACK (
   2364           GNUNET_JSON_pack_array_steal ("choices",
   2365                                         choices),
   2366           GNUNET_JSON_pack_object_steal ("token_families",
   2367                                          token_families));
   2368         break;
   2369       }
   2370     default:
   2371       GNUNET_assert (0);
   2372     }
   2373     GNUNET_assert (0 ==
   2374                    json_object_update (oc->serialize_order.contract,
   2375                                        xtra));
   2376     json_decref (xtra);
   2377   }
   2378 
   2379 
   2380   /* Pack does not work here, because it doesn't set zero-values for timestamps */
   2381   GNUNET_assert (0 ==
   2382                  json_object_set_new (oc->serialize_order.contract,
   2383                                       "refund_deadline",
   2384                                       GNUNET_JSON_from_timestamp (
   2385                                         oc->parse_order.refund_deadline)));
   2386   /* auto_refund should only be set if it is not 0 */
   2387   if (! GNUNET_TIME_relative_is_zero (oc->parse_order.auto_refund))
   2388   {
   2389     /* Pack does not work here, because it sets zero-values for relative times */
   2390     GNUNET_assert (0 ==
   2391                    json_object_set_new (oc->serialize_order.contract,
   2392                                         "auto_refund",
   2393                                         GNUNET_JSON_from_time_rel (
   2394                                           oc->parse_order.auto_refund)));
   2395   }
   2396 
   2397   oc->phase++;
   2398 }
   2399 
   2400 
   2401 /* ***************** ORDER_PHASE_SET_MAX_FEE **************** */
   2402 
   2403 
   2404 /**
   2405  * Set @a max_fee in @a oc based on @a max_stefan_fee value if not overridden
   2406  * by @a client_fee.  If neither is set, set the fee to zero using currency
   2407  * from @a brutto.
   2408  *
   2409  * @param[in,out] oc order context
   2410  * @param brutto brutto amount to compute fee for
   2411  * @param client_fee client-given fee override (or invalid)
   2412  * @param max_stefan_fee maximum STEFAN fee of any exchange
   2413  * @param max_fee set to the maximum stefan fee
   2414  */
   2415 static void
   2416 compute_fee (struct OrderContext *oc,
   2417              const struct TALER_Amount *brutto,
   2418              const struct TALER_Amount *client_fee,
   2419              const struct TALER_Amount *max_stefan_fee,
   2420              struct TALER_Amount *max_fee)
   2421 {
   2422   const struct TALER_MERCHANTDB_InstanceSettings *settings
   2423     = &oc->hc->instance->settings;
   2424 
   2425   if (GNUNET_OK ==
   2426       TALER_amount_is_valid (client_fee))
   2427   {
   2428     *max_fee = *client_fee;
   2429     return;
   2430   }
   2431   if ( (settings->use_stefan) &&
   2432        (NULL != max_stefan_fee) &&
   2433        (GNUNET_OK ==
   2434         TALER_amount_is_valid (max_stefan_fee)) )
   2435   {
   2436     *max_fee = *max_stefan_fee;
   2437     return;
   2438   }
   2439   GNUNET_assert (
   2440     GNUNET_OK ==
   2441     TALER_amount_set_zero (brutto->currency,
   2442                            max_fee));
   2443 }
   2444 
   2445 
   2446 /**
   2447  * Initialize "set_max_fee" in @a oc based on STEFAN value or client
   2448  * preference. Upon success, continue processing in next phase.
   2449  *
   2450  * @param[in,out] oc order context
   2451  */
   2452 static void
   2453 phase_set_max_fee (struct OrderContext *oc)
   2454 {
   2455   switch (oc->parse_order.version)
   2456   {
   2457   case TALER_MERCHANT_CONTRACT_VERSION_0:
   2458     compute_fee (oc,
   2459                  &oc->parse_order.details.v0.brutto,
   2460                  &oc->parse_order.details.v0.max_fee,
   2461                  &oc->set_exchanges.details.v0.max_stefan_fee,
   2462                  &oc->set_max_fee.details.v0.max_fee);
   2463     break;
   2464   case TALER_MERCHANT_CONTRACT_VERSION_1:
   2465     oc->set_max_fee.details.v1.max_fees
   2466       = GNUNET_new_array (oc->parse_choices.choices_len,
   2467                           struct TALER_Amount);
   2468     for (unsigned int i = 0; i<oc->parse_choices.choices_len; i++)
   2469       compute_fee (oc,
   2470                    &oc->parse_choices.choices[i].amount,
   2471                    &oc->parse_choices.choices[i].max_fee,
   2472                    NULL != oc->set_exchanges.details.v1.max_stefan_fees
   2473                    ? &oc->set_exchanges.details.v1.max_stefan_fees[i]
   2474                    : NULL,
   2475                    &oc->set_max_fee.details.v1.max_fees[i]);
   2476     break;
   2477   default:
   2478     GNUNET_break (0);
   2479     break;
   2480   }
   2481   oc->phase++;
   2482 }
   2483 
   2484 
   2485 /* ***************** ORDER_PHASE_SELECT_WIRE_METHOD **************** */
   2486 
   2487 /**
   2488  * Phase to select a wire method that will be acceptable for the order.
   2489  * If none is "perfect" (allows all choices), might jump back to the
   2490  * previous phase to force "/keys" downloads to see if that helps.
   2491  *
   2492  * @param[in,out] oc order context
   2493  */
   2494 static void
   2495 phase_select_wire_method (struct OrderContext *oc)
   2496 {
   2497   const struct TALER_Amount *ea;
   2498   struct WireMethodCandidate *best = NULL;
   2499   unsigned int max_choices = 0;
   2500   unsigned int want_choices = 0;
   2501 
   2502   for (struct WireMethodCandidate *wmc = oc->add_payment_details.wmc_head;
   2503        NULL != wmc;
   2504        wmc = wmc->next)
   2505   {
   2506     unsigned int num_choices = 0;
   2507 
   2508     switch (oc->parse_order.version)
   2509     {
   2510     case TALER_MERCHANT_CONTRACT_VERSION_0:
   2511       want_choices = 1;
   2512       ea = &oc->parse_order.details.v0.brutto;
   2513       if (TALER_amount_is_zero (ea) ||
   2514           TALER_amount_set_test_above (&wmc->total_exchange_limits,
   2515                                        ea))
   2516         num_choices++;
   2517       break;
   2518     case TALER_MERCHANT_CONTRACT_VERSION_1:
   2519       want_choices = oc->parse_choices.choices_len;
   2520       for (unsigned int i = 0; i<oc->parse_choices.choices_len; i++)
   2521       {
   2522         ea = &oc->parse_choices.choices[i].amount;
   2523         if (TALER_amount_is_zero (ea) ||
   2524             TALER_amount_set_test_above (&wmc->total_exchange_limits,
   2525                                          ea))
   2526           num_choices++;
   2527       }
   2528       break;
   2529     default:
   2530       GNUNET_assert (0);
   2531     }
   2532     if (num_choices > max_choices)
   2533     {
   2534       best = wmc;
   2535       max_choices = num_choices;
   2536     }
   2537   }
   2538 
   2539   if ( (want_choices > max_choices) &&
   2540        (oc->set_exchanges.promising_exchange) &&
   2541        (! oc->set_exchanges.forced_reload) )
   2542   {
   2543     oc->set_exchanges.exchange_ok = false;
   2544     /* Not all choices in the contract can work with these
   2545        exchanges, try again with forcing /keys download */
   2546     for (struct WireMethodCandidate *wmc = oc->add_payment_details.wmc_head;
   2547          NULL != wmc;
   2548          wmc = wmc->next)
   2549     {
   2550       json_array_clear (wmc->exchanges);
   2551       TALER_amount_set_free (&wmc->total_exchange_limits);
   2552     }
   2553     oc->phase = ORDER_PHASE_SET_EXCHANGES;
   2554     return;
   2555   }
   2556 
   2557   if ( (NULL == best) &&
   2558        (NULL != oc->parse_request.payment_target) )
   2559   {
   2560     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   2561                 "Cannot create order: lacking suitable exchanges for payment target `%s'\n",
   2562                 oc->parse_request.payment_target);
   2563     reply_with_error (
   2564       oc,
   2565       MHD_HTTP_CONFLICT,
   2566       TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_NO_EXCHANGES_FOR_WIRE_METHOD,
   2567       oc->parse_request.payment_target);
   2568     return;
   2569   }
   2570 
   2571   if (NULL == best)
   2572   {
   2573     MHD_RESULT mret;
   2574 
   2575     /* We actually do not have ANY workable exchange(s) */
   2576     mret = TALER_MHD_reply_json_steal (
   2577       oc->connection,
   2578       GNUNET_JSON_PACK (
   2579         TALER_JSON_pack_ec (
   2580           TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_AMOUNT_EXCEEDS_LEGAL_LIMITS),
   2581         GNUNET_JSON_pack_array_incref (
   2582           "exchange_rejections",
   2583           oc->set_exchanges.exchange_rejections)),
   2584       MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS);
   2585     finalize_order (oc,
   2586                     mret);
   2587     return;
   2588   }
   2589 
   2590   if (want_choices > max_choices)
   2591   {
   2592     /* Some choices are unpayable */
   2593     GNUNET_log (
   2594       GNUNET_ERROR_TYPE_WARNING,
   2595       "Creating order, but some choices do not work with the selected wire method\n");
   2596   }
   2597   if ( (0 == json_array_size (best->exchanges)) &&
   2598        (oc->add_payment_details.need_exchange) )
   2599   {
   2600     /* We did not find any reasonable exchange */
   2601     GNUNET_log (
   2602       GNUNET_ERROR_TYPE_WARNING,
   2603       "Creating order, but only for choices without payment\n");
   2604   }
   2605 
   2606   oc->select_wire_method.wm
   2607     = best->wm;
   2608   oc->select_wire_method.exchanges
   2609     = json_incref (best->exchanges);
   2610   oc->phase++;
   2611 }
   2612 
   2613 
   2614 /* ***************** ORDER_PHASE_SET_EXCHANGES **************** */
   2615 
   2616 /**
   2617  * Exchange `/keys` processing is done, resume handling
   2618  * the order.
   2619  *
   2620  * @param[in,out] oc context to resume
   2621  */
   2622 static void
   2623 resume_with_keys (struct OrderContext *oc)
   2624 {
   2625   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2626               "Resuming order processing after /keys downloads\n");
   2627   GNUNET_assert (GNUNET_YES == oc->suspended);
   2628   GNUNET_CONTAINER_DLL_remove (oc_head,
   2629                                oc_tail,
   2630                                oc);
   2631   oc->suspended = GNUNET_NO;
   2632   MHD_resume_connection (oc->connection);
   2633   TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */
   2634 }
   2635 
   2636 
   2637 /**
   2638  * Given a @a brutto amount for exchange with @a keys, set the
   2639  * @a stefan_fee. Note that @a stefan_fee is updated to the maximum
   2640  * of the input and the computed fee.
   2641  *
   2642  * @param[in,out] keys exchange keys
   2643  * @param brutto some brutto amount the client is to pay
   2644  * @param[in,out] stefan_fee set to STEFAN fee to be paid by the merchant
   2645  */
   2646 static void
   2647 compute_stefan_fee (const struct TALER_EXCHANGE_Keys *keys,
   2648                     const struct TALER_Amount *brutto,
   2649                     struct TALER_Amount *stefan_fee)
   2650 {
   2651   struct TALER_Amount net;
   2652 
   2653   if (GNUNET_SYSERR !=
   2654       TALER_EXCHANGE_keys_stefan_b2n (keys,
   2655                                       brutto,
   2656                                       &net))
   2657   {
   2658     struct TALER_Amount fee;
   2659 
   2660     TALER_EXCHANGE_keys_stefan_round (keys,
   2661                                       &net);
   2662     if (-1 == TALER_amount_cmp (brutto,
   2663                                 &net))
   2664     {
   2665       /* brutto < netto! */
   2666       /* => after rounding, there is no real difference */
   2667       net = *brutto;
   2668     }
   2669     GNUNET_assert (0 <=
   2670                    TALER_amount_subtract (&fee,
   2671                                           brutto,
   2672                                           &net));
   2673     if ( (GNUNET_OK !=
   2674           TALER_amount_is_valid (stefan_fee)) ||
   2675          (-1 == TALER_amount_cmp (stefan_fee,
   2676                                   &fee)) )
   2677     {
   2678       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2679                   "Updated STEFAN-based fee to %s\n",
   2680                   TALER_amount2s (&fee));
   2681       *stefan_fee = fee;
   2682     }
   2683   }
   2684 }
   2685 
   2686 
   2687 /**
   2688  * Update MAX STEFAN fees based on @a keys.
   2689  *
   2690  * @param[in,out] oc order context to update
   2691  * @param keys keys to derive STEFAN fees from
   2692  */
   2693 static void
   2694 update_stefan (struct OrderContext *oc,
   2695                const struct TALER_EXCHANGE_Keys *keys)
   2696 {
   2697   switch (oc->parse_order.version)
   2698   {
   2699   case TALER_MERCHANT_CONTRACT_VERSION_0:
   2700     compute_stefan_fee (keys,
   2701                         &oc->parse_order.details.v0.brutto,
   2702                         &oc->set_exchanges.details.v0.max_stefan_fee);
   2703     break;
   2704   case TALER_MERCHANT_CONTRACT_VERSION_1:
   2705     oc->set_exchanges.details.v1.max_stefan_fees
   2706       = GNUNET_new_array (oc->parse_choices.choices_len,
   2707                           struct TALER_Amount);
   2708     for (unsigned int i = 0; i<oc->parse_choices.choices_len; i++)
   2709       if (0 == strcasecmp (keys->currency,
   2710                            oc->parse_choices.choices[i].amount.currency))
   2711         compute_stefan_fee (keys,
   2712                             &oc->parse_choices.choices[i].amount,
   2713                             &oc->set_exchanges.details.v1.max_stefan_fees[i]);
   2714     break;
   2715   default:
   2716     GNUNET_assert (0);
   2717   }
   2718 }
   2719 
   2720 
   2721 /**
   2722  * Check our KYC status at all exchanges as our current limit is
   2723  * too low and we failed to create an order.
   2724  *
   2725  * @param oc order context
   2726  * @param wmc wire method candidate to notify for
   2727  * @param exchange_url exchange to notify about
   2728  */
   2729 static void
   2730 notify_kyc_required (const struct OrderContext *oc,
   2731                      const struct WireMethodCandidate *wmc,
   2732                      const char *exchange_url)
   2733 {
   2734   struct GNUNET_DB_EventHeaderP es = {
   2735     .size = htons (sizeof (es)),
   2736     .type = htons (TALER_DBEVENT_MERCHANT_EXCHANGE_KYC_RULE_TRIGGERED)
   2737   };
   2738   char *hws;
   2739   char *extra;
   2740 
   2741   hws = GNUNET_STRINGS_data_to_string_alloc (
   2742     &wmc->wm->h_wire,
   2743     sizeof (wmc->wm->h_wire));
   2744 
   2745   GNUNET_asprintf (&extra,
   2746                    "%s %s",
   2747                    hws,
   2748                    exchange_url);
   2749   TMH_db->event_notify (TMH_db->cls,
   2750                         &es,
   2751                         extra,
   2752                         strlen (extra) + 1);
   2753   GNUNET_free (extra);
   2754   GNUNET_free (hws);
   2755 }
   2756 
   2757 
   2758 /**
   2759  * Add a reason why a particular exchange was rejected to our
   2760  * response data.
   2761  *
   2762  * @param[in,out] oc order context to update
   2763  * @param exchange_url exchange this is about
   2764  * @param ec error code to set for the exchange
   2765  */
   2766 static void
   2767 add_rejection (struct OrderContext *oc,
   2768                const char *exchange_url,
   2769                enum TALER_ErrorCode ec)
   2770 {
   2771   if (NULL == oc->set_exchanges.exchange_rejections)
   2772   {
   2773     oc->set_exchanges.exchange_rejections = json_array ();
   2774     GNUNET_assert (NULL != oc->set_exchanges.exchange_rejections);
   2775   }
   2776   GNUNET_assert (0 ==
   2777                  json_array_append_new (
   2778                    oc->set_exchanges.exchange_rejections,
   2779                    GNUNET_JSON_PACK (
   2780                      GNUNET_JSON_pack_string ("exchange_url",
   2781                                               exchange_url),
   2782                      TALER_JSON_pack_ec (ec))));
   2783 }
   2784 
   2785 
   2786 /**
   2787  * Checks the limits that apply for this @a exchange and
   2788  * the @a wmc and if the exchange is acceptable at all, adds it
   2789  * to the list of exchanges for the @a wmc.
   2790  *
   2791  * @param oc context of the order
   2792  * @param exchange internal handle for the exchange
   2793  * @param exchange_url base URL of this exchange
   2794  * @param wmc wire method to evaluate this exchange for
   2795  * @return true if the exchange is acceptable for the contract
   2796  */
   2797 static bool
   2798 get_acceptable (struct OrderContext *oc,
   2799                 const struct TMH_Exchange *exchange,
   2800                 const char *exchange_url,
   2801                 struct WireMethodCandidate *wmc)
   2802 {
   2803   const struct TALER_Amount *max_needed = NULL;
   2804   unsigned int priority = 42; /* make compiler happy */
   2805   json_t *j_exchange;
   2806   enum TMH_ExchangeStatus res;
   2807   struct TALER_Amount max_amount;
   2808 
   2809   for (unsigned int i = 0;
   2810        i<oc->add_payment_details.num_max_choice_limits;
   2811        i++)
   2812   {
   2813     struct TALER_Amount *val = &oc->add_payment_details.max_choice_limits[i];
   2814 
   2815     if (0 == strcasecmp (val->currency,
   2816                          TMH_EXCHANGES_get_currency (exchange)))
   2817     {
   2818       max_needed = val;
   2819       break;
   2820     }
   2821   }
   2822   if (NULL == max_needed)
   2823   {
   2824     /* exchange currency not relevant for any of our choices, skip it */
   2825     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2826                 "Exchange %s with currency `%s' is not applicable to this order\n",
   2827                 exchange_url,
   2828                 TMH_EXCHANGES_get_currency (exchange));
   2829     add_rejection (oc,
   2830                    exchange_url,
   2831                    TALER_EC_MERCHANT_GENERIC_CURRENCY_MISMATCH);
   2832     return false;
   2833   }
   2834 
   2835   max_amount = *max_needed;
   2836   res = TMH_exchange_check_debit (
   2837     oc->hc->instance->settings.id,
   2838     exchange,
   2839     wmc->wm,
   2840     &max_amount);
   2841   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2842               "Exchange %s evaluated at %d with max %s\n",
   2843               exchange_url,
   2844               res,
   2845               TALER_amount2s (&max_amount));
   2846   if (TALER_amount_is_zero (&max_amount))
   2847   {
   2848     if (! TALER_amount_is_zero (max_needed))
   2849     {
   2850       /* Trigger re-checking the current deposit limit when
   2851        * paying non-zero amount with zero deposit limit */
   2852       notify_kyc_required (oc,
   2853                            wmc,
   2854                            exchange_url);
   2855     }
   2856     /* If deposit is impossible, we don't list the
   2857      * exchange in the contract terms. */
   2858     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2859                 "Exchange %s deposit limit is zero, skipping it\n",
   2860                 exchange_url);
   2861     add_rejection (oc,
   2862                    exchange_url,
   2863                    TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_EXCHANGE_LEGALLY_REFUSED);
   2864     return false;
   2865   }
   2866   switch (res)
   2867   {
   2868   case TMH_ES_OK:
   2869   case TMH_ES_RETRY_OK:
   2870     priority = 1024;   /* high */
   2871     oc->set_exchanges.exchange_ok = true;
   2872     break;
   2873   case TMH_ES_NO_ACC:
   2874     if (oc->set_exchanges.forced_reload)
   2875       priority = 0;   /* fresh negative response */
   2876     else
   2877       priority = 512; /* stale negative response */
   2878     break;
   2879   case TMH_ES_NO_CURR:
   2880     if (oc->set_exchanges.forced_reload)
   2881       priority = 0;   /* fresh negative response */
   2882     else
   2883       priority = 512; /* stale negative response */
   2884     break;
   2885   case TMH_ES_NO_KEYS:
   2886     if (oc->set_exchanges.forced_reload)
   2887       priority = 256;   /* fresh, no accounts yet */
   2888     else
   2889       priority = 768;  /* stale, no accounts yet */
   2890     break;
   2891   case TMH_ES_NO_ACC_RETRY_OK:
   2892     if (oc->set_exchanges.forced_reload)
   2893     {
   2894       priority = 0;   /* fresh negative response */
   2895     }
   2896     else
   2897     {
   2898       oc->set_exchanges.promising_exchange = true;
   2899       priority = 512; /* stale negative response */
   2900     }
   2901     break;
   2902   case TMH_ES_NO_CURR_RETRY_OK:
   2903     if (oc->set_exchanges.forced_reload)
   2904       priority = 0;   /* fresh negative response */
   2905     else
   2906       priority = 512; /* stale negative response */
   2907     break;
   2908   case TMH_ES_NO_KEYS_RETRY_OK:
   2909     if (oc->set_exchanges.forced_reload)
   2910     {
   2911       priority = 256;   /* fresh, no accounts yet */
   2912     }
   2913     else
   2914     {
   2915       oc->set_exchanges.promising_exchange = true;
   2916       priority = 768;  /* stale, no accounts yet */
   2917     }
   2918     break;
   2919   }
   2920   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2921               "Exchange %s deposit limit is %s, adding it!\n",
   2922               exchange_url,
   2923               TALER_amount2s (&max_amount));
   2924 
   2925   j_exchange = GNUNET_JSON_PACK (
   2926     GNUNET_JSON_pack_string ("url",
   2927                              exchange_url),
   2928     GNUNET_JSON_pack_uint64 ("priority",
   2929                              priority),
   2930     TALER_JSON_pack_amount ("max_contribution",
   2931                             &max_amount),
   2932     GNUNET_JSON_pack_data_auto ("master_pub",
   2933                                 TMH_EXCHANGES_get_master_pub (exchange)));
   2934   GNUNET_assert (NULL != j_exchange);
   2935   /* Add exchange to list of exchanges for this wire method
   2936      candidate */
   2937   GNUNET_assert (0 ==
   2938                  json_array_append_new (wmc->exchanges,
   2939                                         j_exchange));
   2940   GNUNET_assert (0 <=
   2941                  TALER_amount_set_add (&wmc->total_exchange_limits,
   2942                                        &max_amount,
   2943                                        max_needed));
   2944   return true;
   2945 }
   2946 
   2947 
   2948 /**
   2949  * Function called with the result of a #TMH_EXCHANGES_keys4exchange()
   2950  * operation.
   2951  *
   2952  * @param cls closure with our `struct RekeyExchange *`
   2953  * @param keys the keys of the exchange
   2954  * @param exchange representation of the exchange
   2955  */
   2956 static void
   2957 keys_cb (
   2958   void *cls,
   2959   struct TALER_EXCHANGE_Keys *keys,
   2960   struct TMH_Exchange *exchange)
   2961 {
   2962   struct RekeyExchange *rx = cls;
   2963   struct OrderContext *oc = rx->oc;
   2964   const struct TALER_MERCHANTDB_InstanceSettings *settings =
   2965     &oc->hc->instance->settings;
   2966   bool applicable = false;
   2967 
   2968   rx->fo = NULL;
   2969   GNUNET_CONTAINER_DLL_remove (oc->set_exchanges.pending_reload_head,
   2970                                oc->set_exchanges.pending_reload_tail,
   2971                                rx);
   2972   if (NULL == keys)
   2973   {
   2974     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   2975                 "Failed to download %skeys\n",
   2976                 rx->url);
   2977     oc->set_exchanges.promising_exchange = true;
   2978     add_rejection (oc,
   2979                    rx->url,
   2980                    TALER_EC_MERCHANT_GENERIC_EXCHANGE_KEYS_FAILURE);
   2981     goto cleanup;
   2982   }
   2983   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2984               "Got response for %skeys\n",
   2985               rx->url);
   2986 
   2987   /* Evaluate the use of this exchange for each wire method candidate */
   2988   for (unsigned int j = 0; j<keys->accounts_len; j++)
   2989   {
   2990     struct TALER_FullPayto full_payto = keys->accounts[j].fpayto_uri;
   2991     char *wire_method = TALER_payto_get_method (full_payto.full_payto);
   2992 
   2993     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   2994                 "Exchange `%s' has wire method `%s'\n",
   2995                 rx->url,
   2996                 wire_method);
   2997     for (struct WireMethodCandidate *wmc = oc->add_payment_details.wmc_head;
   2998          NULL != wmc;
   2999          wmc = wmc->next)
   3000     {
   3001       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   3002                   "Order could use wire method `%s'\n",
   3003                   wmc->wm->wire_method);
   3004       if (0 == strcmp (wmc->wm->wire_method,
   3005                        wire_method) )
   3006       {
   3007         applicable |= get_acceptable (oc,
   3008                                       exchange,
   3009                                       rx->url,
   3010                                       wmc);
   3011       }
   3012     }
   3013     GNUNET_free (wire_method);
   3014   }
   3015   if ( (! applicable) &&
   3016        (! oc->set_exchanges.forced_reload) )
   3017   {
   3018     /* Checks for 'forced_reload' to not log the error *again*
   3019        if we forced a re-load and are encountering the
   3020        applicability error a 2nd time */
   3021     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   3022                 "Exchange `%s' %u wire methods are not applicable to this order\n",
   3023                 rx->url,
   3024                 keys->accounts_len);
   3025     add_rejection (oc,
   3026                    rx->url,
   3027                    TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_WIRE_METHOD_UNSUPPORTED)
   3028     ;
   3029   }
   3030   if (applicable &&
   3031       settings->use_stefan)
   3032     update_stefan (oc,
   3033                    keys);
   3034 cleanup:
   3035   GNUNET_free (rx->url);
   3036   GNUNET_free (rx);
   3037   if (NULL != oc->set_exchanges.pending_reload_head)
   3038     return;
   3039   resume_with_keys (oc);
   3040 }
   3041 
   3042 
   3043 /**
   3044  * Force re-downloading of /keys from @a exchange,
   3045  * we currently have no acceptable exchange, so we
   3046  * should try to get one.
   3047  *
   3048  * @param cls closure with our `struct OrderContext`
   3049  * @param url base URL of the exchange
   3050  * @param exchange internal handle for the exchange
   3051  */
   3052 static void
   3053 get_exchange_keys (void *cls,
   3054                    const char *url,
   3055                    const struct TMH_Exchange *exchange)
   3056 {
   3057   struct OrderContext *oc = cls;
   3058   struct RekeyExchange *rx;
   3059 
   3060   rx = GNUNET_new (struct RekeyExchange);
   3061   rx->oc = oc;
   3062   rx->url = GNUNET_strdup (url);
   3063   GNUNET_CONTAINER_DLL_insert (oc->set_exchanges.pending_reload_head,
   3064                                oc->set_exchanges.pending_reload_tail,
   3065                                rx);
   3066   if (oc->set_exchanges.forced_reload)
   3067     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3068                 "Forcing download of %skeys\n",
   3069                 url);
   3070   rx->fo = TMH_EXCHANGES_keys4exchange (url,
   3071                                         oc->set_exchanges.forced_reload,
   3072                                         &keys_cb,
   3073                                         rx);
   3074 }
   3075 
   3076 
   3077 /**
   3078  * Task run when we are timing out on /keys and will just
   3079  * proceed with what we got.
   3080  *
   3081  * @param cls our `struct OrderContext *` to resume
   3082  */
   3083 static void
   3084 wakeup_timeout (void *cls)
   3085 {
   3086   struct OrderContext *oc = cls;
   3087 
   3088   oc->set_exchanges.wakeup_task = NULL;
   3089   GNUNET_assert (GNUNET_YES == oc->suspended);
   3090   GNUNET_CONTAINER_DLL_remove (oc_head,
   3091                                oc_tail,
   3092                                oc);
   3093   MHD_resume_connection (oc->connection);
   3094   oc->suspended = GNUNET_NO;
   3095   TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */
   3096 }
   3097 
   3098 
   3099 /**
   3100  * Set list of acceptable exchanges in @a oc. Upon success, continues
   3101  * processing with add_payment_details().
   3102  *
   3103  * @param[in,out] oc order context
   3104  * @return true to suspend execution
   3105  */
   3106 static bool
   3107 phase_set_exchanges (struct OrderContext *oc)
   3108 {
   3109   if (NULL != oc->set_exchanges.wakeup_task)
   3110   {
   3111     GNUNET_SCHEDULER_cancel (oc->set_exchanges.wakeup_task);
   3112     oc->set_exchanges.wakeup_task = NULL;
   3113   }
   3114 
   3115   if (! oc->add_payment_details.need_exchange)
   3116   {
   3117     /* Total amount is zero, so we don't actually need exchanges! */
   3118     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3119                 "Order total is zero, no need for exchanges\n");
   3120     oc->select_wire_method.exchanges = json_array ();
   3121     GNUNET_assert (NULL != oc->select_wire_method.exchanges);
   3122     /* Pick first one, doesn't matter as the amount is zero */
   3123     oc->select_wire_method.wm = oc->hc->instance->wm_head;
   3124     oc->phase = ORDER_PHASE_SET_MAX_FEE;
   3125     return false;
   3126   }
   3127   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3128               "Trying to find exchanges\n");
   3129   if (NULL == oc->set_exchanges.pending_reload_head)
   3130   {
   3131     if (! oc->set_exchanges.exchanges_tried)
   3132     {
   3133       oc->set_exchanges.exchanges_tried = true;
   3134       oc->set_exchanges.keys_timeout
   3135         = GNUNET_TIME_relative_to_absolute (MAX_KEYS_WAIT);
   3136       TMH_exchange_get_trusted (&get_exchange_keys,
   3137                                 oc);
   3138     }
   3139     else if ( (! oc->set_exchanges.forced_reload) &&
   3140               (oc->set_exchanges.promising_exchange) &&
   3141               (! oc->set_exchanges.exchange_ok) )
   3142     {
   3143       for (struct WireMethodCandidate *wmc = oc->add_payment_details.wmc_head;
   3144            NULL != wmc;
   3145            wmc = wmc->next)
   3146         GNUNET_break (0 ==
   3147                       json_array_clear (wmc->exchanges));
   3148       /* Try one more time with forcing /keys download */
   3149       oc->set_exchanges.forced_reload = true;
   3150       TMH_exchange_get_trusted (&get_exchange_keys,
   3151                                 oc);
   3152     }
   3153   }
   3154   if (GNUNET_TIME_absolute_is_past (oc->set_exchanges.keys_timeout))
   3155   {
   3156     struct RekeyExchange *rx;
   3157 
   3158     while (NULL != (rx = oc->set_exchanges.pending_reload_head))
   3159     {
   3160       GNUNET_CONTAINER_DLL_remove (oc->set_exchanges.pending_reload_head,
   3161                                    oc->set_exchanges.pending_reload_tail,
   3162                                    rx);
   3163       TMH_EXCHANGES_keys4exchange_cancel (rx->fo);
   3164       GNUNET_free (rx->url);
   3165       GNUNET_free (rx);
   3166     }
   3167   }
   3168   if (NULL != oc->set_exchanges.pending_reload_head)
   3169   {
   3170     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3171                 "Still trying to (re)load %skeys\n",
   3172                 oc->set_exchanges.pending_reload_head->url);
   3173     oc->set_exchanges.wakeup_task
   3174       = GNUNET_SCHEDULER_add_at (oc->set_exchanges.keys_timeout,
   3175                                  &wakeup_timeout,
   3176                                  oc);
   3177     MHD_suspend_connection (oc->connection);
   3178     oc->suspended = GNUNET_YES;
   3179     GNUNET_CONTAINER_DLL_insert (oc_head,
   3180                                  oc_tail,
   3181                                  oc);
   3182     return true; /* reloads pending */
   3183   }
   3184   oc->phase++;
   3185   return false;
   3186 }
   3187 
   3188 
   3189 /* ***************** ORDER_PHASE_ADD_PAYMENT_DETAILS **************** */
   3190 
   3191 /**
   3192  * Process the @a payment_target and add the details of how the
   3193  * order could be paid to @a order. On success, continue
   3194  * processing with add_payment_fees().
   3195  *
   3196  * @param[in,out] oc order context
   3197  */
   3198 static void
   3199 phase_add_payment_details (struct OrderContext *oc)
   3200 {
   3201   /* First, determine the maximum amounts that could be paid per currency */
   3202   switch (oc->parse_order.version)
   3203   {
   3204   case TALER_MERCHANT_CONTRACT_VERSION_0:
   3205     GNUNET_array_append (oc->add_payment_details.max_choice_limits,
   3206                          oc->add_payment_details.num_max_choice_limits,
   3207                          oc->parse_order.details.v0.brutto);
   3208     if (! TALER_amount_is_zero (
   3209           &oc->parse_order.details.v0.brutto))
   3210     {
   3211       oc->add_payment_details.need_exchange = true;
   3212     }
   3213     break;
   3214   case TALER_MERCHANT_CONTRACT_VERSION_1:
   3215     for (unsigned int i = 0; i<oc->parse_choices.choices_len; i++)
   3216     {
   3217       const struct TALER_Amount *amount
   3218         = &oc->parse_choices.choices[i].amount;
   3219       bool found = false;
   3220 
   3221       if (! TALER_amount_is_zero (amount))
   3222       {
   3223         oc->add_payment_details.need_exchange = true;
   3224       }
   3225       for (unsigned int j = 0; j<oc->add_payment_details.num_max_choice_limits;
   3226            j++)
   3227       {
   3228         struct TALER_Amount *mx = &oc->add_payment_details.max_choice_limits[j];
   3229         if (GNUNET_YES ==
   3230             TALER_amount_cmp_currency (mx,
   3231                                        amount))
   3232         {
   3233           TALER_amount_max (mx,
   3234                             mx,
   3235                             amount);
   3236           found = true;
   3237           break;
   3238         }
   3239       }
   3240       if (! found)
   3241       {
   3242         GNUNET_array_append (oc->add_payment_details.max_choice_limits,
   3243                              oc->add_payment_details.num_max_choice_limits,
   3244                              *amount);
   3245       }
   3246     }
   3247     break;
   3248   default:
   3249     GNUNET_assert (0);
   3250   }
   3251 
   3252   /* Then, create a candidate for each available wire method */
   3253   for (struct TMH_WireMethod *wm = oc->hc->instance->wm_head;
   3254        NULL != wm;
   3255        wm = wm->next)
   3256   {
   3257     struct WireMethodCandidate *wmc;
   3258 
   3259     /* Locate wire method that has a matching payment target */
   3260     if (! wm->active)
   3261       continue; /* ignore inactive methods */
   3262     if ( (NULL != oc->parse_request.payment_target) &&
   3263          (0 != strcasecmp (oc->parse_request.payment_target,
   3264                            wm->wire_method) ) )
   3265       continue; /* honor client preference */
   3266     wmc = GNUNET_new (struct WireMethodCandidate);
   3267     wmc->wm = wm;
   3268     wmc->exchanges = json_array ();
   3269     GNUNET_assert (NULL != wmc->exchanges);
   3270     GNUNET_CONTAINER_DLL_insert (oc->add_payment_details.wmc_head,
   3271                                  oc->add_payment_details.wmc_tail,
   3272                                  wmc);
   3273   }
   3274 
   3275   if (NULL == oc->add_payment_details.wmc_head)
   3276   {
   3277     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   3278                 "No wire method available for instance '%s'\n",
   3279                 oc->hc->instance->settings.id);
   3280     reply_with_error (oc,
   3281                       MHD_HTTP_NOT_FOUND,
   3282                       TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_INSTANCE_CONFIGURATION_LACKS_WIRE,
   3283                       oc->parse_request.payment_target);
   3284     return;
   3285   }
   3286 
   3287   /* next, we'll evaluate available exchanges */
   3288   oc->phase++;
   3289 }
   3290 
   3291 
   3292 /* ***************** ORDER_PHASE_MERGE_INVENTORY **************** */
   3293 
   3294 
   3295 /**
   3296  * Helper function to sort uint64_t array with qsort().
   3297  *
   3298  * @param a pointer to element to compare
   3299  * @param b pointer to element to compare
   3300  * @return 0 on equal, -1 on smaller, 1 on larger
   3301  */
   3302 static int
   3303 uint64_cmp (const void *a,
   3304             const void *b)
   3305 {
   3306   uint64_t ua = *(const uint64_t *) a;
   3307   uint64_t ub = *(const uint64_t *) b;
   3308 
   3309   if (ua < ub)
   3310     return -1;
   3311   if (ua > ub)
   3312     return 1;
   3313   return 0;
   3314 }
   3315 
   3316 
   3317 /**
   3318  * Merge the inventory products into products, querying the
   3319  * database about the details of those products. Upon success,
   3320  * continue processing by calling add_payment_details().
   3321  *
   3322  * @param[in,out] oc order context to process
   3323  */
   3324 static void
   3325 phase_merge_inventory (struct OrderContext *oc)
   3326 {
   3327   uint64_t pots[oc->parse_order.products_len + 1];
   3328   size_t pots_off = 0;
   3329 
   3330   if (0 != oc->parse_order.order_default_money_pot)
   3331     pots[pots_off++] = oc->parse_order.order_default_money_pot;
   3332   /**
   3333    * parse_request.inventory_products => instructions to add products to contract terms
   3334    * parse_order.products => contains products that are not from the backend-managed inventory.
   3335    */
   3336   oc->merge_inventory.products = json_array ();
   3337   for (size_t i = 0; i<oc->parse_order.products_len; i++)
   3338   {
   3339     GNUNET_assert (
   3340       0 ==
   3341       json_array_append_new (
   3342         oc->merge_inventory.products,
   3343         TALER_MERCHANT_product_sold_serialize (&oc->parse_order.products[i])));
   3344     if (0 != oc->parse_order.products[i].product_money_pot)
   3345       pots[pots_off++] = oc->parse_order.products[i].product_money_pot;
   3346   }
   3347 
   3348   /* make sure pots array only has distinct elements */
   3349   qsort (pots,
   3350          pots_off,
   3351          sizeof (uint64_t),
   3352          &uint64_cmp);
   3353   {
   3354     size_t e = 0;
   3355 
   3356     for (size_t i = 1; i<pots_off; i++)
   3357     {
   3358       if (pots[e] != pots[i])
   3359         pots[++e] = pots[i];
   3360     }
   3361     if (pots_off > 0)
   3362       e++;
   3363     pots_off = e;
   3364   }
   3365   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3366               "Found %u unique money pots in order\n",
   3367               (unsigned int) pots_off);
   3368 
   3369   /* check if all money pots exist; note that we do NOT treat
   3370      the inventory products to this check, as (1) the foreign key
   3371      constraint should ensure this, and (2) if the money pot
   3372      were deleted (concurrently), the value is specified to be
   3373      considered 0 (aka none) and so we can proceed anyway. */
   3374   if (pots_off > 0)
   3375   {
   3376     enum GNUNET_DB_QueryStatus qs;
   3377     uint64_t pot_missing;
   3378 
   3379     qs = TMH_db->check_money_pots (TMH_db->cls,
   3380                                    oc->hc->instance->settings.id,
   3381                                    pots_off,
   3382                                    pots,
   3383                                    &pot_missing);
   3384     switch (qs)
   3385     {
   3386     case GNUNET_DB_STATUS_HARD_ERROR:
   3387     case GNUNET_DB_STATUS_SOFT_ERROR:
   3388       GNUNET_break (0);
   3389       reply_with_error (oc,
   3390                         MHD_HTTP_INTERNAL_SERVER_ERROR,
   3391                         TALER_EC_GENERIC_DB_FETCH_FAILED,
   3392                         "check_money_pots");
   3393       return;
   3394     case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
   3395       /* great, good case! */
   3396       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3397                   "All money pots exist\n");
   3398       break;
   3399     case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
   3400       {
   3401         char mstr[32];
   3402 
   3403         GNUNET_snprintf (mstr,
   3404                          sizeof (mstr),
   3405                          "%llu",
   3406                          (unsigned long long) pot_missing);
   3407         reply_with_error (oc,
   3408                           MHD_HTTP_NOT_FOUND,
   3409                           TALER_EC_MERCHANT_GENERIC_MONEY_POT_UNKNOWN,
   3410                           mstr);
   3411         return;
   3412       }
   3413     }
   3414   }
   3415 
   3416   /* Populate products from inventory product array and database */
   3417   {
   3418     GNUNET_assert (NULL != oc->merge_inventory.products);
   3419     for (unsigned int i = 0; i<oc->parse_request.inventory_products_length; i++)
   3420     {
   3421       struct InventoryProduct *ip
   3422         = &oc->parse_request.inventory_products[i];
   3423       struct TALER_MERCHANTDB_ProductDetails pd;
   3424       enum GNUNET_DB_QueryStatus qs;
   3425       size_t num_categories = 0;
   3426       uint64_t *categories = NULL;
   3427 
   3428       qs = TMH_db->lookup_product (TMH_db->cls,
   3429                                    oc->hc->instance->settings.id,
   3430                                    ip->product_id,
   3431                                    &pd,
   3432                                    &num_categories,
   3433                                    &categories);
   3434       if (qs <= 0)
   3435       {
   3436         enum TALER_ErrorCode ec = TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
   3437         unsigned int http_status = 0;
   3438 
   3439         switch (qs)
   3440         {
   3441         case GNUNET_DB_STATUS_HARD_ERROR:
   3442           GNUNET_break (0);
   3443           http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;
   3444           ec = TALER_EC_GENERIC_DB_FETCH_FAILED;
   3445           break;
   3446         case GNUNET_DB_STATUS_SOFT_ERROR:
   3447           GNUNET_break (0);
   3448           http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;
   3449           ec = TALER_EC_GENERIC_DB_SOFT_FAILURE;
   3450           break;
   3451         case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
   3452           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   3453                       "Product %s from order unknown\n",
   3454                       ip->product_id);
   3455           http_status = MHD_HTTP_NOT_FOUND;
   3456           ec = TALER_EC_MERCHANT_GENERIC_PRODUCT_UNKNOWN;
   3457           break;
   3458         case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
   3459           /* case listed to make compilers happy */
   3460           GNUNET_assert (0);
   3461         }
   3462         reply_with_error (oc,
   3463                           http_status,
   3464                           ec,
   3465                           ip->product_id);
   3466         return;
   3467       }
   3468       GNUNET_free (categories);
   3469       oc->parse_order.minimum_age
   3470         = GNUNET_MAX (oc->parse_order.minimum_age,
   3471                       pd.minimum_age);
   3472       {
   3473         const char *eparam;
   3474 
   3475         if ( (! ip->quantity_missing) &&
   3476              (ip->quantity > (uint64_t) INT64_MAX) )
   3477         {
   3478           GNUNET_break_op (0);
   3479           reply_with_error (oc,
   3480                             MHD_HTTP_BAD_REQUEST,
   3481                             TALER_EC_GENERIC_PARAMETER_MALFORMED,
   3482                             "quantity");
   3483           TALER_MERCHANTDB_product_details_free (&pd);
   3484           return;
   3485         }
   3486         if (GNUNET_OK !=
   3487             TALER_MERCHANT_vk_process_quantity_inputs (
   3488               TALER_MERCHANT_VK_QUANTITY,
   3489               pd.allow_fractional_quantity,
   3490               ip->quantity_missing,
   3491               (int64_t) ip->quantity,
   3492               ip->unit_quantity_missing,
   3493               ip->unit_quantity,
   3494               &ip->quantity,
   3495               &ip->quantity_frac,
   3496               &eparam))
   3497         {
   3498           GNUNET_break_op (0);
   3499           reply_with_error (oc,
   3500                             MHD_HTTP_BAD_REQUEST,
   3501                             TALER_EC_GENERIC_PARAMETER_MALFORMED,
   3502                             eparam);
   3503           TALER_MERCHANTDB_product_details_free (&pd);
   3504           return;
   3505         }
   3506       }
   3507       {
   3508         struct TALER_MERCHANT_ProductSold ps = {
   3509           .product_id = (char *) ip->product_id,
   3510           .product_name = pd.product_name,
   3511           .description = pd.description,
   3512           .description_i18n = pd.description_i18n,
   3513           .unit_quantity.integer = ip->quantity,
   3514           .unit_quantity.fractional = ip->quantity_frac,
   3515           .prices_length = pd.price_array_length,
   3516           .prices = GNUNET_new_array (pd.price_array_length,
   3517                                       struct TALER_Amount),
   3518           .prices_are_net = pd.price_is_net,
   3519           .image = pd.image,
   3520           .taxes = pd.taxes,
   3521           .delivery_date = oc->parse_order.delivery_date,
   3522           .product_money_pot = pd.money_pot_id,
   3523           .unit = pd.unit,
   3524 
   3525         };
   3526         json_t *p;
   3527         char unit_quantity_buf[64];
   3528 
   3529         for (size_t j = 0; j<pd.price_array_length; j++)
   3530         {
   3531           struct TALER_Amount atomic_amount;
   3532 
   3533           TALER_amount_set_zero (pd.price_array[j].currency,
   3534                                  &atomic_amount);
   3535           atomic_amount.fraction = 1;
   3536           GNUNET_assert (
   3537             GNUNET_OK ==
   3538             TALER_MERCHANT_amount_multiply_by_quantity (
   3539               &ps.prices[j],
   3540               &pd.price_array[j],
   3541               &ps.unit_quantity,
   3542               TALER_MERCHANT_ROUND_UP,
   3543               &atomic_amount));
   3544         }
   3545 
   3546         TALER_MERCHANT_vk_format_fractional_string (
   3547           TALER_MERCHANT_VK_QUANTITY,
   3548           ip->quantity,
   3549           ip->quantity_frac,
   3550           sizeof (unit_quantity_buf),
   3551           unit_quantity_buf);
   3552         if (0 != pd.money_pot_id)
   3553           pots[pots_off++] = pd.money_pot_id;
   3554         p = TALER_MERCHANT_product_sold_serialize (&ps);
   3555         GNUNET_assert (NULL != p);
   3556         GNUNET_free (ps.prices);
   3557         GNUNET_assert (0 ==
   3558                        json_array_append_new (oc->merge_inventory.products,
   3559                                               p));
   3560       }
   3561       TALER_MERCHANTDB_product_details_free (&pd);
   3562     }
   3563   }
   3564 
   3565   /* check if final product list is well-formed */
   3566   if (! TMH_products_array_valid (oc->merge_inventory.products))
   3567   {
   3568     GNUNET_break_op (0);
   3569     reply_with_error (oc,
   3570                       MHD_HTTP_BAD_REQUEST,
   3571                       TALER_EC_GENERIC_PARAMETER_MALFORMED,
   3572                       "order:products");
   3573     return;
   3574   }
   3575   oc->phase++;
   3576 }
   3577 
   3578 
   3579 /* ***************** ORDER_PHASE_PARSE_CHOICES **************** */
   3580 
   3581 /**
   3582  * Callback function that is called for each donau instance.
   3583  * It simply adds the provided donau_url to the json.
   3584  *
   3585  * @param cls closure with our `struct TALER_MERCHANT_ContractOutput *`
   3586  * @param donau_url the URL of the donau instance
   3587  */
   3588 static void
   3589 add_donau_url (void *cls,
   3590                const char *donau_url)
   3591 {
   3592   struct TALER_MERCHANT_ContractOutput *output = cls;
   3593 
   3594   GNUNET_array_append (output->details.donation_receipt.donau_urls,
   3595                        output->details.donation_receipt.donau_urls_len,
   3596                        GNUNET_strdup (donau_url));
   3597 }
   3598 
   3599 
   3600 /**
   3601  * Add the donau output to the contract output.
   3602  *
   3603  * @param oc order context
   3604  * @param output contract output to add donau URLs to
   3605  */
   3606 static bool
   3607 add_donau_output (struct OrderContext *oc,
   3608                   struct TALER_MERCHANT_ContractOutput *output)
   3609 {
   3610   enum GNUNET_DB_QueryStatus qs;
   3611 
   3612   qs = TMH_db->select_donau_instances_filtered (
   3613     TMH_db->cls,
   3614     output->details.donation_receipt.amount.currency,
   3615     &add_donau_url,
   3616     output);
   3617   if (qs < 0)
   3618   {
   3619     GNUNET_break (0);
   3620     reply_with_error (oc,
   3621                       MHD_HTTP_INTERNAL_SERVER_ERROR,
   3622                       TALER_EC_GENERIC_DB_FETCH_FAILED,
   3623                       "donau url parsing db call");
   3624     for (unsigned int i = 0;
   3625          i < output->details.donation_receipt.donau_urls_len;
   3626          i++)
   3627       GNUNET_free (output->details.donation_receipt.donau_urls[i]);
   3628     GNUNET_array_grow (output->details.donation_receipt.donau_urls,
   3629                        output->details.donation_receipt.donau_urls_len,
   3630                        0);
   3631     return false;
   3632   }
   3633   return true;
   3634 }
   3635 
   3636 
   3637 /**
   3638  * Parse contract choices. Upon success, continue
   3639  * processing with merge_inventory().
   3640  *
   3641  * @param[in,out] oc order context
   3642  */
   3643 static void
   3644 phase_parse_choices (struct OrderContext *oc)
   3645 {
   3646   const json_t *jchoices;
   3647 
   3648   switch (oc->parse_order.version)
   3649   {
   3650   case TALER_MERCHANT_CONTRACT_VERSION_0:
   3651     oc->phase++;
   3652     return;
   3653   case TALER_MERCHANT_CONTRACT_VERSION_1:
   3654     /* handle below */
   3655     break;
   3656   default:
   3657     GNUNET_assert (0);
   3658   }
   3659 
   3660   jchoices = oc->parse_order.details.v1.choices;
   3661 
   3662   if (! json_is_array (jchoices))
   3663     GNUNET_assert (0);
   3664   if (0 == json_array_size (jchoices))
   3665   {
   3666     reply_with_error (oc,
   3667                       MHD_HTTP_BAD_REQUEST,
   3668                       TALER_EC_GENERIC_PARAMETER_MALFORMED,
   3669                       "choices");
   3670     return;
   3671   }
   3672   GNUNET_array_grow (oc->parse_choices.choices,
   3673                      oc->parse_choices.choices_len,
   3674                      json_array_size (jchoices));
   3675   for (unsigned int i = 0; i<oc->parse_choices.choices_len; i++)
   3676   {
   3677     struct TALER_MERCHANT_ContractChoice *choice
   3678       = &oc->parse_choices.choices[i];
   3679     const char *error_name;
   3680     unsigned int error_line;
   3681     const json_t *jinputs;
   3682     const json_t *joutputs;
   3683     bool no_fee;
   3684     struct GNUNET_JSON_Specification spec[] = {
   3685       TALER_JSON_spec_amount_any ("amount",
   3686                                   &choice->amount),
   3687       GNUNET_JSON_spec_mark_optional (
   3688         TALER_JSON_spec_amount_any ("tip",
   3689                                     &choice->tip),
   3690         &choice->no_tip),
   3691       GNUNET_JSON_spec_mark_optional (
   3692         TALER_JSON_spec_amount_any ("max_fee",
   3693                                     &choice->max_fee),
   3694         &no_fee),
   3695       GNUNET_JSON_spec_mark_optional (
   3696         GNUNET_JSON_spec_string_copy ("description",
   3697                                       &choice->description),
   3698         NULL),
   3699       GNUNET_JSON_spec_mark_optional (
   3700         GNUNET_JSON_spec_object_copy ("description_i18n",
   3701                                       &choice->description_i18n),
   3702         NULL),
   3703       GNUNET_JSON_spec_mark_optional (
   3704         GNUNET_JSON_spec_array_const ("inputs",
   3705                                       &jinputs),
   3706         NULL),
   3707       GNUNET_JSON_spec_mark_optional (
   3708         GNUNET_JSON_spec_array_const ("outputs",
   3709                                       &joutputs),
   3710         NULL),
   3711       GNUNET_JSON_spec_end ()
   3712     };
   3713     enum GNUNET_GenericReturnValue ret;
   3714 
   3715     ret = GNUNET_JSON_parse (json_array_get (jchoices,
   3716                                              i),
   3717                              spec,
   3718                              &error_name,
   3719                              &error_line);
   3720     if (GNUNET_OK != ret)
   3721     {
   3722       GNUNET_break_op (0);
   3723       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   3724                   "Choice parsing failed: %s:%u\n",
   3725                   error_name,
   3726                   error_line);
   3727       reply_with_error (oc,
   3728                         MHD_HTTP_BAD_REQUEST,
   3729                         TALER_EC_GENERIC_PARAMETER_MALFORMED,
   3730                         "choice");
   3731       return;
   3732     }
   3733     if ( (! no_fee) &&
   3734          (GNUNET_OK !=
   3735           TALER_amount_cmp_currency (&choice->amount,
   3736                                      &choice->max_fee)) )
   3737     {
   3738       GNUNET_break_op (0);
   3739       GNUNET_JSON_parse_free (spec);
   3740       reply_with_error (oc,
   3741                         MHD_HTTP_BAD_REQUEST,
   3742                         TALER_EC_GENERIC_CURRENCY_MISMATCH,
   3743                         "different currencies used for 'max_fee' and 'amount' currency");
   3744       return;
   3745     }
   3746     if ( (! choice->no_tip) &&
   3747          (GNUNET_OK !=
   3748           TALER_amount_cmp_currency (&choice->amount,
   3749                                      &choice->tip)) )
   3750     {
   3751       GNUNET_break_op (0);
   3752       GNUNET_JSON_parse_free (spec);
   3753       reply_with_error (oc,
   3754                         MHD_HTTP_BAD_REQUEST,
   3755                         TALER_EC_GENERIC_CURRENCY_MISMATCH,
   3756                         "tip and amount");
   3757       return;
   3758     }
   3759 
   3760     if (! TMH_test_exchange_configured_for_currency (
   3761           choice->amount.currency))
   3762     {
   3763       GNUNET_break_op (0);
   3764       GNUNET_JSON_parse_free (spec);
   3765       reply_with_error (oc,
   3766                         MHD_HTTP_CONFLICT,
   3767                         TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_NO_EXCHANGE_FOR_CURRENCY,
   3768                         choice->amount.currency);
   3769       return;
   3770     }
   3771 
   3772     if (NULL != jinputs)
   3773     {
   3774       const json_t *jinput;
   3775       size_t idx;
   3776       json_array_foreach ((json_t *) jinputs, idx, jinput)
   3777       {
   3778         struct TALER_MERCHANT_ContractInput input = {
   3779           .details.token.count = 1
   3780         };
   3781 
   3782         if (GNUNET_OK !=
   3783             TALER_MERCHANT_parse_choice_input ((json_t *) jinput,
   3784                                                &input,
   3785                                                idx,
   3786                                                true))
   3787         {
   3788           GNUNET_break_op (0);
   3789           reply_with_error (oc,
   3790                             MHD_HTTP_BAD_REQUEST,
   3791                             TALER_EC_GENERIC_PARAMETER_MALFORMED,
   3792                             "input");
   3793           return;
   3794         }
   3795 
   3796         switch (input.type)
   3797         {
   3798         case TALER_MERCHANT_CONTRACT_INPUT_TYPE_INVALID:
   3799           GNUNET_assert (0);
   3800           break;
   3801         case TALER_MERCHANT_CONTRACT_INPUT_TYPE_TOKEN:
   3802           /* Ignore inputs tokens with 'count' field set to 0 */
   3803           if (0 == input.details.token.count)
   3804             continue;
   3805 
   3806           if (GNUNET_OK !=
   3807               add_input_token_family (oc,
   3808                                       input.details.token.token_family_slug))
   3809 
   3810           {
   3811             GNUNET_break_op (0);
   3812             reply_with_error (oc,
   3813                               MHD_HTTP_BAD_REQUEST,
   3814                               TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_TOKEN_FAMILY_SLUG_UNKNOWN,
   3815                               input.details.token.token_family_slug);
   3816             return;
   3817           }
   3818 
   3819           GNUNET_array_append (choice->inputs,
   3820                                choice->inputs_len,
   3821                                input);
   3822           continue;
   3823         }
   3824         GNUNET_assert (0);
   3825       }
   3826     }
   3827 
   3828     if (NULL != joutputs)
   3829     {
   3830       const json_t *joutput;
   3831       size_t idx;
   3832       json_array_foreach ((json_t *) joutputs, idx, joutput)
   3833       {
   3834         struct TALER_MERCHANT_ContractOutput output = {
   3835           .details.token.count = 1
   3836         };
   3837 
   3838         if (GNUNET_OK !=
   3839             TALER_MERCHANT_parse_choice_output ((json_t *) joutput,
   3840                                                 &output,
   3841                                                 idx,
   3842                                                 true))
   3843         {
   3844           reply_with_error (oc,
   3845                             MHD_HTTP_BAD_REQUEST,
   3846                             TALER_EC_GENERIC_PARAMETER_MALFORMED,
   3847                             "output");
   3848           return;
   3849         }
   3850 
   3851         switch (output.type)
   3852         {
   3853         case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_INVALID:
   3854           GNUNET_assert (0);
   3855           break;
   3856         case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_DONATION_RECEIPT:
   3857           output.details.donation_receipt.amount = choice->amount;
   3858           if (! add_donau_output (oc,
   3859                                   &output))
   3860           {
   3861             GNUNET_break (0);
   3862             return;
   3863           }
   3864           GNUNET_array_append (choice->outputs,
   3865                                choice->outputs_len,
   3866                                output);
   3867           continue;
   3868         case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_TOKEN:
   3869           /* Ignore inputs tokens with 'count' field set to 0 */
   3870           if (0 == output.details.token.count)
   3871             continue;
   3872 
   3873           if (0 == output.details.token.valid_at.abs_time.abs_value_us)
   3874             output.details.token.valid_at
   3875               = GNUNET_TIME_timestamp_get ();
   3876           if (GNUNET_OK !=
   3877               add_output_token_family (oc,
   3878                                        output.details.token.token_family_slug,
   3879                                        output.details.token.valid_at,
   3880                                        &output.details.token.key_index))
   3881 
   3882           {
   3883             /* note: reply_with_error() was already called */
   3884             GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   3885                         "Could not handle output token family `%s'\n",
   3886                         output.details.token.token_family_slug);
   3887             return;
   3888           }
   3889 
   3890           GNUNET_array_append (choice->outputs,
   3891                                choice->outputs_len,
   3892                                output);
   3893           continue;
   3894         }
   3895         GNUNET_assert (0);
   3896       }
   3897     }
   3898   }
   3899   oc->phase++;
   3900 }
   3901 
   3902 
   3903 /* ***************** ORDER_PHASE_PARSE_ORDER **************** */
   3904 
   3905 
   3906 /**
   3907  * Parse the order field of the request. Upon success, continue
   3908  * processing with parse_choices().
   3909  *
   3910  * @param[in,out] oc order context
   3911  */
   3912 static void
   3913 phase_parse_order (struct OrderContext *oc)
   3914 {
   3915   const struct TALER_MERCHANTDB_InstanceSettings *settings =
   3916     &oc->hc->instance->settings;
   3917   const char *merchant_base_url = NULL;
   3918   uint64_t version = 0;
   3919   const json_t *jmerchant = NULL;
   3920   const json_t *products = NULL;
   3921   const char *order_id = NULL;
   3922   struct GNUNET_JSON_Specification spec[] = {
   3923     GNUNET_JSON_spec_mark_optional (
   3924       GNUNET_JSON_spec_uint64 ("version",
   3925                                &version),
   3926       NULL),
   3927     GNUNET_JSON_spec_string ("summary",
   3928                              &oc->parse_order.summary),
   3929     GNUNET_JSON_spec_mark_optional (
   3930       GNUNET_JSON_spec_array_const ("products",
   3931                                     &products),
   3932       NULL),
   3933     GNUNET_JSON_spec_mark_optional (
   3934       GNUNET_JSON_spec_object_const ("summary_i18n",
   3935                                      &oc->parse_order.summary_i18n),
   3936       NULL),
   3937     GNUNET_JSON_spec_mark_optional (
   3938       GNUNET_JSON_spec_string ("order_id",
   3939                                &order_id),
   3940       NULL),
   3941     GNUNET_JSON_spec_mark_optional (
   3942       GNUNET_JSON_spec_string ("fulfillment_message",
   3943                                &oc->parse_order.fulfillment_message),
   3944       NULL),
   3945     GNUNET_JSON_spec_mark_optional (
   3946       GNUNET_JSON_spec_object_const ("fulfillment_message_i18n",
   3947                                      &oc->parse_order.fulfillment_message_i18n),
   3948       NULL),
   3949     GNUNET_JSON_spec_mark_optional (
   3950       GNUNET_JSON_spec_string ("fulfillment_url",
   3951                                &oc->parse_order.fulfillment_url),
   3952       NULL),
   3953     GNUNET_JSON_spec_mark_optional (
   3954       GNUNET_JSON_spec_string ("public_reorder_url",
   3955                                &oc->parse_order.public_reorder_url),
   3956       NULL),
   3957     GNUNET_JSON_spec_mark_optional (
   3958       TALER_JSON_spec_web_url ("merchant_base_url",
   3959                                &merchant_base_url),
   3960       NULL),
   3961     /* For sanity check, this field must NOT be present */
   3962     GNUNET_JSON_spec_mark_optional (
   3963       GNUNET_JSON_spec_object_const ("merchant",
   3964                                      &jmerchant),
   3965       NULL),
   3966     GNUNET_JSON_spec_mark_optional (
   3967       GNUNET_JSON_spec_timestamp ("timestamp",
   3968                                   &oc->parse_order.timestamp),
   3969       NULL),
   3970     GNUNET_JSON_spec_mark_optional (
   3971       GNUNET_JSON_spec_timestamp ("refund_deadline",
   3972                                   &oc->parse_order.refund_deadline),
   3973       NULL),
   3974     GNUNET_JSON_spec_mark_optional (
   3975       GNUNET_JSON_spec_timestamp ("pay_deadline",
   3976                                   &oc->parse_order.pay_deadline),
   3977       NULL),
   3978     GNUNET_JSON_spec_mark_optional (
   3979       GNUNET_JSON_spec_timestamp ("wire_transfer_deadline",
   3980                                   &oc->parse_order.wire_deadline),
   3981       NULL),
   3982     GNUNET_JSON_spec_mark_optional (
   3983       GNUNET_JSON_spec_object_const ("delivery_location",
   3984                                      &oc->parse_order.delivery_location),
   3985       NULL),
   3986     GNUNET_JSON_spec_mark_optional (
   3987       GNUNET_JSON_spec_timestamp ("delivery_date",
   3988                                   &oc->parse_order.delivery_date),
   3989       NULL),
   3990     GNUNET_JSON_spec_mark_optional (
   3991       GNUNET_JSON_spec_uint32 ("minimum_age",
   3992                                &oc->parse_order.minimum_age),
   3993       NULL),
   3994     GNUNET_JSON_spec_mark_optional (
   3995       GNUNET_JSON_spec_relative_time ("auto_refund",
   3996                                       &oc->parse_order.auto_refund),
   3997       NULL),
   3998     GNUNET_JSON_spec_mark_optional (
   3999       GNUNET_JSON_spec_object_const ("extra",
   4000                                      &oc->parse_order.extra),
   4001       NULL),
   4002     GNUNET_JSON_spec_mark_optional (
   4003       GNUNET_JSON_spec_uint64 ("order_default_money_pot",
   4004                                &oc->parse_order.order_default_money_pot),
   4005       NULL),
   4006     GNUNET_JSON_spec_end ()
   4007   };
   4008   enum GNUNET_GenericReturnValue ret;
   4009   bool computed_refund_deadline;
   4010 
   4011   oc->parse_order.refund_deadline = GNUNET_TIME_UNIT_FOREVER_TS;
   4012   oc->parse_order.wire_deadline = GNUNET_TIME_UNIT_FOREVER_TS;
   4013   ret = TALER_MHD_parse_json_data (oc->connection,
   4014                                    oc->parse_request.order,
   4015                                    spec);
   4016   if (GNUNET_OK != ret)
   4017   {
   4018     GNUNET_break_op (0);
   4019     finalize_order2 (oc,
   4020                      ret);
   4021     return;
   4022   }
   4023   if ( (NULL != products) &&
   4024        (0 != (oc->parse_order.products_len = json_array_size (products))) )
   4025   {
   4026     size_t i;
   4027     json_t *p;
   4028 
   4029     oc->parse_order.products
   4030       = GNUNET_new_array (oc->parse_order.products_len,
   4031                           struct TALER_MERCHANT_ProductSold);
   4032     json_array_foreach (products, i, p)
   4033     {
   4034       if (GNUNET_OK !=
   4035           TALER_MERCHANT_parse_product_sold (p,
   4036                                              &oc->parse_order.products[i]))
   4037       {
   4038         GNUNET_break_op (0);
   4039         reply_with_error (oc,
   4040                           MHD_HTTP_BAD_REQUEST,
   4041                           TALER_EC_GENERIC_PARAMETER_MALFORMED,
   4042                           "order.products");
   4043         return;
   4044       }
   4045     }
   4046   }
   4047   if (NULL != order_id)
   4048   {
   4049     size_t len = strlen (order_id);
   4050 
   4051     for (size_t i = 0; i<len; i++)
   4052     {
   4053       char c = order_id[i];
   4054 
   4055       if (! ( ( (c >= 'A') &&
   4056                 (c <= 'Z') ) ||
   4057               ( (c >= 'a') &&
   4058                 (c <= 'z') ) ||
   4059               ( (c >= '0') &&
   4060                 (c <= '9') ) ||
   4061               (c == '-') ||
   4062               (c == '_') ||
   4063               (c == '.') ||
   4064               (c == ':') ) )
   4065       {
   4066         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   4067                     "Invalid character `%c' in order ID `%s'\n",
   4068                     c,
   4069                     order_id);
   4070         reply_with_error (oc,
   4071                           MHD_HTTP_BAD_REQUEST,
   4072                           TALER_EC_GENERIC_CURRENCY_MISMATCH,
   4073                           "Invalid character in order_id");
   4074         return;
   4075       }
   4076     }
   4077   }
   4078   switch (version)
   4079   {
   4080   case 0:
   4081     {
   4082       bool no_fee;
   4083       const json_t *choices = NULL;
   4084       struct GNUNET_JSON_Specification specv0[] = {
   4085         TALER_JSON_spec_amount_any (
   4086           "amount",
   4087           &oc->parse_order.details.v0.brutto),
   4088         GNUNET_JSON_spec_mark_optional (
   4089           TALER_JSON_spec_amount_any (
   4090             "tip",
   4091             &oc->parse_order.details.v0.tip),
   4092           &oc->parse_order.details.v0.no_tip),
   4093         GNUNET_JSON_spec_mark_optional (
   4094           TALER_JSON_spec_amount_any (
   4095             "max_fee",
   4096             &oc->parse_order.details.v0.max_fee),
   4097           &no_fee),
   4098         /* for sanity check, must be *absent*! */
   4099         GNUNET_JSON_spec_mark_optional (
   4100           GNUNET_JSON_spec_array_const ("choices",
   4101                                         &choices),
   4102           NULL),
   4103         GNUNET_JSON_spec_end ()
   4104       };
   4105 
   4106       ret = TALER_MHD_parse_json_data (oc->connection,
   4107                                        oc->parse_request.order,
   4108                                        specv0);
   4109       if (GNUNET_OK != ret)
   4110       {
   4111         GNUNET_break_op (0);
   4112         finalize_order2 (oc,
   4113                          ret);
   4114         return;
   4115       }
   4116       if ( (! no_fee) &&
   4117            (GNUNET_OK !=
   4118             TALER_amount_cmp_currency (&oc->parse_order.details.v0.brutto,
   4119                                        &oc->parse_order.details.v0.max_fee)) )
   4120       {
   4121         GNUNET_break_op (0);
   4122         GNUNET_JSON_parse_free (spec);
   4123         reply_with_error (oc,
   4124                           MHD_HTTP_BAD_REQUEST,
   4125                           TALER_EC_GENERIC_CURRENCY_MISMATCH,
   4126                           "different currencies used for 'max_fee' and 'amount' currency");
   4127         return;
   4128       }
   4129       if ( (! oc->parse_order.details.v0.no_tip) &&
   4130            (GNUNET_OK !=
   4131             TALER_amount_cmp_currency (&oc->parse_order.details.v0.brutto,
   4132                                        &oc->parse_order.details.v0.tip)) )
   4133       {
   4134         GNUNET_break_op (0);
   4135         GNUNET_JSON_parse_free (spec);
   4136         reply_with_error (oc,
   4137                           MHD_HTTP_BAD_REQUEST,
   4138                           TALER_EC_GENERIC_CURRENCY_MISMATCH,
   4139                           "tip and amount");
   4140         return;
   4141       }
   4142       if (! TMH_test_exchange_configured_for_currency (
   4143             oc->parse_order.details.v0.brutto.currency))
   4144       {
   4145         GNUNET_break_op (0);
   4146         GNUNET_JSON_parse_free (spec);
   4147         reply_with_error (oc,
   4148                           MHD_HTTP_CONFLICT,
   4149                           TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_NO_EXCHANGE_FOR_CURRENCY,
   4150                           oc->parse_order.details.v0.brutto.currency);
   4151         return;
   4152       }
   4153       if (NULL != choices)
   4154       {
   4155         GNUNET_break_op (0);
   4156         GNUNET_JSON_parse_free (spec);
   4157         reply_with_error (oc,
   4158                           MHD_HTTP_BAD_REQUEST,
   4159                           TALER_EC_GENERIC_UNEXPECTED_REQUEST_ERROR,
   4160                           "choices array must be null for v0 contracts");
   4161         return;
   4162       }
   4163       oc->parse_order.version = TALER_MERCHANT_CONTRACT_VERSION_0;
   4164       break;
   4165     }
   4166   case 1:
   4167     {
   4168       struct GNUNET_JSON_Specification specv1[] = {
   4169         GNUNET_JSON_spec_array_const (
   4170           "choices",
   4171           &oc->parse_order.details.v1.choices),
   4172         GNUNET_JSON_spec_end ()
   4173       };
   4174 
   4175       ret = TALER_MHD_parse_json_data (oc->connection,
   4176                                        oc->parse_request.order,
   4177                                        specv1);
   4178       if (GNUNET_OK != ret)
   4179       {
   4180         GNUNET_break_op (0);
   4181         finalize_order2 (oc,
   4182                          ret);
   4183         return;
   4184       }
   4185       oc->parse_order.version = TALER_MERCHANT_CONTRACT_VERSION_1;
   4186       break;
   4187     }
   4188   default:
   4189     GNUNET_break_op (0);
   4190     GNUNET_JSON_parse_free (spec);
   4191     reply_with_error (oc,
   4192                       MHD_HTTP_BAD_REQUEST,
   4193                       TALER_EC_GENERIC_VERSION_MALFORMED,
   4194                       "invalid version specified in order, supported are null, '0' or '1'");
   4195     return;
   4196   }
   4197 
   4198   /* Add order_id if it doesn't exist. */
   4199   if (NULL != order_id)
   4200   {
   4201     oc->parse_order.order_id = GNUNET_strdup (order_id);
   4202   }
   4203   else
   4204   {
   4205     char buf[256];
   4206     time_t timer;
   4207     struct tm *tm_info;
   4208     size_t off;
   4209     uint64_t rand;
   4210     char *last;
   4211 
   4212     time (&timer);
   4213     tm_info = localtime (&timer);
   4214     if (NULL == tm_info)
   4215     {
   4216       GNUNET_JSON_parse_free (spec);
   4217       reply_with_error (
   4218         oc,
   4219         MHD_HTTP_INTERNAL_SERVER_ERROR,
   4220         TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_NO_LOCALTIME,
   4221         NULL);
   4222       return;
   4223     }
   4224     off = strftime (buf,
   4225                     sizeof (buf) - 1,
   4226                     "%Y.%j",
   4227                     tm_info);
   4228     /* Check for error state of strftime */
   4229     GNUNET_assert (0 != off);
   4230     buf[off++] = '-';
   4231     rand = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
   4232                                      UINT64_MAX);
   4233     last = GNUNET_STRINGS_data_to_string (&rand,
   4234                                           sizeof (uint64_t),
   4235                                           &buf[off],
   4236                                           sizeof (buf) - off);
   4237     GNUNET_assert (NULL != last);
   4238     *last = '\0';
   4239 
   4240     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   4241                 "Assigning order ID `%s' server-side\n",
   4242                 buf);
   4243 
   4244     oc->parse_order.order_id = GNUNET_strdup (buf);
   4245     GNUNET_assert (NULL != oc->parse_order.order_id);
   4246   }
   4247 
   4248   /* Patch fulfillment URL with order_id (implements #6467). */
   4249   if (NULL != oc->parse_order.fulfillment_url)
   4250   {
   4251     const char *pos;
   4252 
   4253     pos = strstr (oc->parse_order.fulfillment_url,
   4254                   "${ORDER_ID}");
   4255     if (NULL != pos)
   4256     {
   4257       /* replace ${ORDER_ID} with the real order_id */
   4258       char *nurl;
   4259 
   4260       /* We only allow one placeholder */
   4261       if (strstr (pos + strlen ("${ORDER_ID}"),
   4262                   "${ORDER_ID}"))
   4263       {
   4264         GNUNET_break_op (0);
   4265         reply_with_error (oc,
   4266                           MHD_HTTP_BAD_REQUEST,
   4267                           TALER_EC_GENERIC_PARAMETER_MALFORMED,
   4268                           "fulfillment_url");
   4269         return;
   4270       }
   4271 
   4272       GNUNET_asprintf (&nurl,
   4273                        "%.*s%s%s",
   4274                        /* first output URL until ${ORDER_ID} */
   4275                        (int) (pos - oc->parse_order.fulfillment_url),
   4276                        oc->parse_order.fulfillment_url,
   4277                        /* replace ${ORDER_ID} with the right order_id */
   4278                        oc->parse_order.order_id,
   4279                        /* append rest of original URL */
   4280                        pos + strlen ("${ORDER_ID}"));
   4281 
   4282       oc->parse_order.fulfillment_url = GNUNET_strdup (nurl);
   4283 
   4284       GNUNET_free (nurl);
   4285     }
   4286   }
   4287 
   4288   if ( (GNUNET_TIME_absolute_is_zero (oc->parse_order.pay_deadline.abs_time)) ||
   4289        (GNUNET_TIME_absolute_is_never (oc->parse_order.pay_deadline.abs_time)) )
   4290   {
   4291     oc->parse_order.pay_deadline = GNUNET_TIME_relative_to_timestamp (
   4292       settings->default_pay_delay);
   4293     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   4294                 "Pay deadline was zero (or never), setting to %s\n",
   4295                 GNUNET_TIME_timestamp2s (oc->parse_order.pay_deadline));
   4296   }
   4297   else if (GNUNET_TIME_absolute_is_past (oc->parse_order.pay_deadline.abs_time))
   4298   {
   4299     GNUNET_break_op (0);
   4300     reply_with_error (
   4301       oc,
   4302       MHD_HTTP_BAD_REQUEST,
   4303       TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_PAY_DEADLINE_IN_PAST,
   4304       NULL);
   4305     return;
   4306   }
   4307   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   4308               "Pay deadline is %s\n",
   4309               GNUNET_TIME_timestamp2s (oc->parse_order.pay_deadline));
   4310 
   4311   /* Check soundness of refund deadline, and that a timestamp
   4312    * is actually present.  */
   4313   {
   4314     struct GNUNET_TIME_Timestamp now = GNUNET_TIME_timestamp_get ();
   4315 
   4316     /* Add timestamp if it doesn't exist (or is zero) */
   4317     if (GNUNET_TIME_absolute_is_zero (oc->parse_order.timestamp.abs_time))
   4318     {
   4319       oc->parse_order.timestamp = now;
   4320     }
   4321 
   4322     /* If no refund_deadline given, set one based on refund_delay.  */
   4323     if (GNUNET_TIME_absolute_is_never (
   4324           oc->parse_order.refund_deadline.abs_time))
   4325     {
   4326       if (GNUNET_TIME_relative_is_zero (oc->parse_request.refund_delay))
   4327       {
   4328         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   4329                     "Refund delay is zero, no refunds are possible for this order\n");
   4330         oc->parse_order.refund_deadline = GNUNET_TIME_UNIT_ZERO_TS;
   4331       }
   4332       else
   4333       {
   4334         computed_refund_deadline = true;
   4335         oc->parse_order.refund_deadline
   4336           = GNUNET_TIME_absolute_to_timestamp (
   4337               GNUNET_TIME_absolute_add (oc->parse_order.pay_deadline.abs_time,
   4338                                         oc->parse_request.refund_delay));
   4339       }
   4340     }
   4341 
   4342     if ( (! GNUNET_TIME_absolute_is_zero (
   4343             oc->parse_order.delivery_date.abs_time)) &&
   4344          (GNUNET_TIME_absolute_is_past (
   4345             oc->parse_order.delivery_date.abs_time)) )
   4346     {
   4347       GNUNET_break_op (0);
   4348       reply_with_error (
   4349         oc,
   4350         MHD_HTTP_BAD_REQUEST,
   4351         TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_DELIVERY_DATE_IN_PAST,
   4352         NULL);
   4353       return;
   4354     }
   4355   }
   4356 
   4357   if ( (! GNUNET_TIME_absolute_is_zero (
   4358           oc->parse_order.refund_deadline.abs_time)) &&
   4359        (GNUNET_TIME_absolute_is_past (
   4360           oc->parse_order.refund_deadline.abs_time)) )
   4361   {
   4362     GNUNET_break_op (0);
   4363     reply_with_error (
   4364       oc,
   4365       MHD_HTTP_BAD_REQUEST,
   4366       TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_REFUND_DEADLINE_IN_PAST,
   4367       NULL);
   4368     return;
   4369   }
   4370 
   4371   if (GNUNET_TIME_absolute_is_never (oc->parse_order.wire_deadline.abs_time))
   4372   {
   4373     struct GNUNET_TIME_Absolute start;
   4374 
   4375     start = GNUNET_TIME_absolute_max (
   4376       oc->parse_order.refund_deadline.abs_time,
   4377       oc->parse_order.pay_deadline.abs_time);
   4378     oc->parse_order.wire_deadline
   4379       = GNUNET_TIME_absolute_to_timestamp (
   4380           GNUNET_TIME_round_up (
   4381             GNUNET_TIME_absolute_add (
   4382               start,
   4383               settings->default_wire_transfer_delay),
   4384             settings->default_wire_transfer_rounding_interval));
   4385     if (GNUNET_TIME_absolute_is_never (
   4386           oc->parse_order.wire_deadline.abs_time))
   4387     {
   4388       GNUNET_break_op (0);
   4389       reply_with_error (
   4390         oc,
   4391         MHD_HTTP_BAD_REQUEST,
   4392         TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_WIRE_DEADLINE_IS_NEVER,
   4393         "order:wire_transfer_deadline");
   4394       return;
   4395     }
   4396   }
   4397   else if (computed_refund_deadline)
   4398   {
   4399     /* if we computed the refund_deadline from default settings
   4400        and did have a configured wire_deadline, make sure that
   4401        the refund_deadline is at or below the wire_deadline. */
   4402     oc->parse_order.refund_deadline
   4403       = GNUNET_TIME_timestamp_min (oc->parse_order.refund_deadline,
   4404                                    oc->parse_order.wire_deadline);
   4405   }
   4406   if (GNUNET_TIME_timestamp_cmp (oc->parse_order.wire_deadline,
   4407                                  <,
   4408                                  oc->parse_order.refund_deadline))
   4409   {
   4410     GNUNET_break_op (0);
   4411     reply_with_error (
   4412       oc,
   4413       MHD_HTTP_BAD_REQUEST,
   4414       TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_REFUND_AFTER_WIRE_DEADLINE,
   4415       "order:wire_transfer_deadline;order:refund_deadline");
   4416     return;
   4417   }
   4418 
   4419   if (NULL != merchant_base_url)
   4420   {
   4421     if (('\0' == *merchant_base_url) ||
   4422         ('/' != merchant_base_url[strlen (merchant_base_url) - 1]))
   4423     {
   4424       GNUNET_break_op (0);
   4425       reply_with_error (
   4426         oc,
   4427         MHD_HTTP_BAD_REQUEST,
   4428         TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_PROPOSAL_PARSE_ERROR,
   4429         "merchant_base_url is not valid");
   4430       return;
   4431     }
   4432     oc->parse_order.merchant_base_url
   4433       = GNUNET_strdup (merchant_base_url);
   4434   }
   4435   else
   4436   {
   4437     char *url;
   4438 
   4439     url = make_merchant_base_url (oc->connection,
   4440                                   settings->id);
   4441     if (NULL == url)
   4442     {
   4443       GNUNET_break_op (0);
   4444       reply_with_error (
   4445         oc,
   4446         MHD_HTTP_BAD_REQUEST,
   4447         TALER_EC_GENERIC_PARAMETER_MISSING,
   4448         "order:merchant_base_url");
   4449       return;
   4450     }
   4451     oc->parse_order.merchant_base_url = url;
   4452   }
   4453 
   4454   /* Merchant information must not already be present */
   4455   if (NULL != jmerchant)
   4456   {
   4457     GNUNET_break_op (0);
   4458     reply_with_error (
   4459       oc,
   4460       MHD_HTTP_BAD_REQUEST,
   4461       TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_PROPOSAL_PARSE_ERROR,
   4462       "'merchant' field already set, but must be provided by backend");
   4463     return;
   4464   }
   4465 
   4466   if ( (NULL != oc->parse_order.delivery_location) &&
   4467        (! TMH_location_object_valid (oc->parse_order.delivery_location)) )
   4468   {
   4469     GNUNET_break_op (0);
   4470     reply_with_error (oc,
   4471                       MHD_HTTP_BAD_REQUEST,
   4472                       TALER_EC_GENERIC_PARAMETER_MALFORMED,
   4473                       "delivery_location");
   4474     return;
   4475   }
   4476 
   4477   oc->phase++;
   4478 }
   4479 
   4480 
   4481 /* ***************** ORDER_PHASE_PARSE_REQUEST **************** */
   4482 
   4483 /**
   4484  * Parse the client request. Upon success,
   4485  * continue processing by calling parse_order().
   4486  *
   4487  * @param[in,out] oc order context to process
   4488  */
   4489 static void
   4490 phase_parse_request (struct OrderContext *oc)
   4491 {
   4492   const json_t *ip = NULL;
   4493   const json_t *uuid = NULL;
   4494   const char *otp_id = NULL;
   4495   bool create_token = true; /* default */
   4496   struct GNUNET_JSON_Specification spec[] = {
   4497     GNUNET_JSON_spec_json ("order",
   4498                            &oc->parse_request.order),
   4499     GNUNET_JSON_spec_mark_optional (
   4500       GNUNET_JSON_spec_relative_time ("refund_delay",
   4501                                       &oc->parse_request.refund_delay),
   4502       NULL),
   4503     GNUNET_JSON_spec_mark_optional (
   4504       GNUNET_JSON_spec_string ("payment_target",
   4505                                &oc->parse_request.payment_target),
   4506       NULL),
   4507     GNUNET_JSON_spec_mark_optional (
   4508       GNUNET_JSON_spec_array_const ("inventory_products",
   4509                                     &ip),
   4510       NULL),
   4511     GNUNET_JSON_spec_mark_optional (
   4512       GNUNET_JSON_spec_string ("session_id",
   4513                                &oc->parse_request.session_id),
   4514       NULL),
   4515     GNUNET_JSON_spec_mark_optional (
   4516       GNUNET_JSON_spec_array_const ("lock_uuids",
   4517                                     &uuid),
   4518       NULL),
   4519     GNUNET_JSON_spec_mark_optional (
   4520       GNUNET_JSON_spec_bool ("create_token",
   4521                              &create_token),
   4522       NULL),
   4523     GNUNET_JSON_spec_mark_optional (
   4524       GNUNET_JSON_spec_string ("otp_id",
   4525                                &otp_id),
   4526       NULL),
   4527     GNUNET_JSON_spec_end ()
   4528   };
   4529   enum GNUNET_GenericReturnValue ret;
   4530 
   4531   oc->parse_request.refund_delay
   4532     = oc->hc->instance->settings.default_refund_delay;
   4533   ret = TALER_MHD_parse_json_data (oc->connection,
   4534                                    oc->hc->request_body,
   4535                                    spec);
   4536   if (GNUNET_OK != ret)
   4537   {
   4538     GNUNET_break_op (0);
   4539     finalize_order2 (oc,
   4540                      ret);
   4541     return;
   4542   }
   4543   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   4544               "Refund delay is %s\n",
   4545               GNUNET_TIME_relative2s (oc->parse_request.refund_delay,
   4546                                       false));
   4547   TMH_db->expire_locks (TMH_db->cls);
   4548   if (NULL != otp_id)
   4549   {
   4550     struct TALER_MERCHANTDB_OtpDeviceDetails td;
   4551     enum GNUNET_DB_QueryStatus qs;
   4552 
   4553     memset (&td,
   4554             0,
   4555             sizeof (td));
   4556     qs = TMH_db->select_otp (TMH_db->cls,
   4557                              oc->hc->instance->settings.id,
   4558                              otp_id,
   4559                              &td);
   4560     switch (qs)
   4561     {
   4562     case GNUNET_DB_STATUS_HARD_ERROR:
   4563       GNUNET_break (0);
   4564       reply_with_error (oc,
   4565                         MHD_HTTP_INTERNAL_SERVER_ERROR,
   4566                         TALER_EC_GENERIC_DB_FETCH_FAILED,
   4567                         "select_otp");
   4568       return;
   4569     case GNUNET_DB_STATUS_SOFT_ERROR:
   4570       GNUNET_break (0);
   4571       reply_with_error (oc,
   4572                         MHD_HTTP_INTERNAL_SERVER_ERROR,
   4573                         TALER_EC_GENERIC_DB_SOFT_FAILURE,
   4574                         "select_otp");
   4575       return;
   4576     case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
   4577       reply_with_error (oc,
   4578                         MHD_HTTP_NOT_FOUND,
   4579                         TALER_EC_MERCHANT_GENERIC_OTP_DEVICE_UNKNOWN,
   4580                         otp_id);
   4581       return;
   4582     case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
   4583       break;
   4584     }
   4585     oc->parse_request.pos_key = td.otp_key;
   4586     oc->parse_request.pos_algorithm = td.otp_algorithm;
   4587     GNUNET_free (td.otp_description);
   4588   }
   4589   if (create_token)
   4590   {
   4591     GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
   4592                                 &oc->parse_request.claim_token,
   4593                                 sizeof (oc->parse_request.claim_token));
   4594   }
   4595   /* Compute h_post_data (for idempotency check) */
   4596   {
   4597     char *req_body_enc;
   4598 
   4599     /* Dump normalized JSON to string. */
   4600     if (NULL == (req_body_enc
   4601                    = json_dumps (oc->hc->request_body,
   4602                                  JSON_ENCODE_ANY
   4603                                  | JSON_COMPACT
   4604                                  | JSON_SORT_KEYS)))
   4605     {
   4606       GNUNET_break (0);
   4607       GNUNET_JSON_parse_free (spec);
   4608       reply_with_error (oc,
   4609                         MHD_HTTP_INTERNAL_SERVER_ERROR,
   4610                         TALER_EC_GENERIC_ALLOCATION_FAILURE,
   4611                         "request body normalization for hashing");
   4612       return;
   4613     }
   4614     GNUNET_CRYPTO_hash (req_body_enc,
   4615                         strlen (req_body_enc),
   4616                         &oc->parse_request.h_post_data.hash);
   4617     GNUNET_free (req_body_enc);
   4618   }
   4619 
   4620   /* parse the inventory_products (optionally given) */
   4621   if (NULL != ip)
   4622   {
   4623     unsigned int ipl = (unsigned int) json_array_size (ip);
   4624 
   4625     if ( (json_array_size (ip) != (size_t) ipl) ||
   4626          (ipl > MAX_PRODUCTS) )
   4627     {
   4628       GNUNET_break_op (0);
   4629       GNUNET_JSON_parse_free (spec);
   4630       reply_with_error (oc,
   4631                         MHD_HTTP_BAD_REQUEST,
   4632                         TALER_EC_GENERIC_PARAMETER_MALFORMED,
   4633                         "inventory_products (too many)");
   4634       return;
   4635     }
   4636     GNUNET_array_grow (oc->parse_request.inventory_products,
   4637                        oc->parse_request.inventory_products_length,
   4638                        (unsigned int) json_array_size (ip));
   4639     for (unsigned int i = 0; i<oc->parse_request.inventory_products_length; i++)
   4640     {
   4641       struct InventoryProduct *ipr = &oc->parse_request.inventory_products[i];
   4642       const char *error_name;
   4643       unsigned int error_line;
   4644       struct GNUNET_JSON_Specification ispec[] = {
   4645         GNUNET_JSON_spec_string ("product_id",
   4646                                  &ipr->product_id),
   4647         GNUNET_JSON_spec_mark_optional (
   4648           GNUNET_JSON_spec_uint64 ("quantity",
   4649                                    &ipr->quantity),
   4650           &ipr->quantity_missing),
   4651         GNUNET_JSON_spec_mark_optional (
   4652           GNUNET_JSON_spec_string ("unit_quantity",
   4653                                    &ipr->unit_quantity),
   4654           &ipr->unit_quantity_missing),
   4655         GNUNET_JSON_spec_mark_optional (
   4656           GNUNET_JSON_spec_uint64 ("product_money_pot",
   4657                                    &ipr->product_money_pot),
   4658           NULL),
   4659         GNUNET_JSON_spec_end ()
   4660       };
   4661 
   4662       ret = GNUNET_JSON_parse (json_array_get (ip,
   4663                                                i),
   4664                                ispec,
   4665                                &error_name,
   4666                                &error_line);
   4667       if (GNUNET_OK != ret)
   4668       {
   4669         GNUNET_break_op (0);
   4670         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   4671                     "Product parsing failed at #%u: %s:%u\n",
   4672                     i,
   4673                     error_name,
   4674                     error_line);
   4675         reply_with_error (oc,
   4676                           MHD_HTTP_BAD_REQUEST,
   4677                           TALER_EC_GENERIC_PARAMETER_MALFORMED,
   4678                           "inventory_products");
   4679         return;
   4680       }
   4681       if (ipr->quantity_missing && ipr->unit_quantity_missing)
   4682       {
   4683         ipr->quantity = 1;
   4684         ipr->quantity_missing = false;
   4685       }
   4686     }
   4687   }
   4688 
   4689   /* parse the lock_uuids (optionally given) */
   4690   if (NULL != uuid)
   4691   {
   4692     GNUNET_array_grow (oc->parse_request.uuids,
   4693                        oc->parse_request.uuids_length,
   4694                        json_array_size (uuid));
   4695     for (unsigned int i = 0; i<oc->parse_request.uuids_length; i++)
   4696     {
   4697       json_t *ui = json_array_get (uuid,
   4698                                    i);
   4699 
   4700       if (! json_is_string (ui))
   4701       {
   4702         GNUNET_break_op (0);
   4703         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   4704                     "UUID parsing failed at #%u\n",
   4705                     i);
   4706         reply_with_error (oc,
   4707                           MHD_HTTP_BAD_REQUEST,
   4708                           TALER_EC_GENERIC_PARAMETER_MALFORMED,
   4709                           "lock_uuids");
   4710         return;
   4711       }
   4712       TMH_uuid_from_string (json_string_value (ui),
   4713                             &oc->parse_request.uuids[i]);
   4714     }
   4715   }
   4716   oc->phase++;
   4717 }
   4718 
   4719 
   4720 /* ***************** Main handler **************** */
   4721 
   4722 
   4723 MHD_RESULT
   4724 TMH_private_post_orders (
   4725   const struct TMH_RequestHandler *rh,
   4726   struct MHD_Connection *connection,
   4727   struct TMH_HandlerContext *hc)
   4728 {
   4729   struct OrderContext *oc = hc->ctx;
   4730 
   4731   if (NULL == oc)
   4732   {
   4733     oc = GNUNET_new (struct OrderContext);
   4734     hc->ctx = oc;
   4735     hc->cc = &clean_order;
   4736     oc->connection = connection;
   4737     oc->hc = hc;
   4738   }
   4739   while (1)
   4740   {
   4741     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   4742                 "Processing order in phase %d\n",
   4743                 oc->phase);
   4744     switch (oc->phase)
   4745     {
   4746     case ORDER_PHASE_PARSE_REQUEST:
   4747       phase_parse_request (oc);
   4748       break;
   4749     case ORDER_PHASE_PARSE_ORDER:
   4750       phase_parse_order (oc);
   4751       break;
   4752     case ORDER_PHASE_PARSE_CHOICES:
   4753       phase_parse_choices (oc);
   4754       break;
   4755     case ORDER_PHASE_MERGE_INVENTORY:
   4756       phase_merge_inventory (oc);
   4757       break;
   4758     case ORDER_PHASE_ADD_PAYMENT_DETAILS:
   4759       phase_add_payment_details (oc);
   4760       break;
   4761     case ORDER_PHASE_SET_EXCHANGES:
   4762       if (phase_set_exchanges (oc))
   4763         return MHD_YES;
   4764       break;
   4765     case ORDER_PHASE_SELECT_WIRE_METHOD:
   4766       phase_select_wire_method (oc);
   4767       break;
   4768     case ORDER_PHASE_SET_MAX_FEE:
   4769       phase_set_max_fee (oc);
   4770       break;
   4771     case ORDER_PHASE_SERIALIZE_ORDER:
   4772       phase_serialize_order (oc);
   4773       break;
   4774     case ORDER_PHASE_CHECK_CONTRACT:
   4775       phase_check_contract (oc);
   4776       break;
   4777     case ORDER_PHASE_SALT_FORGETTABLE:
   4778       phase_salt_forgettable (oc);
   4779       break;
   4780     case ORDER_PHASE_EXECUTE_ORDER:
   4781       phase_execute_order (oc);
   4782       break;
   4783     case ORDER_PHASE_FINISHED_MHD_YES:
   4784       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   4785                   "Finished processing order (1)\n");
   4786       return MHD_YES;
   4787     case ORDER_PHASE_FINISHED_MHD_NO:
   4788       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   4789                   "Finished processing order (0)\n");
   4790       return MHD_NO;
   4791     }
   4792   }
   4793 }
   4794 
   4795 
   4796 /* end of taler-merchant-httpd_post-private-orders.c */