diff options
Diffstat (limited to 'src/exchange')
| -rw-r--r-- | src/exchange/taler-exchange-httpd_db.c | 413 | ||||
| -rw-r--r-- | src/exchange/taler-exchange-httpd_db.h | 55 | ||||
| -rw-r--r-- | src/exchange/taler-exchange-httpd_responses.c | 131 | ||||
| -rw-r--r-- | src/exchange/taler-exchange-httpd_responses.h | 84 | ||||
| -rw-r--r-- | src/exchange/taler-exchange-httpd_track_transaction.c | 204 | ||||
| -rw-r--r-- | src/exchange/taler-exchange-httpd_track_transfer.c | 379 | 
6 files changed, 583 insertions, 683 deletions
| diff --git a/src/exchange/taler-exchange-httpd_db.c b/src/exchange/taler-exchange-httpd_db.c index bfe2112c..bed2a7fb 100644 --- a/src/exchange/taler-exchange-httpd_db.c +++ b/src/exchange/taler-exchange-httpd_db.c @@ -1209,417 +1209,4 @@ TEH_DB_execute_admin_add_incoming (struct MHD_Connection *connection,  } -/** - * Closure for #handle_transaction_data. - */ -struct WtidTransactionContext -{ - -  /** -   * Total amount of the wire transfer, as calculated by -   * summing up the individual amounts. To be rounded down -   * to calculate the real transfer amount at the end. -   * Only valid if @e is_valid is #GNUNET_YES. -   */ -  struct TALER_Amount total; - -  /** -   * Public key of the merchant, only valid if @e is_valid -   * is #GNUNET_YES. -   */ -  struct TALER_MerchantPublicKeyP merchant_pub; - -  /** -   * Which method was used to wire the funds? -   */ -  char *wire_method; - -  /** -   * Hash of the wire details of the merchant (identical for all -   * deposits), only valid if @e is_valid is #GNUNET_YES. -   */ -  struct GNUNET_HashCode h_wire; - -  /** -   * Execution time of the wire transfer -   */ -  struct GNUNET_TIME_Absolute exec_time; - -  /** -   * Head of DLL with details for /wire/deposit response. -   */ -  struct TEH_TrackTransferDetail *wdd_head; - -  /** -   * Head of DLL with details for /wire/deposit response. -   */ -  struct TEH_TrackTransferDetail *wdd_tail; - -  /** -   * JSON array with details about the individual deposits. -   */ -  json_t *deposits; - -  /** -   * Initially #GNUNET_NO, if we found no deposits so far.  Set to -   * #GNUNET_YES if we got transaction data, and the database replies -   * remained consistent with respect to @e merchant_pub and @e h_wire -   * (as they should).  Set to #GNUNET_SYSERR if we encountered an -   * internal error. -   */ -  int is_valid; - -}; - - -/** - * Function called with the results of the lookup of the - * transaction data for the given wire transfer identifier. - * - * @param cls our context for transmission - * @param rowid which row in the DB is the information from (for diagnostics) - * @param merchant_pub public key of the merchant (should be same for all callbacks with the same @e cls) - * @param wire_method which wire plugin was used - * @param h_wire hash of wire transfer details of the merchant (should be same for all callbacks with the same @e cls) - * @param exec_time execution time of the wire transfer (should be same for all callbacks with the same @e cls) - * @param h_contract_terms which proposal was this payment about - * @param coin_pub which public key was this payment about - * @param deposit_value amount contributed by this coin in total - * @param deposit_fee deposit fee charged by exchange for this coin - */ -static void -handle_transaction_data (void *cls, -                         uint64_t rowid, -                         const struct TALER_MerchantPublicKeyP *merchant_pub, -                         const char *wire_method, -                         const struct GNUNET_HashCode *h_wire, -                         struct GNUNET_TIME_Absolute exec_time, -                         const struct GNUNET_HashCode *h_contract_terms, -                         const struct TALER_CoinSpendPublicKeyP *coin_pub, -                         const struct TALER_Amount *deposit_value, -                         const struct TALER_Amount *deposit_fee) -{ -  struct WtidTransactionContext *ctx = cls; -  struct TALER_Amount delta; -  struct TEH_TrackTransferDetail *wdd; - -  if (GNUNET_SYSERR == ctx->is_valid) -    return; -  if (GNUNET_NO == ctx->is_valid) -  { -    ctx->merchant_pub = *merchant_pub; -    ctx->h_wire = *h_wire; -    ctx->exec_time = exec_time; -    ctx->wire_method = GNUNET_strdup (wire_method); -    ctx->is_valid = GNUNET_YES; -    if (GNUNET_OK != -        TALER_amount_subtract (&ctx->total, -                               deposit_value, -                               deposit_fee)) -    { -      GNUNET_break (0); -      ctx->is_valid = GNUNET_SYSERR; -      return; -    } -  } -  else -  { -    if ( (0 != memcmp (&ctx->merchant_pub, -                       merchant_pub, -                       sizeof (struct TALER_MerchantPublicKeyP))) || -         (0 != strcmp (wire_method, -                       ctx->wire_method)) || -         (0 != memcmp (&ctx->h_wire, -                       h_wire, -                       sizeof (struct GNUNET_HashCode))) ) -    { -      GNUNET_break (0); -      ctx->is_valid = GNUNET_SYSERR; -      return; -    } -    if (GNUNET_OK != -        TALER_amount_subtract (&delta, -                               deposit_value, -                               deposit_fee)) -    { -      GNUNET_break (0); -      ctx->is_valid = GNUNET_SYSERR; -      return; -    } -    if (GNUNET_OK != -        TALER_amount_add (&ctx->total, -                          &ctx->total, -                          &delta)) -    { -      GNUNET_break (0); -      ctx->is_valid = GNUNET_SYSERR; -      return; -    } -  } -  wdd = GNUNET_new (struct TEH_TrackTransferDetail); -  wdd->deposit_value = *deposit_value; -  wdd->deposit_fee = *deposit_fee; -  wdd->h_contract_terms = *h_contract_terms; -  wdd->coin_pub = *coin_pub; -  GNUNET_CONTAINER_DLL_insert (ctx->wdd_head, -                               ctx->wdd_tail, -                               wdd); -} - - -/** - * Execute a "/track/transfer".  Returns the transaction information - * associated with the given wire transfer identifier. - * - * @param connection the MHD connection to handle - * @param wtid wire transfer identifier to resolve - * @return MHD result code - */ -int -TEH_DB_execute_track_transfer (struct MHD_Connection *connection, -                               const struct TALER_WireTransferIdentifierRawP *wtid) -{ -  int ret; -  struct WtidTransactionContext ctx; -  struct TALER_EXCHANGEDB_Session *session; -  struct TEH_TrackTransferDetail *wdd; -  struct GNUNET_TIME_Absolute wire_fee_start_date; -  struct GNUNET_TIME_Absolute wire_fee_end_date; -  struct TALER_Amount wire_fee; -  struct TALER_MasterSignatureP wire_fee_master_sig; - -  if (NULL == (session = TEH_plugin->get_session (TEH_plugin->cls))) -  { -    GNUNET_break (0); -    return TEH_RESPONSE_reply_internal_db_error (connection, -						 TALER_EC_DB_SETUP_FAILED); -  } -  ctx.is_valid = GNUNET_NO; -  ctx.wdd_head = NULL; -  ctx.wdd_tail = NULL; -  ctx.wire_method = NULL; -  ret = TEH_plugin->lookup_wire_transfer (TEH_plugin->cls, -                                          session, -                                          wtid, -                                          &handle_transaction_data, -                                          &ctx); -  if (GNUNET_SYSERR == ret) -  { -    GNUNET_break (0); -    ret = TEH_RESPONSE_reply_internal_db_error (connection, -						TALER_EC_TRACK_TRANSFER_DB_FETCH_FAILED); -    goto cleanup; -  } -  if (GNUNET_SYSERR == ctx.is_valid) -  { -    GNUNET_break (0); -    ret = TEH_RESPONSE_reply_internal_db_error (connection, -						TALER_EC_TRACK_TRANSFER_DB_INCONSISTENT); -    goto cleanup; -  } -  if (GNUNET_NO == ctx.is_valid) -  { -    ret = TEH_RESPONSE_reply_arg_unknown (connection, -					  TALER_EC_TRACK_TRANSFER_WTID_NOT_FOUND, -                                          "wtid"); -    goto cleanup; -  } -  if (GNUNET_OK != -      TEH_plugin->get_wire_fee (TEH_plugin->cls, -                                session, -                                ctx.wire_method, -                                ctx.exec_time, -                                &wire_fee_start_date, -                                &wire_fee_end_date, -                                &wire_fee, -                                &wire_fee_master_sig)) -  { -    GNUNET_break (0); -    ret = TEH_RESPONSE_reply_internal_db_error (connection, -						TALER_EC_TRACK_TRANSFER_WIRE_FEE_NOT_FOUND); -    goto cleanup; -  } -  if (GNUNET_OK != -      TALER_amount_subtract (&ctx.total, -                             &ctx.total, -                             &wire_fee)) -  { -    GNUNET_break (0); -    ret = TEH_RESPONSE_reply_internal_db_error (connection, -						TALER_EC_TRACK_TRANSFER_WIRE_FEE_INCONSISTENT); -    goto cleanup; -  } -  ret = TEH_RESPONSE_reply_track_transfer_details (connection, -                                                   &ctx.total, -                                                   &ctx.merchant_pub, -                                                   &ctx.h_wire, -                                                   &wire_fee, -                                                   ctx.exec_time, -                                                   ctx.wdd_head); - cleanup: -  while (NULL != (wdd = ctx.wdd_head)) -  { -    GNUNET_CONTAINER_DLL_remove (ctx.wdd_head, -                                 ctx.wdd_tail, -                                 wdd); -    GNUNET_free (wdd); -  } -  GNUNET_free_non_null (ctx.wire_method); -  return ret; -} - - -/** - * Closure for #handle_wtid_data. - */ -struct DepositWtidContext -{ - -  /** -   * Where should we send the reply? -   */ -  struct MHD_Connection *connection; - -  /** -   * Hash of the proposal data we are looking up. -   */ -  struct GNUNET_HashCode h_contract_terms; - -  /** -   * Hash of the wire transfer details we are looking up. -   */ -  struct GNUNET_HashCode h_wire; - -  /** -   * Public key we are looking up. -   */ -  struct TALER_CoinSpendPublicKeyP coin_pub; - -  /** -   * MHD result code to return. -   */ -  int res; -}; - - -/** - * Function called with the results of the lookup of the - * wire transfer identifier information. - * - * @param cls our context for transmission - * @param wtid raw wire transfer identifier, NULL - *         if the transaction was not yet done - * @param coin_contribution how much did the coin we asked about - *        contribute to the total transfer value? (deposit value including fee) - * @param coin_fee how much did the exchange charge for the deposit fee - * @param execution_time when was the transaction done, or - *         when we expect it to be done (if @a wtid was NULL); - *         #GNUNET_TIME_UNIT_FOREVER_ABS if the /deposit is unknown - *         to the exchange - */ -static void -handle_wtid_data (void *cls, -		  const struct TALER_WireTransferIdentifierRawP *wtid, -                  const struct TALER_Amount *coin_contribution, -                  const struct TALER_Amount *coin_fee, -		  struct GNUNET_TIME_Absolute execution_time) -{ -  struct DepositWtidContext *ctx = cls; -  struct TALER_Amount coin_delta; - -  if (NULL == wtid) -  { -    ctx->res = TEH_RESPONSE_reply_transfer_pending (ctx->connection, -                                                    execution_time); -  } -  else -  { -    if (GNUNET_SYSERR == -        TALER_amount_subtract (&coin_delta, -                               coin_contribution, -                               coin_fee)) -    { -      GNUNET_break (0); -      ctx->res = TEH_RESPONSE_reply_internal_db_error (ctx->connection, -						       TALER_EC_TRACK_TRANSACTION_DB_FEE_INCONSISTENT); -    } -    else -    { -      ctx->res = TEH_RESPONSE_reply_track_transaction (ctx->connection, -                                                       &ctx->h_contract_terms, -                                                       &ctx->h_wire, -                                                       &ctx->coin_pub, -                                                       &coin_delta, -                                                       wtid, -                                                       execution_time); -    } -  } -} - - -/** - * Execute a "/track/transaction".  Returns the transfer information - * associated with the given deposit. - * - * @param connection the MHD connection to handle - * @param h_contract_terms hash of the proposal data - * @param h_wire hash of the wire details - * @param coin_pub public key of the coin to link - * @param merchant_pub public key of the merchant - * @return MHD result code - */ -int -TEH_DB_execute_track_transaction (struct MHD_Connection *connection, -                                  const struct GNUNET_HashCode *h_contract_terms, -                                  const struct GNUNET_HashCode *h_wire, -                                  const struct TALER_CoinSpendPublicKeyP *coin_pub, -                                  const struct TALER_MerchantPublicKeyP *merchant_pub) -{ -  int ret; -  struct DepositWtidContext ctx; -  struct TALER_EXCHANGEDB_Session *session; - -  if (NULL == (session = TEH_plugin->get_session (TEH_plugin->cls))) -  { -    GNUNET_break (0); -    return TEH_RESPONSE_reply_internal_db_error (connection, -						 TALER_EC_DB_SETUP_FAILED); -  } -  ctx.connection = connection; -  ctx.h_contract_terms = *h_contract_terms; -  ctx.h_wire = *h_wire; -  ctx.coin_pub = *coin_pub; -  ctx.res = GNUNET_SYSERR; -  ret = TEH_plugin->wire_lookup_deposit_wtid (TEH_plugin->cls, -                                              session, -					      h_contract_terms, -					      h_wire, -					      coin_pub, -					      merchant_pub, -					      &handle_wtid_data, -					      &ctx); -  if (GNUNET_SYSERR == ret) -  { -    GNUNET_break (0); -    GNUNET_break (GNUNET_SYSERR == ctx.res); -    return TEH_RESPONSE_reply_internal_db_error (connection, -						 TALER_EC_TRACK_TRANSACTION_DB_FETCH_FAILED); -  } -  if (GNUNET_NO == ret) -  { -    GNUNET_break (GNUNET_SYSERR == ctx.res); -    return TEH_RESPONSE_reply_transaction_unknown (connection, -						   TALER_EC_TRACK_TRANSACTION_NOT_FOUND); -  } -  if (GNUNET_SYSERR == ctx.res) -  { -    GNUNET_break (0); -    return TEH_RESPONSE_reply_internal_error (connection, -					      TALER_EC_TRACK_TRANSACTION_WTID_RESOLUTION_ERROR, -                                              "bug resolving deposit wtid"); -  } -  return ctx.res; -} - -  /* end of taler-exchange-httpd_db.c */ diff --git a/src/exchange/taler-exchange-httpd_db.h b/src/exchange/taler-exchange-httpd_db.h index 5e2a27a3..662f034d 100644 --- a/src/exchange/taler-exchange-httpd_db.h +++ b/src/exchange/taler-exchange-httpd_db.h @@ -197,60 +197,5 @@ TEH_DB_execute_admin_add_incoming (struct MHD_Connection *connection,                                     const json_t *transfer_details); -/** - * Execute a "/track/transfer".  Returns the transaction information - * associated with the given wire transfer identifier. - * - * @param connection the MHD connection to handle - * @param wtid wire transfer identifier to resolve - * @return MHD result code - */ -int -TEH_DB_execute_track_transfer (struct MHD_Connection *connection, -                               const struct TALER_WireTransferIdentifierRawP *wtid); - - -/** - * Execute a "/track/transaction".  Returns the transfer information - * associated with the given deposit. - * - * @param connection the MHD connection to handle - * @param h_contract_terms hash of the contract - * @param h_wire hash of the wire details - * @param coin_pub public key of the coin to link - * @param merchant_pub public key of the merchant - * @return MHD result code - */ -int -TEH_DB_execute_track_transaction (struct MHD_Connection *connection, -                                  const struct GNUNET_HashCode *h_contract_terms, -                                  const struct GNUNET_HashCode *h_wire, -                                  const struct TALER_CoinSpendPublicKeyP *coin_pub, -                                  const struct TALER_MerchantPublicKeyP *merchant_pub); - - -/** - * Execute a "/payback".  The validity of the coin and signature have - * already been checked.  The database must now check that the coin is - * not (double) spent, and execute the transaction (record details, - * generate success or failure response). - * - * @param connection the MHD connection to handle - * @param coin information about the coin - * @param value how much are coins of the @a coin's denomination worth? - * @param h_blind blinded coin to use for the lookup - * @param coin_blind blinding factor used (for later verification by the auditor) - * @param coin_sig signature of the coin - * @return MHD result code - */ -int -TEH_DB_execute_payback (struct MHD_Connection *connection, -                        const struct TALER_CoinPublicInfo *coin, -                        const struct TALER_Amount *value, -                        const struct GNUNET_HashCode *h_blind, -                        const struct TALER_DenominationBlindingKeyP *coin_blind, -                        const struct TALER_CoinSpendSignatureP *coin_sig); - -  #endif  /* TALER_EXCHANGE_HTTPD_DB_H */ diff --git a/src/exchange/taler-exchange-httpd_responses.c b/src/exchange/taler-exchange-httpd_responses.c index 7dab61ed..286572fe 100644 --- a/src/exchange/taler-exchange-httpd_responses.c +++ b/src/exchange/taler-exchange-httpd_responses.c @@ -1163,135 +1163,4 @@ TEH_RESPONSE_reply_transfer_pending (struct MHD_Connection *connection,  } -/** - * A merchant asked for details about a deposit.  Provide - * them. Generates the 200 reply. - * - * @param connection connection to the client - * @param h_contract_terms hash of the contract - * @param h_wire hash of wire account details - * @param coin_pub public key of the coin - * @param coin_contribution how much did the coin we asked about - *        contribute to the total transfer value? (deposit value minus fee) - * @param wtid raw wire transfer identifier - * @param exec_time execution time of the wire transfer - * @return MHD result code - */ -int -TEH_RESPONSE_reply_track_transaction (struct MHD_Connection *connection, -                                      const struct GNUNET_HashCode *h_contract_terms, -                                      const struct GNUNET_HashCode *h_wire, -                                      const struct TALER_CoinSpendPublicKeyP *coin_pub, -                                      const struct TALER_Amount *coin_contribution, -                                      const struct TALER_WireTransferIdentifierRawP *wtid, -                                      struct GNUNET_TIME_Absolute exec_time) -{ -  struct TALER_ConfirmWirePS cw; -  struct TALER_ExchangePublicKeyP pub; -  struct TALER_ExchangeSignatureP sig; - -  cw.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE); -  cw.purpose.size = htonl (sizeof (struct TALER_ConfirmWirePS)); -  cw.h_wire = *h_wire; -  cw.h_contract_terms = *h_contract_terms; -  cw.wtid = *wtid; -  cw.coin_pub = *coin_pub; -  cw.execution_time = GNUNET_TIME_absolute_hton (exec_time); -  TALER_amount_hton (&cw.coin_contribution, -                     coin_contribution); -  TEH_KS_sign (&cw.purpose, -               &pub, -               &sig); -  return TEH_RESPONSE_reply_json_pack (connection, -                                       MHD_HTTP_OK, -                                       "{s:o, s:o, s:o, s:o, s:o}", -                                       "wtid", GNUNET_JSON_from_data_auto (wtid), -                                       "execution_time", GNUNET_JSON_from_time_abs (exec_time), -                                       "coin_contribution", TALER_JSON_from_amount (coin_contribution), -                                       "exchange_sig", GNUNET_JSON_from_data_auto (&sig), -                                       "exchange_pub", GNUNET_JSON_from_data_auto (&pub)); -} - - -/** - * A merchant asked for transaction details about a wire transfer. - * Provide them. Generates the 200 reply. - * - * @param connection connection to the client - * @param total total amount that was transferred - * @param merchant_pub public key of the merchant - * @param h_wire destination account - * @param wire_fee wire fee that was charged - * @param exec_time execution time of the wire transfer - * @param wdd_head linked list with details about the combined deposits - * @return MHD result code - */ -int -TEH_RESPONSE_reply_track_transfer_details (struct MHD_Connection *connection, -                                           const struct TALER_Amount *total, -                                           const struct TALER_MerchantPublicKeyP *merchant_pub, -                                           const struct GNUNET_HashCode *h_wire, -                                           const struct TALER_Amount *wire_fee, -                                           struct GNUNET_TIME_Absolute exec_time, -                                           const struct TEH_TrackTransferDetail *wdd_head) -{ -  const struct TEH_TrackTransferDetail *wdd_pos; -  json_t *deposits; -  struct TALER_WireDepositDetailP dd; -  struct GNUNET_HashContext *hash_context; -  struct TALER_WireDepositDataPS wdp; -  struct TALER_ExchangePublicKeyP pub; -  struct TALER_ExchangeSignatureP sig; - -  GNUNET_TIME_round_abs (&exec_time); -  deposits = json_array (); -  hash_context = GNUNET_CRYPTO_hash_context_start (); -  for (wdd_pos = wdd_head; NULL != wdd_pos; wdd_pos = wdd_pos->next) -  { -    dd.h_contract_terms = wdd_pos->h_contract_terms; -    dd.execution_time = GNUNET_TIME_absolute_hton (exec_time); -    dd.coin_pub = wdd_pos->coin_pub; -    TALER_amount_hton (&dd.deposit_value, -                       &wdd_pos->deposit_value); -    TALER_amount_hton (&dd.deposit_fee, -                       &wdd_pos->deposit_fee); -    GNUNET_CRYPTO_hash_context_read (hash_context, -                                     &dd, -                                     sizeof (struct TALER_WireDepositDetailP)); -    GNUNET_assert (0 == -                   json_array_append_new (deposits, -                                          json_pack ("{s:o, s:o, s:o, s:o}", -                                                     "h_contract_terms", GNUNET_JSON_from_data_auto (&wdd_pos->h_contract_terms), -                                                     "coin_pub", GNUNET_JSON_from_data_auto (&wdd_pos->coin_pub), -                                                     "deposit_value", TALER_JSON_from_amount (&wdd_pos->deposit_value), -                                                     "deposit_fee", TALER_JSON_from_amount (&wdd_pos->deposit_fee)))); -  } -  wdp.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE_DEPOSIT); -  wdp.purpose.size = htonl (sizeof (struct TALER_WireDepositDataPS)); -  TALER_amount_hton (&wdp.total, -                     total); -  TALER_amount_hton (&wdp.wire_fee, -                     wire_fee); -  wdp.merchant_pub = *merchant_pub; -  wdp.h_wire = *h_wire; -  GNUNET_CRYPTO_hash_context_finish (hash_context, -                                     &wdp.h_details); -  TEH_KS_sign (&wdp.purpose, -               &pub, -               &sig); -  return TEH_RESPONSE_reply_json_pack (connection, -                                       MHD_HTTP_OK, -                                       "{s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o}", -                                       "total", TALER_JSON_from_amount (total), -                                       "wire_fee", TALER_JSON_from_amount (wire_fee), -                                       "merchant_pub", GNUNET_JSON_from_data_auto (merchant_pub), -                                       "H_wire", GNUNET_JSON_from_data_auto (h_wire), -                                       "execution_time", GNUNET_JSON_from_time_abs (exec_time), -                                       "deposits", deposits, -                                       "exchange_sig", GNUNET_JSON_from_data_auto (&sig), -                                       "exchange_pub", GNUNET_JSON_from_data_auto (&pub)); -} - - -  /* end of taler-exchange-httpd_responses.c */ diff --git a/src/exchange/taler-exchange-httpd_responses.h b/src/exchange/taler-exchange-httpd_responses.h index 8a51d8d5..5a52be38 100644 --- a/src/exchange/taler-exchange-httpd_responses.h +++ b/src/exchange/taler-exchange-httpd_responses.h @@ -301,90 +301,6 @@ TEH_RESPONSE_reply_transfer_pending (struct MHD_Connection *connection,  /** - * A merchant asked for details about a deposit.  Provide - * them. Generates the 200 reply. - * - * @param connection connection to the client - * @param h_contract_terms hash of the proposal data - * @param h_wire hash of wire account details - * @param coin_pub public key of the coin - * @param coin_contribution contribution of this coin to the total amount transferred - * @param wtid raw wire transfer identifier - * @param exec_time execution time of the wire transfer - * @return MHD result code - */ -int -TEH_RESPONSE_reply_track_transaction (struct MHD_Connection *connection, -                                      const struct GNUNET_HashCode *h_contract_terms, -                                      const struct GNUNET_HashCode *h_wire, -                                      const struct TALER_CoinSpendPublicKeyP *coin_pub, -                                      const struct TALER_Amount *coin_contribution, -                                      const struct TALER_WireTransferIdentifierRawP *wtid, -                                      struct GNUNET_TIME_Absolute exec_time); - - -/** - * Detail for /wire/deposit response. - */ -struct TEH_TrackTransferDetail -{ - -  /** -   * We keep deposit details in a DLL. -   */ -  struct TEH_TrackTransferDetail *next; - -  /** -   * We keep deposit details in a DLL. -   */ -  struct TEH_TrackTransferDetail *prev; - -  /** -   * Hash of the proposal data. -   */ -  struct GNUNET_HashCode h_contract_terms; - -  /** -   * Coin's public key. -   */ -  struct TALER_CoinSpendPublicKeyP coin_pub; - -  /** -   * Total value of the coin. -   */ -  struct TALER_Amount deposit_value; - -  /** -   * Fees charged by the exchange for the deposit. -   */ -  struct TALER_Amount deposit_fee; -}; - - -/** - * A merchant asked for transaction details about a wire transfer. - * Provide them. Generates the 200 reply. - * - * @param connection connection to the client - * @param total total amount that was transferred - * @param merchant_pub public key of the merchant - * @param h_wire destination account - * @param wire_fee wire fee that was charged - * @param exec_time execution time of the wire transfer - * @param wdd_head linked list with details about the combined deposits - * @return MHD result code - */ -int -TEH_RESPONSE_reply_track_transfer_details (struct MHD_Connection *connection, -                                           const struct TALER_Amount *total, -                                           const struct TALER_MerchantPublicKeyP *merchant_pub, -                                           const struct GNUNET_HashCode *h_wire, -                                           const struct TALER_Amount *wire_fee, -                                           struct GNUNET_TIME_Absolute exec_time, -                                           const struct TEH_TrackTransferDetail *wdd_head); - - -/**   * Send a confirmation response to a "/refresh/melt" request.   *   * @param connection the connection to send the response to diff --git a/src/exchange/taler-exchange-httpd_track_transaction.c b/src/exchange/taler-exchange-httpd_track_transaction.c index 9b2aaeca..b617021e 100644 --- a/src/exchange/taler-exchange-httpd_track_transaction.c +++ b/src/exchange/taler-exchange-httpd_track_transaction.c @@ -25,11 +25,215 @@  #include <pthread.h>  #include "taler_signatures.h"  #include "taler-exchange-httpd_parsing.h" +#include "taler-exchange-httpd_keystate.h"  #include "taler-exchange-httpd_track_transaction.h"  #include "taler-exchange-httpd_responses.h"  /** + * A merchant asked for details about a deposit.  Provide + * them. Generates the 200 reply. + * + * @param connection connection to the client + * @param h_contract_terms hash of the contract + * @param h_wire hash of wire account details + * @param coin_pub public key of the coin + * @param coin_contribution how much did the coin we asked about + *        contribute to the total transfer value? (deposit value minus fee) + * @param wtid raw wire transfer identifier + * @param exec_time execution time of the wire transfer + * @return MHD result code + */ +int +TEH_RESPONSE_reply_track_transaction (struct MHD_Connection *connection, +                                      const struct GNUNET_HashCode *h_contract_terms, +                                      const struct GNUNET_HashCode *h_wire, +                                      const struct TALER_CoinSpendPublicKeyP *coin_pub, +                                      const struct TALER_Amount *coin_contribution, +                                      const struct TALER_WireTransferIdentifierRawP *wtid, +                                      struct GNUNET_TIME_Absolute exec_time) +{ +  struct TALER_ConfirmWirePS cw; +  struct TALER_ExchangePublicKeyP pub; +  struct TALER_ExchangeSignatureP sig; + +  cw.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE); +  cw.purpose.size = htonl (sizeof (struct TALER_ConfirmWirePS)); +  cw.h_wire = *h_wire; +  cw.h_contract_terms = *h_contract_terms; +  cw.wtid = *wtid; +  cw.coin_pub = *coin_pub; +  cw.execution_time = GNUNET_TIME_absolute_hton (exec_time); +  TALER_amount_hton (&cw.coin_contribution, +                     coin_contribution); +  TEH_KS_sign (&cw.purpose, +               &pub, +               &sig); +  return TEH_RESPONSE_reply_json_pack (connection, +                                       MHD_HTTP_OK, +                                       "{s:o, s:o, s:o, s:o, s:o}", +                                       "wtid", GNUNET_JSON_from_data_auto (wtid), +                                       "execution_time", GNUNET_JSON_from_time_abs (exec_time), +                                       "coin_contribution", TALER_JSON_from_amount (coin_contribution), +                                       "exchange_sig", GNUNET_JSON_from_data_auto (&sig), +                                       "exchange_pub", GNUNET_JSON_from_data_auto (&pub)); +} + + +/** + * Closure for #handle_wtid_data. + */ +struct DepositWtidContext +{ + +  /** +   * Where should we send the reply? +   */ +  struct MHD_Connection *connection; + +  /** +   * Hash of the proposal data we are looking up. +   */ +  struct GNUNET_HashCode h_contract_terms; + +  /** +   * Hash of the wire transfer details we are looking up. +   */ +  struct GNUNET_HashCode h_wire; + +  /** +   * Public key we are looking up. +   */ +  struct TALER_CoinSpendPublicKeyP coin_pub; + +  /** +   * MHD result code to return. +   */ +  int res; +}; + + +/** + * Function called with the results of the lookup of the + * wire transfer identifier information. + * + * @param cls our context for transmission + * @param wtid raw wire transfer identifier, NULL + *         if the transaction was not yet done + * @param coin_contribution how much did the coin we asked about + *        contribute to the total transfer value? (deposit value including fee) + * @param coin_fee how much did the exchange charge for the deposit fee + * @param execution_time when was the transaction done, or + *         when we expect it to be done (if @a wtid was NULL); + *         #GNUNET_TIME_UNIT_FOREVER_ABS if the /deposit is unknown + *         to the exchange + */ +static void +handle_wtid_data (void *cls, +		  const struct TALER_WireTransferIdentifierRawP *wtid, +                  const struct TALER_Amount *coin_contribution, +                  const struct TALER_Amount *coin_fee, +		  struct GNUNET_TIME_Absolute execution_time) +{ +  struct DepositWtidContext *ctx = cls; +  struct TALER_Amount coin_delta; + +  if (NULL == wtid) +  { +    ctx->res = TEH_RESPONSE_reply_transfer_pending (ctx->connection, +                                                    execution_time); +  } +  else +  { +    if (GNUNET_SYSERR == +        TALER_amount_subtract (&coin_delta, +                               coin_contribution, +                               coin_fee)) +    { +      GNUNET_break (0); +      ctx->res = TEH_RESPONSE_reply_internal_db_error (ctx->connection, +						       TALER_EC_TRACK_TRANSACTION_DB_FEE_INCONSISTENT); +    } +    else +    { +      ctx->res = TEH_RESPONSE_reply_track_transaction (ctx->connection, +                                                       &ctx->h_contract_terms, +                                                       &ctx->h_wire, +                                                       &ctx->coin_pub, +                                                       &coin_delta, +                                                       wtid, +                                                       execution_time); +    } +  } +} + + +/** + * Execute a "/track/transaction".  Returns the transfer information + * associated with the given deposit. + * + * @param connection the MHD connection to handle + * @param h_contract_terms hash of the proposal data + * @param h_wire hash of the wire details + * @param coin_pub public key of the coin to link + * @param merchant_pub public key of the merchant + * @return MHD result code + */ +int +TEH_DB_execute_track_transaction (struct MHD_Connection *connection, +                                  const struct GNUNET_HashCode *h_contract_terms, +                                  const struct GNUNET_HashCode *h_wire, +                                  const struct TALER_CoinSpendPublicKeyP *coin_pub, +                                  const struct TALER_MerchantPublicKeyP *merchant_pub) +{ +  int ret; +  struct DepositWtidContext ctx; +  struct TALER_EXCHANGEDB_Session *session; + +  if (NULL == (session = TEH_plugin->get_session (TEH_plugin->cls))) +  { +    GNUNET_break (0); +    return TEH_RESPONSE_reply_internal_db_error (connection, +						 TALER_EC_DB_SETUP_FAILED); +  } +  ctx.connection = connection; +  ctx.h_contract_terms = *h_contract_terms; +  ctx.h_wire = *h_wire; +  ctx.coin_pub = *coin_pub; +  ctx.res = GNUNET_SYSERR; +  ret = TEH_plugin->wire_lookup_deposit_wtid (TEH_plugin->cls, +                                              session, +					      h_contract_terms, +					      h_wire, +					      coin_pub, +					      merchant_pub, +					      &handle_wtid_data, +					      &ctx); +  if (GNUNET_SYSERR == ret) +  { +    GNUNET_break (0); +    GNUNET_break (GNUNET_SYSERR == ctx.res); +    return TEH_RESPONSE_reply_internal_db_error (connection, +						 TALER_EC_TRACK_TRANSACTION_DB_FETCH_FAILED); +  } +  if (GNUNET_NO == ret) +  { +    GNUNET_break (GNUNET_SYSERR == ctx.res); +    return TEH_RESPONSE_reply_transaction_unknown (connection, +						   TALER_EC_TRACK_TRANSACTION_NOT_FOUND); +  } +  if (GNUNET_SYSERR == ctx.res) +  { +    GNUNET_break (0); +    return TEH_RESPONSE_reply_internal_error (connection, +					      TALER_EC_TRACK_TRANSACTION_WTID_RESOLUTION_ERROR, +                                              "bug resolving deposit wtid"); +  } +  return ctx.res; +} + + +/**   * Check the merchant signature, and if it is valid,   * return the wire transfer identifier.   * diff --git a/src/exchange/taler-exchange-httpd_track_transfer.c b/src/exchange/taler-exchange-httpd_track_transfer.c index f54df282..1b9dd9fa 100644 --- a/src/exchange/taler-exchange-httpd_track_transfer.c +++ b/src/exchange/taler-exchange-httpd_track_transfer.c @@ -25,11 +25,390 @@  #include <pthread.h>  #include "taler_signatures.h"  #include "taler-exchange-httpd_parsing.h" +#include "taler-exchange-httpd_keystate.h"  #include "taler-exchange-httpd_track_transfer.h"  #include "taler-exchange-httpd_responses.h"  /** + * Detail for /wire/deposit response. + */ +struct TEH_TrackTransferDetail +{ + +  /** +   * We keep deposit details in a DLL. +   */ +  struct TEH_TrackTransferDetail *next; + +  /** +   * We keep deposit details in a DLL. +   */ +  struct TEH_TrackTransferDetail *prev; + +  /** +   * Hash of the proposal data. +   */ +  struct GNUNET_HashCode h_contract_terms; + +  /** +   * Coin's public key. +   */ +  struct TALER_CoinSpendPublicKeyP coin_pub; + +  /** +   * Total value of the coin. +   */ +  struct TALER_Amount deposit_value; + +  /** +   * Fees charged by the exchange for the deposit. +   */ +  struct TALER_Amount deposit_fee; +}; + + +/** + * A merchant asked for transaction details about a wire transfer. + * Provide them. Generates the 200 reply. + * + * @param connection connection to the client + * @param total total amount that was transferred + * @param merchant_pub public key of the merchant + * @param h_wire destination account + * @param wire_fee wire fee that was charged + * @param exec_time execution time of the wire transfer + * @param wdd_head linked list with details about the combined deposits + * @return MHD result code + */ +int +TEH_RESPONSE_reply_track_transfer_details (struct MHD_Connection *connection, +                                           const struct TALER_Amount *total, +                                           const struct TALER_MerchantPublicKeyP *merchant_pub, +                                           const struct GNUNET_HashCode *h_wire, +                                           const struct TALER_Amount *wire_fee, +                                           struct GNUNET_TIME_Absolute exec_time, +                                           const struct TEH_TrackTransferDetail *wdd_head) +{ +  const struct TEH_TrackTransferDetail *wdd_pos; +  json_t *deposits; +  struct TALER_WireDepositDetailP dd; +  struct GNUNET_HashContext *hash_context; +  struct TALER_WireDepositDataPS wdp; +  struct TALER_ExchangePublicKeyP pub; +  struct TALER_ExchangeSignatureP sig; + +  GNUNET_TIME_round_abs (&exec_time); +  deposits = json_array (); +  hash_context = GNUNET_CRYPTO_hash_context_start (); +  for (wdd_pos = wdd_head; NULL != wdd_pos; wdd_pos = wdd_pos->next) +  { +    dd.h_contract_terms = wdd_pos->h_contract_terms; +    dd.execution_time = GNUNET_TIME_absolute_hton (exec_time); +    dd.coin_pub = wdd_pos->coin_pub; +    TALER_amount_hton (&dd.deposit_value, +                       &wdd_pos->deposit_value); +    TALER_amount_hton (&dd.deposit_fee, +                       &wdd_pos->deposit_fee); +    GNUNET_CRYPTO_hash_context_read (hash_context, +                                     &dd, +                                     sizeof (struct TALER_WireDepositDetailP)); +    GNUNET_assert (0 == +                   json_array_append_new (deposits, +                                          json_pack ("{s:o, s:o, s:o, s:o}", +                                                     "h_contract_terms", GNUNET_JSON_from_data_auto (&wdd_pos->h_contract_terms), +                                                     "coin_pub", GNUNET_JSON_from_data_auto (&wdd_pos->coin_pub), +                                                     "deposit_value", TALER_JSON_from_amount (&wdd_pos->deposit_value), +                                                     "deposit_fee", TALER_JSON_from_amount (&wdd_pos->deposit_fee)))); +  } +  wdp.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE_DEPOSIT); +  wdp.purpose.size = htonl (sizeof (struct TALER_WireDepositDataPS)); +  TALER_amount_hton (&wdp.total, +                     total); +  TALER_amount_hton (&wdp.wire_fee, +                     wire_fee); +  wdp.merchant_pub = *merchant_pub; +  wdp.h_wire = *h_wire; +  GNUNET_CRYPTO_hash_context_finish (hash_context, +                                     &wdp.h_details); +  TEH_KS_sign (&wdp.purpose, +               &pub, +               &sig); +  return TEH_RESPONSE_reply_json_pack (connection, +                                       MHD_HTTP_OK, +                                       "{s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o}", +                                       "total", TALER_JSON_from_amount (total), +                                       "wire_fee", TALER_JSON_from_amount (wire_fee), +                                       "merchant_pub", GNUNET_JSON_from_data_auto (merchant_pub), +                                       "H_wire", GNUNET_JSON_from_data_auto (h_wire), +                                       "execution_time", GNUNET_JSON_from_time_abs (exec_time), +                                       "deposits", deposits, +                                       "exchange_sig", GNUNET_JSON_from_data_auto (&sig), +                                       "exchange_pub", GNUNET_JSON_from_data_auto (&pub)); +} + + +/** + * Closure for #handle_transaction_data. + */ +struct WtidTransactionContext +{ + +  /** +   * Total amount of the wire transfer, as calculated by +   * summing up the individual amounts. To be rounded down +   * to calculate the real transfer amount at the end. +   * Only valid if @e is_valid is #GNUNET_YES. +   */ +  struct TALER_Amount total; + +  /** +   * Public key of the merchant, only valid if @e is_valid +   * is #GNUNET_YES. +   */ +  struct TALER_MerchantPublicKeyP merchant_pub; + +  /** +   * Which method was used to wire the funds? +   */ +  char *wire_method; + +  /** +   * Hash of the wire details of the merchant (identical for all +   * deposits), only valid if @e is_valid is #GNUNET_YES. +   */ +  struct GNUNET_HashCode h_wire; + +  /** +   * Execution time of the wire transfer +   */ +  struct GNUNET_TIME_Absolute exec_time; + +  /** +   * Head of DLL with details for /wire/deposit response. +   */ +  struct TEH_TrackTransferDetail *wdd_head; + +  /** +   * Head of DLL with details for /wire/deposit response. +   */ +  struct TEH_TrackTransferDetail *wdd_tail; + +  /** +   * JSON array with details about the individual deposits. +   */ +  json_t *deposits; + +  /** +   * Initially #GNUNET_NO, if we found no deposits so far.  Set to +   * #GNUNET_YES if we got transaction data, and the database replies +   * remained consistent with respect to @e merchant_pub and @e h_wire +   * (as they should).  Set to #GNUNET_SYSERR if we encountered an +   * internal error. +   */ +  int is_valid; + +}; + + +/** + * Function called with the results of the lookup of the + * transaction data for the given wire transfer identifier. + * + * @param cls our context for transmission + * @param rowid which row in the DB is the information from (for diagnostics) + * @param merchant_pub public key of the merchant (should be same for all callbacks with the same @e cls) + * @param wire_method which wire plugin was used + * @param h_wire hash of wire transfer details of the merchant (should be same for all callbacks with the same @e cls) + * @param exec_time execution time of the wire transfer (should be same for all callbacks with the same @e cls) + * @param h_contract_terms which proposal was this payment about + * @param coin_pub which public key was this payment about + * @param deposit_value amount contributed by this coin in total + * @param deposit_fee deposit fee charged by exchange for this coin + */ +static void +handle_transaction_data (void *cls, +                         uint64_t rowid, +                         const struct TALER_MerchantPublicKeyP *merchant_pub, +                         const char *wire_method, +                         const struct GNUNET_HashCode *h_wire, +                         struct GNUNET_TIME_Absolute exec_time, +                         const struct GNUNET_HashCode *h_contract_terms, +                         const struct TALER_CoinSpendPublicKeyP *coin_pub, +                         const struct TALER_Amount *deposit_value, +                         const struct TALER_Amount *deposit_fee) +{ +  struct WtidTransactionContext *ctx = cls; +  struct TALER_Amount delta; +  struct TEH_TrackTransferDetail *wdd; + +  if (GNUNET_SYSERR == ctx->is_valid) +    return; +  if (GNUNET_NO == ctx->is_valid) +  { +    ctx->merchant_pub = *merchant_pub; +    ctx->h_wire = *h_wire; +    ctx->exec_time = exec_time; +    ctx->wire_method = GNUNET_strdup (wire_method); +    ctx->is_valid = GNUNET_YES; +    if (GNUNET_OK != +        TALER_amount_subtract (&ctx->total, +                               deposit_value, +                               deposit_fee)) +    { +      GNUNET_break (0); +      ctx->is_valid = GNUNET_SYSERR; +      return; +    } +  } +  else +  { +    if ( (0 != memcmp (&ctx->merchant_pub, +                       merchant_pub, +                       sizeof (struct TALER_MerchantPublicKeyP))) || +         (0 != strcmp (wire_method, +                       ctx->wire_method)) || +         (0 != memcmp (&ctx->h_wire, +                       h_wire, +                       sizeof (struct GNUNET_HashCode))) ) +    { +      GNUNET_break (0); +      ctx->is_valid = GNUNET_SYSERR; +      return; +    } +    if (GNUNET_OK != +        TALER_amount_subtract (&delta, +                               deposit_value, +                               deposit_fee)) +    { +      GNUNET_break (0); +      ctx->is_valid = GNUNET_SYSERR; +      return; +    } +    if (GNUNET_OK != +        TALER_amount_add (&ctx->total, +                          &ctx->total, +                          &delta)) +    { +      GNUNET_break (0); +      ctx->is_valid = GNUNET_SYSERR; +      return; +    } +  } +  wdd = GNUNET_new (struct TEH_TrackTransferDetail); +  wdd->deposit_value = *deposit_value; +  wdd->deposit_fee = *deposit_fee; +  wdd->h_contract_terms = *h_contract_terms; +  wdd->coin_pub = *coin_pub; +  GNUNET_CONTAINER_DLL_insert (ctx->wdd_head, +                               ctx->wdd_tail, +                               wdd); +} + + +/** + * Execute a "/track/transfer".  Returns the transaction information + * associated with the given wire transfer identifier. + * + * @param connection the MHD connection to handle + * @param wtid wire transfer identifier to resolve + * @return MHD result code + */ +int +TEH_DB_execute_track_transfer (struct MHD_Connection *connection, +                               const struct TALER_WireTransferIdentifierRawP *wtid) +{ +  int ret; +  struct WtidTransactionContext ctx; +  struct TALER_EXCHANGEDB_Session *session; +  struct TEH_TrackTransferDetail *wdd; +  struct GNUNET_TIME_Absolute wire_fee_start_date; +  struct GNUNET_TIME_Absolute wire_fee_end_date; +  struct TALER_Amount wire_fee; +  struct TALER_MasterSignatureP wire_fee_master_sig; + +  if (NULL == (session = TEH_plugin->get_session (TEH_plugin->cls))) +  { +    GNUNET_break (0); +    return TEH_RESPONSE_reply_internal_db_error (connection, +						 TALER_EC_DB_SETUP_FAILED); +  } +  ctx.is_valid = GNUNET_NO; +  ctx.wdd_head = NULL; +  ctx.wdd_tail = NULL; +  ctx.wire_method = NULL; +  ret = TEH_plugin->lookup_wire_transfer (TEH_plugin->cls, +                                          session, +                                          wtid, +                                          &handle_transaction_data, +                                          &ctx); +  if (GNUNET_SYSERR == ret) +  { +    GNUNET_break (0); +    ret = TEH_RESPONSE_reply_internal_db_error (connection, +						TALER_EC_TRACK_TRANSFER_DB_FETCH_FAILED); +    goto cleanup; +  } +  if (GNUNET_SYSERR == ctx.is_valid) +  { +    GNUNET_break (0); +    ret = TEH_RESPONSE_reply_internal_db_error (connection, +						TALER_EC_TRACK_TRANSFER_DB_INCONSISTENT); +    goto cleanup; +  } +  if (GNUNET_NO == ctx.is_valid) +  { +    ret = TEH_RESPONSE_reply_arg_unknown (connection, +					  TALER_EC_TRACK_TRANSFER_WTID_NOT_FOUND, +                                          "wtid"); +    goto cleanup; +  } +  if (GNUNET_OK != +      TEH_plugin->get_wire_fee (TEH_plugin->cls, +                                session, +                                ctx.wire_method, +                                ctx.exec_time, +                                &wire_fee_start_date, +                                &wire_fee_end_date, +                                &wire_fee, +                                &wire_fee_master_sig)) +  { +    GNUNET_break (0); +    ret = TEH_RESPONSE_reply_internal_db_error (connection, +						TALER_EC_TRACK_TRANSFER_WIRE_FEE_NOT_FOUND); +    goto cleanup; +  } +  if (GNUNET_OK != +      TALER_amount_subtract (&ctx.total, +                             &ctx.total, +                             &wire_fee)) +  { +    GNUNET_break (0); +    ret = TEH_RESPONSE_reply_internal_db_error (connection, +						TALER_EC_TRACK_TRANSFER_WIRE_FEE_INCONSISTENT); +    goto cleanup; +  } +  ret = TEH_RESPONSE_reply_track_transfer_details (connection, +                                                   &ctx.total, +                                                   &ctx.merchant_pub, +                                                   &ctx.h_wire, +                                                   &wire_fee, +                                                   ctx.exec_time, +                                                   ctx.wdd_head); + cleanup: +  while (NULL != (wdd = ctx.wdd_head)) +  { +    GNUNET_CONTAINER_DLL_remove (ctx.wdd_head, +                                 ctx.wdd_tail, +                                 wdd); +    GNUNET_free (wdd); +  } +  GNUNET_free_non_null (ctx.wire_method); +  return ret; +} + + +/**   * Handle a "/track/transfer" request.   *   * @param rh context of the handler | 
