merchant

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

commit 9e2795084737fa588a0b0552ca04cbd165aba10b
parent fe973b29bba8a6f46989743e4263a23e473735b8
Author: Marcello Stanisci <marcello.stanisci@inria.fr>
Date:   Thu, 13 Oct 2016 00:27:43 +0200

adapting callback for 'find_transaction' DB functions family

Diffstat:
Msrc/backend/taler-merchant-httpd_history.c | 2++
Msrc/backend/taler-merchant-httpd_pay.c | 641++++++++++++++++++++++++++++++++++++++++---------------------------------------
Msrc/backend/taler-merchant-httpd_track-transaction.c | 11+++++++----
Msrc/backenddb/plugin_merchantdb_postgres.c | 25++++++++++++++++++-------
Msrc/backenddb/test_merchantdb.c | 16++++++++++++----
Msrc/include/taler_merchantdb_plugin.h | 13+++++++++----
6 files changed, 370 insertions(+), 338 deletions(-)

diff --git a/src/backend/taler-merchant-httpd_history.c b/src/backend/taler-merchant-httpd_history.c @@ -31,6 +31,7 @@ * * @param cls closure * @param transaction_id of the contract + * @param merchant_pub merchant's public key * @param exchange_uri URI of the exchange * @param h_contract hash of the contract * @param h_wire hash of our wire details @@ -42,6 +43,7 @@ static void history_cb (void *cls, uint64_t transaction_id, + const struct TALER_MerchantPublicKeyP *merchant_pub, const char *exchange_uri, const struct GNUNET_HashCode *h_contract, const struct GNUNET_HashCode *h_wire, diff --git a/src/backend/taler-merchant-httpd_pay.c b/src/backend/taler-merchant-httpd_pay.c @@ -786,6 +786,7 @@ check_coin_paid (void *cls, * * @param cls closure with the `struct PayContext` * @param transaction_id of the contract + * @param merchant_pub merchant's public key * @param exchange_uri URI of the exchange * @param h_contract hash of the contract * @param h_xwire hash of our wire details @@ -794,325 +795,327 @@ check_coin_paid (void *cls, * @param total_amount total amount we receive for the contract after fees */ static void -check_transaction_exists (void *cls, - uint64_t transaction_id, - const char *exchange_uri, - const struct GNUNET_HashCode *h_contract, - const struct GNUNET_HashCode *h_xwire, - struct GNUNET_TIME_Absolute timestamp, - struct GNUNET_TIME_Absolute refund, - const struct TALER_Amount *total_amount) -{ - struct PayContext *pc = cls; - - if ( (0 == memcmp (h_contract, - &pc->h_contract, - sizeof (struct GNUNET_HashCode))) && - (0 == memcmp (h_xwire, - &pc->mi->h_wire, - sizeof (struct GNUNET_HashCode))) && - (timestamp.abs_value_us == pc->timestamp.abs_value_us) && - (refund.abs_value_us == pc->refund_deadline.abs_value_us) && - (0 == TALER_amount_cmp (total_amount, - &pc->amount) ) ) - { - pc->transaction_exits = GNUNET_YES; - } - else - { - GNUNET_break_op (0); - pc->transaction_exits = GNUNET_SYSERR; - } -} - -extern struct MerchantInstance * -get_instance (struct json_t *json); - -/** - * Accomplish this payment. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure - * (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a - * upload_data - * @return MHD result code - */ -int -MH_handler_pay (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size) -{ - struct PayContext *pc; - int res; - json_t *root; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "In handler for /pay.\n"); - if (NULL == *connection_cls) - { - pc = GNUNET_new (struct PayContext); - pc->hc.cc = &pay_context_cleanup; - pc->connection = connection; - *connection_cls = pc; - } - else - { - /* not the first call, recover state */ - pc = *connection_cls; - } - if (0 != pc->response_code) - { - /* We are *done* processing the request, just queue the response (!) */ - if (UINT_MAX == pc->response_code) - { - GNUNET_break (0); - return MHD_NO; /* hard error */ - } - res = MHD_queue_response (connection, - pc->response_code, - pc->response); - if (NULL != pc->response) - { - MHD_destroy_response (pc->response); - pc->response = NULL; - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Queueing response (%u) for /pay (%s).\n", - (unsigned int) pc->response_code, - res ? "OK" : "FAILED"); - return res; - } - if (NULL != pc->chosen_exchange) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Shouldn't be here. Old MHD version?\n"); - return MHD_YES; - } - res = TMH_PARSE_post_json (connection, - &pc->json_parse_context, - upload_data, - upload_data_size, - &root); - if (GNUNET_SYSERR == res) - { - GNUNET_break (0); - return TMH_RESPONSE_reply_external_error (connection, - "failed to parse JSON body"); - } - if ((GNUNET_NO == res) || (NULL == root)) - return MHD_YES; /* the POST's body has to be further fetched */ - - mi = get_instance (root); - - /* Got the JSON upload, parse it */ - { - json_t *coins; - json_t *coin; - unsigned int coins_index; - struct TALER_MerchantSignatureP merchant_sig; - struct TALER_ContractPS cp; - const char *chosen_exchange; - struct GNUNET_JSON_Specification spec[] = { - TALER_JSON_spec_amount ("amount", &pc->amount), - GNUNET_JSON_spec_json ("coins", &coins), - GNUNET_JSON_spec_fixed_auto ("H_contract", &pc->h_contract), - TALER_JSON_spec_amount ("max_fee", &pc->max_fee), - GNUNET_JSON_spec_fixed_auto ("merchant_sig", &merchant_sig), - GNUNET_JSON_spec_string ("exchange", &chosen_exchange), - GNUNET_JSON_spec_absolute_time ("refund_deadline", &pc->refund_deadline), - GNUNET_JSON_spec_absolute_time ("timestamp", &pc->timestamp), - GNUNET_JSON_spec_uint64 ("transaction_id", &pc->transaction_id), - GNUNET_JSON_spec_end() - }; - - res = TMH_PARSE_json_data (connection, - root, - spec); - if (GNUNET_YES != res) - { - json_decref (root); - GNUNET_break (0); - return (GNUNET_NO == res) ? MHD_YES : MHD_NO; - } - pc->mi = get_instance (root); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "/pay: picked instance %s\n", - pc->mi->id); - - if (NULL == pc->mi) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Not able to find the specified receiver\n"); - json_decref (root); - return TMH_RESPONSE_reply_external_error (connection, - "Unknown receiver given"); - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "The receiver for this deposit is '%s', whose bank details are '%s'\n", - pc->mi->id, - json_dumps (pc->mi->j_wire, JSON_COMPACT)); - pc->chosen_exchange = GNUNET_strdup (chosen_exchange); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Parsed JSON for /pay.\n"); - cp.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_CONTRACT); - cp.purpose.size = htonl (sizeof (struct TALER_ContractPS)); - cp.transaction_id = GNUNET_htonll (pc->transaction_id); - TALER_amount_hton (&cp.total_amount, - &pc->amount); - TALER_amount_hton (&cp.max_fee, - &pc->max_fee); - cp.h_contract = pc->h_contract; - cp.merchant_pub = pc->mi->pubkey; - if (GNUNET_OK != - GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MERCHANT_CONTRACT, - &cp.purpose, - &merchant_sig.eddsa_sig, - &pc->mi->pubkey.eddsa_pub)) - { - GNUNET_break (0); - GNUNET_JSON_parse_free (spec); - json_decref (root); - return TMH_RESPONSE_reply_external_error (connection, - "invalid merchant signature supplied"); - } - - /* 'wire_transfer_deadline' is optional, if it is not present, - generate it here; it will be timestamp plus the - wire_transfer_delay supplied in config file */ - if (NULL == json_object_get (root, - "wire_transfer_deadline")) - { - pc->wire_transfer_deadline = GNUNET_TIME_absolute_add (pc->timestamp, - wire_transfer_delay); - if (pc->wire_transfer_deadline.abs_value_us < pc->refund_deadline.abs_value_us) - { - /* Refund value very large, delay wire transfer accordingly */ - pc->wire_transfer_deadline = pc->refund_deadline; - } - } - else - { - struct GNUNET_JSON_Specification espec[] = { - GNUNET_JSON_spec_absolute_time ("wire_transfer_deadline", - &pc->wire_transfer_deadline), - GNUNET_JSON_spec_end() - }; - - res = TMH_PARSE_json_data (connection, - root, - espec); - if (GNUNET_YES != res) - { - GNUNET_JSON_parse_free (spec); - json_decref (root); - GNUNET_break (0); - return (GNUNET_NO == res) ? MHD_YES : MHD_NO; - } - if (pc->wire_transfer_deadline.abs_value_us < pc->refund_deadline.abs_value_us) - { - GNUNET_break (0); - GNUNET_JSON_parse_free (spec); - json_decref (root); - return TMH_RESPONSE_reply_external_error (connection, - "refund deadline after wire transfer deadline"); - } - } - - - pc->coins_cnt = json_array_size (coins); - if (0 == pc->coins_cnt) - { - GNUNET_JSON_parse_free (spec); - json_decref (root); - return TMH_RESPONSE_reply_external_error (connection, - "no coins given"); - } - /* note: 1 coin = 1 deposit confirmation expected */ - pc->dc = GNUNET_new_array (pc->coins_cnt, - struct DepositConfirmation); - - /* This loop populates the array 'dc' in 'pc' */ - json_array_foreach (coins, coins_index, coin) - { - struct DepositConfirmation *dc = &pc->dc[coins_index]; - struct GNUNET_JSON_Specification spec[] = { - TALER_JSON_spec_denomination_public_key ("denom_pub", &dc->denom), - TALER_JSON_spec_amount ("f" /* FIXME */, &dc->amount_with_fee), - GNUNET_JSON_spec_fixed_auto ("coin_pub", &dc->coin_pub), - TALER_JSON_spec_denomination_signature ("ub_sig", &dc->ub_sig), - GNUNET_JSON_spec_fixed_auto ("coin_sig", &dc->coin_sig), - GNUNET_JSON_spec_end() - }; - - res = TMH_PARSE_json_data (connection, - coin, - spec); - if (GNUNET_YES != res) - { - GNUNET_JSON_parse_free (spec); - json_decref (root); - GNUNET_break (0); - return (GNUNET_NO == res) ? MHD_YES : MHD_NO; - } - - { - char *s; - - s = TALER_amount_to_string (&dc->amount_with_fee); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Coin #%i has f %s\n", - coins_index, - s); - GNUNET_free (s); - } - - dc->index = coins_index; - dc->pc = pc; - } - GNUNET_JSON_parse_free (spec); - } /* end of parsing of JSON upload */ - pc->pending = pc->coins_cnt; - - /* Check if this payment attempt has already succeeded */ - if (GNUNET_SYSERR == - db->find_payments_by_id (db->cls, - pc->transaction_id, - &check_coin_paid, - pc)) - { - GNUNET_break (0); - json_decref (root); - return TMH_RESPONSE_reply_internal_error (connection, - "Merchant database error"); - } - if (0 == pc->pending) - { - struct MHD_Response *resp; - int ret; - - /* Payment succeeded in the past; take short cut - and accept immediately */ - resp = MHD_create_response_from_buffer (0, - NULL, - MHD_RESPMEM_PERSISTENT); - ret = MHD_queue_response (connection, - MHD_HTTP_OK, - resp); - MHD_destroy_response (resp); - json_decref (root); - return ret; - } - /* Check if transaction is already known, if not store it. */ - if (GNUNET_SYSERR == - db->find_transaction_by_id (db->cls, - pc->transaction_id, - &check_transaction_exists, - pc)) + check_transaction_exists (void *cls, + uint64_t transaction_id, + const struct TALER_MerchantPublicKeyP *merchant_pub, + const char *exchange_uri, + const struct GNUNET_HashCode *h_contract, + const struct GNUNET_HashCode *h_xwire, + struct GNUNET_TIME_Absolute timestamp, + struct GNUNET_TIME_Absolute refund, + const struct TALER_Amount *total_amount) + { + struct PayContext *pc = cls; + + if ( (0 == memcmp (h_contract, + &pc->h_contract, + sizeof (struct GNUNET_HashCode))) && + (0 == memcmp (h_xwire, + &pc->mi->h_wire, + sizeof (struct GNUNET_HashCode))) && + (timestamp.abs_value_us == pc->timestamp.abs_value_us) && + (refund.abs_value_us == pc->refund_deadline.abs_value_us) && + (0 == TALER_amount_cmp (total_amount, + &pc->amount) ) ) + { + pc->transaction_exits = GNUNET_YES; + } + else + { + GNUNET_break_op (0); + pc->transaction_exits = GNUNET_SYSERR; + } + } + + extern struct MerchantInstance * + get_instance (struct json_t *json); + + /** + * Accomplish this payment. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure + * (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a + * upload_data + * @return MHD result code + */ + int + MH_handler_pay (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size) + { + struct PayContext *pc; + int res; + json_t *root; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "In handler for /pay.\n"); + if (NULL == *connection_cls) + { + pc = GNUNET_new (struct PayContext); + pc->hc.cc = &pay_context_cleanup; + pc->connection = connection; + *connection_cls = pc; + } + else + { + /* not the first call, recover state */ + pc = *connection_cls; + } + if (0 != pc->response_code) + { + /* We are *done* processing the request, just queue the response (!) */ + if (UINT_MAX == pc->response_code) + { + GNUNET_break (0); + return MHD_NO; /* hard error */ + } + res = MHD_queue_response (connection, + pc->response_code, + pc->response); + if (NULL != pc->response) + { + MHD_destroy_response (pc->response); + pc->response = NULL; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Queueing response (%u) for /pay (%s).\n", + (unsigned int) pc->response_code, + res ? "OK" : "FAILED"); + return res; + } + if (NULL != pc->chosen_exchange) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Shouldn't be here. Old MHD version?\n"); + return MHD_YES; + } + res = TMH_PARSE_post_json (connection, + &pc->json_parse_context, + upload_data, + upload_data_size, + &root); + if (GNUNET_SYSERR == res) + { + GNUNET_break (0); + return TMH_RESPONSE_reply_external_error (connection, + "failed to parse JSON body"); + } + if ((GNUNET_NO == res) || (NULL == root)) + return MHD_YES; /* the POST's body has to be further fetched */ + + mi = get_instance (root); + + /* Got the JSON upload, parse it */ + { + json_t *coins; + json_t *coin; + unsigned int coins_index; + struct TALER_MerchantSignatureP merchant_sig; + struct TALER_ContractPS cp; + const char *chosen_exchange; + struct GNUNET_JSON_Specification spec[] = { + TALER_JSON_spec_amount ("amount", &pc->amount), + GNUNET_JSON_spec_json ("coins", &coins), + GNUNET_JSON_spec_fixed_auto ("H_contract", &pc->h_contract), + TALER_JSON_spec_amount ("max_fee", &pc->max_fee), + GNUNET_JSON_spec_fixed_auto ("merchant_sig", &merchant_sig), + GNUNET_JSON_spec_string ("exchange", &chosen_exchange), + GNUNET_JSON_spec_absolute_time ("refund_deadline", &pc->refund_deadline), + GNUNET_JSON_spec_absolute_time ("timestamp", &pc->timestamp), + GNUNET_JSON_spec_uint64 ("transaction_id", &pc->transaction_id), + GNUNET_JSON_spec_end() + }; + + res = TMH_PARSE_json_data (connection, + root, + spec); + if (GNUNET_YES != res) + { + json_decref (root); + GNUNET_break (0); + return (GNUNET_NO == res) ? MHD_YES : MHD_NO; + } + pc->mi = get_instance (root); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "/pay: picked instance %s\n", + pc->mi->id); + + if (NULL == pc->mi) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Not able to find the specified receiver\n"); + json_decref (root); + return TMH_RESPONSE_reply_external_error (connection, + "Unknown receiver given"); + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "The receiver for this deposit is '%s', whose bank details are '%s'\n", + pc->mi->id, + json_dumps (pc->mi->j_wire, JSON_COMPACT)); + pc->chosen_exchange = GNUNET_strdup (chosen_exchange); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Parsed JSON for /pay.\n"); + cp.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_CONTRACT); + cp.purpose.size = htonl (sizeof (struct TALER_ContractPS)); + cp.transaction_id = GNUNET_htonll (pc->transaction_id); + TALER_amount_hton (&cp.total_amount, + &pc->amount); + TALER_amount_hton (&cp.max_fee, + &pc->max_fee); + cp.h_contract = pc->h_contract; + cp.merchant_pub = pc->mi->pubkey; + if (GNUNET_OK != + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MERCHANT_CONTRACT, + &cp.purpose, + &merchant_sig.eddsa_sig, + &pc->mi->pubkey.eddsa_pub)) + { + GNUNET_break (0); + GNUNET_JSON_parse_free (spec); + json_decref (root); + return TMH_RESPONSE_reply_external_error (connection, + "invalid merchant signature supplied"); + } + + /* 'wire_transfer_deadline' is optional, if it is not present, + generate it here; it will be timestamp plus the + wire_transfer_delay supplied in config file */ + if (NULL == json_object_get (root, + "wire_transfer_deadline")) + { + pc->wire_transfer_deadline = GNUNET_TIME_absolute_add (pc->timestamp, + wire_transfer_delay); + if (pc->wire_transfer_deadline.abs_value_us < pc->refund_deadline.abs_value_us) + { + /* Refund value very large, delay wire transfer accordingly */ + pc->wire_transfer_deadline = pc->refund_deadline; + } + } + else + { + struct GNUNET_JSON_Specification espec[] = { + GNUNET_JSON_spec_absolute_time ("wire_transfer_deadline", + &pc->wire_transfer_deadline), + GNUNET_JSON_spec_end() + }; + + res = TMH_PARSE_json_data (connection, + root, + espec); + if (GNUNET_YES != res) + { + GNUNET_JSON_parse_free (spec); + json_decref (root); + GNUNET_break (0); + return (GNUNET_NO == res) ? MHD_YES : MHD_NO; + } + if (pc->wire_transfer_deadline.abs_value_us < pc->refund_deadline.abs_value_us) + { + GNUNET_break (0); + GNUNET_JSON_parse_free (spec); + json_decref (root); + return TMH_RESPONSE_reply_external_error (connection, + "refund deadline after wire transfer deadline"); + } + } + + + pc->coins_cnt = json_array_size (coins); + if (0 == pc->coins_cnt) + { + GNUNET_JSON_parse_free (spec); + json_decref (root); + return TMH_RESPONSE_reply_external_error (connection, + "no coins given"); + } + /* note: 1 coin = 1 deposit confirmation expected */ + pc->dc = GNUNET_new_array (pc->coins_cnt, + struct DepositConfirmation); + + /* This loop populates the array 'dc' in 'pc' */ + json_array_foreach (coins, coins_index, coin) + { + struct DepositConfirmation *dc = &pc->dc[coins_index]; + struct GNUNET_JSON_Specification spec[] = { + TALER_JSON_spec_denomination_public_key ("denom_pub", &dc->denom), + TALER_JSON_spec_amount ("f" /* FIXME */, &dc->amount_with_fee), + GNUNET_JSON_spec_fixed_auto ("coin_pub", &dc->coin_pub), + TALER_JSON_spec_denomination_signature ("ub_sig", &dc->ub_sig), + GNUNET_JSON_spec_fixed_auto ("coin_sig", &dc->coin_sig), + GNUNET_JSON_spec_end() + }; + + res = TMH_PARSE_json_data (connection, + coin, + spec); + if (GNUNET_YES != res) + { + GNUNET_JSON_parse_free (spec); + json_decref (root); + GNUNET_break (0); + return (GNUNET_NO == res) ? MHD_YES : MHD_NO; + } + + { + char *s; + + s = TALER_amount_to_string (&dc->amount_with_fee); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Coin #%i has f %s\n", + coins_index, + s); + GNUNET_free (s); + } + + dc->index = coins_index; + dc->pc = pc; + } + GNUNET_JSON_parse_free (spec); + } /* end of parsing of JSON upload */ + pc->pending = pc->coins_cnt; + + /* Check if this payment attempt has already succeeded */ + if (GNUNET_SYSERR == + db->find_payments_by_id (db->cls, + pc->transaction_id, + &check_coin_paid, + pc)) + { + GNUNET_break (0); + json_decref (root); + return TMH_RESPONSE_reply_internal_error (connection, + "Merchant database error"); + } + if (0 == pc->pending) + { + struct MHD_Response *resp; + int ret; + + /* Payment succeeded in the past; take short cut + and accept immediately */ + resp = MHD_create_response_from_buffer (0, + NULL, + MHD_RESPMEM_PERSISTENT); + ret = MHD_queue_response (connection, + MHD_HTTP_OK, + resp); + MHD_destroy_response (resp); + json_decref (root); + return ret; + } + /* Check if transaction is already known, if not store it. */ + if (GNUNET_SYSERR == + db->find_transaction (db->cls, + pc->transaction_id, + &pc->mi->pubkey, + &check_transaction_exists, + pc)) { GNUNET_break (0); json_decref (root); diff --git a/src/backend/taler-merchant-httpd_track-transaction.c b/src/backend/taler-merchant-httpd_track-transaction.c @@ -670,6 +670,7 @@ handle_track_transaction_timeout (void *cls) * * @param cls closure * @param transaction_id of the contract + * @param merchant's public key * @param exchange_uri URI of the exchange * @param h_contract hash of the contract * @param h_wire hash of our wire details @@ -680,6 +681,7 @@ handle_track_transaction_timeout (void *cls) static void transaction_cb (void *cls, uint64_t transaction_id, + const struct TALER_MerchantPublicKeyP *merchant_pub, const char *exchange_uri, const struct GNUNET_HashCode *h_contract, const struct GNUNET_HashCode *h_wire, @@ -865,10 +867,11 @@ MH_handler_track_transaction (struct TMH_RequestHandler *rh, return TMH_RESPONSE_reply_bad_request (connection, "id argument must be a number"); - ret = db->find_transaction_by_id (db->cls, - transaction_id, - &transaction_cb, - tctx); + ret = db->find_transaction (db->cls, + transaction_id, + &tctx->mi->pubkey, + &transaction_cb, + tctx); if (GNUNET_NO == ret) { return TMH_RESPONSE_reply_not_found (connection, diff --git a/src/backenddb/plugin_merchantdb_postgres.c b/src/backenddb/plugin_merchantdb_postgres.c @@ -262,6 +262,7 @@ postgres_initialize (void *cls) "find_transactions_by_date", "SELECT" " transaction_id" + ",merchant_pub" ",exchange_uri" ",h_contract" ",h_wire" @@ -287,8 +288,9 @@ postgres_initialize (void *cls) ",total_amount_frac" ",total_amount_curr" " FROM merchant_transactions" - " WHERE transaction_id=$1", - 1); + " WHERE transaction_id=$1" + " AND merchant_pub=$2", + 2); PG_PREPARE (pg, "find_deposits", "SELECT" @@ -589,6 +591,7 @@ postgres_find_transactions_by_date (void *cls, } for (i = 0; i < n; i++) { + struct TALER_MerchantPublicKeyP merchant_pub; char *exchange_uri; struct GNUNET_HashCode h_contract; struct GNUNET_HashCode h_wire; @@ -601,6 +604,8 @@ postgres_find_transactions_by_date (void *cls, &exchange_uri), GNUNET_PQ_result_spec_uint64 ("transaction_id", &transaction_id), + GNUNET_PQ_result_spec_auto_from_type ("merchant_pub", + &merchant_pub), GNUNET_PQ_result_spec_auto_from_type ("h_contract", &h_contract), GNUNET_PQ_result_spec_auto_from_type ("h_wire", @@ -625,6 +630,7 @@ postgres_find_transactions_by_date (void *cls, } cb (cb_cls, transaction_id, + &merchant_pub, exchange_uri, &h_contract, &h_wire, @@ -642,21 +648,25 @@ postgres_find_transactions_by_date (void *cls, * * @param cls our plugin handle * @param transaction_id the transaction id to search + * @param merchant_pub merchant's public key. It's AND'd with transaction_id + * in order to find the result. * @param cb function to call with transaction data * @param cb_cls closure for @a cb * @return #GNUNET_OK if found, #GNUNET_NO if not, #GNUNET_SYSERR * upon error */ static int -postgres_find_transaction_by_id (void *cls, - uint64_t transaction_id, - TALER_MERCHANTDB_TransactionCallback cb, - void *cb_cls) +postgres_find_transaction (void *cls, + uint64_t transaction_id, + const struct TALER_MerchantPublicKeyP *merchant_pub, + TALER_MERCHANTDB_TransactionCallback cb, + void *cb_cls) { struct PostgresClosure *pg = cls; PGresult *result; struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_uint64 (&transaction_id), + GNUNET_PQ_query_param_auto_from_type (merchant_pub), GNUNET_PQ_query_param_end }; @@ -715,6 +725,7 @@ postgres_find_transaction_by_id (void *cls, } cb (cb_cls, transaction_id, + merchant_pub, exchange_uri, &h_contract, &h_wire, @@ -1098,7 +1109,7 @@ libtaler_plugin_merchantdb_postgres_init (void *cls) plugin->store_deposit = &postgres_store_deposit; plugin->store_coin_to_transfer = &postgres_store_coin_to_transfer; plugin->store_transfer_to_proof = &postgres_store_transfer_to_proof; - plugin->find_transaction_by_id = &postgres_find_transaction_by_id; + plugin->find_transaction = &postgres_find_transaction; plugin->find_transactions_by_date = &postgres_find_transactions_by_date; plugin->find_payments_by_id = &postgres_find_payments_by_id; plugin->find_transfers_by_id = &postgres_find_transfers_by_id; diff --git a/src/backenddb/test_merchantdb.c b/src/backenddb/test_merchantdb.c @@ -136,6 +136,7 @@ static json_t *transfer_proof; * * @param cls closure * @param transaction_id of the contract + * @param merchant_pub public key of the merchant * @param exchange_uri URI of the exchange * @param h_contract hash of the contract * @param h_wire hash of our wire details @@ -146,6 +147,7 @@ static json_t *transfer_proof; static void transaction_cb (void *cls, uint64_t atransaction_id, + const struct TALER_MerchantPublicKeyP *amerchant_pub, const char *aexchange_uri, const struct GNUNET_HashCode *ah_contract, const struct GNUNET_HashCode *ah_wire, @@ -155,6 +157,9 @@ transaction_cb (void *cls, { #define CHECK(a) do { if (! (a)) { GNUNET_break (0); result = 3; } } while (0) CHECK (atransaction_id == transaction_id); + CHECK (0 == memcmp (amerchant_pub, + &merchant_pub, + sizeof (struct TALER_MerchantPublicKeyP))); CHECK (0 == strcmp (aexchange_uri, EXCHANGE_URI)); CHECK (0 == memcmp (ah_contract, @@ -176,6 +181,7 @@ transaction_cb (void *cls, * * @param cls closure * @param transaction_id of the contract + * @param merchant_pub merchant's public key * @param exchange_uri URI of the exchange * @param h_contract hash of the contract * @param h_wire hash of our wire details @@ -187,6 +193,7 @@ transaction_cb (void *cls, static void history_cb (void *cls, uint64_t transaction_id, + const struct TALER_MerchantPublicKeyP *merchant_pub, const char *exchange_uri, const struct GNUNET_HashCode *h_contract, const struct GNUNET_HashCode *h_wire, @@ -359,10 +366,11 @@ run (void *cls) &signkey_pub, transfer_proof)); FAILIF (GNUNET_OK != - plugin->find_transaction_by_id (plugin->cls, - transaction_id, - &transaction_cb, - NULL)); + plugin->find_transaction (plugin->cls, + transaction_id, + &merchant_pub, + &transaction_cb, + NULL)); /* FIXME: put here find_transactions_by_date () */ FAILIF (1 != diff --git a/src/include/taler_merchantdb_plugin.h b/src/include/taler_merchantdb_plugin.h @@ -36,6 +36,7 @@ struct TALER_MERCHANTDB_Plugin; * * @param cls closure * @param transaction_id of the contract + * @param merchant_pub merchant's public key * @param exchange_uri URI of the exchange * @param h_contract hash of the contract * @param h_wire hash of our wire details @@ -46,6 +47,7 @@ struct TALER_MERCHANTDB_Plugin; typedef void (*TALER_MERCHANTDB_TransactionCallback)(void *cls, uint64_t transaction_id, + const struct TALER_MerchantPublicKeyP *merchant_pub, const char *exchange_uri, const struct GNUNET_HashCode *h_contract, const struct GNUNET_HashCode *h_wire, @@ -253,15 +255,18 @@ struct TALER_MERCHANTDB_Plugin * * @param cls our plugin handle * @param transaction_id the transaction id to search + * @param merchant_pub merchant's public key. It's AND'd with transaction_id + * in order to find the result. * @param cb function to call with transaction data * @param cb_cls closure for @a cb * @return number of found tuples, #GNUNET_SYSERR upon error */ int - (*find_transaction_by_id) (void *cls, - uint64_t transaction_id, - TALER_MERCHANTDB_TransactionCallback cb, - void *cb_cls); + (*find_transaction) (void *cls, + uint64_t transaction_id, + const struct TALER_MerchantPublicKeyP *merchant_pub, + TALER_MERCHANTDB_TransactionCallback cb, + void *cb_cls); /**