diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/merchant.conf | 6 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd.c | 53 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd.h | 23 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd_exchanges.c | 14 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd_history.c | 68 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd_parsing.c | 5 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd_pay.c | 143 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd_proposal.c | 79 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd_refund.c | 217 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd_responses.c | 50 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd_responses.h | 16 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd_track-transaction.c | 79 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd_track-transfer.c | 9 | ||||
-rw-r--r-- | src/backenddb/plugin_merchantdb_postgres.c | 2 |
14 files changed, 441 insertions, 323 deletions
diff --git a/src/backend/merchant.conf b/src/backend/merchant.conf index 55117874..5e16ef17 100644 --- a/src/backend/merchant.conf +++ b/src/backend/merchant.conf @@ -45,8 +45,14 @@ WIREFORMAT = test # Determines which wire plugin will be used. We currently only # support one wire plugin at a time! +# How long do we want the exchange to sit on wire transfers +# for aggregation? WIRE_TRANSFER_DELAY = 3 week +# How fast do we want customers to pay, i.e. how long will our +# proposal be valid? +DEFAULT_PAY_DEADLINE = 1 day + # Configuration for postgres database. [merchantdb-postgres] CONFIG = postgres:///talermerchant diff --git a/src/backend/taler-merchant-httpd.c b/src/backend/taler-merchant-httpd.c index 9f0da2b0..437537d5 100644 --- a/src/backend/taler-merchant-httpd.c +++ b/src/backend/taler-merchant-httpd.c @@ -73,6 +73,12 @@ static long long unsigned port; struct GNUNET_TIME_Relative wire_transfer_delay; /** + * If the frontend does NOT specify a payment deadline, how long should + * offers we make be valid by default? + */ +struct GNUNET_TIME_Relative default_pay_deadline; + +/** * Default maximum wire fee to assume, unless stated differently in the proposal * already. */ @@ -222,28 +228,27 @@ url_handler (void *cls, "<html><title>404: not found</title></html>", 0, &TMH_MHD_handler_static_response, MHD_HTTP_NOT_FOUND }; - struct TM_HandlerContext *hc; - struct TMH_RequestHandler *rh; - unsigned int i; - int ret; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Handling request for URL `%s'\n", url); - for (i=0;NULL != handlers[i].url;i++) + for (unsigned int i=0;NULL != handlers[i].url;i++) { - rh = &handlers[i]; + struct TMH_RequestHandler *rh = &handlers[i]; + if ( (0 == strcasecmp (url, rh->url)) && ( (NULL == rh->method) || (0 == strcasecmp (method, rh->method)) ) ) { + struct TM_HandlerContext *hc; + int ret; + ret = rh->handler (rh, - connection, - con_cls, - upload_data, - upload_data_size); + connection, + con_cls, + upload_data, + upload_data_size); hc = *con_cls; if (NULL != hc) hc->rh = rh; @@ -435,11 +440,12 @@ prepare_daemon () GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding run_daemon select task\n"); - ret = - GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH, - tv, wrs, wws, - &run_daemon, - NULL); + ret = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH, + tv, + wrs, + wws, + &run_daemon, + NULL); GNUNET_NETWORK_fdset_destroy (wrs); GNUNET_NETWORK_fdset_destroy (wws); return ret; @@ -641,7 +647,7 @@ TMH_lookup_instance (const char *name) * a wrong instance */ struct MerchantInstance * -get_instance (struct json_t *json) +TMH_lookup_instance_json (struct json_t *json) { struct json_t *instance; const char *instance_str; @@ -789,6 +795,19 @@ run (void *cls, return; } + if (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_time (config, + "merchant", + "DEFAULT_PAY_DEADLINE", + &default_pay_deadline)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "merchant", + "DEFAULT_PAY_DEADLINE"); + GNUNET_SCHEDULER_shutdown (); + return; + } + if (GNUNET_OK != TALER_config_get_denom (config, "merchant", diff --git a/src/backend/taler-merchant-httpd.h b/src/backend/taler-merchant-httpd.h index 0526ad20..c67a9713 100644 --- a/src/backend/taler-merchant-httpd.h +++ b/src/backend/taler-merchant-httpd.h @@ -269,6 +269,12 @@ extern struct TALER_MERCHANTDB_Plugin *db; extern struct GNUNET_TIME_Relative wire_transfer_delay; /** + * If the frontend does NOT specify a payment deadline, how long should + * offers we make be valid by default? + */ +extern struct GNUNET_TIME_Relative default_pay_deadline; + +/** * Kick MHD to run now, to be called after MHD_resume_connection(). * Basically, we need to explicitly resume MHD's event loop whenever * we made progress serving a request. This function re-schedules @@ -287,4 +293,21 @@ struct MerchantInstance * TMH_lookup_instance (const char *name); +/** + * Extract merchant instance from the given JSON + * + * @param json the JSON to inspect; it is not required to + * comply with any particular format. It will only be checked + * if the field "instance" is there. + * @return a pointer to a #struct MerchantInstance. This will be + * the 'default' merchant if the frontend did not specif any + * "instance" field. The user should not care to free the returned + * value, as it is taken from a global array that will be freed + * by the general shutdown routine. NULL if the frontend specified + * a wrong instance + */ +struct MerchantInstance * +TMH_lookup_instance_json (struct json_t *json); + + #endif diff --git a/src/backend/taler-merchant-httpd_exchanges.c b/src/backend/taler-merchant-httpd_exchanges.c index 8799fa20..ea84e6bd 100644 --- a/src/backend/taler-merchant-httpd_exchanges.c +++ b/src/backend/taler-merchant-httpd_exchanges.c @@ -398,14 +398,15 @@ get_wire_fees (struct Exchange *exchange, static int process_find_operations (struct Exchange *exchange) { - struct TMH_EXCHANGES_FindOperation *fo; struct TMH_EXCHANGES_FindOperation *fn; struct GNUNET_TIME_Absolute now; int need_wire; now = GNUNET_TIME_absolute_get (); need_wire = GNUNET_NO; - for (fo = exchange->fo_head; NULL != fo; fo = fn) + for (struct TMH_EXCHANGES_FindOperation *fo = exchange->fo_head; + NULL != fo; + fo = fn) { const struct TALER_Amount *wire_fee; @@ -887,9 +888,6 @@ accept_exchanges (void *cls, int TMH_EXCHANGES_init (const struct GNUNET_CONFIGURATION_Handle *cfg) { - struct Exchange *exchange; - json_t *j_exchange; - merchant_curl_ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule, &merchant_curl_rc); @@ -905,8 +903,12 @@ TMH_EXCHANGES_init (const struct GNUNET_CONFIGURATION_Handle *cfg) (void *) cfg); /* build JSON with list of trusted exchanges (will be included in contracts) */ trusted_exchanges = json_array (); - for (exchange = exchange_head; NULL != exchange; exchange = exchange->next) + for (struct Exchange *exchange = exchange_head; + NULL != exchange; + exchange = exchange->next) { + json_t *j_exchange; + if (GNUNET_YES != exchange->trusted) continue; j_exchange = json_pack ("{s:s, s:o}", diff --git a/src/backend/taler-merchant-httpd_history.c b/src/backend/taler-merchant-httpd_history.c index e4058722..9d6459ef 100644 --- a/src/backend/taler-merchant-httpd_history.c +++ b/src/backend/taler-merchant-httpd_history.c @@ -93,11 +93,12 @@ MH_handler_history (struct TMH_RequestHandler *rh, const char *str; struct GNUNET_TIME_Absolute date; json_t *response; - unsigned int ret; + int ret; unsigned long long seconds; struct MerchantInstance *mi; int start = -1; unsigned int delta; + enum GNUNET_DB_QueryStatus qs; response = json_array (); str = MHD_lookup_connection_value (connection, @@ -107,7 +108,9 @@ MH_handler_history (struct TMH_RequestHandler *rh, if (NULL != str) { - if (1 != sscanf (str, "%llu", &seconds)) + if (1 != sscanf (str, + "%llu", + &seconds)) { json_decref (response); return TMH_RESPONSE_reply_arg_invalid (connection, @@ -147,13 +150,17 @@ MH_handler_history (struct TMH_RequestHandler *rh, if (NULL != str) { - - ret = db->find_contract_terms_history (db->cls, - str, - &mi->pubkey, - &pd_cb, - response); - if (GNUNET_SYSERR == ret) + qs = db->find_contract_terms_history (db->cls, + str, + &mi->pubkey, + &pd_cb, + response); + /* single, read-only SQL statements should never cause + serialization problems */ + GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs); + /* Always report on hard error as well to enable diagnostics */ + GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs); + if (0 > qs) { json_decref (response); return TMH_RESPONSE_reply_internal_error (connection, @@ -174,7 +181,9 @@ MH_handler_history (struct TMH_RequestHandler *rh, "start"); if (NULL != str) { - if ( (1 != sscanf (str, "%d", &start)) || + if ( (1 != sscanf (str, + "%d", + &start)) || (0 > start) ) { json_decref (response); @@ -190,7 +199,9 @@ MH_handler_history (struct TMH_RequestHandler *rh, if (NULL != str) { - if (1 != sscanf (str, "%u", &delta)) + if (1 != sscanf (str, + "%u", + &delta)) return TMH_RESPONSE_reply_arg_invalid (connection, TALER_EC_PARAMETER_MALFORMED, "delta"); @@ -202,23 +213,28 @@ MH_handler_history (struct TMH_RequestHandler *rh, delta); if (0 > start) - ret = db->find_contract_terms_by_date (db->cls, - date, - &mi->pubkey, - delta, - &pd_cb, - response); + qs = db->find_contract_terms_by_date (db->cls, + date, + &mi->pubkey, + delta, + &pd_cb, + response); else - ret = db->find_contract_terms_by_date_and_range (db->cls, - date, - &mi->pubkey, - (unsigned int) start, - delta, - GNUNET_NO, - &pd_cb, - response); - if (GNUNET_SYSERR == ret) + qs = db->find_contract_terms_by_date_and_range (db->cls, + date, + &mi->pubkey, + (unsigned int) start, + delta, + GNUNET_NO, + &pd_cb, + response); + if (0 > qs) { + /* single, read-only SQL statements should never cause + serialization problems */ + GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs); + /* Always report on hard error as well to enable diagnostics */ + GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs); json_decref (response); return TMH_RESPONSE_reply_internal_error (connection, TALER_EC_HISTORY_DB_FETCH_ERROR, diff --git a/src/backend/taler-merchant-httpd_parsing.c b/src/backend/taler-merchant-httpd_parsing.c index 6dc91ac1..f04313a6 100644 --- a/src/backend/taler-merchant-httpd_parsing.c +++ b/src/backend/taler-merchant-httpd_parsing.c @@ -133,6 +133,7 @@ buffer_append (struct Buffer *buf, { char *new_buf; size_t new_size = buf->alloc ? buf->alloc : 1; + while (new_size < buf->fill + data_size) new_size *= 2; if (new_size > max_size) @@ -143,7 +144,9 @@ buffer_append (struct Buffer *buf, buf->data = new_buf; buf->alloc = new_size; } - memcpy (buf->data + buf->fill, data, data_size); + memcpy (buf->data + buf->fill, + data, + data_size); buf->fill += data_size; return GNUNET_OK; } diff --git a/src/backend/taler-merchant-httpd_pay.c b/src/backend/taler-merchant-httpd_pay.c index 902a7dc8..2e3767be 100644 --- a/src/backend/taler-merchant-httpd_pay.c +++ b/src/backend/taler-merchant-httpd_pay.c @@ -38,6 +38,10 @@ */ #define PAY_TIMEOUT (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)) +/** + * How often do we retry the simple INSERT database transaction? + */ +#define MAX_RETRIES 3 /** * Information we keep for an individual call to the /pay handler. @@ -325,7 +329,9 @@ static struct PayContext *pc_tail; void MH_force_pc_resume () { - for (struct PayContext *pc = pc_head; NULL != pc; pc = pc->next) + for (struct PayContext *pc = pc_head; + NULL != pc; + pc = pc->next) { if (GNUNET_YES == pc->suspended) { @@ -375,11 +381,9 @@ resume_pay_with_response (struct PayContext *pc, static void abort_deposit (struct PayContext *pc) { - unsigned int i; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Aborting pending /deposit operations\n"); - for (i=0;i<pc->coins_cnt;i++) + for (unsigned int i;i<pc->coins_cnt;i++) { struct DepositConfirmation *dci = &pc->dc[i]; @@ -449,6 +453,7 @@ deposit_cb (void *cls, { struct DepositConfirmation *dc = cls; struct PayContext *pc = dc->pc; + enum GNUNET_DB_QueryStatus qs; dc->dh = NULL; pc->pending--; @@ -493,19 +498,26 @@ deposit_cb (void *cls, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Storing successful payment for h_contract_terms '%s'\n", GNUNET_h2s (&pc->h_contract_terms)); - - if (GNUNET_OK != - db->store_deposit (db->cls, - &pc->h_contract_terms, - &pc->mi->pubkey, - &dc->coin_pub, - &dc->amount_with_fee, - &dc->deposit_fee, - &dc->refund_fee, - sign_key, - proof)) + for (unsigned int i=0;i<MAX_RETRIES;i++) { - GNUNET_break (0); + qs = db->store_deposit (db->cls, + &pc->h_contract_terms, + &pc->mi->pubkey, + &dc->coin_pub, + &dc->amount_with_fee, + &dc->deposit_fee, + &dc->refund_fee, + sign_key, + proof); + if (GNUNET_DB_STATUS_SOFT_ERROR != qs) + break; + } + if (0 > qs) + { + /* Special report if retries insufficient */ + GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs); + /* Always report on hard error as well to enable diagnostics */ + GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs); /* internal error */ abort_deposit (pc); /* Forward error including 'proof' for the body */ @@ -929,7 +941,6 @@ check_coin_paid (void *cls, const json_t *exchange_proof) { struct PayContext *pc = cls; - unsigned int i; if (0 != memcmp (&pc->h_contract_terms, h_contract_terms, @@ -938,7 +949,7 @@ check_coin_paid (void *cls, GNUNET_break (0); return; } - for (i=0;i<pc->coins_cnt;i++) + for (unsigned int i=0;i<pc->coins_cnt;i++) { struct DepositConfirmation *dc = &pc->dc[i]; /* Get matching coin from results*/ @@ -1009,11 +1020,6 @@ check_transaction_exists (void *cls, } -// FIXME: declare in proper header! -extern struct MerchantInstance * -get_instance (struct json_t *json); - - /** * Try to parse the pay request into the given pay context. * Schedules an error response in the connection on failure. @@ -1046,6 +1052,7 @@ parse_pay (struct MHD_Connection *connection, GNUNET_JSON_spec_fixed_auto ("merchant_pub", &merchant_pub), GNUNET_JSON_spec_end() }; + enum GNUNET_DB_QueryStatus qs; res = TMH_PARSE_json_data (connection, root, @@ -1055,11 +1062,23 @@ parse_pay (struct MHD_Connection *connection, GNUNET_break (0); return res; } - res = db->find_contract_terms (db->cls, + qs = db->find_contract_terms (db->cls, &pc->contract_terms, order_id, &merchant_pub); - if (GNUNET_OK != res) + if (0 > qs) + { + /* single, read-only SQL statements should never cause + serialization problems */ + GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs); + /* Always report on hard error as well to enable diagnostics */ + GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs); + return TMH_RESPONSE_reply_internal_error (connection, + TALER_EC_PAY_DB_FETCH_PAY_ERROR, + "db error to previous /pay data"); + + } + if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) { GNUNET_JSON_parse_free (spec); if (MHD_YES != @@ -1106,15 +1125,16 @@ parse_pay (struct MHD_Connection *connection, } return GNUNET_NO; } - pc->mi = get_instance (merchant); + pc->mi = TMH_lookup_instance_json (merchant); if (NULL == pc->mi) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unable to find the specified instance\n"); GNUNET_JSON_parse_free (spec); - if (MHD_NO == TMH_RESPONSE_reply_not_found (connection, - TALER_EC_PAY_INSTANCE_UNKNOWN, - "Unknown instance given")) + if (MHD_NO == + TMH_RESPONSE_reply_not_found (connection, + TALER_EC_PAY_INSTANCE_UNKNOWN, + "Unknown instance given")) { GNUNET_break (0); return GNUNET_SYSERR; @@ -1296,6 +1316,7 @@ handler_pay_json (struct MHD_Connection *connection, struct PayContext *pc) { int ret; + enum GNUNET_DB_QueryStatus qs; ret = parse_pay (connection, root, @@ -1304,14 +1325,18 @@ handler_pay_json (struct MHD_Connection *connection, return (GNUNET_NO == ret) ? MHD_YES : MHD_NO; /* Check if this payment attempt has already succeeded */ - if (GNUNET_SYSERR == - db->find_payments (db->cls, - &pc->h_contract_terms, - &pc->mi->pubkey, - &check_coin_paid, - pc)) + qs = db->find_payments (db->cls, + &pc->h_contract_terms, + &pc->mi->pubkey, + &check_coin_paid, + pc); + if (0 > qs) { - GNUNET_break (0); + /* single, read-only SQL statements should never cause + serialization problems */ + GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs); + /* Always report on hard error as well to enable diagnostics */ + GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs); return TMH_RESPONSE_reply_internal_error (connection, TALER_EC_PAY_DB_FETCH_TRANSACTION_ERROR, "Merchant database error"); @@ -1333,14 +1358,18 @@ handler_pay_json (struct MHD_Connection *connection, return ret; } /* Check if transaction is already known, if not store it. */ - if (GNUNET_SYSERR == - db->find_transaction (db->cls, - &pc->h_contract_terms, - &pc->mi->pubkey, - &check_transaction_exists, - pc)) + qs = db->find_transaction (db->cls, + &pc->h_contract_terms, + &pc->mi->pubkey, + &check_transaction_exists, + pc); + if (0 > qs) { - GNUNET_break (0); + /* single, read-only SQL statements should never cause + serialization problems */ + GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs); + /* Always report on hard error as well to enable diagnostics */ + GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs); return TMH_RESPONSE_reply_internal_error (connection, TALER_EC_PAY_DB_FETCH_TRANSACTION_ERROR, "Merchant database error"); @@ -1378,17 +1407,25 @@ handler_pay_json (struct MHD_Connection *connection, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Storing transaction '%s'\n", GNUNET_h2s (&pc->h_contract_terms)); - if (GNUNET_OK != - db->store_transaction (db->cls, - &pc->h_contract_terms, - &pc->mi->pubkey, - pc->chosen_exchange, - &pc->mi->h_wire, - pc->timestamp, - pc->refund_deadline, - &pc->amount)) + for (unsigned int i=0;i<MAX_RETRIES;i++) { - GNUNET_break (0); + qs = db->store_transaction (db->cls, + &pc->h_contract_terms, + &pc->mi->pubkey, + pc->chosen_exchange, + &pc->mi->h_wire, + pc->timestamp, + pc->refund_deadline, + &pc->amount); + if (GNUNET_DB_STATUS_SOFT_ERROR != qs) + break; + } + if (0 > qs) + { + /* Special report if retries insufficient */ + GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs); + /* Always report on hard error as well to enable diagnostics */ + GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs); return TMH_RESPONSE_reply_internal_error (connection, TALER_EC_PAY_DB_STORE_TRANSACTION_ERROR, "Merchant database error"); diff --git a/src/backend/taler-merchant-httpd_proposal.c b/src/backend/taler-merchant-httpd_proposal.c index a4311795..ae0c3dcc 100644 --- a/src/backend/taler-merchant-httpd_proposal.c +++ b/src/backend/taler-merchant-httpd_proposal.c @@ -30,6 +30,12 @@ /** + * How often do we retry the simple INSERT database transaction? + */ +#define MAX_RETRIES 3 + + +/** * Check that the given JSON array of products is well-formed. * * @param products JSON array to check @@ -115,10 +121,6 @@ json_parse_cleanup (struct TM_HandlerContext *hc) } -extern struct MerchantInstance * -get_instance (struct json_t *json); - - /** * Transform an order into a proposal and store it in the database. * Write the resulting proposal or an error message ot a MHD connection @@ -156,12 +158,12 @@ proposal_put (struct MHD_Connection *connection, GNUNET_JSON_spec_absolute_time ("pay_deadline", &pay_deadline), GNUNET_JSON_spec_end () }; - + enum GNUNET_DB_QueryStatus qs; /* Add order_id if it doesn't exist. */ - - if (NULL == json_string_value (json_object_get (order, - "order_id"))) + if (NULL == + json_string_value (json_object_get (order, + "order_id"))) { char buf[256]; time_t timer; @@ -175,7 +177,8 @@ proposal_put (struct MHD_Connection *connection, sizeof (buf), "%H:%M:%S", tm_info); - snprintf (buf + off, sizeof (buf) - off, + snprintf (buf + off, + sizeof (buf) - off, "-%llX", (long long unsigned) GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX)); @@ -210,8 +213,7 @@ proposal_put (struct MHD_Connection *connection, { struct GNUNET_TIME_Absolute t; - /* FIXME: read the delay for pay_deadline from config */ - t = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_HOURS); + t = GNUNET_TIME_relative_to_absolute (default_pay_deadline); (void) GNUNET_TIME_round_abs (&t); json_object_set_new (order, "pay_deadline", @@ -258,7 +260,7 @@ proposal_put (struct MHD_Connection *connection, "order:products"); } - mi = get_instance (merchant); + mi = TMH_lookup_instance_json (merchant); if (NULL == mi) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, @@ -299,22 +301,28 @@ proposal_put (struct MHD_Connection *connection, &pdps.purpose, &merchant_sig); - /* fetch timestamp from order */ - - if (GNUNET_OK != - db->insert_contract_terms (db->cls, - order_id, - &mi->pubkey, - timestamp, - order)) + for (unsigned int i=0;i<MAX_RETRIES;i++) + { + qs = db->insert_contract_terms (db->cls, + order_id, + &mi->pubkey, + timestamp, + order); + if (GNUNET_DB_STATUS_SOFT_ERROR != qs) + break; + } + if (0 > qs) { + /* Special report if retries insufficient */ + GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs); + /* Always report on hard error as well to enable diagnostics */ + GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs); GNUNET_JSON_parse_free (spec); return TMH_RESPONSE_reply_internal_error (connection, TALER_EC_PROPOSAL_STORE_DB_ERROR, "db error: could not store this proposal's data into db"); } - res = TMH_RESPONSE_reply_json_pack (connection, MHD_HTTP_OK, "{s:O, s:o s:o}", @@ -369,7 +377,8 @@ MH_handler_proposal_put (struct TMH_RequestHandler *rh, if (GNUNET_SYSERR == res) return MHD_NO; /* the POST's body has to be further fetched */ - if ((GNUNET_NO == res) || (NULL == root)) + if ( (GNUNET_NO == res) || + (NULL == root) ) return MHD_YES; order = json_object_get (root, @@ -412,6 +421,7 @@ MH_handler_proposal_lookup (struct TMH_RequestHandler *rh, const char *order_id; const char *instance; int res; + enum GNUNET_DB_QueryStatus qs; json_t *contract_terms; struct MerchantInstance *mi; @@ -434,18 +444,25 @@ MH_handler_proposal_lookup (struct TMH_RequestHandler *rh, TALER_EC_PARAMETER_MISSING, "order_id"); - res = db->find_contract_terms (db->cls, - &contract_terms, - order_id, - &mi->pubkey); - if (GNUNET_NO == res) - return TMH_RESPONSE_reply_not_found (connection, - TALER_EC_PROPOSAL_LOOKUP_NOT_FOUND, - "unknown transaction id"); - if (GNUNET_SYSERR == res) + qs = db->find_contract_terms (db->cls, + &contract_terms, + order_id, + &mi->pubkey); + if (0 > qs) + { + /* single, read-only SQL statements should never cause + serialization problems */ + GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs); + /* Always report on hard error as well to enable diagnostics */ + GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs); return TMH_RESPONSE_reply_internal_error (connection, TALER_EC_PROPOSAL_LOOKUP_DB_ERROR, "An error occurred while retrieving proposal data from db"); + } + if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) + return TMH_RESPONSE_reply_not_found (connection, + TALER_EC_PROPOSAL_LOOKUP_NOT_FOUND, + "unknown transaction id"); res = TMH_RESPONSE_reply_json (connection, contract_terms, diff --git a/src/backend/taler-merchant-httpd_refund.c b/src/backend/taler-merchant-httpd_refund.c index 0dc23efe..b196870f 100644 --- a/src/backend/taler-merchant-httpd_refund.c +++ b/src/backend/taler-merchant-httpd_refund.c @@ -28,6 +28,14 @@ #define REFUND_CONFIRMATION 0 + +/** + * How often do we retry the non-trivial refund INSERT database + * transaction? + */ +#define MAX_RETRIES 5 + + /** * We confirm with a signature that the refund has been successfully * done. Even though the frontend doesn't usually do crypto, this signature @@ -67,9 +75,9 @@ struct ProcessRefundData struct MerchantInstance *merchant; /** - * Return code: GNUNET_OK if successful, GNUNET_SYSERR otherwise + * Return code: #TALER_EC_NONE if successful. */ - int ret; + enum TALER_ErrorCode ec; }; /** @@ -107,10 +115,6 @@ json_parse_cleanup (struct TM_HandlerContext *hc) } -extern struct MerchantInstance * -get_instance (struct json_t *json); - - /** * Handle request for increasing the refund associated with * a contract. @@ -140,7 +144,6 @@ MH_handler_refund_increase (struct TMH_RequestHandler *rh, struct GNUNET_HashCode h_contract_terms; struct RefundConfirmationP confirmation; struct GNUNET_CRYPTO_EddsaSignature sig; - struct GNUNET_JSON_Specification spec[] = { TALER_JSON_spec_amount ("refund", &refund), GNUNET_JSON_spec_string ("order_id", &order_id), @@ -148,7 +151,7 @@ MH_handler_refund_increase (struct TMH_RequestHandler *rh, GNUNET_JSON_spec_string ("instance", &merchant), GNUNET_JSON_spec_end () }; - + enum GNUNET_DB_QueryStatus qs; if (NULL == *connection_cls) { @@ -169,7 +172,8 @@ MH_handler_refund_increase (struct TMH_RequestHandler *rh, if (GNUNET_SYSERR == res) return MHD_NO; /* the POST's body has to be further fetched */ - if ((GNUNET_NO == res) || (NULL == root)) + if ( (GNUNET_NO == res) || + (NULL == root) ) return MHD_YES; res = TMH_PARSE_json_data (connection, @@ -196,14 +200,26 @@ MH_handler_refund_increase (struct TMH_RequestHandler *rh, GNUNET_JSON_parse_free (spec); return TMH_RESPONSE_reply_not_found (connection, TALER_EC_REFUND_INSTANCE_UNKNOWN, - "Unknown instance given"); + "Unknown instance given"); } /* Convert order id to h_contract_terms */ - if (GNUNET_OK != db->find_contract_terms (db->cls, - &contract_terms, - order_id, - &mi->pubkey)) + qs = db->find_contract_terms (db->cls, + &contract_terms, + order_id, + &mi->pubkey); + if (0 > qs) + { + /* single, read-only SQL statements should never cause + serialization problems */ + GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs); + /* Always report on hard error as well to enable diagnostics */ + GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs); + return TMH_RESPONSE_reply_internal_error (connection, + TALER_EC_REFUND_LOOKUP_DB_ERROR, + "An error occurred while retrieving payment data from db"); + } + if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unknown order id given: %s\n", @@ -220,45 +236,40 @@ MH_handler_refund_increase (struct TMH_RequestHandler *rh, GNUNET_JSON_parse_free (spec); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not hash contract terms\n"); - /** - * Do we really need a error code for failing to hash something? - * The HTTP 500 Internal server error sufficies for now. - */ return TMH_RESPONSE_reply_internal_error (connection, - TALER_EC_NONE, + TALER_EC_INTERNAL_LOGIC_ERROR, "Could not hash contract terms"); } - - res = db->increase_refund_for_contract (db->cls, - &h_contract_terms, - &mi->pubkey, - &refund, - reason); - if (GNUNET_NO == res) + for (unsigned int i=0;i<MAX_RETRIES;i++) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Inconsistent refund amount: %s\n", - TALER_amount_to_string (&refund)); - GNUNET_JSON_parse_free (spec); - /** - * FIXME: should the db function distinguish between a refund amount - * lower than the previous one and a one which is too big to be paid back? - */ - return TMH_RESPONSE_reply_external_error (connection, - TALER_EC_REFUND_INCONSISTENT_AMOUNT, - "Amount incorrect: either not bigger" - " than the previous one or too big to" - " be paid back"); + qs = db->increase_refund_for_contract (db->cls, + &h_contract_terms, + &mi->pubkey, + &refund, + reason); + if (GNUNET_DB_STATUS_SOFT_ERROR != qs) + break; } - - if (GNUNET_SYSERR == res) + if (0 > qs) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Could not commit refund increase\n"); + /* Special report if retries insufficient */ + GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs); + /* Always report on hard error as well to enable diagnostics */ + GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs); GNUNET_JSON_parse_free (spec); return TMH_RESPONSE_reply_internal_error (connection, - TALER_EC_NONE, - "Internal hard db error"); + TALER_EC_REFUND_MERCHANT_DB_COMMIT_ERROR, + "Internal database error or refund amount too big"); + } + if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Refunded amount lower or equal to previous refund: %s\n", + TALER_amount2s (&refund)); + GNUNET_JSON_parse_free (spec); + return TMH_RESPONSE_reply_external_error (connection, + TALER_EC_REFUND_INCONSISTENT_AMOUNT, + "Amount incorrect: not larger than the previous one"); } /** @@ -278,9 +289,10 @@ MH_handler_refund_increase (struct TMH_RequestHandler *rh, confirmation.purpose.purpose = REFUND_CONFIRMATION; confirmation.purpose.size = htonl (sizeof (struct RefundConfirmationP)); - if (GNUNET_OK != GNUNET_CRYPTO_eddsa_sign (&mi->privkey.eddsa_priv, - &confirmation.purpose, - &sig)) + if (GNUNET_OK != + GNUNET_CRYPTO_eddsa_sign (&mi->privkey.eddsa_priv, + &confirmation.purpose, + &sig)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to sign successful refund confirmation\n"); @@ -308,7 +320,7 @@ MH_handler_refund_increase (struct TMH_RequestHandler *rh, * @param refund_amount refund amount which is being taken from coin_pub * @param refund_fee cost of this refund operation */ -void +static void process_refunds_cb (void *cls, const struct TALER_CoinSpendPublicKeyP *coin_pub, uint64_t rtransaction_id, @@ -332,13 +344,14 @@ process_refunds_cb (void *cls, TALER_amount_hton (&rr.refund_fee, refund_fee); - if (GNUNET_OK != GNUNET_CRYPTO_eddsa_sign (&prd->merchant->privkey.eddsa_priv, - &rr.purpose, - &sig)) + if (GNUNET_OK != + GNUNET_CRYPTO_eddsa_sign (&prd->merchant->privkey.eddsa_priv, + &rr.purpose, + &sig)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not sign refund request\n"); - prd->ret = GNUNET_SYSERR; + prd->ec = TALER_EC_INTERNAL_LOGIC_ERROR; return; } @@ -354,7 +367,7 @@ process_refunds_cb (void *cls, { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not pack a response's element up\n"); - prd->ret = GNUNET_SYSERR; + prd->ec = TALER_EC_PARSER_OUT_OF_MEMORY; return; } @@ -363,7 +376,7 @@ process_refunds_cb (void *cls, { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not append a response's element\n"); - prd->ret = GNUNET_SYSERR; + prd->ec = TALER_EC_PARSER_OUT_OF_MEMORY; return; } } @@ -389,8 +402,9 @@ MH_handler_refund_lookup (struct TMH_RequestHandler *rh, const char *instance; struct GNUNET_HashCode h_contract_terms; json_t *contract_terms; - int res; struct MerchantInstance *mi; + enum GNUNET_DB_QueryStatus qs; + struct ProcessRefundData prd; instance = MHD_lookup_connection_value (connection, MHD_GET_ARGUMENT_KIND, @@ -429,11 +443,23 @@ MH_handler_refund_lookup (struct TMH_RequestHandler *rh, } /* Convert order id to h_contract_terms */ - res = db->find_contract_terms (db->cls, - &contract_terms, - order_id, - &mi->pubkey); - if (GNUNET_NO == res) + qs = db->find_contract_terms (db->cls, + &contract_terms, + order_id, + &mi->pubkey); + if (0 > qs) + { + /* single, read-only SQL statements should never cause + serialization problems */ + GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs); + /* Always report on hard error as well to enable diagnostics */ + GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs); + return TMH_RESPONSE_reply_internal_error (connection, + TALER_EC_REFUND_LOOKUP_DB_ERROR, + "database error looking up order_id from merchant_contract_terms table"); + } + + if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unknown order id given: %s\n", @@ -442,18 +468,6 @@ MH_handler_refund_lookup (struct TMH_RequestHandler *rh, TALER_EC_REFUND_ORDER_ID_UNKNOWN, "Order id not found in database"); } - if (GNUNET_SYSERR == res) - { - - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "database hard error on order_id lookup: %s\n", - order_id); - - return TMH_RESPONSE_reply_internal_error (connection, - TALER_EC_NONE, - "database hard error: looking up" - " oder_id from merchant_contract_terms table"); - } if (GNUNET_OK != TALER_JSON_hash (contract_terms, @@ -461,57 +475,46 @@ MH_handler_refund_lookup (struct TMH_RequestHandler *rh, { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not hash contract terms\n"); - /** - * Do we really need a error code for failing to hash something? - * The HTTP 500 Internal server error sufficies for now. - */ return TMH_RESPONSE_reply_internal_error (connection, - TALER_EC_NONE, + TALER_EC_INTERNAL_LOGIC_ERROR, "Could not hash contract terms"); } - struct ProcessRefundData cb_cls; - cb_cls.response = json_array (); - cb_cls.h_contract_terms = &h_contract_terms; - cb_cls.merchant = mi; - res = db->get_refunds_from_contract_terms_hash (db->cls, - &mi->pubkey, - &h_contract_terms, - process_refunds_cb, - &cb_cls); - - if (GNUNET_NO == res) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Contract terms hash not found in database\n"); - /*This is very odd, as the unhashed version *was* found earlier*/ - return TMH_RESPONSE_reply_not_found (connection, - TALER_EC_REFUND_H_CONTRACT_TERMS_UNKNOWN, - "h_contract_terms not found among granted refunds"); + prd.response = json_array (); + prd.h_contract_terms = &h_contract_terms; + prd.merchant = mi; + prd.ec = TALER_EC_NONE; + for (unsigned int i=0;i<MAX_RETRIES;i++) + { + qs = db->get_refunds_from_contract_terms_hash (db->cls, + &mi->pubkey, + &h_contract_terms, + &process_refunds_cb, + &prd); + if (GNUNET_DB_STATUS_SOFT_ERROR != qs) + break; } - - if (GNUNET_SYSERR == res) + if (0 > qs) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "database hard error on order_id lookup: %s\n", order_id); - + json_decref (prd.response); return TMH_RESPONSE_reply_internal_error (connection, - TALER_EC_NONE, + TALER_EC_REFUND_LOOKUP_DB_ERROR, "database hard error: looking for " "h_contract_terms in merchant_refunds table"); } - if (GNUNET_SYSERR == cb_cls.ret) + if (TALER_EC_NONE != prd.ec) { + json_decref (prd.response); /* NOTE: error already logged by the callback */ return TMH_RESPONSE_reply_internal_error (connection, - TALER_EC_NONE, + prd.ec, "Could not generate a response"); } - - return TMH_RESPONSE_reply_json (connection, - cb_cls.response, - MHD_HTTP_OK); + return TMH_RESPONSE_reply_json (connection, + prd.response, + MHD_HTTP_OK); } diff --git a/src/backend/taler-merchant-httpd_responses.c b/src/backend/taler-merchant-httpd_responses.c index 8cbdf6b0..1ea2600e 100644 --- a/src/backend/taler-merchant-httpd_responses.c +++ b/src/backend/taler-merchant-httpd_responses.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014, 2015, 2016 GNUnet e.V. + Copyright (C) 2014-2017 GNUnet e.V. TALER is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software @@ -395,52 +395,4 @@ TMH_RESPONSE_reply_arg_invalid (struct MHD_Connection *connection, } -/** - * Generate /track/transaction response. - * - * @param num_transfers how many wire transfers make up the transaction - * @param transfers data on each wire transfer - * @param exchange_uri URI of the exchange that made the transfer - * @return MHD response object - */ -struct MHD_Response * -TMH_RESPONSE_make_track_transaction_ok (unsigned int num_transfers, - const struct TALER_MERCHANT_TransactionWireTransfer *transfers, - const char *exchange_uri) -{ - struct MHD_Response *ret; - unsigned int i; - json_t *j_transfers; - struct TALER_Amount sum; - - j_transfers = json_array (); - for (i=0;i<num_transfers;i++) - { - const struct TALER_MERCHANT_TransactionWireTransfer *transfer = &transfers[i]; - unsigned int j; - - sum = transfer->coins[0].amount_with_fee; - for (j=1;j<transfer->num_coins;j++) - { - const struct TALER_MERCHANT_CoinWireTransfer *coin = &transfer->coins[j]; - - GNUNET_assert (GNUNET_SYSERR != TALER_amount_add (&sum, - &sum, - &coin->amount_with_fee)); - } - - GNUNET_assert (0 == - json_array_append_new (j_transfers, - json_pack ("{s:s, s:o, s:o, s:o}", - "exchange", exchange_uri, - "wtid", GNUNET_JSON_from_data_auto (&transfer->wtid), - "execution_time", GNUNET_JSON_from_time_abs (transfer->execution_time), - "amount", TALER_JSON_from_amount (&sum)))); - } - ret = TMH_RESPONSE_make_json (j_transfers); - json_decref (j_transfers); - return ret; -} - - /* end of taler-exchange-httpd_responses.c */ diff --git a/src/backend/taler-merchant-httpd_responses.h b/src/backend/taler-merchant-httpd_responses.h index 0b552fdd..ea290c5f 100644 --- a/src/backend/taler-merchant-httpd_responses.h +++ b/src/backend/taler-merchant-httpd_responses.h @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014, 2015, 2016 GNUnet e.V. + Copyright (C) 2014-2017 GNUnet e.V. TALER is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software @@ -70,20 +70,6 @@ TMH_RESPONSE_make_json_pack (const char *fmt, /** - * Generate /track/transaction response. - * - * @param num_transfers how many wire transfers make up the transaction - * @param transfers data on each wire transfer - * @param exchange_uri URI of the exchange that made the transfer - * @return MHD response object - */ -struct MHD_Response * -TMH_RESPONSE_make_track_transaction_ok (unsigned int num_transfers, - const struct TALER_MERCHANT_TransactionWireTransfer *transfers, - const char *exchange_uri); - - -/** * Function to call to handle the request by building a JSON * reply from a format string and varargs. * diff --git a/src/backend/taler-merchant-httpd_track-transaction.c b/src/backend/taler-merchant-httpd_track-transaction.c index 9d8768f7..67bfb47b 100644 --- a/src/backend/taler-merchant-httpd_track-transaction.c +++ b/src/backend/taler-merchant-httpd_track-transaction.c @@ -44,6 +44,53 @@ extern struct GNUNET_CONTAINER_MultiHashMap *by_id_map; /** + * Generate /track/transaction response. + * + * @param num_transfers how many wire transfers make up the transaction + * @param transfers data on each wire transfer + * @param exchange_uri URI of the exchange that made the transfer + * @return MHD response object + */ +static struct MHD_Response * +make_track_transaction_ok (unsigned int num_transfers, + const struct TALER_MERCHANT_TransactionWireTransfer *transfers, + const char *exchange_uri) +{ + struct MHD_Response *ret; + json_t *j_transfers; + struct TALER_Amount sum; + + j_transfers = json_array (); + for (unsigned int i=0;i<num_transfers;i++) + { + const struct TALER_MERCHANT_TransactionWireTransfer *transfer = &transfers[i]; + + sum = transfer->coins[0].amount_with_fee; + for (unsigned int j=1;j<transfer->num_coins;j++) + { + const struct TALER_MERCHANT_CoinWireTransfer *coin = &transfer->coins[j]; + + GNUNET_assert (GNUNET_SYSERR != TALER_amount_add (&sum, + &sum, + &coin->amount_with_fee)); + } + + GNUNET_assert (0 == + json_array_append_new (j_transfers, + json_pack ("{s:s, s:o, s:o, s:o}", + "exchange", exchange_uri, + "wtid", GNUNET_JSON_from_data_auto (&transfer->wtid), + "execution_time", GNUNET_JSON_from_time_abs (transfer->execution_time), + "amount", TALER_JSON_from_amount (&sum)))); + } + ret = TMH_RESPONSE_make_json (j_transfers); + json_decref (j_transfers); + return ret; +} + + + +/** * Context for a /track/transaction operation. */ struct TrackTransactionContext; @@ -358,8 +405,6 @@ wire_deposits_cb (void *cls, const struct TALER_TrackTransferDetails *details) { struct TrackTransactionContext *tctx = cls; - struct TrackCoinContext *tcc; - unsigned int i; tctx->wdh = NULL; if (MHD_HTTP_OK != http_status) @@ -387,11 +432,13 @@ wire_deposits_cb (void *cls, GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to store transfer-to-proof mapping in DB\n"); } - for (tcc=tctx->tcc_head;NULL != tcc;tcc=tcc->next) + for (struct TrackCoinContext *tcc=tctx->tcc_head; + NULL != tcc; + tcc=tcc->next) { if (GNUNET_YES == tcc->have_wtid) continue; - for (i=0;i<details_length;i++) + for (unsigned int i=0;i<details_length;i++) { if (0 == memcmp (&details[i].coin_pub, @@ -574,10 +621,11 @@ trace_coins (struct TrackTransactionContext *tctx) is worst-case O(n^2), in pracitce this is O(n) */ for (tcc = tctx->tcc_head; NULL != tcc; tcc = tcc->next) { - struct TrackCoinContext *tcc2; int found = GNUNET_NO; - for (tcc2 = tctx->tcc_head; tcc2 != tcc; tcc2 = tcc2->next) + for (struct TrackCoinContext *tcc2 = tctx->tcc_head; + tcc2 != tcc; + tcc2 = tcc2->next) { if (0 == memcmp (&tcc->wtid, &tcc2->wtid, @@ -601,10 +649,11 @@ trace_coins (struct TrackTransactionContext *tctx) wtid_off = 0; for (tcc = tctx->tcc_head; NULL != tcc; tcc = tcc->next) { - struct TrackCoinContext *tcc2; int found = GNUNET_NO; - for (tcc2 = tctx->tcc_head; tcc2 != tcc; tcc2 = tcc2->next) + for (struct TrackCoinContext *tcc2 = tctx->tcc_head; + tcc2 != tcc; + tcc2 = tcc2->next) { if (0 == memcmp (&tcc->wtid, &tcc2->wtid, @@ -624,7 +673,9 @@ trace_coins (struct TrackTransactionContext *tctx) wt->execution_time = tcc->execution_time; /* count number of coins with this wtid */ num_coins = 0; - for (tcc2 = tctx->tcc_head; NULL != tcc2; tcc2 = tcc2->next) + for (struct TrackCoinContext *tcc2 = tctx->tcc_head; + NULL != tcc2; + tcc2 = tcc2->next) { if (0 == memcmp (&wt->wtid, &tcc2->wtid, @@ -636,7 +687,9 @@ trace_coins (struct TrackTransactionContext *tctx) wt->coins = GNUNET_new_array (num_coins, struct TALER_MERCHANT_CoinWireTransfer); num_coins = 0; - for (tcc2 = tctx->tcc_head; NULL != tcc2; tcc2 = tcc2->next) + for (struct TrackCoinContext *tcc2 = tctx->tcc_head; + NULL != tcc2; + tcc2 = tcc2->next) { if (0 == memcmp (&wt->wtid, &tcc2->wtid, @@ -653,9 +706,9 @@ trace_coins (struct TrackTransactionContext *tctx) } /* for all tcc */ GNUNET_assert (wtid_off == num_wtid); - resp = TMH_RESPONSE_make_track_transaction_ok (num_wtid, - wts, - tctx->exchange_uri); + resp = make_track_transaction_ok (num_wtid, + wts, + tctx->exchange_uri); for (wtid_off=0;wtid_off < num_wtid; wtid_off++) GNUNET_free (wts[wtid_off].coins); resume_track_transaction_with_response (tctx, diff --git a/src/backend/taler-merchant-httpd_track-transfer.c b/src/backend/taler-merchant-httpd_track-transfer.c index b8644be9..71fdda4e 100644 --- a/src/backend/taler-merchant-httpd_track-transfer.c +++ b/src/backend/taler-merchant-httpd_track-transfer.c @@ -130,11 +130,13 @@ struct TrackTransferContext int check_transfer_result; }; + /** * Represents an entry in the table used to sum up * individual deposits for each h_contract_terms. */ -struct Entry { +struct Entry +{ /** * Sum accumulator for deposited value. @@ -195,8 +197,8 @@ hashmap_free (void *cls, void *value) { struct TALER_Amount *amount = value; + GNUNET_free (amount); - /*NOTE: how to find out when iteration should stop?*/ return GNUNET_YES; } @@ -494,7 +496,6 @@ wire_transfer_cb (void *cls, const struct TALER_TrackTransferDetails *details) { struct TrackTransferContext *rctx = cls; - unsigned int i; int ret; json_t *jresponse; @@ -534,7 +535,7 @@ wire_transfer_cb (void *cls, return; } rctx->original_response = json; - for (i=0;i<details_length;i++) + for (unsigned int i=0;i<details_length;i++) { rctx->current_offset = i; rctx->current_detail = &details[i]; diff --git a/src/backenddb/plugin_merchantdb_postgres.c b/src/backenddb/plugin_merchantdb_postgres.c index 20c49607..bb1f286f 100644 --- a/src/backenddb/plugin_merchantdb_postgres.c +++ b/src/backenddb/plugin_merchantdb_postgres.c @@ -1686,7 +1686,7 @@ postgres_get_refunds_from_contract_terms_hash (void *cls, &grc); if (0 >= qs) return qs; - return grc.qs; /*FIXME: who sets this?*/ + return grc.qs; } |