add post HTTP request check for hanging transactions

This commit is contained in:
Christian Grothoff 2019-04-18 14:38:24 +02:00
parent 5d3ae9655e
commit 32a3a0ffb0
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
4 changed files with 67 additions and 63 deletions

View File

@ -146,6 +146,12 @@ handle_mhd_completion_callback (void *cls,
return;
TEH_PARSE_post_cleanup_callback (*con_cls);
*con_cls = NULL;
/* check that we didn't leave any transactions hanging */
/* NOTE: In high-performance production, we might want to
remove this. */
TEH_plugin->preflight (TEH_plugin->cls,
TEH_plugin->get_session (TEH_plugin->cls));
}

View File

@ -87,9 +87,9 @@ TEH_DB_know_coin_transaction (void *cls,
int
TEH_DB_run_transaction (struct MHD_Connection *connection,
const char *name,
int *mhd_ret,
TEH_DB_TransactionCallback cb,
void *cb_cls)
int *mhd_ret,
TEH_DB_TransactionCallback cb,
void *cb_cls)
{
struct TALER_EXCHANGEDB_Session *session;
@ -100,7 +100,7 @@ TEH_DB_run_transaction (struct MHD_Connection *connection,
GNUNET_break (0);
if (NULL != mhd_ret)
*mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection,
TALER_EC_DB_SETUP_FAILED);
TALER_EC_DB_SETUP_FAILED);
return GNUNET_SYSERR;
}
TEH_plugin->preflight (TEH_plugin->cls,
@ -110,23 +110,23 @@ TEH_DB_run_transaction (struct MHD_Connection *connection,
enum GNUNET_DB_QueryStatus qs;
if (GNUNET_OK !=
TEH_plugin->start (TEH_plugin->cls,
session,
TEH_plugin->start (TEH_plugin->cls,
session,
name))
{
GNUNET_break (0);
if (NULL != mhd_ret)
*mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection,
TALER_EC_DB_START_FAILED);
*mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection,
TALER_EC_DB_START_FAILED);
return GNUNET_SYSERR;
}
qs = cb (cb_cls,
connection,
session,
mhd_ret);
connection,
session,
mhd_ret);
if (0 > qs)
TEH_plugin->rollback (TEH_plugin->cls,
session);
session);
if (GNUNET_DB_STATUS_HARD_ERROR == qs)
return GNUNET_SYSERR;
if (0 <= qs)
@ -135,13 +135,13 @@ TEH_DB_run_transaction (struct MHD_Connection *connection,
if (GNUNET_DB_STATUS_HARD_ERROR == qs)
{
if (NULL != mhd_ret)
*mhd_ret = TEH_RESPONSE_reply_commit_error (connection,
TALER_EC_DB_COMMIT_FAILED_HARD);
*mhd_ret = TEH_RESPONSE_reply_commit_error (connection,
TALER_EC_DB_COMMIT_FAILED_HARD);
return GNUNET_SYSERR;
}
/* make sure callback did not violate invariants! */
GNUNET_assert ( (NULL == mhd_ret) ||
(-1 == *mhd_ret) );
(-1 == *mhd_ret) );
if (0 <= qs)
return GNUNET_OK;
}

View File

@ -130,9 +130,9 @@ struct DepositContext
*/
static enum GNUNET_DB_QueryStatus
deposit_transaction (void *cls,
struct MHD_Connection *connection,
struct TALER_EXCHANGEDB_Session *session,
int *mhd_ret)
struct MHD_Connection *connection,
struct TALER_EXCHANGEDB_Session *session,
int *mhd_ret)
{
struct DepositContext *dc = cls;
const struct TALER_EXCHANGEDB_Deposit *deposit = dc->deposit;
@ -141,8 +141,8 @@ deposit_transaction (void *cls,
enum GNUNET_DB_QueryStatus qs;
qs = TEH_plugin->have_deposit (TEH_plugin->cls,
session,
deposit,
session,
deposit,
GNUNET_YES /* check refund deadline */);
if (qs < 0)
{
@ -159,19 +159,19 @@ deposit_transaction (void *cls,
struct TALER_Amount amount_without_fee;
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"/deposit replay, accepting again!\n");
"/deposit replay, accepting again!\n");
GNUNET_assert (GNUNET_OK ==
TALER_amount_subtract (&amount_without_fee,
&deposit->amount_with_fee,
&deposit->deposit_fee));
*mhd_ret = reply_deposit_success (connection,
&deposit->coin.coin_pub,
&deposit->h_wire,
&deposit->h_contract_terms,
deposit->timestamp,
deposit->refund_deadline,
&deposit->merchant_pub,
&amount_without_fee);
&deposit->coin.coin_pub,
&deposit->h_wire,
&deposit->h_contract_terms,
deposit->timestamp,
deposit->refund_deadline,
&deposit->merchant_pub,
&amount_without_fee);
/* Treat as 'hard' DB error as we want to rollback and
never try again. */
return GNUNET_DB_STATUS_HARD_ERROR;
@ -184,13 +184,13 @@ deposit_transaction (void *cls,
session,
&deposit->coin.coin_pub,
GNUNET_NO,
&tl);
&tl);
if (0 > qs)
return qs;
if (GNUNET_OK !=
TEH_DB_calculate_transaction_list_totals (tl,
&spent,
&spent))
&spent,
&spent))
{
TEH_plugin->free_coin_transaction_list (TEH_plugin->cls,
tl);
@ -239,7 +239,7 @@ deposit_transaction (void *cls,
*/
static int
verify_and_execute_deposit (struct MHD_Connection *connection,
const struct TALER_EXCHANGEDB_Deposit *deposit)
const struct TALER_EXCHANGEDB_Deposit *deposit)
{
struct TALER_DepositRequestPS dr;
int mhd_ret;
@ -269,7 +269,7 @@ verify_and_execute_deposit (struct MHD_Connection *connection,
{
TALER_LOG_WARNING ("Invalid signature on /deposit request\n");
return TEH_RESPONSE_reply_signature_invalid (connection,
TALER_EC_DEPOSIT_COIN_SIGNATURE_INVALID,
TALER_EC_DEPOSIT_COIN_SIGNATURE_INVALID,
"coin_sig");
}
@ -284,7 +284,7 @@ verify_and_execute_deposit (struct MHD_Connection *connection,
}
dki = TEH_KS_denomination_key_lookup (mks,
&deposit->coin.denom_pub,
TEH_KS_DKU_DEPOSIT);
TEH_KS_DKU_DEPOSIT);
if (NULL == dki)
{
TEH_KS_release (mks);
@ -300,9 +300,9 @@ verify_and_execute_deposit (struct MHD_Connection *connection,
if (GNUNET_OK !=
TEH_DB_run_transaction (connection,
"execute deposit",
&mhd_ret,
&deposit_transaction,
&dc))
&mhd_ret,
&deposit_transaction,
&dc))
return mhd_ret;
/* generate regular response */
@ -311,13 +311,13 @@ verify_and_execute_deposit (struct MHD_Connection *connection,
&deposit->amount_with_fee,
&deposit->deposit_fee));
return reply_deposit_success (connection,
&deposit->coin.coin_pub,
&deposit->h_wire,
&deposit->h_contract_terms,
deposit->timestamp,
deposit->refund_deadline,
&deposit->merchant_pub,
&amount_without_fee);
&deposit->coin.coin_pub,
&deposit->h_wire,
&deposit->h_contract_terms,
deposit->timestamp,
deposit->refund_deadline,
&deposit->merchant_pub,
&amount_without_fee);
}

