aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/taler-merchant-httpd_private-post-transfers.c277
-rw-r--r--src/backenddb/merchant-0001.sql2
-rw-r--r--src/backenddb/plugin_merchantdb_postgres.c325
-rw-r--r--src/include/taler_merchantdb_plugin.h96
4 files changed, 524 insertions, 176 deletions
diff --git a/src/backend/taler-merchant-httpd_private-post-transfers.c b/src/backend/taler-merchant-httpd_private-post-transfers.c
index fd9752d8..519e69f5 100644
--- a/src/backend/taler-merchant-httpd_private-post-transfers.c
+++ b/src/backend/taler-merchant-httpd_private-post-transfers.c
@@ -299,11 +299,12 @@ check_transfer (void *cls,
GNUNET_break_op (0);
ptc->check_transfer_result = GNUNET_SYSERR;
/* Build the `TrackTransferConflictDetails` */
+ ptc->response_code = MHD_HTTP_ACCEPTED;
ptc->response
= TALER_MHD_make_json_pack (
"{s:I, s:s, s:s, s:o, s:o,"
" s:I, s:o, s:o, s:o, s:o,"
- " s:o, s:o, s:o }",
+ " s:o, s:o, s:o, s:o, s:o }",
"code",
(json_int_t) TALER_EC_POST_TRANSFERS_CONFLICTING_REPORTS,
"hint",
@@ -330,6 +331,10 @@ check_transfer (void *cls,
GNUNET_JSON_from_data_auto (&ttd->h_contract_terms),
"amount_with_fee",
TALER_JSON_from_amount (amount_with_fee),
+ "coin_value",
+ TALER_JSON_from_amount (&ttd->coin_value),
+ "coin_fee",
+ TALER_JSON_from_amount (&ttd->coin_fee),
"deposit_fee",
TALER_JSON_from_amount (deposit_fee));
return;
@@ -339,16 +344,14 @@ check_transfer (void *cls,
/**
- * Check that the given @a wire_fee is what the
- * @a exchange_pub should charge at the @a execution_time.
- * If the fee is correct (according to our database),
- * return #GNUNET_OK. If we do not have the fee structure
- * in our DB, we just accept it and return #GNUNET_NO;
- * if we have proof that the fee is bogus, we respond with
- * the proof to the client and return #GNUNET_SYSERR.
+ * Check that the given @a wire_fee is what the @a exchange_pub should charge
+ * at the @a execution_time. If the fee is correct (according to our
+ * database), return #GNUNET_OK. If we do not have the fee structure in our
+ * DB, we just accept it and return #GNUNET_NO; if we have proof that the fee
+ * is bogus, we respond with the proof to the client and return
+ * #GNUNET_SYSERR.
*
* @param ptc context of the transfer to respond to
- * @param json response from the exchange
* @param execution_time time of the wire transfer
* @param wire_fee fee claimed by the exchange
* @return #GNUNET_SYSERR if we returned hard proof of
@@ -356,7 +359,6 @@ check_transfer (void *cls,
*/
static int
check_wire_fee (struct PostTransfersContext *ptc,
- const json_t *json,
struct GNUNET_TIME_Absolute execution_time,
const struct TALER_Amount *wire_fee)
{
@@ -397,11 +399,14 @@ check_wire_fee (struct PostTransfersContext *ptc,
return GNUNET_OK; /* expected_fee >= wire_fee */
}
/* Wire fee check failed, export proof to client */
- resume_transfer_with_response (
- ptc,
- MHD_HTTP_FAILED_DEPENDENCY,
+ /* FIXME: This is not actually the *full* proof, as we are
+ not including the exchange's bogus response with the
+ signature claiming a different wire fee. Also, this
+ error is not described in the API docs! */
+ ptc->response_code = MHD_HTTP_ACCEPTED;
+ ptc->response =
TALER_MHD_make_json_pack (
- "{s:I, s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:O}",
+ "{s:I, s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o}",
"code", (json_int_t) TALER_EC_POST_TRANSFERS_JSON_BAD_WIRE_FEE,
"wire_fee", TALER_JSON_from_amount (wire_fee),
"execution_time", GNUNET_JSON_from_time_abs (execution_time),
@@ -410,8 +415,7 @@ check_wire_fee (struct PostTransfersContext *ptc,
"start_date", GNUNET_JSON_from_time_abs (start_date),
"end_date", GNUNET_JSON_from_time_abs (end_date),
"master_sig", GNUNET_JSON_from_data_auto (&master_sig),
- "master_pub", GNUNET_JSON_from_data_auto (&ptc->master_pub),
- "json", json));
+ "master_pub", GNUNET_JSON_from_data_auto (&ptc->master_pub));
GNUNET_free (wire_method);
return GNUNET_SYSERR;
}
@@ -452,85 +456,6 @@ wire_transfer_cb (void *cls,
return;
}
- if (GNUNET_SYSERR ==
- check_wire_fee (ptc,
- hr->reply,
- td->execution_time,
- &td->wire_fee))
- return;
-
- /* Now we want to double-check that any (Taler coin) deposit
- * which is accounted into _this_ wire transfer, does exist
- * into _our_ database. This is the rationale: if the
- * exchange paid us for it, we must have received it _beforehands_!
- *
- * details_length is how many (Taler coin) deposits have been
- * aggregated into _this_ wire transfer.
- *///
- for (unsigned int i = 0; i < td->details_length; i++)
- {
- const struct TALER_TrackTransferDetails *ttd = &td->details[i];
-
- ptc->current_offset = i;
- ptc->current_detail = ttd;
- /* Set the coin as "never seen" before. */
- ptc->check_transfer_result = GNUNET_NO;
- TMH_db->preflight (TMH_db->cls);
- qs = TMH_db->lookup_deposits_by_contract_and_coin (TMH_db->cls,
- instance_id,
- &ttd->h_contract_terms,
- &ttd->coin_pub,
- &check_transfer,
- ptc);
- if (0 > qs)
- {
- /* single, read-only SQL statements should never cause
- serialization problems */
- GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
- /* Always report on hard error as well to enable diagnostics */
- GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
- resume_transfer_with_error (
- ptc,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_POST_TRANSFERS_DB_FETCH_DEPOSIT_ERROR,
- "failed to obtain deposit data from local database");
- return;
- }
- if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
- {
- /* The exchange says we made this deposit, but WE do not
- recall making it (corrupted / unreliable database?)!
- Well, let's say thanks and accept the money! */
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Failed to find payment data in DB\n");
- ptc->check_transfer_result = GNUNET_OK;
- }
- if (GNUNET_NO == ptc->check_transfer_result)
- {
- /* Internal error: how can we have called #check_transfer()
- but still have no result? */
- GNUNET_break (0);
- resume_transfer_with_error (ptc,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_POST_TRANSFERS_DB_INTERNAL_LOGIC_ERROR,
- "internal logic error");
- return;
- }
- if (GNUNET_SYSERR == ptc->check_transfer_result)
- {
- /* #check_transfer() failed, report conflict! */
- GNUNET_break_op (0);
- GNUNET_assert (NULL != ptc->response);
- resume_transfer_with_response (ptc,
- MHD_HTTP_FAILED_DEPENDENCY,
- ptc->response);
- ptc->response = NULL;
- return;
- }
- }
-
- /* Response is consistent with the /deposit we made,
- remember it for future reference */
for (unsigned int r = 0; r<MAX_RETRIES; r++)
{
TMH_db->preflight (TMH_db->cls);
@@ -674,6 +599,81 @@ process_transfer_with_exchange (void *cls,
/**
+ * Now we want to double-check that any (Taler coin) deposit which is
+ * accounted into _this_ wire transfer, does exist into _our_ database. This
+ * is the rationale: if the exchange paid us for it, we must have received it
+ * _beforehands_!
+ *
+ * @param cls a `struct PostTransfersContext`
+ * @param current_offset at which offset in the exchange's reply are the @a ttd
+ * @param ttd details about an aggregated transfer (to check)
+ */
+static void
+verify_exchange_claim_cb (void *cls,
+ unsigned int current_offset,
+ const struct TALER_TrackTransferDetails *ttd)
+{
+ struct PostTransfersContext *ptc = cls;
+ enum GNUNET_DB_QueryStatus qs;
+
+ if (0 != ptc->response_code)
+ return; /* already encountered an error */
+ ptc->current_offset = current_offset;
+ ptc->current_detail = ttd;
+ /* Set the coin as "never seen" before. */
+ ptc->check_transfer_result = GNUNET_NO;
+ TMH_db->preflight (TMH_db->cls);
+ qs = TMH_db->lookup_deposits_by_contract_and_coin (
+ TMH_db->cls,
+ ptc->hc->instance->settings.id,
+ &ttd->h_contract_terms,
+ &ttd->coin_pub,
+ &check_transfer,
+ ptc);
+ if (0 > qs)
+ {
+ /* single, read-only SQL statements should never cause
+ serialization problems */
+ GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
+ /* Always report on hard error as well to enable diagnostics */
+ GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
+ ptc->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
+ ptc->response
+ = TALER_MHD_make_error (TALER_EC_POST_TRANSFERS_DB_FETCH_DEPOSIT_ERROR,
+ "failed to obtain deposit data from local database");
+ return;
+ }
+ if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
+ {
+ /* The exchange says we made this deposit, but WE do not
+ recall making it (corrupted / unreliable database?)!
+ Well, let's say thanks and accept the money! */
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Failed to find payment data in DB\n");
+ ptc->check_transfer_result = GNUNET_OK;
+ }
+ if (GNUNET_NO == ptc->check_transfer_result)
+ {
+ /* Internal error: how can we have called #check_transfer()
+ but still have no result? */
+ GNUNET_break (0);
+ ptc->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
+ ptc->response =
+ TALER_MHD_make_error (TALER_EC_POST_TRANSFERS_DB_INTERNAL_LOGIC_ERROR,
+ "internal logic error");
+ return;
+ }
+ if (GNUNET_SYSERR == ptc->check_transfer_result)
+ {
+ /* #check_transfer() failed, report conflict! */
+ GNUNET_break_op (0);
+ GNUNET_assert (NULL != ptc->response);
+ return;
+ }
+}
+
+
+/**
* Represents an entry in the table used to sum up
* individual deposits for each h_contract_terms/order_id
* (as the exchange gives us per coin, and we return
@@ -710,7 +710,7 @@ struct Entry
* @param deposit_fee the fee charged for @a deposit_value
*/
static void
-transfer_details_cb (void *cls,
+transfer_summary_cb (void *cls,
const char *order_id,
const struct TALER_Amount *deposit_value,
const struct TALER_Amount *deposit_fee)
@@ -846,6 +846,7 @@ TMH_private_post_transfers (const struct TMH_RequestHandler *rh,
hc->cc = &transfer_cleanup;
}
+queue:
if (0 != ptc->response_code)
{
MHD_RESULT ret;
@@ -910,43 +911,86 @@ TMH_private_post_transfers (const struct TMH_RequestHandler *rh,
/* Check if transfer data is in database! */
{
- struct GNUNET_CONTAINER_MultiHashMap *map;
struct GNUNET_TIME_Absolute execution_time;
struct TALER_Amount total_amount;
struct TALER_Amount wire_fee;
+ bool verified;
TMH_db->preflight (TMH_db->cls);
- map = GNUNET_CONTAINER_multihashmap_create (16,
- GNUNET_NO);
- qs = TMH_db->lookup_transfer_details (TMH_db->cls,
- hc->instance->settings.id,
- ptc->exchange_url,
- ptc->payto_uri,
- &ptc->wtid,
- &total_amount,
- &wire_fee,
- execution_time,
- &transfer_details_cb,
- map);
+ qs = TMH_db->lookup_transfer (TMH_db->cls,
+ ptc->exchange_url,
+ &ptc->wtid,
+ &total_amount,
+ &wire_fee,
+ &execution_time,
+ &verified);
if (0 > qs)
{
/* Simple select queries should not cause serialization issues */
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
/* Always report on hard error as well to enable diagnostics */
GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
- GNUNET_CONTAINER_multihashmap_iterate (map,
- &hashmap_free,
- NULL);
- GNUNET_CONTAINER_multihashmap_destroy (map);
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_POST_TRANSFERS_DB_LOOKUP_ERROR,
"Failed to query database about transfer details");
}
- if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs)
+ if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
+ goto fetch;
+ if (! verified)
+ {
+ if (GNUNET_SYSERR ==
+ check_wire_fee (ptc,
+ execution_time,
+ &wire_fee))
+ {
+ GNUNET_assert (0 != ptc->response_code);
+ goto queue;
+ }
+
+ qs = TMH_db->lookup_transfer_details (TMH_db->cls,
+ ptc->exchange_url,
+ &ptc->wtid,
+ &verify_exchange_claim_cb,
+ ptc);
+ if (0 != ptc->response_code)
+ goto queue;
+ verified = true;
+ qs = TMH_db->set_transfer_status_to_verified (TMH_db->cls,
+ ptc->exchange_url,
+ &ptc->wtid);
+ GNUNET_break (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs);
+ }
+
+ /* Short version: we already verified, generate the summary response */
+ GNUNET_assert (verified);
{
+ struct GNUNET_CONTAINER_MultiHashMap *map;
json_t *deposit_sums;
+ map = GNUNET_CONTAINER_multihashmap_create (16,
+ GNUNET_NO);
+ qs = TMH_db->lookup_transfer_summary (TMH_db->cls,
+ ptc->exchange_url,
+ &ptc->wtid,
+ &transfer_summary_cb,
+ map);
+ if (0 > qs)
+ {
+ /* Simple select queries should not cause serialization issues */
+ GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
+ /* Always report on hard error as well to enable diagnostics */
+ GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
+ GNUNET_CONTAINER_multihashmap_iterate (map,
+ &hashmap_free,
+ NULL);
+ GNUNET_CONTAINER_multihashmap_destroy (map);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_POST_TRANSFERS_DB_LOOKUP_ERROR,
+ "Failed to query database about transfer details");
+ }
+
deposit_sums = json_array ();
GNUNET_assert (NULL != deposit_sums);
GNUNET_CONTAINER_multihashmap_iterate (map,
@@ -961,11 +1005,12 @@ TMH_private_post_transfers (const struct TMH_RequestHandler *rh,
"wire_fee", TALER_JSON_from_amount (&wire_fee),
"execution_time", GNUNET_JSON_from_time_abs (execution_time),
"deposit_sums", deposit_sums);
- }
- }
+ } /* end of 'verified == true' */
+ } /* end of 'transfer data in database' */
/* reply not in database, ensure the POST is in the database, and
start work to obtain the reply from the exchange */
+fetch:
qs = TMH_db->insert_transfer (TMH_db->cls,
ptc->hc->instance->settings.id,
ptc->exchange_url,
diff --git a/src/backenddb/merchant-0001.sql b/src/backenddb/merchant-0001.sql
index 754b47f3..9eb60e5c 100644
--- a/src/backenddb/merchant-0001.sql
+++ b/src/backenddb/merchant-0001.sql
@@ -370,6 +370,8 @@ CREATE TABLE IF NOT EXISTS merchant_transfer_signatures
REFERENCES merchant_transfers (credit_serial) ON DELETE CASCADE
,signkey_serial BIGINT NOT NULL
REFERENCES merchant_exchange_signing_keys (signkey_serial) ON DELETE CASCADE
+ ,wire_fee_val INT8 NOT NULL
+ ,wire_fee_frac INT4 NOT NULL
,execution_time INT8 NOT NULL
,exchange_sig BYTEA NOT NULL CHECK (LENGTH(exchange_sig)=64)
);
diff --git a/src/backenddb/plugin_merchantdb_postgres.c b/src/backenddb/plugin_merchantdb_postgres.c
index c196790c..8e402d31 100644
--- a/src/backenddb/plugin_merchantdb_postgres.c
+++ b/src/backenddb/plugin_merchantdb_postgres.c
@@ -2848,6 +2848,7 @@ RETRY:
{
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_uint64 (&credit_serial),
+ TALER_PQ_query_param_amount (&td->wire_fee),
GNUNET_PQ_query_param_absolute_time (&td->execution_time),
GNUNET_PQ_query_param_auto_from_type (&td->exchange_sig),
GNUNET_PQ_query_param_auto_from_type (&td->exchange_pub),
@@ -3118,14 +3119,109 @@ postgres_lookup_deposits_by_contract_and_coin (
/**
- * Closure for #lookup_transfer_details_cb().
+ * Lookup transfer status.
+ *
+ * @param cls closure
+ * @param exchange_url the exchange that made the transfer
+ * @param wtid wire transfer subject
+ * @param[out] total_amount amount that was transferred (in total, minus @a wire_fee)
+ * @param[out] wire_fee the wire fee the exchange charged
+ * @param[out] execution_time when the transfer was executed by the exchange
+ * @param[out] verified did we confirm the transfer was OK
+ * @return transaction status
*/
-struct LookupTransferDetailsContext
+static enum GNUNET_DB_QueryStatus
+postgres_lookup_transfer (
+ void *cls,
+ const char *exchange_url,
+ const struct TALER_WireTransferIdentifierRawP *wtid,
+ struct TALER_Amount *total_amount,
+ struct TALER_Amount *wire_fee,
+ struct GNUNET_TIME_Absolute *execution_time,
+ bool *verified)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (exchange_url),
+ GNUNET_PQ_query_param_auto_from_type (wtid),
+ GNUNET_PQ_query_param_end
+ };
+ uint8_t verified8;
+ struct TALER_Amount credit_amount;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ TALER_PQ_RESULT_SPEC_AMOUNT ("credit_amount",
+ &credit_amount),
+ TALER_PQ_RESULT_SPEC_AMOUNT ("wire_fee",
+ wire_fee),
+ GNUNET_PQ_result_spec_absolute_time ("execution_time",
+ execution_time),
+ GNUNET_PQ_result_spec_auto_from_type ("verified",
+ &verified8),
+ GNUNET_PQ_result_spec_end
+ };
+ enum GNUNET_DB_QueryStatus qs;
+
+ check_connection (pg);
+ qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "lookup_transfer",
+ params,
+ rs);
+ if (qs > 0)
+ {
+ *verified = (0 != verified8);
+ // FIXME: unclear if table stores 'total' including or excluding fee :-(.
+ // Check and update DOCS and taler_exchange_service.h header!
+ if (0 >
+ TALER_amount_add (total_amount,
+ &credit_amount,
+ wire_fee))
+ {
+ GNUNET_break (0);
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ }
+ }
+ return qs;
+}
+
+
+/**
+ * Set transfer status to verified.
+ *
+ * @param cls closure
+ * @param exchange_url the exchange that made the transfer
+ * @param wtid wire transfer subject
+ * @return transaction status
+ */
+static enum GNUNET_DB_QueryStatus
+postgres_set_transfer_status_to_verified (
+ void *cls,
+ const char *exchange_url,
+ const struct TALER_WireTransferIdentifierRawP *wtid)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (wtid),
+ GNUNET_PQ_query_param_string (exchange_url),
+ GNUNET_PQ_query_param_end
+ };
+
+ check_connection (pg);
+ return GNUNET_PQ_eval_prepared_non_select (
+ pg->conn,
+ "set_transfer_status_to_verified",
+ params);
+}
+
+
+/**
+ * Closure for #lookup_transfer_summary_cb().
+ */
+struct LookupTransferSummaryContext
{
/**
* Function to call for each order that was aggregated.
*/
- TALER_MERCHANTDB_TransferDetailsCallback cb;
+ TALER_MERCHANTDB_TransferSummaryCallback cb;
/**
* Closure for @e cb.
@@ -3148,16 +3244,16 @@ struct LookupTransferDetailsContext
* Function to be called with the results of a SELECT statement
* that has returned @a num_results results.
*
- * @param cls of type `struct LookupTransferDetailsContext *`
+ * @param cls of type `struct LookupTransferSummaryContext *`
* @param result the postgres result
* @param num_result the number of results in @a result
*/
static void
-lookup_transfer_details_cb (void *cls,
+lookup_transfer_summary_cb (void *cls,
PGresult *result,
unsigned int num_results)
{
- struct LookupTransferDetailsContext *ltdc = cls;
+ struct LookupTransferSummaryContext *ltdc = cls;
struct PostgresClosure *pg = ltdc->pg;
for (unsigned int i = 0; i<num_results; i++)
@@ -3195,16 +3291,134 @@ lookup_transfer_details_cb (void *cls,
/**
+ * Lookup transfer summary.
+ *
+ * @param cls closure
+ * @param exchange_url the exchange that made the transfer
+ * @param wtid wire transfer subject
+ * @param cb function to call with detailed transfer data
+ * @param cb_cls closure for @a cb
+ * @return transaction status
+ */
+static enum GNUNET_DB_QueryStatus
+postgres_lookup_transfer_summary (
+ void *cls,
+ const char *exchange_url,
+ const struct TALER_WireTransferIdentifierRawP *wtid,
+ TALER_MERCHANTDB_TransferSummaryCallback cb,
+ void *cb_cls)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (exchange_url),
+ GNUNET_PQ_query_param_auto_from_type (wtid),
+ GNUNET_PQ_query_param_end
+ };
+ struct LookupTransferSummaryContext ltdc = {
+ .cb = cb,
+ .cb_cls = cb_cls,
+ .pg = pg
+ };
+ enum GNUNET_DB_QueryStatus qs;
+
+ check_connection (pg);
+ qs = GNUNET_PQ_eval_prepared_multi_select (
+ pg->conn,
+ "lookup_transfer_summary",
+ params,
+ &lookup_transfer_summary_cb,
+ &ltdc);
+ if (0 >= qs)
+ return qs;
+ return ltdc.qs;
+}
+
+
+/**
+ * Closure for #lookup_transfer_details_cb().
+ */
+struct LookupTransferDetailsContext
+{
+ /**
+ * Function to call for each order that was aggregated.
+ */
+ TALER_MERCHANTDB_TransferDetailsCallback cb;
+
+ /**
+ * Closure for @e cb.
+ */
+ void *cb_cls;
+
+ /**
+ * Plugin context.
+ */
+ struct PostgresClosure *pg;
+
+ /**
+ * Transaction result.
+ */
+ enum GNUNET_DB_QueryStatus qs;
+};
+
+
+/**
+ * Function to be called with the results of a SELECT statement
+ * that has returned @a num_results results.
+ *
+ * @param cls of type `struct LookupTransferDetailsContext *`
+ * @param result the postgres result
+ * @param num_result the number of results in @a result
+ */
+static void
+lookup_transfer_details_cb (void *cls,
+ PGresult *result,
+ unsigned int num_results)
+{
+ struct LookupTransferDetailsContext *ltdc = cls;
+ struct PostgresClosure *pg = ltdc->pg;
+
+ for (unsigned int i = 0; i<num_results; i++)
+ {
+ uint32_t current_offset;
+ struct TALER_TrackTransferDetails ttd;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_uint32 ("offset_in_exchange_list",
+ &current_offset),
+ GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms",
+ &ttd.h_contract_terms),
+ GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
+ &ttd.coin_pub),
+ TALER_PQ_RESULT_SPEC_AMOUNT ("exchange_deposit_value",
+ &ttd.coin_value),
+ TALER_PQ_RESULT_SPEC_AMOUNT ("exchange_deposit_fee",
+ &ttd.coin_fee),
+ GNUNET_PQ_result_spec_end
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result,
+ rs,
+ i))
+ {
+ GNUNET_break (0);
+ ltdc->qs = GNUNET_DB_STATUS_HARD_ERROR;
+ return;
+ }
+ ltdc->qs = i + 1;
+ ltdc->cb (ltdc->cb_cls,
+ (unsigned int) current_offset,
+ &ttd);
+ GNUNET_PQ_cleanup_result (rs);
+ }
+}
+
+
+/**
* Lookup transfer details.
*
* @param cls closure
- * @param instance_id instance to lookup payments for
* @param exchange_url the exchange that made the transfer
- * @param payto_uri account that received the transfer
* @param wtid wire transfer subject
- * @param total_amount amount that was transferred (in total, minus @a wire_fee)
- * @param wire_fee the wire fee the exchange charged
- * @param execution_time when the transfer was executed by the exchange
* @param cb function to call with detailed transfer data
* @param cb_cls closure for @a cb
* @return transaction status
@@ -3212,25 +3426,15 @@ lookup_transfer_details_cb (void *cls,
static enum GNUNET_DB_QueryStatus
postgres_lookup_transfer_details (
void *cls,
- const char *instance_id,
const char *exchange_url,
- const char *payto_uri,
const struct TALER_WireTransferIdentifierRawP *wtid,
- const struct TALER_Amount *total_amount,
- const struct TALER_Amount *wire_fee,
- struct GNUNET_TIME_Absolute execution_time,
TALER_MERCHANTDB_TransferDetailsCallback cb,
void *cb_cls)
{
struct PostgresClosure *pg = cls;
- struct TALER_Amount transfer_amount;
struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
GNUNET_PQ_query_param_string (exchange_url),
- GNUNET_PQ_query_param_string (payto_uri),
GNUNET_PQ_query_param_auto_from_type (wtid),
- TALER_PQ_query_param_amount (&transfer_amount),
- GNUNET_PQ_query_param_absolute_time (&execution_time),
GNUNET_PQ_query_param_end
};
struct LookupTransferDetailsContext ltdc = {
@@ -3240,14 +3444,6 @@ postgres_lookup_transfer_details (
};
enum GNUNET_DB_QueryStatus qs;
- if (0 >
- TALER_amount_subtract (&transfer_amount,
- total_amount,
- wire_fee))
- {
- GNUNET_break (0);
- return GNUNET_DB_STATUS_HARD_ERROR;
- }
check_connection (pg);
qs = GNUNET_PQ_eval_prepared_multi_select (
pg->conn,
@@ -5687,14 +5883,16 @@ libtaler_plugin_merchantdb_postgres_init (void *cls)
"INSERT INTO merchant_transfer_signatures"
"(credit_serial"
",signkey_serial"
+ ",wire_fee_val"
+ ",wire_fee_frac"
",execution_time"
",exchange_sig) "
- "SELECT $1, signkey_serial, $2, $3"
+ "SELECT $1, signkey_serial, $2, $3, $4, $5"
" FROM merchant_exchange_signing_keys"
- " WHERE exchange_pub=$4"
+ " WHERE exchange_pub=$6"
" ORDER BY start_date DESC"
" LIMIT 1",
- 4),
+ 6),
/* for postgres_insert_transfer_details() */
GNUNET_PQ_make_prepare ("insert_transfer_to_coin_mapping",
"INSERT INTO merchant_transfer_to_coin"
@@ -5755,8 +5953,30 @@ libtaler_plugin_merchantdb_postgres_init (void *cls)
" FROM merchant_instances"
" WHERE merchant_id=$1)",
3),
- /* for postgres_lookup_transfer_details() */
- GNUNET_PQ_make_prepare ("lookup_transfer_details",
+ /* for postgres_lookup_transfer() */
+ GNUNET_PQ_make_prepare ("lookup_transfer",
+ "SELECT"
+ " credit_amount_val"
+ ",credit_amount_frac"
+ ",wire_fee_val"
+ ",wire_fee_frac"
+ ",execution_time"
+ ",verified"
+ " FROM merchant_transfers"
+ " JOIN merchant_transfer_signatures USING (credit_serial)"
+ " JOIN merchant_accounts USING (account_serial)"
+ " WHERE wtid=$2"
+ " AND exchange_url=$1",
+ 2),
+ /* for postgres_set_transfer_status_to_verified() */
+ GNUNET_PQ_make_prepare ("set_transfer_status_to_verified",
+ "UPDATE merchant_transfers SET"
+ " verified=TRUE"
+ " WHERE wtid=$1"
+ " AND exchange_url=$2",
+ 2),
+ /* for postgres_lookup_transfer_summary() */
+ GNUNET_PQ_make_prepare ("lookup_transfer_summary",
"SELECT"
" order_id"
",exchange_deposit_value_val"
@@ -5764,22 +5984,29 @@ libtaler_plugin_merchantdb_postgres_init (void *cls)
",exchange_deposit_fee_val"
",exchange_deposit_fee_frac"
" FROM merchant_transfers"
- " JOIN merchant_accounts USING (account_serial)"
" JOIN merchant_transfer_to_coin USING (credit_serial)"
- " JOIN merchant_transfer_signatures USING (credit_serial)"
" JOIN merchant_deposits USING (deposit_serial)"
" JOIN merchant_contract_terms USING (order_serial)"
- " WHERE wtid=$4"
- " AND merchant_transfers.exchange_url=$2"
- " AND credit_amount_val=$5"
- " AND credit_amount_frac=$6"
- " AND payto_uri=$3"
- " AND execution_time=$7"
- " AND merchant_contract_terms.merchant_serial="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1)",
- 7),
+ " WHERE wtid=$2"
+ " AND merchant_transfers.exchange_url=$1",
+ 2),
+ /* for postgres_lookup_transfer_details() */
+ GNUNET_PQ_make_prepare ("lookup_transfer_details",
+ "SELECT"
+ " merchant_contract_terms.h_contract_terms"
+ ",merchant_transfer_to_coin.offset_in_exchange_list"
+ ",merchant_deposits.coin_pub"
+ ",exchange_deposit_value_val"
+ ",exchange_deposit_value_frac"
+ ",exchange_deposit_fee_val"
+ ",exchange_deposit_fee_frac"
+ " FROM merchant_transfer_to_coin"
+ " JOIN merchant_deposits USING (deposit_serial)"
+ " JOIN merchant_contract_terms USING (order_serial)"
+ " JOIN merchant_transfers USING (credit_serial)"
+ " WHERE merchant_transfers.wtid=$2"
+ " AND merchant_transfers.exchange_url=$1",
+ 2),
/* OLD API: */
#if 0
@@ -6101,6 +6328,10 @@ libtaler_plugin_merchantdb_postgres_init (void *cls)
plugin->lookup_wire_fee = &postgres_lookup_wire_fee;
plugin->lookup_deposits_by_contract_and_coin =
&postgres_lookup_deposits_by_contract_and_coin;
+ plugin->lookup_transfer = &postgres_lookup_transfer;
+ plugin->set_transfer_status_to_verified =
+ &postgres_set_transfer_status_to_verified;
+ plugin->lookup_transfer_summary = &postgres_lookup_transfer_summary;
plugin->lookup_transfer_details = &postgres_lookup_transfer_details;
/* OLD API: */
diff --git a/src/include/taler_merchantdb_plugin.h b/src/include/taler_merchantdb_plugin.h
index ec584bff..a9816a0f 100644
--- a/src/include/taler_merchantdb_plugin.h
+++ b/src/include/taler_merchantdb_plugin.h
@@ -403,13 +403,28 @@ enum TALER_MERCHANTDB_RefundStatus
* @param deposit_fee the fee charged for @a deposit_value
*/
typedef void
-(*TALER_MERCHANTDB_TransferDetailsCallback)(
+(*TALER_MERCHANTDB_TransferSummaryCallback)(
void *cls,
const char *order_id,
const struct TALER_Amount *deposit_value,
const struct TALER_Amount *deposit_fee);
+/**
+ * Function called with detailed information about a wire transfer and
+ * the underlying deposits that are being aggregated.
+ *
+ * @param cls closure
+ * @param current_offset offset in the exchange reply we are at
+ * @param ttd details about the transfer at @a current_offset
+ */
+typedef void
+(*TALER_MERCHANTDB_TransferDetailsCallback)(
+ void *cls,
+ unsigned int current_offset,
+ const struct TALER_TrackTransferDetails *ttd);
+
+
/* **************** OLD: ******************** */
/**
@@ -1328,16 +1343,76 @@ struct TALER_MERCHANTDB_Plugin
/**
- * Lookup transfer details.
+ * Lookup transfer status.
*
* @param cls closure
* @param instance_id instance to lookup payments for
- * @param exchange_url
- * @param payto_uri
- * @param wtid
- * @param total_amount
- * @param wire_fee
- * @param execution_time
+ * @param exchange_url the exchange that made the transfer
+ * @param payto_uri account that received the transfer
+ * @param wtid wire transfer subject
+ * @param[out] total_amount amount that was transferred (in total, minus @a wire_fee)
+ * @param[out] wire_fee the wire fee the exchange charged
+ * @param[out] execution_time when the transfer was executed by the exchange
+ * @param[out] verified did we confirm the transfer was OK
+ * @return transaction status
+ */
+ enum GNUNET_DB_QueryStatus
+ (*lookup_transfer)(
+ void *cls,
+ const char *exchange_url,
+ const struct TALER_WireTransferIdentifierRawP *wtid,
+ struct TALER_Amount *total_amount,
+ struct TALER_Amount *wire_fee,
+ struct GNUNET_TIME_Absolute *execution_time,
+ bool *verified);
+
+
+ /**
+ * Set transfer status to verified.
+ *
+ * @param cls closure
+ * @param instance_id instance to lookup payments for
+ * @param exchange_url the exchange that made the transfer
+ * @param payto_uri account that received the transfer
+ * @param wtid wire transfer subject
+ * @return transaction status
+ */
+ enum GNUNET_DB_QueryStatus
+ (*set_transfer_status_to_verified)(
+ void *cls,
+ const char *exchange_url,
+ const struct TALER_WireTransferIdentifierRawP *wtid);
+
+
+ /**
+ * Lookup transfer summary (used if we already verified the details).
+ *
+ * @param cls closure
+ * @param instance_id instance to lookup payments for
+ * @param exchange_url the exchange that made the transfer
+ * @param payto_uri account that received the transfer
+ * @param wtid wire transfer subject
+ * @param cb function to call with detailed transfer data
+ * @param cb_cls closure for @a cb
+ * @return transaction status
+ */
+ enum GNUNET_DB_QueryStatus
+ (*lookup_transfer_summary)(
+ void *cls,
+ const char *exchange_url,
+ const struct TALER_WireTransferIdentifierRawP *wtid,
+ TALER_MERCHANTDB_TransferSummaryCallback cb,
+ void *cb_cls);
+
+
+ /**
+ * Lookup transfer details. Used if we still need to verify the details.
+ *
+ * @param cls closure
+ * @param instance_id instance to lookup payments for
+ * @param exchange_url the exchange that made the transfer
+ * @param payto_uri account that received the transfer
+ * @param wtid wire transfer subject
* @param cb function to call with detailed transfer data
* @param cb_cls closure for @a cb
* @return transaction status
@@ -1345,13 +1420,8 @@ struct TALER_MERCHANTDB_Plugin
enum GNUNET_DB_QueryStatus
(*lookup_transfer_details)(
void *cls,
- const char *instance_id,
const char *exchange_url,
- const char *payto_uri,
const struct TALER_WireTransferIdentifierRawP *wtid,
- const struct TALER_Amount *total_amount,
- const struct TALER_Amount *wire_fee,
- struct GNUNET_TIME_Absolute execution_time,
TALER_MERCHANTDB_TransferDetailsCallback cb,
void *cb_cls);