summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/Makefile.am4
-rw-r--r--src/backend/taler-merchant-httpd_post-tips-ID-pickup.c166
-rw-r--r--src/include/taler_merchantdb_plugin.h47
3 files changed, 153 insertions, 64 deletions
diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am
index 1c42b7f5..8960b15f 100644
--- a/src/backend/Makefile.am
+++ b/src/backend/Makefile.am
@@ -74,7 +74,9 @@ taler_merchant_httpd_SOURCES = \
taler-merchant-httpd_post-orders-ID-claim.c \
taler-merchant-httpd_post-orders-ID-claim.h \
taler-merchant-httpd_post-orders-ID-pay.c \
- taler-merchant-httpd_post-orders-ID-pay.h
+ taler-merchant-httpd_post-orders-ID-pay.h \
+ taler-merchant-httpd_post-tips-ID-pickup.c \
+ taler-merchant-httpd_post-tips-ID-pickup.h
DEAD = \
taler-merchant-httpd_check-payment.c taler-merchant-httpd_check-payment.h \
diff --git a/src/backend/taler-merchant-httpd_post-tips-ID-pickup.c b/src/backend/taler-merchant-httpd_post-tips-ID-pickup.c
index c24c2c05..e6437c39 100644
--- a/src/backend/taler-merchant-httpd_post-tips-ID-pickup.c
+++ b/src/backend/taler-merchant-httpd_post-tips-ID-pickup.c
@@ -26,7 +26,7 @@
#include "taler-merchant-httpd.h"
#include "taler-merchant-httpd_mhd.h"
#include "taler-merchant-httpd_exchanges.h"
-#include "taler-merchant-httpd_tip-pickup.h"
+#include "taler-merchant-httpd_post-tips-ID-pickup.h"
/**
@@ -59,6 +59,16 @@ struct PlanchetOperation
struct PickupContext *pc;
/**
+ * Kept in a DLL.
+ */
+ struct PlanchetOperation *prev;
+
+ /**
+ * Kept in a DLL.
+ */
+ struct PlanchetOperation *next;
+
+ /**
* Find operation (while active), later NULL.
*/
struct TMH_EXCHANGES_FindOperation *fo;
@@ -128,7 +138,7 @@ struct PickupContext
/**
* Which reserve are we draining?
*/
- struct TALER_ReservePrivateKey reserve_priv;
+ struct TALER_ReservePrivateKeyP reserve_priv;
/**
* Which tip is being picked up?
@@ -136,6 +146,12 @@ struct PickupContext
struct GNUNET_HashCode tip_id;
/**
+ * What is the ID of the pickup operation? (Basically a
+ * hash over the key inputs).
+ */
+ struct GNUNET_HashCode pickup_id;
+
+ /**
* Array of our planchets.
*/
struct TALER_PlanchetDetail *planchets;
@@ -264,6 +280,7 @@ withdraw_cb (void *cls,
{
struct PlanchetOperation *po = cls;
struct PickupContext *pc = po->pc;
+ enum GNUNET_DB_QueryStatus qs;
GNUNET_CONTAINER_DLL_remove (pc->po_head,
pc->po_tail,
@@ -383,9 +400,9 @@ try_withdraw (struct PickupContext *pc,
&do_withdraw,
po);
GNUNET_assert (NULL != po->fo);
- GNUNET_CONTAINER_DLL_insert (pc->fo_head,
- pc->fo_tail,
- fo);
+ GNUNET_CONTAINER_DLL_insert (pc->po_head,
+ pc->po_tail,
+ po);
}
@@ -460,7 +477,7 @@ compute_total_requested (void *cls,
&pd->denom_pub_hash);
if (NULL == dpk)
{
- pc->http_status = MHD_HTTP_BAD_REQUEST;
+ pc->http_status = MHD_HTTP_CONFLICT;
pc->response =
TALER_MHD_make_json_pack (
"{s:I, s:I, s:I, s:O}",
@@ -489,8 +506,48 @@ compute_total_requested (void *cls,
}
}
pc->tr_initialized = true;
+}
+
+
+/**
+ * The tip lookup operation failed. Generate an error response based on the @a qs.
+ *
+ * @param connection connection to generate error for
+ * @param qs DB status to base error creation on
+ * @return MHD result code
+ */
+static MHD_RESULT
+reply_lookup_tip_failed (struct MHD_Connection *connection,
+ enum GNUNET_DB_QueryStatus qs)
+{
+ unsigned int response_code;
+ enum TALER_ErrorCode ec;
- return;
+ TMH_db->rollback (TMH_db->cls);
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ ec = TALER_EC_TIP_PICKUP_TIP_ID_UNKNOWN;
+ response_code = MHD_HTTP_NOT_FOUND;
+ break;
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ ec = TALER_EC_TIP_PICKUP_DB_ERROR_SOFT;
+ response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
+ break;
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ ec = TALER_EC_TIP_PICKUP_DB_ERROR_HARD;
+ response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
+ break;
+ default:
+ GNUNET_break (0);
+ ec = TALER_EC_INTERNAL_LOGIC_ERROR;
+ response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
+ break;
+ }
+ return TALER_MHD_reply_with_error (connection,
+ response_code,
+ ec,
+ "Could not process pickup");
}
@@ -509,19 +566,13 @@ TMH_post_tips_ID_pickup (const struct TMH_RequestHandler *rh,
struct TMH_HandlerContext *hc)
{
struct PickupContext *pc = hc->ctx;
-
- char *justification;
char *exchange_url;
-
struct TALER_Amount total_authorized;
+ struct TALER_Amount total_requested;
struct TALER_Amount total_picked_up;
struct TALER_Amount total_remaining;
struct GNUNET_TIME_Absolute expiration;
- struct GNUNET_TIME_Absolute timestamp_expire;
- struct TALER_ReservePrivateKey reserve_priv;
- MHD_RESULT ret;
enum GNUNET_DB_QueryStatus qs;
- unsigned int num_coins;
unsigned int num_retries;
if (NULL == pc)
@@ -613,6 +664,8 @@ TMH_post_tips_ID_pickup (const struct TMH_RequestHandler *rh,
sizeof (pc->tip_id));
for (unsigned int i = 0; i<pc->planchets_length; i++)
{
+ struct TALER_PlanchetDetail *pd = &pc->planchets[index];
+
GNUNET_CRYPTO_hash_context_read (hc,
&pd->denom_pub_hash,
sizeof (pd->denom_pub_hash));
@@ -627,7 +680,7 @@ TMH_post_tips_ID_pickup (const struct TMH_RequestHandler *rh,
if (NULL != pc->response)
{
- MDH_RESULT ret;
+ MHD_RESULT ret;
ret = MHD_queue_response (connection,
pc->http_status,
@@ -638,6 +691,17 @@ TMH_post_tips_ID_pickup (const struct TMH_RequestHandler *rh,
if (! pc->tr_initialized)
{
+ qs = TMH_db->lookup_tip (TMH_db->cls,
+ hc->instance->settings.id,
+ &pc->tip_id,
+ &total_authorized,
+ &total_picked_up,
+ &expiration,
+ &exchange_url,
+ &pc->reserve_priv);
+ if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
+ return reply_lookup_tip_failed (connection,
+ qs);
MHD_suspend_connection (connection);
pc->tt = GNUNET_SCHEDULER_add_delayed (EXCHANGE_TIMEOUT,
&do_timeout,
@@ -674,25 +738,25 @@ RETRY:
"Could not begin transaction");
}
{
- struct GNUNET_CRYPTO_RsaSignature *sigs[num_coins];
+ struct GNUNET_CRYPTO_RsaSignature *sigs[GNUNET_NZL (pc->planchets_length)];
qs = TMH_db->lookup_pickup (TMH_db->cls,
hc->instance->settings.id,
- &tip_id,
- &pickup_id,
+ &pc->tip_id,
+ &pc->pickup_id,
&exchange_url,
- &pc->reserve_priv;
- num_coins,
+ &pc->reserve_priv,
+ pc->planchets_length,
sigs);
if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
{
- for (unsigned int i = 0; i<num_coins; i++)
+ for (unsigned int i = 0; i< pc->planchets_length; i++)
{
if (NULL == sigs[i])
{
try_withdraw (pc,
exchange_url,
- planchets[i],
+ &pc->planchets[i],
i);
qs = GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
}
@@ -703,7 +767,7 @@ RETRY:
GNUNET_CONTAINER_DLL_insert (pc_head,
pc_tail,
pc);
- pc->tt = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
+ pc->tt = GNUNET_SCHEDULER_add_delayed (EXCHANGE_TIMEOUT,
&do_timeout,
pc);
TMH_db->rollback (TMH_db->cls);
@@ -724,7 +788,7 @@ RETRY:
blind_sigs = json_array ();
GNUNET_assert (NULL != blind_sigs);
- for (unsigned int i = 0; i<num_coins; i++)
+ for (unsigned int i = 0; i<pc->planchets_length; i++)
{
GNUNET_assert (0 ==
json_array_append_new (
@@ -761,51 +825,27 @@ RETRY:
qs = TMH_db->lookup_tip (TMH_db->cls,
hc->instance->settings.id,
- &tip_id,
+ &pc->tip_id,
&total_authorized,
&total_picked_up,
&expiration,
&exchange_url,
&pc->reserve_priv);
+ if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+ goto RETRY;
if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
- {
- unsigned int response_code;
- enum TALER_ErrorCode ec;
-
- TMH_db->rollback (TMH_db->cls);
- switch (qs)
- {
- case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
- ec = TALER_EC_TIP_PICKUP_TIP_ID_UNKNOWN;
- response_code = MHD_HTTP_NOT_FOUND;
- break;
- case GNUNET_DB_STATUS_SOFT_ERROR:
- goto RETRY;
- case GNUNET_DB_STATUS_HARD_ERROR:
- ec = TALER_EC_TIP_PICKUP_DB_ERROR_HARD;
- response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
- break;
- default:
- GNUNET_break (0);
- ec = TALER_EC_INTERNAL_LOGIC_ERROR;
- response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
- break;
- }
- return TALER_MHD_reply_with_error (connection,
- response_code,
- ec,
- "Could not process pickup");
- }
+ return reply_lookup_tip_failed (connection,
+ qs);
if (0 == GNUNET_TIME_absolute_get_remaining (expiration).rel_value_us)
{
TMH_db->rollback (TMH_db->cls);
return TALER_MHD_reply_with_error (connection,
- response_code,
- ec,
- "Could not process pickup");
+ MHD_HTTP_GONE,
+ TALER_EC_TIP_PICKUP_HAS_EXPIRED,
+ "Could not process pickup: it is too late");
}
if (0 >
- TALER_amount_subtract (&total_left,
+ TALER_amount_subtract (&total_remaining,
&total_authorized,
&total_picked_up))
{
@@ -818,14 +858,14 @@ RETRY:
}
if (0 >
- TALER_amount_cmp (&total_left,
+ TALER_amount_cmp (&total_remaining,
&total_requested))
{
GNUNET_break (0);
TMH_db->rollback (TMH_db->cls);
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_BAD_REQUEST,
- TALER_EC_PICKUP_AMOUNT_EXCEEDS_TIP_REMAINING,
+ TALER_EC_TIP_PICKUP_AMOUNT_EXCEEDS_TIP_REMAINING,
"requested amount exceeds amount left in tip");
}
@@ -835,9 +875,9 @@ RETRY:
&total_requested));
qs = TMH_db->insert_pickup (TMH_db->cls,
hc->instance->settings.id,
- &tip_id,
+ &pc->tip_id,
&total_picked_up,
- &pickup_id,
+ &pc->pickup_id,
&total_requested);
if (qs < 0)
{
@@ -864,11 +904,11 @@ RETRY:
pc->tt = GNUNET_SCHEDULER_add_delayed (EXCHANGE_TIMEOUT,
&do_timeout,
pc);
- for (unsigned int i = 0; i<num_coins; i++)
+ for (unsigned int i = 0; i<pc->planchets_length; i++)
{
try_withdraw (pc,
exchange_url,
- planchets[i],
+ &pc->planchets[i],
i);
}
return MHD_YES;
diff --git a/src/include/taler_merchantdb_plugin.h b/src/include/taler_merchantdb_plugin.h
index 2dc764e8..1324b4d9 100644
--- a/src/include/taler_merchantdb_plugin.h
+++ b/src/include/taler_merchantdb_plugin.h
@@ -1781,6 +1781,53 @@ struct TALER_MERCHANTDB_Plugin
struct TALER_MERCHANTDB_PickupDetails **pickups);
+ /**
+ * Insert details about a tip pickup operation. The @a total_picked_up
+ * UPDATES the total amount under the @a tip_id, while the @a
+ * total_requested is the amount to be associated with this @a pickup_id.
+ * While there is usually only one pickup event that picks up the entire
+ * amount, our schema allows for wallets to pick up the amount incrementally
+ * over multiple pick up operations.
+ *
+ * @param cls closure, typically a connection to the db
+ * @param tip_id the unique ID for the tip
+ * @param total_picked_up how much was picked up overall at this
+ * point (includes @total_requested)
+ * @param pickup_id unique ID for the operation
+ * @param total_requested how much is being picked up in this operation
+ * @return transaction status, usually
+ * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT for success
+ * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if @a credit_uuid already known
+ */
+ enum GNUNET_DB_QueryStatus
+ (*insert_pickup)(void *cls,
+ const char *instance_id,
+ const struct GNUNET_HashCode *tip_id,
+ const struct TALER_Amount *total_picked_up,
+ const struct GNUNET_HashCode *pickup_id,
+ const struct TALER_Amount *total_requested);
+
+
+ /**
+ * Insert blind signature obtained from the exchange during a
+ * tip pickup operation.
+ *
+ * @param cls closure, typically a connection to the db
+ * @param pickup_id unique ID for the operation
+ * @param offset offset of the blind signature for the pickup
+ * @param blind_sig the blind signature
+ * @return transaction status, usually
+ * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT for success
+ * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if @a credit_uuid already known
+ */
+ enum GNUNET_DB_QueryStatus
+ (*insert_pickup_blind_signature)(
+ void *cls,
+ const struct GNUNET_HashCode *pickup_id,
+ uint32_t offset,
+ const struct GNUNET_CRYPTO_RsaSignature *blind_sig);
+
+
/* ****************** OLD API ******************** */