diff --git a/doc/taler-exchange-dbinit.1 b/doc/taler-exchange-dbinit.1 index 456a85b0c..92bf83b09 100644 --- a/doc/taler-exchange-dbinit.1 +++ b/doc/taler-exchange-dbinit.1 @@ -19,6 +19,9 @@ Use the configuration and other resources for the exchange to operate from DIRNA .IP "\-h, \-\-help" Print short help on options. .B +.IP "\-r, \-\-reset" +Drop tables. Dangerous, will delete all existing data in the database before creating the tables. +.B .IP "\-v, \-\-version" Print version information. diff --git a/src/exchange-lib/exchange_api_refund.c b/src/exchange-lib/exchange_api_refund.c index 82ae5e8ab..3a840c7c4 100644 --- a/src/exchange-lib/exchange_api_refund.c +++ b/src/exchange-lib/exchange_api_refund.c @@ -169,6 +169,10 @@ handle_refund_finished (void *cls, /* Nothing really to verify, this should never happen, we should pass the JSON reply to the application */ break; + case MHD_HTTP_GONE: + /* Kind of normal: the money was already sent to the merchant + (it was too late for the refund). */ + break; case MHD_HTTP_INTERNAL_SERVER_ERROR: /* Server had an internal issue; we should retry, but this API leaves this to the application */ @@ -266,7 +270,7 @@ TALER_EXCHANGE_refund (struct TALER_EXCHANGE_Handle *exchange, " s:I, s:I," /* transaction id, rtransaction id */ " s:o, s:o}", /* merchant_pub, merchant_sig */ "refund_amount", TALER_JSON_from_amount (amount), - "refund_fee", TALER_JSON_from_amount (amount), + "refund_fee", TALER_JSON_from_amount (refund_fee), "H_contract", GNUNET_JSON_from_data_auto (h_contract), "coin_pub", GNUNET_JSON_from_data_auto (coin_pub), "transaction_id", (json_int_t) transaction_id, diff --git a/src/exchange-lib/test_exchange_api.c b/src/exchange-lib/test_exchange_api.c index 169d68f39..6612609fa 100644 --- a/src/exchange-lib/test_exchange_api.c +++ b/src/exchange-lib/test_exchange_api.c @@ -2926,7 +2926,10 @@ run (void *cls) }, /* Run transfers. Should do nothing as refund deadline blocks it */ { .oc = OC_RUN_AGGREGATOR, - .label = "run-aggregator" }, + .label = "run-aggregator-refund" }, + /* check that aggregator didn't do anything, as expected */ + { .oc = OC_CHECK_BANK_TRANSFERS_EMPTY, + .label = "check-refund-not-run" }, /* Trigger refund */ { .oc = OC_REFUND, .label = "refund-ok", @@ -2949,11 +2952,18 @@ run (void *cls) }, /* Run transfers. This will do the transfer as refund deadline was 0 */ { .oc = OC_RUN_AGGREGATOR, - .label = "run-aggregator" }, + .label = "run-aggregator-3" }, + /* Check that deposit did run */ + { .oc = OC_CHECK_BANK_TRANSFER, + .label = "check_bank_transfer-pre-refund", + .details.check_bank_transfer.amount = "EUR:4.98", + .details.check_bank_transfer.account_debit = 2, + .details.check_bank_transfer.account_credit = 42 + }, /* Run failing refund, as past deadline & aggregation */ { .oc = OC_REFUND, .label = "refund-fail", - .expected_response_code = MHD_HTTP_OK, + .expected_response_code = MHD_HTTP_GONE, .details.refund.amount = "EUR:4.99", .details.refund.fee = "EUR:0.01", .details.refund.deposit_ref = "deposit-refund-2", @@ -3015,6 +3025,16 @@ main (int argc, NULL); GNUNET_OS_process_wait (proc); GNUNET_OS_process_destroy (proc); + proc = GNUNET_OS_start_process (GNUNET_NO, + GNUNET_OS_INHERIT_STD_ALL, + NULL, NULL, NULL, + "taler-exchange-dbinit", + "taler-exchange-dbinit", + "-c", "test_exchange_api.conf", + "-r", + NULL); + GNUNET_OS_process_wait (proc); + GNUNET_OS_process_destroy (proc); exchanged = GNUNET_OS_start_process (GNUNET_NO, GNUNET_OS_INHERIT_STD_ALL, NULL, NULL, NULL, diff --git a/src/exchange-tools/taler-exchange-dbinit.c b/src/exchange-tools/taler-exchange-dbinit.c index e51f5a21a..16d76e4d0 100644 --- a/src/exchange-tools/taler-exchange-dbinit.c +++ b/src/exchange-tools/taler-exchange-dbinit.c @@ -23,12 +23,16 @@ #include "taler_exchangedb_plugin.h" - /** * Return value from main(). */ static int global_ret; +/** + * -r option: do full DB reset + */ +static int reset_db; + /** * Main function that will be run. * @@ -53,6 +57,8 @@ run (void *cls, global_ret = 1; return; } + if (reset_db) + (void) plugin->drop_tables (plugin->cls); if (GNUNET_OK != plugin->create_tables (plugin->cls)) { @@ -79,6 +85,9 @@ main (int argc, char *const *argv) { const struct GNUNET_GETOPT_CommandLineOption options[] = { + {'r', "reset", NULL, + "reset database (DANGEROUS: all existing data is lost!)", 0, + &GNUNET_GETOPT_set_one, &reset_db}, GNUNET_GETOPT_OPTION_END }; diff --git a/src/exchange/taler-exchange-httpd_db.c b/src/exchange/taler-exchange-httpd_db.c index 712df02a9..981c97289 100644 --- a/src/exchange/taler-exchange-httpd_db.c +++ b/src/exchange/taler-exchange-httpd_db.c @@ -340,11 +340,13 @@ TMH_DB_execute_refund (struct MHD_Connection *connection, MHD_HTTP_NOT_FOUND); } deposit_found = GNUNET_NO; + refund_found = GNUNET_NO; for (tlp = tl; NULL != tlp; tlp = tlp->next) { switch (tlp->type) { case TALER_EXCHANGEDB_TT_DEPOSIT: + if (GNUNET_NO == deposit_found) { dep = tlp->details.deposit; if ( (0 == memcmp (&dep->merchant_pub, @@ -364,6 +366,7 @@ TMH_DB_execute_refund (struct MHD_Connection *connection, /* Melts cannot be refunded, ignore here */ break; case TALER_EXCHANGEDB_TT_REFUND: + if (GNUNET_NO == refund_found) { ref = tlp->details.refund; /* First, check if existing refund request is identical */ @@ -476,15 +479,13 @@ TMH_DB_execute_refund (struct MHD_Connection *connection, MHD_HTTP_GONE); } - /* We no longer need 'tl' or 'dep' or 'ref' */ - TMH_plugin->free_coin_transaction_list (TMH_plugin->cls, - tl); - /* check refund amount is sufficiently low */ if (1 == TALER_amount_cmp (&refund->refund_amount, &dep->amount_with_fee) ) { GNUNET_break_op (0); /* cannot refund more than original value */ + TMH_plugin->free_coin_transaction_list (TMH_plugin->cls, + tl); return TMH_RESPONSE_reply_refund_failure (connection, MHD_HTTP_PRECONDITION_FAILED); } @@ -500,6 +501,8 @@ TMH_DB_execute_refund (struct MHD_Connection *connection, not good... */ GNUNET_break (0); TMH_KS_release (mks); + TMH_plugin->free_coin_transaction_list (TMH_plugin->cls, + tl); return TMH_RESPONSE_reply_internal_error (connection, "denomination key not found"); } @@ -513,6 +516,8 @@ TMH_DB_execute_refund (struct MHD_Connection *connection, { TMH_plugin->rollback (TMH_plugin->cls, session); + TMH_plugin->free_coin_transaction_list (TMH_plugin->cls, + tl); return TMH_RESPONSE_reply_arg_invalid (connection, "refund_fee"); } @@ -521,6 +526,8 @@ TMH_DB_execute_refund (struct MHD_Connection *connection, GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Refund fee proposed by merchant is higher than necessary.\n"); } + TMH_plugin->free_coin_transaction_list (TMH_plugin->cls, + tl); /* Finally, store new refund data */ if (GNUNET_OK != diff --git a/src/exchange/taler-exchange-httpd_refund.c b/src/exchange/taler-exchange-httpd_refund.c index d8c9a6eed..d6d769134 100644 --- a/src/exchange/taler-exchange-httpd_refund.c +++ b/src/exchange/taler-exchange-httpd_refund.c @@ -50,18 +50,18 @@ static int verify_and_execute_refund (struct MHD_Connection *connection, const struct TALER_EXCHANGEDB_Refund *refund) { - struct TALER_RefundRequestPS dr; + struct TALER_RefundRequestPS rr; - dr.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_REFUND); - dr.purpose.size = htonl (sizeof (struct TALER_RefundRequestPS)); - dr.h_contract = refund->h_contract; - dr.transaction_id = GNUNET_htonll (refund->transaction_id); - dr.coin_pub = refund->coin.coin_pub; - dr.merchant = refund->merchant_pub; - dr.rtransaction_id = GNUNET_htonll (refund->rtransaction_id); - TALER_amount_hton (&dr.refund_amount, + rr.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_REFUND); + rr.purpose.size = htonl (sizeof (struct TALER_RefundRequestPS)); + rr.h_contract = refund->h_contract; + rr.transaction_id = GNUNET_htonll (refund->transaction_id); + rr.coin_pub = refund->coin.coin_pub; + rr.merchant = refund->merchant_pub; + rr.rtransaction_id = GNUNET_htonll (refund->rtransaction_id); + TALER_amount_hton (&rr.refund_amount, &refund->refund_amount); - TALER_amount_hton (&dr.refund_fee, + TALER_amount_hton (&rr.refund_fee, &refund->refund_fee); if (GNUNET_YES != TALER_amount_cmp_currency (&refund->refund_amount, @@ -80,7 +80,7 @@ verify_and_execute_refund (struct MHD_Connection *connection, } if (GNUNET_OK != GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MERCHANT_REFUND, - &dr.purpose, + &rr.purpose, &refund->merchant_sig.eddsa_sig, &refund->merchant_pub.eddsa_pub)) { diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c index f53b23104..e2b158c90 100644 --- a/src/exchangedb/plugin_exchangedb_postgres.c +++ b/src/exchangedb/plugin_exchangedb_postgres.c @@ -2260,13 +2260,18 @@ postgres_test_deposit_done (void *cls, PQclear (result); return GNUNET_SYSERR; } + if (1 != PQntuples (result)) + { + GNUNET_break (0); + PQclear (result); + return GNUNET_SYSERR; + } { - /* NOTE: maybe wrong type for a 'boolean' */ - uint32_t done = 0; + uint8_t done = 0; struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_uint32 ("done", - &done), + GNUNET_PQ_result_spec_auto_from_type ("done", + &done), GNUNET_PQ_result_spec_end }; if (GNUNET_OK != @@ -3703,6 +3708,16 @@ postgres_get_coin_transactions (void *cls, tl->next = head; tl->type = TALER_EXCHANGEDB_TT_DEPOSIT; tl->details.deposit = deposit; + if (GNUNET_SYSERR == get_known_coin (cls, + session, + &deposit->coin.coin_pub, + &deposit->coin)) + { + GNUNET_break (0); + GNUNET_free (deposit); + PQclear (result); + goto cleanup; + } head = tl; continue; } @@ -3762,6 +3777,16 @@ postgres_get_coin_transactions (void *cls, tl->next = head; tl->type = TALER_EXCHANGEDB_TT_REFRESH_MELT; tl->details.melt = melt; + if (GNUNET_SYSERR == get_known_coin (cls, + session, + coin_pub, + &melt->coin)) + { + GNUNET_break (0); + GNUNET_free (melt); + PQclear (result); + goto cleanup; + } head = tl; continue; } @@ -3826,6 +3851,16 @@ postgres_get_coin_transactions (void *cls, tl->next = head; tl->type = TALER_EXCHANGEDB_TT_REFUND; tl->details.refund = refund; + if (GNUNET_SYSERR == get_known_coin (cls, + session, + coin_pub, + &refund->coin)) + { + GNUNET_break (0); + GNUNET_free (refund); + PQclear (result); + goto cleanup; + } head = tl; continue; }