diff options
Diffstat (limited to 'src/exchange/taler-exchange-httpd_transfers_get.c')
-rw-r--r-- | src/exchange/taler-exchange-httpd_transfers_get.c | 283 |
1 files changed, 190 insertions, 93 deletions
diff --git a/src/exchange/taler-exchange-httpd_transfers_get.c b/src/exchange/taler-exchange-httpd_transfers_get.c index abf0fdbc8..18d96f955 100644 --- a/src/exchange/taler-exchange-httpd_transfers_get.c +++ b/src/exchange/taler-exchange-httpd_transfers_get.c @@ -51,7 +51,7 @@ struct AggregatedDepositDetail /** * Hash of the contract terms. */ - struct GNUNET_HashCode h_contract_terms; + struct TALER_PrivateContractHashP h_contract_terms; /** * Coin's public key of the deposited coin. @@ -59,14 +59,20 @@ struct AggregatedDepositDetail struct TALER_CoinSpendPublicKeyP coin_pub; /** - * Total value of the coin in the deposit. + * Total value of the coin in the deposit (after + * refunds). */ struct TALER_Amount deposit_value; /** - * Fees charged by the exchange for the deposit of this coin. + * Fees charged by the exchange for the deposit of this coin (possibly after reduction due to refunds). */ struct TALER_Amount deposit_fee; + + /** + * Total amount refunded for this coin. + */ + struct TALER_Amount refund_total; }; @@ -77,7 +83,7 @@ struct AggregatedDepositDetail * @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 payto_uri 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 @@ -87,19 +93,18 @@ static MHD_RESULT reply_transfer_details (struct MHD_Connection *connection, const struct TALER_Amount *total, const struct TALER_MerchantPublicKeyP *merchant_pub, - const struct GNUNET_HashCode *h_wire, + const char *payto_uri, const struct TALER_Amount *wire_fee, - struct GNUNET_TIME_Absolute exec_time, + struct GNUNET_TIME_Timestamp exec_time, const struct AggregatedDepositDetail *wdd_head) { json_t *deposits; - struct TALER_WireDepositDetailP dd; struct GNUNET_HashContext *hash_context; - struct TALER_WireDepositDataPS wdp; + struct GNUNET_HashCode h_details; struct TALER_ExchangePublicKeyP pub; struct TALER_ExchangeSignatureP sig; + struct TALER_PaytoHashP h_payto; - GNUNET_TIME_round_abs (&exec_time); deposits = json_array (); GNUNET_assert (NULL != deposits); hash_context = GNUNET_CRYPTO_hash_context_start (); @@ -107,16 +112,12 @@ reply_transfer_details (struct MHD_Connection *connection, 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)); + TALER_exchange_online_wire_deposit_append (hash_context, + &wdd_pos->h_contract_terms, + exec_time, + &wdd_pos->coin_pub, + &wdd_pos->deposit_value, + &wdd_pos->deposit_fee); if (0 != json_array_append_new ( deposits, @@ -125,6 +126,13 @@ reply_transfer_details (struct MHD_Connection *connection, &wdd_pos->h_contract_terms), GNUNET_JSON_pack_data_auto ("coin_pub", &wdd_pos->coin_pub), + + GNUNET_JSON_pack_allow_null ( + TALER_JSON_pack_amount ("refund_total", + TALER_amount_is_zero ( + &wdd_pos->refund_total) + ? NULL + : &wdd_pos->refund_total)), TALER_JSON_pack_amount ("deposit_value", &wdd_pos->deposit_value), TALER_JSON_pack_amount ("deposit_fee", @@ -138,23 +146,21 @@ reply_transfer_details (struct MHD_Connection *connection, "json_array_append_new() failed"); } } - 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); + &h_details); { enum TALER_ErrorCode ec; if (TALER_EC_NONE != - (ec = TEH_keys_exchange_sign (&wdp, - &pub, - &sig))) + (ec = TALER_exchange_online_wire_deposit_sign ( + &TEH_keys_exchange_sign_, + total, + wire_fee, + merchant_pub, + payto_uri, + &h_details, + &pub, + &sig))) { json_decref (deposits); return TALER_MHD_reply_with_ec (connection, @@ -163,6 +169,8 @@ reply_transfer_details (struct MHD_Connection *connection, } } + TALER_payto_hash (payto_uri, + &h_payto); return TALER_MHD_REPLY_JSON_PACK ( connection, MHD_HTTP_OK, @@ -172,10 +180,10 @@ reply_transfer_details (struct MHD_Connection *connection, wire_fee), GNUNET_JSON_pack_data_auto ("merchant_pub", merchant_pub), - GNUNET_JSON_pack_data_auto ("h_wire", - h_wire), - GNUNET_JSON_pack_time_abs ("execution_time", - exec_time), + GNUNET_JSON_pack_data_auto ("h_payto", + &h_payto), + GNUNET_JSON_pack_timestamp ("execution_time", + exec_time), GNUNET_JSON_pack_array_steal ("deposits", deposits), GNUNET_JSON_pack_data_auto ("exchange_sig", @@ -211,20 +219,14 @@ struct WtidTransactionContext struct TALER_MerchantPublicKeyP merchant_pub; /** - * 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; - - /** - * Wire fee applicable at @e exec_time. + * Wire fees applicable at @e exec_time. */ - struct TALER_Amount wire_fee; + struct TALER_WireFeeSet fees; /** * Execution time of the wire transfer */ - struct GNUNET_TIME_Absolute exec_time; + struct GNUNET_TIME_Timestamp exec_time; /** * Head of DLL with deposit details for transfers GET response. @@ -237,9 +239,9 @@ struct WtidTransactionContext struct AggregatedDepositDetail *wdd_tail; /** - * Which method was used to wire the funds? + * Where were the funds wired? */ - char *wire_method; + char *payto_uri; /** * JSON array with details about the individual deposits. @@ -253,65 +255,150 @@ struct WtidTransactionContext * (as they should). Set to #GNUNET_SYSERR if we encountered an * internal error. */ - int is_valid; + enum GNUNET_GenericReturnValue is_valid; }; /** + * Callback that totals up the applicable refunds. + * + * @param cls a `struct TALER_Amount` where we keep the total + * @param amount_with_fee amount being refunded + */ +static enum GNUNET_GenericReturnValue +add_refunds (void *cls, + const struct TALER_Amount *amount_with_fee) + +{ + struct TALER_Amount *total = cls; + + if (0 > + TALER_amount_add (total, + total, + amount_with_fee)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** * Function called with the results of the lookup of the individual deposits * that were aggregated for the given wire transfer. * * @param cls our context for transmission * @param rowid which row in the DB is the information from (for diagnostics), ignored * @param merchant_pub public key of the merchant (should be same for all callbacks with the same @e cls) - * @param h_wire hash of wire transfer details of the merchant (should be same for all callbacks with the same @e cls) - * @param wire where the funds were sent + * @param account_payto_uri where the funds were sent + * @param h_payto hash over @a account_payto_uri as it is in the DB * @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 denom_pub denomination public key of the @a coin_pub (ignored) * @param coin_pub which public key was this payment about - * @param deposit_value amount contributed by this coin in total + * @param deposit_value amount contributed by this coin in total (including fee) * @param deposit_fee deposit fee charged by exchange for this coin */ static void -handle_deposit_data (void *cls, - uint64_t rowid, - const struct TALER_MerchantPublicKeyP *merchant_pub, - const struct GNUNET_HashCode *h_wire, - const json_t *wire, - struct GNUNET_TIME_Absolute exec_time, - const struct GNUNET_HashCode *h_contract_terms, - const struct TALER_DenominationPublicKey *denom_pub, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - const struct TALER_Amount *deposit_value, - const struct TALER_Amount *deposit_fee) +handle_deposit_data ( + void *cls, + uint64_t rowid, + const struct TALER_MerchantPublicKeyP *merchant_pub, + const char *account_payto_uri, + const struct TALER_PaytoHashP *h_payto, + struct GNUNET_TIME_Timestamp exec_time, + const struct TALER_PrivateContractHashP *h_contract_terms, + const struct TALER_DenominationPublicKey *denom_pub, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_Amount *deposit_value, + const struct TALER_Amount *deposit_fee) { struct WtidTransactionContext *ctx = cls; - char *wire_method; + struct TALER_Amount total_refunds; + struct TALER_Amount dval; + struct TALER_Amount dfee; + enum GNUNET_DB_QueryStatus qs; (void) rowid; (void) denom_pub; + (void) h_payto; if (GNUNET_SYSERR == ctx->is_valid) return; - if (NULL == (wire_method = TALER_JSON_wire_to_method (wire))) + GNUNET_assert (GNUNET_OK == + TALER_amount_set_zero (deposit_value->currency, + &total_refunds)); + qs = TEH_plugin->select_refunds_by_coin (TEH_plugin->cls, + coin_pub, + merchant_pub, + h_contract_terms, + &add_refunds, + &total_refunds); + if (qs < 0) { GNUNET_break (0); ctx->is_valid = GNUNET_SYSERR; return; } + if (1 == + TALER_amount_cmp (&total_refunds, + deposit_value)) + { + /* Refunds exceeded total deposit? not OK! */ + GNUNET_break (0); + ctx->is_valid = GNUNET_SYSERR; + return; + } + if (0 == + TALER_amount_cmp (&total_refunds, + deposit_value)) + { + /* total_refunds == deposit_value; + in this case, the total contributed to the + wire transfer is zero (as are fees) */ + GNUNET_assert (GNUNET_OK == + TALER_amount_set_zero (deposit_value->currency, + &dval)); + GNUNET_assert (GNUNET_OK == + TALER_amount_set_zero (deposit_value->currency, + &dfee)); + + } + else + { + /* Compute deposit value by subtracting refunds */ + GNUNET_assert (0 < + TALER_amount_subtract (&dval, + deposit_value, + &total_refunds)); + if (-1 == + TALER_amount_cmp (&dval, + deposit_fee)) + { + /* dval < deposit_fee, so after refunds less than + the deposit fee remains; reduce deposit fee to + the remaining value of the coin */ + dfee = dval; + } + else + { + /* Partial refund, deposit fee remains */ + dfee = *deposit_fee; + } + } + if (GNUNET_NO == ctx->is_valid) { /* First one we encounter, setup general information in 'ctx' */ ctx->merchant_pub = *merchant_pub; - ctx->h_wire = *h_wire; + ctx->payto_uri = GNUNET_strdup (account_payto_uri); ctx->exec_time = exec_time; - ctx->wire_method = wire_method; /* captures the reference */ ctx->is_valid = GNUNET_YES; if (0 > TALER_amount_subtract (&ctx->total, - deposit_value, - deposit_fee)) + &dval, + &dfee)) { GNUNET_break (0); ctx->is_valid = GNUNET_SYSERR; @@ -326,21 +413,17 @@ handle_deposit_data (void *cls, (it should, otherwise the deposits should not have been aggregated) */ if ( (0 != GNUNET_memcmp (&ctx->merchant_pub, merchant_pub)) || - (0 != strcmp (wire_method, - ctx->wire_method)) || - (0 != GNUNET_memcmp (&ctx->h_wire, - h_wire)) ) + (0 != strcmp (account_payto_uri, + ctx->payto_uri)) ) { GNUNET_break (0); ctx->is_valid = GNUNET_SYSERR; - GNUNET_free (wire_method); return; } - GNUNET_free (wire_method); if (0 > TALER_amount_subtract (&delta, - deposit_value, - deposit_fee)) + &dval, + &dfee)) { GNUNET_break (0); ctx->is_valid = GNUNET_SYSERR; @@ -361,8 +444,9 @@ handle_deposit_data (void *cls, struct AggregatedDepositDetail *wdd; wdd = GNUNET_new (struct AggregatedDepositDetail); - wdd->deposit_value = *deposit_value; - wdd->deposit_fee = *deposit_fee; + wdd->deposit_value = dval; + wdd->deposit_fee = dfee; + wdd->refund_total = total_refunds; wdd->h_contract_terms = *h_contract_terms; wdd->coin_pub = *coin_pub; GNUNET_CONTAINER_DLL_insert (ctx->wdd_head, @@ -389,8 +473,7 @@ free_ctx (struct WtidTransactionContext *ctx) wdd); GNUNET_free (wdd); } - GNUNET_free (ctx->wire_method); - ctx->wire_method = NULL; + GNUNET_free (ctx->payto_uri); } @@ -417,10 +500,9 @@ get_transfer_deposits (void *cls, { struct WtidTransactionContext *ctx = cls; enum GNUNET_DB_QueryStatus qs; - struct GNUNET_TIME_Absolute wire_fee_start_date; - struct GNUNET_TIME_Absolute wire_fee_end_date; + struct GNUNET_TIME_Timestamp wire_fee_start_date; + struct GNUNET_TIME_Timestamp wire_fee_end_date; struct TALER_MasterSignatureP wire_fee_master_sig; - struct TALER_Amount closing_fee; /* resetting to NULL/0 in case transaction was repeated after serialization failure */ @@ -458,14 +540,28 @@ get_transfer_deposits (void *cls, NULL); return GNUNET_DB_STATUS_HARD_ERROR; } - qs = TEH_plugin->get_wire_fee (TEH_plugin->cls, - ctx->wire_method, - ctx->exec_time, - &wire_fee_start_date, - &wire_fee_end_date, - &ctx->wire_fee, - &closing_fee, - &wire_fee_master_sig); + { + char *wire_method; + + wire_method = TALER_payto_get_method (ctx->payto_uri); + if (NULL == wire_method) + { + GNUNET_break (0); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_INVARIANT_FAILURE, + "payto:// without wire method encountered"); + return GNUNET_DB_STATUS_HARD_ERROR; + } + qs = TEH_plugin->get_wire_fee (TEH_plugin->cls, + wire_method, + ctx->exec_time, + &wire_fee_start_date, + &wire_fee_end_date, + &ctx->fees, + &wire_fee_master_sig); + GNUNET_free (wire_method); + } if (0 >= qs) { if ( (GNUNET_DB_STATUS_HARD_ERROR == qs) || @@ -482,7 +578,7 @@ get_transfer_deposits (void *cls, if (0 > TALER_amount_subtract (&ctx->total, &ctx->total, - &ctx->wire_fee)) + &ctx->fees.wire)) { GNUNET_break (0); *mhd_ret = TALER_MHD_reply_with_error (connection, @@ -520,6 +616,7 @@ TEH_handler_transfers_get (struct TEH_RequestContext *rc, if (GNUNET_OK != TEH_DB_run_transaction (rc->connection, "run transfers GET", + TEH_MT_REQUEST_OTHER, &mhd_ret, &get_transfer_deposits, &ctx)) @@ -530,8 +627,8 @@ TEH_handler_transfers_get (struct TEH_RequestContext *rc, mhd_ret = reply_transfer_details (rc->connection, &ctx.total, &ctx.merchant_pub, - &ctx.h_wire, - &ctx.wire_fee, + ctx.payto_uri, + &ctx.fees.wire, ctx.exec_time, ctx.wdd_head); free_ctx (&ctx); |