properly separate DB logic from parsing logic for /refresh/commit

This commit is contained in:
Christian Grothoff 2015-01-21 13:31:05 +01:00
parent 82217f67db
commit 4d8f4903db
5 changed files with 276 additions and 165 deletions

View File

@ -1087,7 +1087,8 @@ TALER_MINT_DB_upsert_known_coin (PGconn *db_conn, struct KnownCoin *known_coin)
int int
TALER_MINT_DB_insert_refresh_commit_link (PGconn *db_conn, struct RefreshCommitLink *commit_link) TALER_MINT_DB_insert_refresh_commit_link (PGconn *db_conn,
const struct RefreshCommitLink *commit_link)
{ {
uint16_t cnc_index_nbo = htons (commit_link->cnc_index); uint16_t cnc_index_nbo = htons (commit_link->cnc_index);
uint16_t oldcoin_index_nbo = htons (commit_link->oldcoin_index); uint16_t oldcoin_index_nbo = htons (commit_link->oldcoin_index);
@ -1121,7 +1122,8 @@ TALER_MINT_DB_insert_refresh_commit_link (PGconn *db_conn, struct RefreshCommitL
int int
TALER_MINT_DB_insert_refresh_commit_coin (PGconn *db_conn, struct RefreshCommitCoin *commit_coin) TALER_MINT_DB_insert_refresh_commit_coin (PGconn *db_conn,
const struct RefreshCommitCoin *commit_coin)
{ {
uint16_t cnc_index_nbo = htons (commit_coin->cnc_index); uint16_t cnc_index_nbo = htons (commit_coin->cnc_index);
uint16_t newcoin_index_nbo = htons (commit_coin->newcoin_index); uint16_t newcoin_index_nbo = htons (commit_coin->newcoin_index);

View File

@ -91,10 +91,12 @@ TALER_MINT_DB_upsert_known_coin (PGconn *db_conn, struct KnownCoin *known_coin);
int int
TALER_MINT_DB_insert_refresh_commit_link (PGconn *db_conn, struct RefreshCommitLink *commit_link); TALER_MINT_DB_insert_refresh_commit_link (PGconn *db_conn,
const struct RefreshCommitLink *commit_link);
int int
TALER_MINT_DB_insert_refresh_commit_coin (PGconn *db_conn, struct RefreshCommitCoin *commit_coin); TALER_MINT_DB_insert_refresh_commit_coin (PGconn *db_conn,
const struct RefreshCommitCoin *commit_coin);
int int

View File

@ -686,3 +686,124 @@ TALER_MINT_db_execute_refresh_melt (struct MHD_Connection *connection,
} }
/**
* Execute a /refresh/commit.
*
* @param connection the MHD connection to handle
* @param kappa size of x-dimension of @commit_coin and @commit_link arrays
* @param num_oldcoins size of y-dimension of @commit_coin and @commit_link arrays
* @param num_newcoins size of y-dimension of @commit_coin and @commit_link arrays
* @return MHD result code
*/
int
TALER_MINT_db_execute_refresh_commit (struct MHD_Connection *connection,
const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
unsigned int kappa,
unsigned int num_oldcoins,
unsigned int num_newcoins,
struct RefreshCommitCoin *const*commit_coin,
struct RefreshCommitLink *const*commit_link)
{
PGconn *db_conn;
struct RefreshSession refresh_session;
unsigned int i;
unsigned int j;
int res;
if (NULL == (db_conn = TALER_MINT_DB_get_connection ()))
{
// FIXME: return 'internal error'?
GNUNET_break (0);
return MHD_NO;
}
/* Send response immediately if we already know the session.
* Do _not_ care about fields other than session_pub in this case. */
res = TALER_MINT_DB_get_refresh_session (db_conn,
refresh_session_pub,
&refresh_session);
// FIXME: this should check that kappa and num_newcoins match
// our expectations from refresh_session!
for (i = 0; i < refresh_session.kappa; i++)
{
for (j = 0; j < refresh_session.num_newcoins; j++)
{
if (GNUNET_OK !=
TALER_MINT_DB_insert_refresh_commit_coin (db_conn,
&commit_coin[i][j]))
{
// FIXME: return 'internal error'?
GNUNET_break (0);
GNUNET_break (GNUNET_OK == TALER_MINT_DB_rollback (db_conn));
return MHD_NO;
}
if (GNUNET_OK !=
TALER_MINT_DB_insert_refresh_commit_link (db_conn, &commit_link[i][j]))
{
// FIXME: return 'internal error'?
GNUNET_break (0);
GNUNET_break (GNUNET_OK == TALER_MINT_DB_rollback (db_conn));
return MHD_NO;
}
}
}
if ( (GNUNET_YES == res) &&
(GNUNET_YES == refresh_session.has_commit_sig) )
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"sending cached commit response\n");
res = TALER_MINT_reply_refresh_commit_success (connection,
&refresh_session);
GNUNET_break (res != GNUNET_SYSERR);
return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
}
if (GNUNET_SYSERR == res)
{
// FIXME: return 'internal error'?
GNUNET_break (0);
return MHD_NO;
}
if (GNUNET_OK != TALER_MINT_DB_transaction (db_conn))
{
// FIXME: return 'internal error'?
GNUNET_break (0);
return MHD_NO;
}
/* Re-fetch the session information from the database,
* in case a concurrent transaction modified it. */
res = TALER_MINT_DB_get_refresh_session (db_conn,
refresh_session_pub,
&refresh_session);
if (GNUNET_OK != res)
{
// FIXME: return 'internal error'?
GNUNET_break (GNUNET_SYSERR != res);
GNUNET_break (GNUNET_OK == TALER_MINT_DB_rollback (db_conn));
return MHD_NO;
}
if (GNUNET_OK != TALER_MINT_DB_commit (db_conn))
{
// FIXME: return 'internal error'?
GNUNET_break (0);
return MHD_NO;
}
return TALER_MINT_reply_refresh_commit_success (connection, &refresh_session);
}

View File

@ -91,4 +91,23 @@ TALER_MINT_db_execute_refresh_melt (struct MHD_Connection *connection,
const struct TALER_CoinPublicInfo *coin_public_infos); const struct TALER_CoinPublicInfo *coin_public_infos);
/**
* Execute a /refresh/commit.
*
* @param connection the MHD connection to handle
* @param kappa size of x-dimension of @commit_coin and @commit_link arrays
* @param num_oldcoins size of y-dimension of @commit_coin and @commit_link arrays
* @param num_newcoins size of y-dimension of @commit_coin and @commit_link arrays
* @return MHD result code
*/
int
TALER_MINT_db_execute_refresh_commit (struct MHD_Connection *connection,
const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
unsigned int kappa,
unsigned int num_oldcoins,
unsigned int num_newcoins,
struct RefreshCommitCoin *const* commit_coin,
struct RefreshCommitLink *const* commit_link);
#endif /* _NEURO_MINT_DB_H */ #endif /* _NEURO_MINT_DB_H */

View File

@ -460,12 +460,21 @@ TALER_MINT_handler_refresh_commit (struct RequestHandler *rh,
{ {
struct GNUNET_CRYPTO_EddsaPublicKey refresh_session_pub; struct GNUNET_CRYPTO_EddsaPublicKey refresh_session_pub;
int res; int res;
PGconn *db_conn; unsigned int i;
struct RefreshSession refresh_session; unsigned int j;
int i; unsigned int kappa;
unsigned int num_oldcoins;
unsigned int num_newcoins;
struct GNUNET_HashCode commit_hash; struct GNUNET_HashCode commit_hash;
struct GNUNET_HashContext *hash_context; struct GNUNET_HashContext *hash_context;
json_t *root; json_t *root;
struct RefreshCommitSignatureBody body;
json_t *commit_sig_json;
struct RefreshCommitCoin **commit_coin;
struct RefreshCommitLink **commit_link;
json_t *coin_evs;
json_t *transfer_pubs;
json_t *coin_detail;
res = TALER_MINT_parse_post_json (connection, res = TALER_MINT_parse_post_json (connection,
connection_cls, connection_cls,
@ -478,238 +487,196 @@ TALER_MINT_handler_refresh_commit (struct RequestHandler *rh,
return MHD_YES; return MHD_YES;
res = GNUNET_MINT_parse_navigate_json (connection, root, res = GNUNET_MINT_parse_navigate_json (connection, root,
JNAV_FIELD, "session_pub", JNAV_FIELD, "session_pub",
JNAV_RET_DATA, JNAV_RET_DATA,
&refresh_session_pub, &refresh_session_pub,
sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)); sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
if (GNUNET_OK != res) if (GNUNET_OK != res)
{ {
GNUNET_break (GNUNET_SYSERR != res); GNUNET_break (GNUNET_SYSERR != res);
return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
} }
if (NULL == (db_conn = TALER_MINT_DB_get_connection ())) /* Determine dimensionality of the request (kappa, #old and #new coins) */
{ res = GNUNET_MINT_parse_navigate_json (connection, root,
// FIXME: return 'internal error'? JNAV_FIELD, "coin_evs",
GNUNET_break (0); JNAV_RET_TYPED_JSON, JSON_ARRAY, &coin_evs);
return MHD_NO;
}
/* Send response immediately if we already know the session.
* Do _not_ care about fields other than session_pub in this case. */
res = TALER_MINT_DB_get_refresh_session (db_conn,
&refresh_session_pub,
&refresh_session);
if ( (GNUNET_YES == res) &&
(GNUNET_YES == refresh_session.has_commit_sig) )
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"sending cached commit response\n");
res = TALER_MINT_reply_refresh_commit_success (connection,
&refresh_session);
GNUNET_break (res != GNUNET_SYSERR);
return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
}
if (GNUNET_SYSERR == res)
{
// FIXME: return 'internal error'?
GNUNET_break (0);
return MHD_NO;
}
if (GNUNET_OK != TALER_MINT_DB_transaction (db_conn))
{
// FIXME: return 'internal error'?
GNUNET_break (0);
return MHD_NO;
}
/* Re-fetch the session information from the database,
* in case a concurrent transaction modified it. */
res = TALER_MINT_DB_get_refresh_session (db_conn,
&refresh_session_pub,
&refresh_session);
if (GNUNET_OK != res) if (GNUNET_OK != res)
return res;
kappa = json_array_size (coin_evs);
if (3 > kappa)
{ {
// FIXME: return 'internal error'? GNUNET_break_op (0);
GNUNET_break (GNUNET_SYSERR != res); // FIXME: generate error message
GNUNET_break (GNUNET_OK == TALER_MINT_DB_rollback (db_conn));
return MHD_NO; return MHD_NO;
} }
res = GNUNET_MINT_parse_navigate_json (connection, root,
JNAV_INDEX, (int) 0,
JNAV_RET_DATA,
JSON_ARRAY, &coin_detail);
if (GNUNET_OK != res)
return res;
num_newcoins = json_array_size (coin_detail);
res = GNUNET_MINT_parse_navigate_json (connection, root,
JNAV_FIELD, "transfer_pubs",
JNAV_RET_TYPED_JSON, JSON_ARRAY, &transfer_pubs);
if (GNUNET_OK != res)
return res;
if (json_array_size (transfer_pubs) != kappa)
{
GNUNET_break_op (0);
// FIXME: generate error message
return MHD_NO;
}
res = GNUNET_MINT_parse_navigate_json (connection, root,
JNAV_INDEX, (int) 0,
JNAV_RET_DATA,
JSON_ARRAY, &coin_detail);
if (GNUNET_OK != res)
return res;
num_oldcoins = json_array_size (coin_detail);
hash_context = GNUNET_CRYPTO_hash_context_start (); hash_context = GNUNET_CRYPTO_hash_context_start ();
commit_coin = GNUNET_malloc (kappa *
for (i = 0; i < refresh_session.kappa; i++) sizeof (struct RefreshCommitCoin *));
for (i = 0; i < kappa; i++)
{ {
unsigned int j; commit_coin[i] = GNUNET_malloc (num_newcoins *
sizeof (struct RefreshCommitCoin));
for (j = 0; j < refresh_session.num_newcoins; j++) for (j = 0; j < num_newcoins; j++)
{ {
struct RefreshCommitCoin commit_coin;
res = GNUNET_MINT_parse_navigate_json (connection, root, res = GNUNET_MINT_parse_navigate_json (connection, root,
JNAV_FIELD, "coin_evs", JNAV_FIELD, "coin_evs",
JNAV_INDEX, (int) i, JNAV_INDEX, (int) i,
JNAV_INDEX, (int) j, JNAV_INDEX, (int) j,
JNAV_RET_DATA, JNAV_RET_DATA,
&commit_coin.coin_ev, commit_coin[i][j].coin_ev,
sizeof (struct TALER_RSA_BlindedSignaturePurpose)); sizeof (struct TALER_RSA_BlindedSignaturePurpose));
if (GNUNET_OK != res) if (GNUNET_OK != res)
{ {
// FIXME: return 'internal error'? // FIXME: return 'internal error'?
GNUNET_break (0); GNUNET_break (0);
GNUNET_break (GNUNET_OK == TALER_MINT_DB_rollback (db_conn));
GNUNET_CRYPTO_hash_context_abort (hash_context); GNUNET_CRYPTO_hash_context_abort (hash_context);
return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
} }
GNUNET_CRYPTO_hash_context_read (hash_context, GNUNET_CRYPTO_hash_context_read (hash_context,
&commit_coin.coin_ev, &commit_coin[i][j].coin_ev,
sizeof (struct TALER_RSA_BlindedSignaturePurpose)); sizeof (struct TALER_RSA_BlindedSignaturePurpose));
res = GNUNET_MINT_parse_navigate_json (connection, root, res = GNUNET_MINT_parse_navigate_json (connection, root,
JNAV_FIELD, "link_encs", JNAV_FIELD, "link_encs",
JNAV_INDEX, (int) i, JNAV_INDEX, (int) i,
JNAV_INDEX, (int) j, JNAV_INDEX, (int) j,
JNAV_RET_DATA, JNAV_RET_DATA,
commit_coin.link_enc, commit_coin[i][j].link_enc,
TALER_REFRESH_LINK_LENGTH); TALER_REFRESH_LINK_LENGTH);
if (GNUNET_OK != res) if (GNUNET_OK != res)
{ {
// FIXME: return 'internal error'? // FIXME: return 'internal error'?
GNUNET_break (0); GNUNET_break (0);
GNUNET_break (GNUNET_OK == TALER_MINT_DB_rollback (db_conn));
GNUNET_CRYPTO_hash_context_abort (hash_context); GNUNET_CRYPTO_hash_context_abort (hash_context);
return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
} }
GNUNET_CRYPTO_hash_context_read (hash_context, GNUNET_CRYPTO_hash_context_read (hash_context,
commit_coin.link_enc, commit_coin[i][j].link_enc,
TALER_REFRESH_LINK_LENGTH); TALER_REFRESH_LINK_LENGTH);
commit_coin[i][j].cnc_index = i;
commit_coin.cnc_index = i; commit_coin[i][j].newcoin_index = j;
commit_coin.newcoin_index = j; commit_coin[i][j].session_pub = refresh_session_pub;
commit_coin.session_pub = refresh_session_pub;
if (GNUNET_OK !=
TALER_MINT_DB_insert_refresh_commit_coin (db_conn,
&commit_coin))
{
// FIXME: return 'internal error'?
GNUNET_break (0);
GNUNET_break (GNUNET_OK == TALER_MINT_DB_rollback (db_conn));
GNUNET_CRYPTO_hash_context_abort (hash_context);
return MHD_NO;
}
} }
} }
for (i = 0; i < refresh_session.kappa; i++) commit_link = GNUNET_malloc (kappa *
sizeof (struct RefreshCommitLink *));
for (i = 0; i < kappa; i++)
{ {
unsigned int j; commit_link[i] = GNUNET_malloc (num_oldcoins *
for (j = 0; j < refresh_session.num_oldcoins; j++) sizeof (struct RefreshCommitLink));
for (j = 0; j < num_oldcoins; j++)
{ {
struct RefreshCommitLink commit_link;
res = GNUNET_MINT_parse_navigate_json (connection, root, res = GNUNET_MINT_parse_navigate_json (connection, root,
JNAV_FIELD, "transfer_pubs", JNAV_FIELD, "transfer_pubs",
JNAV_INDEX, (int) i, JNAV_INDEX, (int) i,
JNAV_INDEX, (int) j, JNAV_INDEX, (int) j,
JNAV_RET_DATA, JNAV_RET_DATA,
&commit_link.transfer_pub, &commit_link[i][j].transfer_pub,
sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
if (GNUNET_OK != res) if (GNUNET_OK != res)
{ {
GNUNET_break (GNUNET_SYSERR != res); GNUNET_break (GNUNET_SYSERR != res);
GNUNET_break (GNUNET_OK == TALER_MINT_DB_rollback (db_conn));
GNUNET_CRYPTO_hash_context_abort (hash_context); GNUNET_CRYPTO_hash_context_abort (hash_context);
return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
} }
GNUNET_CRYPTO_hash_context_read (hash_context, GNUNET_CRYPTO_hash_context_read (hash_context,
&commit_link.transfer_pub, &commit_link[i][j].transfer_pub,
sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
res = GNUNET_MINT_parse_navigate_json (connection, root, res = GNUNET_MINT_parse_navigate_json (connection, root,
JNAV_FIELD, "secret_encs", JNAV_FIELD, "secret_encs",
JNAV_INDEX, (int) i, JNAV_INDEX, (int) i,
JNAV_INDEX, (int) j, JNAV_INDEX, (int) j,
JNAV_RET_DATA, JNAV_RET_DATA,
commit_link.shared_secret_enc, commit_link[i][j].shared_secret_enc,
TALER_REFRESH_SHARED_SECRET_LENGTH); TALER_REFRESH_SHARED_SECRET_LENGTH);
if (GNUNET_OK != res) if (GNUNET_OK != res)
{ {
GNUNET_break (GNUNET_SYSERR != res); GNUNET_break (GNUNET_SYSERR != res);
GNUNET_break (GNUNET_OK == TALER_MINT_DB_rollback (db_conn));
GNUNET_CRYPTO_hash_context_abort (hash_context); GNUNET_CRYPTO_hash_context_abort (hash_context);
return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
} }
GNUNET_CRYPTO_hash_context_read (hash_context, GNUNET_CRYPTO_hash_context_read (hash_context,
commit_link.shared_secret_enc, commit_link[i][j].shared_secret_enc,
TALER_REFRESH_SHARED_SECRET_LENGTH); TALER_REFRESH_SHARED_SECRET_LENGTH);
commit_link.cnc_index = i; commit_link[i][j].cnc_index = i;
commit_link.oldcoin_index = j; commit_link[i][j].oldcoin_index = j;
commit_link.session_pub = refresh_session_pub; commit_link[i][j].session_pub = refresh_session_pub;
if (GNUNET_OK != TALER_MINT_DB_insert_refresh_commit_link (db_conn, &commit_link))
{
// FIXME: return 'internal error'?
GNUNET_break (0);
GNUNET_break (GNUNET_OK == TALER_MINT_DB_rollback (db_conn));
GNUNET_CRYPTO_hash_context_abort (hash_context);
return MHD_NO;
}
} }
} }
GNUNET_CRYPTO_hash_context_finish (hash_context, &commit_hash); GNUNET_CRYPTO_hash_context_finish (hash_context, &commit_hash);
commit_sig_json = json_object_get (root, "commit_signature");
if (NULL == commit_sig_json)
{ {
struct RefreshCommitSignatureBody body; return TALER_MINT_reply_json_pack (connection,
json_t *commit_sig_json; MHD_HTTP_BAD_REQUEST,
"{s:s}",
commit_sig_json = json_object_get (root, "commit_signature"); "error",
if (NULL == commit_sig_json) "commit_signature missing");
{
GNUNET_break (GNUNET_OK == TALER_MINT_DB_rollback (db_conn));
return TALER_MINT_reply_json_pack (connection,
MHD_HTTP_BAD_REQUEST,
"{s:s}",
"error",
"commit_signature missing");
}
body.commit_hash = commit_hash;
body.purpose.purpose = htonl (TALER_SIGNATURE_REFRESH_COMMIT);
body.purpose.size = htonl (sizeof (struct RefreshCommitSignatureBody));
if (GNUNET_OK != (res = request_json_check_signature (connection,
commit_sig_json,
&refresh_session_pub,
&body.purpose)))
{
GNUNET_break (GNUNET_OK == TALER_MINT_DB_rollback (db_conn));
return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
}
} }
if (GNUNET_OK != TALER_MINT_DB_commit (db_conn)) body.commit_hash = commit_hash;
body.purpose.purpose = htonl (TALER_SIGNATURE_REFRESH_COMMIT);
body.purpose.size = htonl (sizeof (struct RefreshCommitSignatureBody));
if (GNUNET_OK != (res = request_json_check_signature (connection,
commit_sig_json,
&refresh_session_pub,
&body.purpose)))
{ {
// FIXME: return 'internal error'? return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
GNUNET_break (0);
return MHD_NO;
} }
return TALER_MINT_reply_refresh_commit_success (connection, &refresh_session); res = TALER_MINT_db_execute_refresh_commit (connection,
&refresh_session_pub,
kappa,
num_oldcoins,
num_newcoins,
commit_coin,
commit_link);
// FIXME: free memory
return res;
} }