View File

@ -1075,11 +1075,9 @@ postgres_prepare (PGconn *db_conn)
",h_contract_terms"
",h_wire"
" FROM deposits"
" WHERE ("
" (coin_pub=$1)"
" WHERE ((coin_pub=$1)"
" AND (merchant_pub=$3)"
" AND (h_contract_terms=$2)"
" )"
" AND (h_contract_terms=$2))"
" FOR UPDATE;",
3),
/* Fetch deposits with rowid '\geq' the given parameter */
@ -2893,15 +2891,15 @@ postgres_have_deposit (void *cls,
struct TALER_EXCHANGEDB_Deposit deposit2;
struct GNUNET_PQ_ResultSpec rs[] = {
TALER_PQ_result_spec_amount ("amount_with_fee",
&deposit2.amount_with_fee),
&deposit2.amount_with_fee),
TALER_PQ_result_spec_absolute_time ("timestamp",
&deposit2.timestamp),
&deposit2.timestamp),
TALER_PQ_result_spec_absolute_time ("refund_deadline",
&deposit2.refund_deadline),
&deposit2.refund_deadline),
TALER_PQ_result_spec_absolute_time ("wire_deadline",
&deposit2.wire_deadline),
&deposit2.wire_deadline),
GNUNET_PQ_result_spec_auto_from_type ("h_wire",
&deposit2.h_wire),
&deposit2.h_wire),
GNUNET_PQ_result_spec_end
};
enum GNUNET_DB_QueryStatus qs;
@ -2910,9 +2908,9 @@ postgres_have_deposit (void *cls,
"Getting deposits for coin %s\n",
TALER_B2S (&deposit->coin.coin_pub));
qs = GNUNET_PQ_eval_prepared_singleton_select (session->conn,
"get_deposit",
params,
rs);
"get_deposit",
params,
rs);
if (0 >= qs)
return qs;
/* Now we check that the other information in @a deposit
@ -3650,19 +3648,19 @@ postgres_get_melt (void *cls,
};
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_rsa_public_key ("denom_pub",
&refresh_melt->session.coin.denom_pub.rsa_public_key),
&refresh_melt->session.coin.denom_pub.rsa_public_key),
TALER_PQ_result_spec_amount ("fee_refresh",
&refresh_melt->melt_fee),
&refresh_melt->melt_fee),
GNUNET_PQ_result_spec_rsa_signature ("denom_sig",
&refresh_melt->session.coin.denom_sig.rsa_signature),
&refresh_melt->session.coin.denom_sig.rsa_signature),
GNUNET_PQ_result_spec_uint32 ("noreveal_index",
&refresh_melt->session.noreveal_index),
&refresh_melt->session.noreveal_index),
GNUNET_PQ_result_spec_auto_from_type ("old_coin_pub",
&refresh_melt->session.coin.coin_pub),
&refresh_melt->session.coin.coin_pub),
GNUNET_PQ_result_spec_auto_from_type ("old_coin_sig",
&refresh_melt->session.coin_sig),
&refresh_melt->session.coin_sig),
TALER_PQ_result_spec_amount ("amount_with_fee",
&refresh_melt->session.amount_with_fee),
&refresh_melt->session.amount_with_fee),
GNUNET_PQ_result_spec_end
};
enum GNUNET_DB_QueryStatus qs;