diff options
author | Christian Grothoff <christian@grothoff.org> | 2024-04-01 20:35:58 +0200 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2024-04-01 20:35:58 +0200 |
commit | 2e4727bfff65d52114ea8ae300836d71c05e342e (patch) | |
tree | 2353ef04abd358090f9a4aae2bb35429314e1da1 | |
parent | 7e5ab53a78beb172cba18005e2370904c653e3df (diff) |
implement protocol v19: consider refunds when returning transaction aggregation data
-rw-r--r-- | src/exchange/taler-exchange-httpd_config.h | 2 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_transfers_get.c | 146 | ||||
-rw-r--r-- | src/include/taler_crypto_lib.h | 10 | ||||
-rw-r--r-- | src/include/taler_exchangedb_plugin.h | 15 | ||||
-rw-r--r-- | src/lib/Makefile.am | 2 | ||||
-rw-r--r-- | src/lib/exchange_api_handle.c | 4 | ||||
-rw-r--r-- | src/lib/exchange_api_transfers_get.c | 22 |
7 files changed, 159 insertions, 42 deletions
diff --git a/src/exchange/taler-exchange-httpd_config.h b/src/exchange/taler-exchange-httpd_config.h index 40293e89a..640e3b6e9 100644 --- a/src/exchange/taler-exchange-httpd_config.h +++ b/src/exchange/taler-exchange-httpd_config.h @@ -41,7 +41,7 @@ * * Returned via both /config and /keys endpoints. */ -#define EXCHANGE_PROTOCOL_VERSION "18:1:1" +#define EXCHANGE_PROTOCOL_VERSION "19:0:2" /** diff --git a/src/exchange/taler-exchange-httpd_transfers_get.c b/src/exchange/taler-exchange-httpd_transfers_get.c index 2a6dc8776..18d96f955 100644 --- a/src/exchange/taler-exchange-httpd_transfers_get.c +++ b/src/exchange/taler-exchange-httpd_transfers_get.c @@ -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; }; @@ -120,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", @@ -248,6 +261,31 @@ struct WtidTransactionContext /** + * 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. * @@ -260,29 +298,96 @@ struct WtidTransactionContext * @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 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) +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; + 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; + 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' */ @@ -292,8 +397,8 @@ handle_deposit_data (void *cls, 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; @@ -317,8 +422,8 @@ handle_deposit_data (void *cls, } if (0 > TALER_amount_subtract (&delta, - deposit_value, - deposit_fee)) + &dval, + &dfee)) { GNUNET_break (0); ctx->is_valid = GNUNET_SYSERR; @@ -339,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, diff --git a/src/include/taler_crypto_lib.h b/src/include/taler_crypto_lib.h index e3ae829fd..b941316b5 100644 --- a/src/include/taler_crypto_lib.h +++ b/src/include/taler_crypto_lib.h @@ -1336,15 +1336,21 @@ struct TALER_TrackTransferDetails struct TALER_CoinSpendPublicKeyP coin_pub; /** - * Value of the deposit (including fee). + * Value of the deposit (including fee), after refunds. */ struct TALER_Amount coin_value; /** - * Fee charged by the exchange for the deposit. + * Fee charged by the exchange for the deposit, + * possibly reduced (or waived) due to refunds. */ struct TALER_Amount coin_fee; + /** + * Total amount of refunds applied to this coin. + */ + struct TALER_Amount refund_total; + }; diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h index 985664c43..2d5857677 100644 --- a/src/include/taler_exchangedb_plugin.h +++ b/src/include/taler_exchangedb_plugin.h @@ -4483,14 +4483,13 @@ struct TALER_EXCHANGEDB_Plugin * @return query result status */ enum GNUNET_DB_QueryStatus - (*select_refunds_by_coin)(void *cls, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - const struct - TALER_MerchantPublicKeyP *merchant_pub, - const struct - TALER_PrivateContractHashP *h_contract, - TALER_EXCHANGEDB_RefundCoinCallback cb, - void *cb_cls); + (*select_refunds_by_coin)( + void *cls, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_MerchantPublicKeyP *merchant_pub, + const struct TALER_PrivateContractHashP *h_contract, + TALER_EXCHANGEDB_RefundCoinCallback cb, + void *cb_cls); /** diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 256efd11d..30d7c744e 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -18,7 +18,7 @@ lib_LTLIBRARIES = \ libtalerexchange.la libtalerexchange_la_LDFLAGS = \ - -version-info 6:0:0 \ + -version-info 7:0:1 \ -no-undefined libtalerexchange_la_SOURCES = \ exchange_api_add_aml_decision.c \ diff --git a/src/lib/exchange_api_handle.c b/src/lib/exchange_api_handle.c index bce3f2876..fdadc8d2a 100644 --- a/src/lib/exchange_api_handle.c +++ b/src/lib/exchange_api_handle.c @@ -40,12 +40,12 @@ * Which version of the Taler protocol is implemented * by this library? Used to determine compatibility. */ -#define EXCHANGE_PROTOCOL_CURRENT 17 +#define EXCHANGE_PROTOCOL_CURRENT 19 /** * How many versions are we backwards compatible with? */ -#define EXCHANGE_PROTOCOL_AGE 0 +#define EXCHANGE_PROTOCOL_AGE 2 /** * Set to 1 for extra debug logging. diff --git a/src/lib/exchange_api_transfers_get.c b/src/lib/exchange_api_transfers_get.c index 14cf51ff9..c558fb42e 100644 --- a/src/lib/exchange_api_transfers_get.c +++ b/src/lib/exchange_api_transfers_get.c @@ -153,21 +153,27 @@ check_transfers_get_response_ok ( GNUNET_JSON_spec_fixed_auto ("h_contract_terms", &detail->h_contract_terms), GNUNET_JSON_spec_fixed_auto ("coin_pub", &detail->coin_pub), - TALER_JSON_spec_amount_any ("deposit_value", &detail->coin_value), - TALER_JSON_spec_amount_any ("deposit_fee", &detail->coin_fee), + TALER_JSON_spec_amount ("deposit_value", + total_expected.currency, + &detail->coin_value), + TALER_JSON_spec_amount ("deposit_fee", + total_expected.currency, + &detail->coin_fee), + GNUNET_JSON_spec_mark_optional ( + TALER_JSON_spec_amount ("refund_total", + total_expected.currency, + &detail->refund_total), + NULL), GNUNET_JSON_spec_end () }; + GNUNET_assert (GNUNET_OK == + TALER_amount_set_zero (td->total_amount.currency, + &detail->refund_total)); if ( (GNUNET_OK != GNUNET_JSON_parse (detail_j, spec_detail, NULL, NULL)) || - (GNUNET_OK != - TALER_amount_cmp_currency (&total_expected, - &detail->coin_value)) || - (GNUNET_OK != - TALER_amount_cmp_currency (&total_expected, - &detail->coin_fee)) || (0 > TALER_amount_add (&total_expected, &total_expected, |