merchant

Merchant backend to process payments, run by merchants
Log | Files | Refs | Submodules | README | LICENSE

commit 0b502ddd4869022dcfe2816e30f7db2529ce1bed
parent 6bd6595a2efcf1b3c895b0fe5c32e77b28b770e2
Author: Christian Grothoff <christian@grothoff.org>
Date:   Fri, 10 Jun 2016 16:18:29 +0200

build /track/transaction response

Diffstat:
Msrc/backend/taler-merchant-httpd_responses.c | 46++++++++++++++++++++++++++++++++++++++++++++++
Msrc/backend/taler-merchant-httpd_responses.h | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/backend/taler-merchant-httpd_track-transaction.c | 176++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Msrc/lib/merchant_api_track_transaction.c | 2+-
Msrc/lib/test_merchant_api.c | 4+++-
5 files changed, 281 insertions(+), 8 deletions(-)

diff --git a/src/backend/taler-merchant-httpd_responses.c b/src/backend/taler-merchant-httpd_responses.c @@ -26,6 +26,7 @@ #include "taler-merchant-httpd.h" #include "taler-merchant-httpd_responses.h" #include <taler/taler_util.h> +#include <taler/taler_json_lib.h> #include <gnunet/gnunet_util_lib.h> @@ -362,4 +363,49 @@ TMH_RESPONSE_reply_arg_invalid (struct MHD_Connection *connection, "parameter", param_name); } + +/** + * Generate /track/transaction response. + * + * @param num_transfers how many wire transfers make up the transaction + * @param transfers data on each wire transfer + * @return MHD response object + */ +struct MHD_Response * +TMH_RESPONSE_make_track_transaction_ok (unsigned int num_transfers, + const struct TMH_TransactionWireTransfer *transfers) +{ + struct MHD_Response *ret; + unsigned int i; + json_t *j_transfers; + + j_transfers = json_array (); + for (i=0;i<num_transfers;i++) + { + const struct TMH_TransactionWireTransfer *transfer = &transfers[i]; + json_t *j_coins; + unsigned int j; + + j_coins = json_array (); + for (j=0;j<transfer->num_coins;j++) + { + const struct TMH_CoinWireTransfer *coin = &transfer->coins[j]; + + json_array_append_new (j_coins, + json_pack ("{s:o, s:o, s:o}", + "coin_pub", GNUNET_JSON_from_data_auto (&coin->coin_pub), + "amount_with_fee", TALER_JSON_from_amount (&coin->amount_with_fee), + "deposit_fee", TALER_JSON_from_amount (&coin->deposit_fee))); + } + json_array_append_new (j_transfers, + json_pack ("{s:o, s:o}", + "wtid", GNUNET_JSON_from_data_auto (&transfer->wtid), + "coins", j_coins)); + } + ret = TMH_RESPONSE_make_json (j_transfers); + json_decref (j_transfers); + return ret; +} + + /* end of taler-exchange-httpd_responses.c */ diff --git a/src/backend/taler-merchant-httpd_responses.h b/src/backend/taler-merchant-httpd_responses.h @@ -65,6 +65,67 @@ struct MHD_Response * TMH_RESPONSE_make_json_pack (const char *fmt, ...); +/** + * Information about a coin aggregated in a wire transfer for a + * /track/transaction response. + */ +struct TMH_CoinWireTransfer +{ + + /** + * Public key of the coin. + */ + struct TALER_CoinSpendPublicKeyP coin_pub; + + /** + * Value of the coin including deposit fee. + */ + struct TALER_Amount amount_with_fee; + + /** + * Deposit fee for the coin. + */ + struct TALER_Amount deposit_fee; + +}; + +/** + * Information about a wire transfer for a /track/transaction response. + */ +struct TMH_TransactionWireTransfer +{ + + /** + * Wire transfer identifier this struct is about. + */ + struct TALER_WireTransferIdentifierRawP wtid; + + /** + * Number of coins of the selected transaction that + * is covered by this wire transfer. + */ + unsigned int num_coins; + + /** + * Information about the coins of the selected transaction + * that are part of the wire transfer. + */ + struct TMH_CoinWireTransfer *coins; + +}; + + +/** + * Generate /track/transaction response. + * + * @param num_transfers how many wire transfers make up the transaction + * @param transfers data on each wire transfer + * @return MHD response object + */ +struct MHD_Response * +TMH_RESPONSE_make_track_transaction_ok (unsigned int num_transfers, + const struct TMH_TransactionWireTransfer *transfers); + /** * Function to call to handle the request by building a JSON diff --git a/src/backend/taler-merchant-httpd_track-transaction.c b/src/backend/taler-merchant-httpd_track-transaction.c @@ -80,6 +80,16 @@ struct TrackCoinContext struct TALER_WireTransferIdentifierRawP wtid; /** + * Value of the coin including deposit fee. + */ + struct TALER_Amount amount_with_fee; + + /** + * Deposit fee for the coin. + */ + struct TALER_Amount deposit_fee; + + /** * Have we obtained the WTID for this coin yet? */ int have_wtid; @@ -373,6 +383,21 @@ wire_deposits_cb (void *cls, /** + * Function called with information about a wire transfer identifier. + * We actually never expect this to be called. + * + * @param cls closure + * @param proof proof from exchange about what the wire transfer was for + */ +static void +proof_cb (void *cls, + const json_t *proof) +{ + GNUNET_break_op (0); +} + + +/** * Function called with detailed wire transfer data. * We were trying to find out in which wire transfer one of the * coins was involved in. Now we know. What we do now is first @@ -403,6 +428,19 @@ wtid_cb (void *cls, tcc->dwh = NULL; tctx->current_wtid = *wtid; + + if (GNUNET_YES == + db->find_proof_by_wtid (db->cls, + tctx->exchange_uri, + wtid, + &proof_cb, + NULL)) + { + GNUNET_break_op (0); + /* FIXME: report error: we got this WTID before, and the + transaction was NOT in the list. So exchange is lying to us! + (or our DB is internally inconsistent.) */ + } tctx->wdh = TALER_EXCHANGE_track_transfer (tctx->eh, wtid, &wire_deposits_cb, @@ -428,12 +466,98 @@ trace_coins (struct TrackTransactionContext *tctx) break; if (NULL == tcc) { -#if ALL_COINS_DONE_FIXME - generate_response (); - resume_track_transaction_with_response (tctx, - MHD_HTTP_OK, - response); -#endif + unsigned int num_wtid = 0; + + /* count how many disjoint wire transfer identifiers there are; + note that there should only usually be one, so while this + is worst-case O(n^2), in pracitce this is O(n) */ + for (tcc = tctx->tcc_head; NULL != tcc; tcc = tcc->next) + { + struct TrackCoinContext *tcc2; + int found = GNUNET_NO; + + for (tcc2 = tctx->tcc_head; tcc2 != tcc; tcc2 = tcc2->next) + { + if (0 == memcmp (&tcc->wtid, + &tcc2->wtid, + sizeof (struct TALER_WireTransferIdentifierRawP))) + { + found = GNUNET_YES; + break; + } + } + if (GNUNET_NO == found) + num_wtid++; + } + { + /* on-stack allocation is fine, as the number of coins and the + number of wire-transfers per-transaction is expected to be tiny. */ + struct MHD_Response *resp; + struct TMH_TransactionWireTransfer wts[num_wtid]; + unsigned int wtid_off; + + wtid_off = 0; + for (tcc = tctx->tcc_head; NULL != tcc; tcc = tcc->next) + { + struct TrackCoinContext *tcc2; + int found = GNUNET_NO; + + for (tcc2 = tctx->tcc_head; tcc2 != tcc; tcc2 = tcc2->next) + { + if (0 == memcmp (&tcc->wtid, + &tcc2->wtid, + sizeof (struct TALER_WireTransferIdentifierRawP))) + { + found = GNUNET_YES; + break; + } + } + if (GNUNET_NO == found) + { + unsigned int num_coins; + struct TMH_TransactionWireTransfer *wt; + + wt = &wts[wtid_off++]; + wt->wtid = tcc->wtid; + /* count number of coins with this wtid */ + num_coins = 0; + for (tcc2 = tctx->tcc_head; NULL != tcc2; tcc2 = tcc2->next) + { + if (0 == memcmp (&wt->wtid, + &tcc2->wtid, + sizeof (struct TALER_WireTransferIdentifierRawP))) + num_coins++; + } + /* initialize coins array */ + wt->num_coins = num_coins; + wt->coins = GNUNET_new_array (num_coins, + struct TMH_CoinWireTransfer); + num_coins = 0; + for (tcc2 = tctx->tcc_head; NULL != tcc2; tcc2 = tcc2->next) + { + if (0 == memcmp (&wt->wtid, + &tcc2->wtid, + sizeof (struct TALER_WireTransferIdentifierRawP))) + { + struct TMH_CoinWireTransfer *coin = &wt->coins[num_coins++]; + + coin->coin_pub = tcc2->coin_pub; + coin->amount_with_fee = tcc2->amount_with_fee; + coin->deposit_fee = tcc2->deposit_fee; + } + } + } /* GNUNET_NO == found */ + } /* for all tcc */ + GNUNET_assert (wtid_off == num_wtid); + + resp = TMH_RESPONSE_make_track_transaction_ok (num_wtid, + wts); + for (wtid_off=0;wtid_off < num_wtid; wtid_off++) + GNUNET_free (wts[wtid_off].coins); + resume_track_transaction_with_response (tctx, + MHD_HTTP_OK, + resp); + } /* end of scope for 'wts' and 'resp' */ return; } tcc->dwh = TALER_EXCHANGE_track_transaction (tctx->eh, @@ -527,6 +651,39 @@ transaction_cb (void *cls, /** + * Information about the wire transfer corresponding to + * a deposit operation. Note that it is in theory possible + * that we have a @a transaction_id and @a coin_pub in the + * result that do not match a deposit that we know about, + * for example because someone else deposited funds into + * our account. + * + * @param cls closure + * @param transaction_id ID of the contract + * @param coin_pub public key of the coin + * @param wtid identifier of the wire transfer in which the exchange + * send us the money for the coin deposit + * @param exchange_proof proof from exchange about what the deposit was for + * NULL if we have not asked for this signature + */ +static void +transfer_cb (void *cls, + uint64_t transaction_id, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_WireTransferIdentifierRawP *wtid, + const json_t *exchange_proof) +{ + struct TrackCoinContext *tcc = cls; + + GNUNET_break (0 == memcmp (coin_pub, + &tcc->coin_pub, + sizeof (struct TALER_CoinSpendPublicKeyP))); + tcc->wtid = *wtid; + tcc->have_wtid = GNUNET_YES; +} + + +/** * Function called with information about a coin that was deposited. * * @param cls closure @@ -550,9 +707,16 @@ coin_cb (void *cls, tcc = GNUNET_new (struct TrackCoinContext); tcc->tctx = tctx; tcc->coin_pub = *coin_pub; + tcc->amount_with_fee = *amount_with_fee; + tcc->deposit_fee = *deposit_fee; GNUNET_CONTAINER_DLL_insert (tctx->tcc_head, tctx->tcc_tail, tcc); + GNUNET_break (GNUNET_SYSERR != + db->find_transfers_by_id (db->cls, + transaction_id, + &transfer_cb, + tcc)); } diff --git a/src/lib/merchant_api_track_transaction.c b/src/lib/merchant_api_track_transaction.c @@ -154,7 +154,7 @@ TALER_MERCHANT_track_transaction (struct GNUNET_CURL_Context *ctx, tdo->cb = track_transaction_cb; tdo->cb_cls = track_transaction_cb_cls; GNUNET_asprintf (&tdo->url, - "%s/track/transaction?transaction=%llu", + "%s/track/transaction?id=%llu", backend_uri, (unsigned long long) transaction_id); eh = curl_easy_init (); diff --git a/src/lib/test_merchant_api.c b/src/lib/test_merchant_api.c @@ -1997,6 +1997,7 @@ run (void *cls) { .oc = OC_CHECK_BANK_TRANSFERS_EMPTY, .label = "check_bank_empty" }, +#if 0 /* Trace the WTID back to the original transaction */ { .oc = OC_TRACK_TRANSFER, .label = "track-transfer-1", @@ -2004,8 +2005,9 @@ run (void *cls) .details.track_transfer.check_bank_ref = "check_bank_transfer-499c", .details.track_transfer.expected_pay_ref = "deposit-simple" }, +#endif -#if 0 +#if 1 /* Trace transaction to WTID */ { .oc = OC_TRACK_TRANSACTION, .label = "track-transaction-1",