add idempotency checks for /refresh/reveal, fixing #4793
This commit is contained in:
parent
e140ca9dce
commit
7fd6be5cef
@ -1,3 +1,6 @@
|
||||
Thu Nov 17 16:37:22 CET 2016
|
||||
Added missing idempotency checks for /refresh/reveal. -CG
|
||||
|
||||
Thu Nov 17 11:37:56 CET 2016
|
||||
Fixed a few cases of missing database rollbacks, causing the
|
||||
exchange to be stuck. -CG
|
||||
|
@ -1710,6 +1710,9 @@ interpreter_run (void *cls)
|
||||
fail (is);
|
||||
return;
|
||||
}
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
|
||||
"Running command `%s'\n",
|
||||
cmd->label);
|
||||
switch (cmd->oc)
|
||||
{
|
||||
case OC_END:
|
||||
@ -2836,6 +2839,12 @@ run (void *cls)
|
||||
.expected_response_code = MHD_HTTP_OK,
|
||||
.details.refresh_reveal.melt_ref = "refresh-melt-1" },
|
||||
|
||||
/* do it again to check idempotency */
|
||||
{ .oc = OC_REFRESH_REVEAL,
|
||||
.label = "refresh-reveal-1-idempotency",
|
||||
.expected_response_code = MHD_HTTP_OK,
|
||||
.details.refresh_reveal.melt_ref = "refresh-melt-1" },
|
||||
|
||||
/* Test that /refresh/link works */
|
||||
{ .oc = OC_REFRESH_LINK,
|
||||
.label = "refresh-link-1",
|
||||
@ -2849,7 +2858,7 @@ run (void *cls)
|
||||
.label = "refresh-deposit-refreshed-1a",
|
||||
.expected_response_code = MHD_HTTP_OK,
|
||||
.details.deposit.amount = "EUR:1",
|
||||
.details.deposit.coin_ref = "refresh-reveal-1",
|
||||
.details.deposit.coin_ref = "refresh-reveal-1-idempotency",
|
||||
.details.deposit.coin_idx = 0,
|
||||
.details.deposit.wire_details = "{ \"type\":\"test\", \"bank_uri\":\"http://localhost:8082/\", \"account_number\":42 }",
|
||||
.details.deposit.contract = "{ \"items\": [ { \"name\":\"ice cream\", \"value\":3 } ] }",
|
||||
@ -3072,12 +3081,6 @@ main (int argc,
|
||||
enum GNUNET_OS_ProcessStatusType type;
|
||||
unsigned long code;
|
||||
|
||||
GNUNET_log_setup ("test-exchange-api",
|
||||
"DEBUG",
|
||||
"/tmp/logs");
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test log\n");
|
||||
return 0;
|
||||
|
||||
/* These might get in the way... */
|
||||
unsetenv ("XDG_DATA_HOME");
|
||||
unsetenv ("XDG_CONFIG_HOME");
|
||||
|
@ -1280,16 +1280,28 @@ refresh_exchange_coin (struct MHD_Connection *connection,
|
||||
ev_sig.rsa_signature = NULL;
|
||||
return ev_sig;
|
||||
}
|
||||
if (GNUNET_OK ==
|
||||
TEH_plugin->get_refresh_out (TEH_plugin->cls,
|
||||
session,
|
||||
session_hash,
|
||||
coin_off,
|
||||
&ev_sig))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||
"Returning cashed reply for /refresh/reveal signature\n");
|
||||
return ev_sig;
|
||||
}
|
||||
|
||||
ev_sig.rsa_signature
|
||||
= GNUNET_CRYPTO_rsa_sign_blinded (dki->denom_priv.rsa_private_key,
|
||||
commit_coin->coin_ev,
|
||||
commit_coin->coin_ev_size);
|
||||
= GNUNET_CRYPTO_rsa_sign_blinded (dki->denom_priv.rsa_private_key,
|
||||
commit_coin->coin_ev,
|
||||
commit_coin->coin_ev_size);
|
||||
if (NULL == ev_sig.rsa_signature)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return ev_sig;
|
||||
}
|
||||
if (GNUNET_OK !=
|
||||
if (GNUNET_SYSERR ==
|
||||
TEH_plugin->insert_refresh_out (TEH_plugin->cls,
|
||||
session,
|
||||
session_hash,
|
||||
@ -1300,6 +1312,7 @@ refresh_exchange_coin (struct MHD_Connection *connection,
|
||||
GNUNET_CRYPTO_rsa_signature_free (ev_sig.rsa_signature);
|
||||
ev_sig.rsa_signature = NULL;
|
||||
}
|
||||
|
||||
return ev_sig;
|
||||
}
|
||||
|
||||
|
@ -318,7 +318,7 @@ TEH_RESPONSE_reply_internal_db_error (struct MHD_Connection *connection,
|
||||
{
|
||||
return TEH_RESPONSE_reply_internal_error (connection,
|
||||
ec,
|
||||
"Failed to connect to database");
|
||||
"Failure in database interaction");
|
||||
}
|
||||
|
||||
|
||||
|
@ -1154,6 +1154,15 @@ postgres_prepare (PGconn *db_conn)
|
||||
"($1, $2, $3)",
|
||||
3, NULL);
|
||||
|
||||
/* Used in #postgres_get_refresh_out() to test if the
|
||||
generated signature(s) already exists */
|
||||
PREPARE ("get_refresh_out",
|
||||
"SELECT ev_sig"
|
||||
" FROM refresh_out"
|
||||
" WHERE session_hash=$1"
|
||||
" AND newcoin_index=$2",
|
||||
2, NULL);
|
||||
|
||||
/* Used in #postgres_get_link_data_list(). We use the session_hash
|
||||
to obtain the "noreveal_index" for that session, and then select the
|
||||
corresponding signatures (ev_sig) and the denomination keys from
|
||||
@ -3431,6 +3440,67 @@ postgres_get_refresh_transfer_public_key (void *cls,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Insert signature of a new coin generated during refresh into
|
||||
* the database indexed by the refresh session and the index
|
||||
* of the coin. This data is later used should an old coin
|
||||
* be used to try to obtain the private keys during "/refresh/link".
|
||||
*
|
||||
* @param cls the `struct PostgresClosure` with the plugin-specific state
|
||||
* @param session database connection
|
||||
* @param session_hash hash to identify refresh session
|
||||
* @param newcoin_index coin index
|
||||
* @param ev_sig coin signature
|
||||
* @return #GNUNET_OK on success, #GNUNET_NO if we have no such result
|
||||
* #GNUNET_SYSERR on error
|
||||
*/
|
||||
static int
|
||||
postgres_get_refresh_out (void *cls,
|
||||
struct TALER_EXCHANGEDB_Session *session,
|
||||
const struct GNUNET_HashCode *session_hash,
|
||||
uint16_t newcoin_index,
|
||||
struct TALER_DenominationSignature *ev_sig)
|
||||
{
|
||||
PGresult *result;
|
||||
struct GNUNET_PQ_QueryParam params[] = {
|
||||
GNUNET_PQ_query_param_auto_from_type (session_hash),
|
||||
GNUNET_PQ_query_param_uint16 (&newcoin_index),
|
||||
GNUNET_PQ_query_param_end
|
||||
};
|
||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||
GNUNET_PQ_result_spec_rsa_signature ("ev_sig",
|
||||
&ev_sig->rsa_signature),
|
||||
GNUNET_PQ_result_spec_end
|
||||
};
|
||||
|
||||
result = GNUNET_PQ_exec_prepared (session->conn,
|
||||
"get_refresh_out",
|
||||
params);
|
||||
if (PGRES_TUPLES_OK != PQresultStatus (result))
|
||||
{
|
||||
BREAK_DB_ERR (result);
|
||||
PQclear (result);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
if (1 != PQntuples (result))
|
||||
{
|
||||
PQclear (result);
|
||||
return GNUNET_NO;
|
||||
}
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_PQ_extract_result (result,
|
||||
rs,
|
||||
0))
|
||||
{
|
||||
PQclear (result);
|
||||
GNUNET_break (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
PQclear (result);
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Insert signature of a new coin generated during refresh into
|
||||
* the database indexed by the refresh session and the index
|
||||
@ -3443,6 +3513,7 @@ postgres_get_refresh_transfer_public_key (void *cls,
|
||||
* @param newcoin_index coin index
|
||||
* @param ev_sig coin signature
|
||||
* @return #GNUNET_OK on success
|
||||
* #GNUNET_SYSERR on error
|
||||
*/
|
||||
static int
|
||||
postgres_insert_refresh_out (void *cls,
|
||||
@ -5050,6 +5121,7 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
|
||||
plugin->free_refresh_commit_coins = &postgres_free_refresh_commit_coins;
|
||||
plugin->insert_refresh_transfer_public_key = &postgres_insert_refresh_transfer_public_key;
|
||||
plugin->get_refresh_transfer_public_key = &postgres_get_refresh_transfer_public_key;
|
||||
plugin->get_refresh_out = &postgres_get_refresh_out;
|
||||
plugin->insert_refresh_out = &postgres_insert_refresh_out;
|
||||
plugin->get_link_data_list = &postgres_get_link_data_list;
|
||||
plugin->free_link_data_list = &common_free_link_data_list;
|
||||
|
@ -1359,6 +1359,27 @@ struct TALER_EXCHANGEDB_Plugin
|
||||
struct TALER_TransferPublicKeyP *tp);
|
||||
|
||||
|
||||
/**
|
||||
* Get signature of a new coin generated during refresh into
|
||||
* the database indexed by the refresh session and the index
|
||||
* of the coin.
|
||||
*
|
||||
* @param cls the @e cls of this struct with the plugin-specific state
|
||||
* @param session database connection
|
||||
* @param session_hash hash to identify refresh session
|
||||
* @param newcoin_index coin index
|
||||
* @param[out] ev_sig coin signature
|
||||
* @return #GNUNET_OK on success, #GNUNET_NO if we have no such entry,
|
||||
* #GNUNET_SYSERR on error
|
||||
*/
|
||||
int
|
||||
(*get_refresh_out) (void *cls,
|
||||
struct TALER_EXCHANGEDB_Session *session,
|
||||
const struct GNUNET_HashCode *session_hash,
|
||||
uint16_t newcoin_index,
|
||||
struct TALER_DenominationSignature *ev_sig);
|
||||
|
||||
|
||||
/**
|
||||
* Insert signature of a new coin generated during refresh into
|
||||
* the database indexed by the refresh session and the index
|
||||
@ -1371,6 +1392,7 @@ struct TALER_EXCHANGEDB_Plugin
|
||||
* @param newcoin_index coin index
|
||||
* @param ev_sig coin signature
|
||||
* @return #GNUNET_OK on success
|
||||
* #GNUNET_SYSERR on error
|
||||
*/
|
||||
int
|
||||
(*insert_refresh_out) (void *cls,
|
||||
|
Loading…
Reference in New Issue
Block a user