From 5b0f4ae9e68c3f5065c2c62bed7c7d3bc0b4423a Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Tue, 9 Apr 2024 17:45:08 +0200 Subject: implement protocol v14 / fix #8717 --- src/backend/taler-merchant-httpd_config.c | 10 +- .../taler-merchant-httpd_post-orders-ID-pay.c | 4 +- .../taler-merchant-httpd_private-get-orders-ID.c | 125 ++++++++++++--------- src/backenddb/pg_lookup_deposits_by_order.c | 7 +- src/backenddb/test_merchantdb.c | 91 +++++++++------ src/include/taler_merchant_service.h | 10 +- src/include/taler_merchantdb_plugin.h | 4 +- src/lib/merchant_api_get_config.c | 4 +- src/lib/merchant_api_merchant_get_order.c | 5 + 9 files changed, 163 insertions(+), 97 deletions(-) (limited to 'src') diff --git a/src/backend/taler-merchant-httpd_config.c b/src/backend/taler-merchant-httpd_config.c index bb4462bb..3777904f 100644 --- a/src/backend/taler-merchant-httpd_config.c +++ b/src/backend/taler-merchant-httpd_config.c @@ -42,7 +42,7 @@ * #MERCHANT_PROTOCOL_CURRENT and #MERCHANT_PROTOCOL_AGE in * merchant_api_config.c! */ -#define MERCHANT_PROTOCOL_VERSION "13:1:9" +#define MERCHANT_PROTOCOL_VERSION "14:0:10" /** @@ -116,7 +116,8 @@ MH_handler_config (struct TMH_RequestHandler *rh, GNUNET_assert (0 == json_object_set_new (specs, cspec->currency, - TALER_CONFIG_currency_specs_to_json ( + TALER_CONFIG_currency_specs_to_json + ( cspec))); } response = TALER_MHD_MAKE_JSON_PACK ( @@ -126,8 +127,9 @@ MH_handler_config (struct TMH_RequestHandler *rh, specs), GNUNET_JSON_pack_array_steal ("exchanges", exchanges), - GNUNET_JSON_pack_string ("implementation", - "urn:net:taler:specs:taler-merchant:c-reference"), + GNUNET_JSON_pack_string ( + "implementation", + "urn:net:taler:specs:taler-merchant:c-reference"), GNUNET_JSON_pack_string ("name", "taler-merchant"), GNUNET_JSON_pack_string ("version", diff --git a/src/backend/taler-merchant-httpd_post-orders-ID-pay.c b/src/backend/taler-merchant-httpd_post-orders-ID-pay.c index 07a6233a..14edfd55 100644 --- a/src/backend/taler-merchant-httpd_post-orders-ID-pay.c +++ b/src/backend/taler-merchant-httpd_post-orders-ID-pay.c @@ -2032,9 +2032,10 @@ phase_execute_pay_transaction (struct PayContext *pc) * @param cls closure with our `struct PayContext *` * @param deposit_serial which deposit operation is this about * @param exchange_url URL of the exchange that issued the coin + * @param h_wire hash of merchant's wire details + * @param deposit_timestamp when was the deposit made * @param amount_with_fee amount the exchange will deposit for this coin * @param deposit_fee fee the exchange will charge for this coin - * @param h_wire hash of merchant's wire details * @param coin_pub public key of the coin */ static void @@ -2043,6 +2044,7 @@ deposit_paid_check ( uint64_t deposit_serial, const char *exchange_url, const struct TALER_MerchantWireHashP *h_wire, + struct GNUNET_TIME_Timestamp deposit_timestamp, const struct TALER_Amount *amount_with_fee, const struct TALER_Amount *deposit_fee, const struct TALER_CoinSpendPublicKeyP *coin_pub) diff --git a/src/backend/taler-merchant-httpd_private-get-orders-ID.c b/src/backend/taler-merchant-httpd_private-get-orders-ID.c index 1c850990..98653997 100644 --- a/src/backend/taler-merchant-httpd_private-get-orders-ID.c +++ b/src/backend/taler-merchant-httpd_private-get-orders-ID.c @@ -262,6 +262,11 @@ struct GetOrderRequestContext */ struct GNUNET_TIME_Timestamp timestamp; + /** + * Timestamp of the last payment. + */ + struct GNUNET_TIME_Timestamp last_payment; + /** * Order summary. Pointer into @e contract_terms. */ @@ -996,15 +1001,16 @@ phase_unpaid_finish (struct GetOrderRequestContext *gorc) * @param pending true if the this refund was not yet processed by the wallet/exchange */ static void -process_refunds_cb (void *cls, - uint64_t refund_serial, - struct GNUNET_TIME_Timestamp timestamp, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - const char *exchange_url, - uint64_t rtransaction_id, - const char *reason, - const struct TALER_Amount *refund_amount, - bool pending) +process_refunds_cb ( + void *cls, + uint64_t refund_serial, + struct GNUNET_TIME_Timestamp timestamp, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const char *exchange_url, + uint64_t rtransaction_id, + const char *reason, + const struct TALER_Amount *refund_amount, + bool pending) { struct GetOrderRequestContext *gorc = cls; @@ -1013,18 +1019,19 @@ process_refunds_cb (void *cls, (unsigned long long) rtransaction_id, TALER_amount2s (refund_amount), reason); - GNUNET_assert (0 == - json_array_append_new ( - gorc->refund_details, - GNUNET_JSON_PACK ( - TALER_JSON_pack_amount ("amount", - refund_amount), - GNUNET_JSON_pack_bool ("pending", - pending), - GNUNET_JSON_pack_timestamp ("timestamp", - timestamp), - GNUNET_JSON_pack_string ("reason", - reason)))); + GNUNET_assert ( + 0 == + json_array_append_new ( + gorc->refund_details, + GNUNET_JSON_PACK ( + TALER_JSON_pack_amount ("amount", + refund_amount), + GNUNET_JSON_pack_bool ("pending", + pending), + GNUNET_JSON_pack_timestamp ("timestamp", + timestamp), + GNUNET_JSON_pack_string ("reason", + reason)))); /* For refunded coins, we are not charged deposit fees, so subtract those again */ for (struct TransferQuery *tq = gorc->tq_head; @@ -1044,10 +1051,11 @@ process_refunds_cb (void *cls, return; } - GNUNET_assert (0 <= - TALER_amount_subtract (&gorc->deposit_fees_total, - &gorc->deposit_fees_total, - &tq->deposit_fee)); + GNUNET_assert ( + 0 <= + TALER_amount_subtract (&gorc->deposit_fees_total, + &gorc->deposit_fees_total, + &tq->deposit_fee)); } } if (GNUNET_OK != @@ -1084,29 +1092,32 @@ phase_check_refunds (struct GetOrderRequestContext *gorc) GNUNET_assert (GNUNET_OK == TALER_amount_set_zero (gorc->contract_amount.currency, &gorc->refund_amount)); - qs = TMH_db->lookup_refunds_detailed (TMH_db->cls, - hc->instance->settings.id, - &gorc->h_contract_terms, - &process_refunds_cb, - gorc); + qs = TMH_db->lookup_refunds_detailed ( + TMH_db->cls, + hc->instance->settings.id, + &gorc->h_contract_terms, + &process_refunds_cb, + gorc); if (0 > qs) { GNUNET_break (0); phase_end (gorc, - TALER_MHD_reply_with_error (gorc->sc.con, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_FETCH_FAILED, - "detailed refunds")); + TALER_MHD_reply_with_error ( + gorc->sc.con, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_FETCH_FAILED, + "detailed refunds")); return; } if (gorc->refund_currency_mismatch) { GNUNET_break (0); phase_end (gorc, - TALER_MHD_reply_with_error (gorc->sc.con, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_FETCH_FAILED, - "refunds in different currency than original order price")); + TALER_MHD_reply_with_error ( + gorc->sc.con, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_FETCH_FAILED, + "refunds in different currency than original order price")); return; } GNUNET_log (GNUNET_ERROR_TYPE_INFO, @@ -1127,19 +1138,22 @@ phase_check_refunds (struct GetOrderRequestContext *gorc) * @param cls a `struct GetOrderRequestContext` * @param deposit_serial identifies the deposit operation * @param exchange_url URL of the exchange that issued @a coin_pub + * @param h_wire hash of the merchant's wire account into which the deposit was made + * @param deposit_timestamp when was the deposit made * @param amount_with_fee amount the exchange will deposit for this coin * @param deposit_fee fee the exchange will charge for this coin - * @param h_wire hash of the merchant's wire account into which the deposit was made * @param coin_pub public key of the deposited coin */ static void -deposit_cb (void *cls, - uint64_t deposit_serial, - const char *exchange_url, - const struct TALER_MerchantWireHashP *h_wire, - const struct TALER_Amount *amount_with_fee, - const struct TALER_Amount *deposit_fee, - const struct TALER_CoinSpendPublicKeyP *coin_pub) +deposit_cb ( + void *cls, + uint64_t deposit_serial, + const char *exchange_url, + const struct TALER_MerchantWireHashP *h_wire, + struct GNUNET_TIME_Timestamp deposit_timestamp, + const struct TALER_Amount *amount_with_fee, + const struct TALER_Amount *deposit_fee, + const struct TALER_CoinSpendPublicKeyP *coin_pub) { struct GetOrderRequestContext *gorc = cls; struct TransferQuery *tq; @@ -1148,6 +1162,9 @@ deposit_cb (void *cls, "Checking deposit status for coin %s (over %s)\n", TALER_B2S (coin_pub), TALER_amount2s (amount_with_fee)); + gorc->last_payment + = GNUNET_TIME_timestamp_max (gorc->last_payment, + deposit_timestamp); tq = GNUNET_new (struct TransferQuery); tq->gorc = gorc; tq->exchange_url = GNUNET_strdup (exchange_url); @@ -1380,7 +1397,12 @@ phase_reply_result (struct GetOrderRequestContext *gorc) &gorc->claim_token, h_contract); } - + if (GNUNET_TIME_absolute_is_zero (gorc->last_payment.abs_time)) + { + GNUNET_break (GNUNET_YES == + TALER_amount_is_zero (&gorc->contract_amount)); + gorc->last_payment = gorc->timestamp; + } ret = TALER_MHD_REPLY_JSON_PACK ( gorc->sc.con, MHD_HTTP_OK, @@ -1403,6 +1425,8 @@ phase_reply_result (struct GetOrderRequestContext *gorc) gorc->contract_terms), GNUNET_JSON_pack_string ("order_status", "paid"), + GNUNET_JSON_pack_timestamp ("last_payment", + gorc->last_payment), GNUNET_JSON_pack_bool ("refunded", gorc->refunded), GNUNET_JSON_pack_bool ("wired", @@ -1443,9 +1467,10 @@ phase_error (struct GetOrderRequestContext *gorc) MHD_RESULT -TMH_private_get_orders_ID (const struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - struct TMH_HandlerContext *hc) +TMH_private_get_orders_ID ( + const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc) { struct GetOrderRequestContext *gorc = hc->ctx; diff --git a/src/backenddb/pg_lookup_deposits_by_order.c b/src/backenddb/pg_lookup_deposits_by_order.c index fdaf1dfc..fb7637f0 100644 --- a/src/backenddb/pg_lookup_deposits_by_order.c +++ b/src/backenddb/pg_lookup_deposits_by_order.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2023 Taler Systems SA + Copyright (C) 2023, 2024 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -74,6 +74,7 @@ lookup_deposits_by_order_cb (void *cls, char *exchange_url; struct TALER_MerchantWireHashP h_wire; struct TALER_CoinSpendPublicKeyP coin_pub; + struct GNUNET_TIME_Timestamp deposit_timestamp; struct TALER_Amount amount_with_fee; struct TALER_Amount deposit_fee; struct GNUNET_PQ_ResultSpec rs[] = { @@ -81,6 +82,8 @@ lookup_deposits_by_order_cb (void *cls, &deposit_serial), GNUNET_PQ_result_spec_string ("exchange_url", &exchange_url), + GNUNET_PQ_result_spec_timestamp ("deposit_timestamp", + &deposit_timestamp), GNUNET_PQ_result_spec_auto_from_type ("h_wire", &h_wire), TALER_PQ_result_spec_amount_with_currency ("amount_with_fee", @@ -105,6 +108,7 @@ lookup_deposits_by_order_cb (void *cls, deposit_serial, exchange_url, &h_wire, + deposit_timestamp, &amount_with_fee, &deposit_fee, &coin_pub); @@ -139,6 +143,7 @@ TMH_PG_lookup_deposits_by_order (void *cls, " dep.deposit_serial" ",mcon.exchange_url" ",acc.h_wire" + ",mcon.deposit_timestamp" ",dep.amount_with_fee" ",dep.deposit_fee" ",dep.coin_pub" diff --git a/src/backenddb/test_merchantdb.c b/src/backenddb/test_merchantdb.c index 1a4c15db..fbb662f8 100644 --- a/src/backenddb/test_merchantdb.c +++ b/src/backenddb/test_merchantdb.c @@ -42,28 +42,28 @@ static struct TALER_MERCHANTDB_Plugin *plugin; * @param test 0 on success, non-zero on failure */ #define TEST_WITH_FAIL_CLAUSE(test, on_fail) \ - if ((test)) \ - { \ - GNUNET_break (0); \ - on_fail \ - } + if ((test)) \ + { \ + GNUNET_break (0); \ + on_fail \ + } #define TEST_COND_RET_ON_FAIL(cond, msg) \ - if (! (cond)) \ - { \ - GNUNET_break (0); \ - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, \ - msg); \ - return 1; \ - } + if (! (cond)) \ + { \ + GNUNET_break (0); \ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, \ + msg); \ + return 1; \ + } /** * @param __test 0 on success, non-zero on failure */ #define TEST_RET_ON_FAIL(__test) \ - TEST_WITH_FAIL_CLAUSE (__test, \ - return 1; \ - ) + TEST_WITH_FAIL_CLAUSE (__test, \ + return 1; \ + ) /* ********** Instances ********** */ @@ -1136,7 +1136,8 @@ run_test_products (struct TestProducts_Closure *cls) stock_dec.product.total_stock = 40; TEST_RET_ON_FAIL (test_update_product (&cls->instance, &stock_dec, - GNUNET_DB_STATUS_SUCCESS_NO_RESULTS)); + GNUNET_DB_STATUS_SUCCESS_NO_RESULTS)) + ; } { struct ProductData lost_dec = cls->products[0]; @@ -1144,7 +1145,8 @@ run_test_products (struct TestProducts_Closure *cls) lost_dec.product.total_lost = 1; TEST_RET_ON_FAIL (test_update_product (&cls->instance, &lost_dec, - GNUNET_DB_STATUS_SUCCESS_NO_RESULTS)); + GNUNET_DB_STATUS_SUCCESS_NO_RESULTS)) + ; } TEST_RET_ON_FAIL (test_lookup_product (&cls->instance, &cls->products[0])); @@ -2195,14 +2197,16 @@ run_test_orders (struct TestOrders_Closure *cls) cls->orders)); /* Test marking orders as wired */ TEST_RET_ON_FAIL (test_mark_order_wired (serial, - GNUNET_DB_STATUS_SUCCESS_ONE_RESULT)); + GNUNET_DB_STATUS_SUCCESS_ONE_RESULT)) + ; TEST_RET_ON_FAIL (test_lookup_payment_status (cls->instance.instance.id, cls->orders[0].id, NULL, true, true)); TEST_RET_ON_FAIL (test_mark_order_wired (1007, - GNUNET_DB_STATUS_SUCCESS_NO_RESULTS)); + GNUNET_DB_STATUS_SUCCESS_NO_RESULTS)) + ; /* If an order has been claimed and we aren't past the pay deadline, we can't delete it. */ TEST_RET_ON_FAIL (test_delete_order (&cls->instance, @@ -2478,7 +2482,8 @@ test_insert_exchange_signkey (const struct ExchangeSignkeyData *signkey, TEST_COND_RET_ON_FAIL (expected_result == plugin->insert_exchange_signkey (plugin->cls, &signkey->master_pub, - &signkey->exchange_pub, + &signkey->exchange_pub + , signkey->start_date, signkey->expire_date, signkey->end_date, @@ -2806,8 +2811,8 @@ test_lookup_deposits_contract_and_coin ( * @param cls pointer to the test lookup closure. * @param deposit_serial row number of the deposit in the database. * @param exchange_url URL to the exchange - * @param amount_with_fee amount of the deposit with fees. * @param h_wire hash of the wire transfer details. + * @param deposit_timestamp when was the deposit made * @param amount_with_fee amount of the deposit with fees. * @param deposit_fee fee charged for the deposit. * @param coin_pub public key of the coin deposited. @@ -2817,11 +2822,13 @@ lookup_deposits_order_cb (void *cls, uint64_t deposit_serial, const char *exchange_url, const struct TALER_MerchantWireHashP *h_wire, + struct GNUNET_TIME_Timestamp deposit_timestamp, const struct TALER_Amount *amount_with_fee, const struct TALER_Amount *deposit_fee, const struct TALER_CoinSpendPublicKeyP *coin_pub) { struct TestLookupDeposits_Closure *cmp = cls; + if (NULL == cmp) return; cmp->results_length += 1; @@ -2871,11 +2878,11 @@ test_lookup_deposits_by_order (uint64_t order_serial, memset (results_matching, 0, sizeof (unsigned int) * deposits_length); - if (deposits_length != plugin->lookup_deposits_by_order (plugin->cls, - order_serial, - & - lookup_deposits_order_cb, - &cmp)) + if (deposits_length != + plugin->lookup_deposits_by_order (plugin->cls, + order_serial, + &lookup_deposits_order_cb, + &cmp)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Lookup deposits by order failed\n"); @@ -2923,8 +2930,8 @@ struct LookupDepositSerial_Closure * @param cls pointer to the test lookup closure. * @param deposit_serial row number of the deposit in the database. * @param exchange_url URL to the exchange - * @param amount_with_fee amount of the deposit with fees. * @param h_wire hash of the wire transfer details. + * @param deposit_timestamp when was the deposit made. * @param amount_with_fee amount of the deposit with fees. * @param deposit_fee fee charged for the deposit. * @param coin_pub public key of the coin deposited. @@ -2934,11 +2941,14 @@ get_deposit_serial_cb (void *cls, uint64_t deposit_serial, const char *exchange_url, const struct TALER_MerchantWireHashP *h_wire, + struct GNUNET_TIME_Timestamp deposit_timestamp, const struct TALER_Amount *amount_with_fee, const struct TALER_Amount *deposit_fee, const struct TALER_CoinSpendPublicKeyP *coin_pub) { struct LookupDepositSerial_Closure *lookup_cls = cls; + + (void) deposit_timestamp; if (NULL == lookup_cls) return; if ((0 == strcmp (lookup_cls->deposit->exchange_url, @@ -4090,7 +4100,8 @@ test_insert_transfer_details ( TEST_COND_RET_ON_FAIL (expected_result == plugin->insert_transfer_details (plugin->cls, instance->instance.id, - transfer->exchange_url, + transfer->exchange_url + , account->payto_uri, &transfer->wtid, &transfer->data), @@ -4458,7 +4469,8 @@ test_lookup_refunds (const struct InstanceData *instance, if (refunds_length != cmp.results_length) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Lookup refunds failed: incorrect number of results returned\n"); + "Lookup refunds failed: incorrect number of results returned\n") + ; return 1; } for (unsigned int i = 0; refunds_length > i; ++i) @@ -4666,7 +4678,8 @@ test_lookup_refunds_detailed ( if (refunds_length != cmp.results_length) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Lookup refunds detailed failed: incorrect number of results\n"); + "Lookup refunds detailed failed: incorrect number of results\n") + ; return 1; } for (unsigned int i = 0; refunds_length > i; ++i) @@ -4980,7 +4993,8 @@ run_test_refunds (struct TestRefunds_Closure *cls) TEST_COND_RET_ON_FAIL (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == plugin->refund_coin (plugin->cls, cls->instance.instance.id, - &cls->deposits[0].h_contract_terms, + &cls->deposits[0].h_contract_terms + , cls->refunds[0].timestamp, cls->refunds[0].coin_pub, cls->refunds[0].reason), @@ -4992,7 +5006,8 @@ run_test_refunds (struct TestRefunds_Closure *cls) TEST_COND_RET_ON_FAIL (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == plugin->refund_coin (plugin->cls, cls->instance.instance.id, - &cls->deposits[0].h_contract_terms, + &cls->deposits[0].h_contract_terms + , cls->refunds[0].timestamp, cls->refunds[0].coin_pub, cls->refunds[0].reason), @@ -5016,14 +5031,16 @@ run_test_refunds (struct TestRefunds_Closure *cls) refund_serial, &cls->refund_proof. exchange_sig, - &cls->signkey.exchange_pub), + &cls->signkey.exchange_pub + ), "Insert refund proof failed\n"); TEST_COND_RET_ON_FAIL (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == plugin->insert_refund_proof (plugin->cls, refund_serial, &cls->refund_proof. exchange_sig, - &cls->signkey.exchange_pub), + &cls->signkey.exchange_pub + ), "Insert refund proof failed\n"); /* Test that we can't give too much in refunds */ GNUNET_assert (GNUNET_OK == @@ -6568,7 +6585,8 @@ test_insert_pending_webhook (const struct InstanceData *instance, http_method, pwebhook->pwebhook. header, - pwebhook->pwebhook.body), + pwebhook->pwebhook.body + ), "Insert pending webhook failed\n"); return 0; } @@ -7020,7 +7038,8 @@ run_test_pending_webhooks (struct TestPendingWebhooks_Closure *cls) &cls->pwebhooks[1])); TEST_RET_ON_FAIL (test_update_pending_webhook (&cls->instance, &cls->pwebhooks[1], - GNUNET_DB_STATUS_SUCCESS_NO_RESULTS)); // ??? + GNUNET_DB_STATUS_SUCCESS_NO_RESULTS)); + // ??? TEST_RET_ON_FAIL (test_lookup_all_webhooks (&cls->instance, 2, cls->pwebhooks)); diff --git a/src/include/taler_merchant_service.h b/src/include/taler_merchant_service.h index 263a6fec..43d67aff 100644 --- a/src/include/taler_merchant_service.h +++ b/src/include/taler_merchant_service.h @@ -34,7 +34,7 @@ /** * Library version (in hex) for compatibility tests. */ -#define TALER_MERCHANT_SERVICE_VERSION 0x00090403 +#define TALER_MERCHANT_SERVICE_VERSION 0x00100000 /** @@ -949,7 +949,7 @@ TALER_MERCHANT_instance_delete_cancel ( * @param arg request to cancel. */ #define TALER_MERCHANT_instance_purge_cancel(arg) \ - TALER_MERCHANT_instance_delete_cancel (arg) + TALER_MERCHANT_instance_delete_cancel (arg) /* *************** Accounts **************** */ @@ -2664,6 +2664,12 @@ struct TALER_MERCHANT_OrderStatusResponse */ bool wired; + /** + * Time of the last payment made on this order. + * Only availalbe if the server supports protocol + * **v14** or higher, otherwise zero. + */ + struct GNUNET_TIME_Timestamp last_payment; } paid; /** diff --git a/src/include/taler_merchantdb_plugin.h b/src/include/taler_merchantdb_plugin.h index e7eb2d0f..c83b3c93 100644 --- a/src/include/taler_merchantdb_plugin.h +++ b/src/include/taler_merchantdb_plugin.h @@ -932,9 +932,10 @@ typedef void * @param cls closure * @param deposit_serial which deposit operation is this about * @param exchange_url URL of the exchange that issued the coin + * @param h_wire hash of merchant's wire details + * @param deposit_timestamp when was the deposit made * @param amount_with_fee amount the exchange will deposit for this coin * @param deposit_fee fee the exchange will charge for this coin - * @param h_wire hash of merchant's wire details * @param coin_pub public key of the coin */ typedef void @@ -943,6 +944,7 @@ typedef void uint64_t deposit_serial, const char *exchange_url, const struct TALER_MerchantWireHashP *h_wire, + struct GNUNET_TIME_Timestamp deposit_timestamp, const struct TALER_Amount *amount_with_fee, const struct TALER_Amount *deposit_fee, const struct TALER_CoinSpendPublicKeyP *coin_pub); diff --git a/src/lib/merchant_api_get_config.c b/src/lib/merchant_api_get_config.c index ddbc20a3..b4b700bd 100644 --- a/src/lib/merchant_api_get_config.c +++ b/src/lib/merchant_api_get_config.c @@ -34,12 +34,12 @@ * Which version of the Taler protocol is implemented * by this library? Used to determine compatibility. */ -#define MERCHANT_PROTOCOL_CURRENT 13 +#define MERCHANT_PROTOCOL_CURRENT 14 /** * How many configs are we backwards-compatible with? */ -#define MERCHANT_PROTOCOL_AGE 1 +#define MERCHANT_PROTOCOL_AGE 2 /** * How many exchanges do we allow at most per merchant? diff --git a/src/lib/merchant_api_merchant_get_order.c b/src/lib/merchant_api_merchant_get_order.c index 3a49db34..3bd4003b 100644 --- a/src/lib/merchant_api_merchant_get_order.c +++ b/src/lib/merchant_api_merchant_get_order.c @@ -202,6 +202,11 @@ handle_paid (struct TALER_MERCHANT_OrderMerchantGetHandle *omgh, &wire_details), GNUNET_JSON_spec_array_const ("refund_details", &refund_details), + /* Only available since **v14** */ + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_timestamp ("last_payment", + &osr->details.ok.details.paid.last_payment), + NULL), GNUNET_JSON_spec_end () }; -- cgit v1.2.3