merchant

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

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


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