From bad572a01072609e96df2d9e1b2e933654fb183b Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sun, 19 Jun 2022 14:04:41 +0200 Subject: -add missing checkpointing logic --- src/auditor/taler-helper-auditor-coins.c | 13 ++ src/auditor/taler-helper-auditor-reserves.c | 195 ++++++++++++++++++++++++---- src/exchangedb/plugin_exchangedb_postgres.c | 88 +++++++++++-- src/include/taler_exchangedb_plugin.h | 36 +++++ src/lib/exchange_api_purse_merge.c | 48 +------ 5 files changed, 304 insertions(+), 76 deletions(-) diff --git a/src/auditor/taler-helper-auditor-coins.c b/src/auditor/taler-helper-auditor-coins.c index e33364844..8021b3982 100644 --- a/src/auditor/taler-helper-auditor-coins.c +++ b/src/auditor/taler-helper-auditor-coins.c @@ -2350,6 +2350,11 @@ check_denomination ( * @param cls closure * @param rowid unique serial ID for the deposit in our DB * @param deposit deposit details + * @param reserve_pub which reserve is the purse merged into, NULL if unknown + * @param flags purse flags + * @param auditor_balance purse balance (according to the + * auditor during auditing) + * @param purse_total target amount the purse should reach * @param denom_pub denomination public key of @a coin_pub * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop */ @@ -2358,6 +2363,10 @@ purse_deposit_cb ( void *cls, uint64_t rowid, const struct TALER_EXCHANGEDB_PurseDeposit *deposit, + const struct TALER_ReservePublicKeyP *reserve_pub, + enum TALER_WalletAccountMergeFlags flags, + const struct TALER_Amount *auditor_balance, + const struct TALER_Amount *purse_total, const struct TALER_DenominationPublicKey *denom_pub) { struct CoinContext *cc = cls; @@ -2366,6 +2375,10 @@ purse_deposit_cb ( const struct TALER_EXCHANGEDB_DenominationKeyInformation *issue; struct DenominationSummary *ds; + (void) flags; + (void) auditor_balance; + (void) purse_total; + (void) reserve_pub; GNUNET_assert (rowid >= ppc.last_purse_deposits_serial_id); ppc.last_purse_deposits_serial_id = rowid + 1; qs = TALER_ARL_get_denomination_info (denom_pub, diff --git a/src/auditor/taler-helper-auditor-reserves.c b/src/auditor/taler-helper-auditor-reserves.c index 49176dcfa..a3976bc9a 100644 --- a/src/auditor/taler-helper-auditor-reserves.c +++ b/src/auditor/taler-helper-auditor-reserves.c @@ -69,6 +69,11 @@ static json_t *denomination_key_validity_withdraw_inconsistencies; */ static json_t *report_reserve_balance_insufficient_inconsistencies; +/** + * Array of reports about purse balance insufficient inconsitencies. + */ +static json_t *report_purse_balance_insufficient_inconsistencies; + /** * Total amount reserves were charged beyond their balance. */ @@ -754,12 +759,13 @@ handle_recoup_by_reserve ( { rev = "revoked"; } - GNUNET_assert (GNUNET_OK == - GNUNET_CONTAINER_multihashmap_put (rc->revoked, - &coin->denom_pub_hash. - hash, - (void *) rev, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); + GNUNET_assert ( + GNUNET_OK == + GNUNET_CONTAINER_multihashmap_put ( + rc->revoked, + &coin->denom_pub_hash.hash, + (void *) rev, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); } } else @@ -1255,6 +1261,12 @@ verify_reserve_balance (void *cls, * @param cls closure * @param rowid unique serial ID for the deposit in our DB * @param deposit deposit details + * @param reserve_pub which reserve is the purse merged into, NULL if unknown + * @param auditor_balance balance of the purse calculated by auditor + * @param flags purse flags + * @param auditor_balance purse balance (according to the + * auditor during auditing) + * @param purse_total target amount the purse should reach * @param denom_pub denomination public key of @a coin_pub * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop */ @@ -1263,12 +1275,25 @@ handle_purse_deposits ( void *cls, uint64_t rowid, const struct TALER_EXCHANGEDB_PurseDeposit *deposit, + const struct TALER_ReservePublicKeyP *reserve_pub, + enum TALER_WalletAccountMergeFlags flags, + const struct TALER_Amount *auditor_balance, + const struct TALER_Amount *purse_total, const struct TALER_DenominationPublicKey *denom_pub) { + struct ReserveContext *rc = cls; const char *base_url = (NULL == deposit->exchange_base_url) ? TALER_ARL_exchange_url : deposit->exchange_base_url; + enum GNUNET_DB_QueryStatus qs; + struct TALER_Amount amount_minus_fee; + struct TALER_Amount new_balance; + struct ReserveSummary *rs; + + /* should be monotonically increasing */ + GNUNET_assert (rowid >= ppr.last_purse_deposits_serial_id); + ppr.last_purse_deposits_serial_id = rowid + 1; if (GNUNET_OK != TALER_wallet_purse_deposit_verify (base_url, @@ -1293,10 +1318,87 @@ handle_purse_deposits ( return GNUNET_OK; } - GNUNET_break (0); // FIXME - // FIXME: need flags + total deposited! - /* Credit purse value (if last op)! */ - return GNUNET_SYSERR; + { + const struct TALER_EXCHANGEDB_DenominationKeyInformation *issue; + enum GNUNET_DB_QueryStatus qs; + struct TALER_DenominationHashP h_denom_pub; + + qs = TALER_ARL_get_denomination_info (denom_pub, + &issue, + &h_denom_pub); + if (0 > qs) + { + GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); + if (GNUNET_DB_STATUS_HARD_ERROR == qs) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Hard database error trying to get denomination %s from database!\n", + TALER_B2S (denom_pub)); + rc->qs = qs; + return GNUNET_SYSERR; + } + if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) + { + report_row_inconsistency ("purse-deposit", + rowid, + "denomination key not found"); + if (TALER_ARL_do_abort ()) + return GNUNET_SYSERR; + return GNUNET_OK; + } + TALER_ARL_amount_subtract (&amount_minus_fee, + &deposit->amount, + &issue->fees.deposit); + } + + TALER_ARL_amount_add (&new_balance, + auditor_balance, + &amount_minus_fee); + qs = TALER_ARL_edb->set_purse_balance (TALER_ARL_edb->cls, + &deposit->purse_pub, + &new_balance); + GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs); + if (qs < 0) + { + GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); + GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs); + rc->qs = qs; + return GNUNET_SYSERR; + } + if (TALER_WAMF_MODE_CREATE_WITH_PURSE_FEE != + (flags & TALER_WAMF_MERGE_MODE_MASK)) + { + /* This just created the purse, actual credit to + the reserve will be done in handle_account_merged() */ + return GNUNET_OK; + } + if ( (NULL != deposit->exchange_base_url) && + (0 != strcmp (deposit->exchange_base_url, + TALER_ARL_exchange_url)) ) + { + /* credited reserve is at another exchange, do NOT credit here! */ + return GNUNET_OK; + } + + rs = setup_reserve (rc, + reserve_pub); + if (NULL == rs) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + if ( (-1 != TALER_amount_cmp (&new_balance, + purse_total)) && + (-1 == TALER_amount_cmp (auditor_balance, + purse_total)) ) + { + /* new balance at or above purse_total + (and previous balance was below); thus + credit reserve with purse value! */ + TALER_ARL_amount_add (&rs->total_in, + &rs->total_in, + purse_total); + } + return GNUNET_OK; } @@ -1307,6 +1409,15 @@ handle_purse_deposits ( * * @param cls closure * @param rowid unique serial ID for the deposit in our DB + * @param partner_base_url where is the reserve, NULL for this exchange + * @param amount total amount expected in the purse + * @param balance current balance in the purse (according to the auditor) + * @param flags purse flags + * @param merge_pub merge capability key + * @param reserve_pub reserve the merge affects + * @param merge_sig signature affirming the merge + * @param purse_pub purse key + * @param merge_timestamp when did the merge happen * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop */ static enum GNUNET_GenericReturnValue @@ -1315,6 +1426,7 @@ handle_purse_merged ( uint64_t rowid, const char *partner_base_url, const struct TALER_Amount *amount, + const struct TALER_Amount *balance, enum TALER_WalletAccountMergeFlags flags, const struct TALER_PurseMergePublicKeyP *merge_pub, const struct TALER_ReservePublicKeyP *reserve_pub, @@ -1326,6 +1438,9 @@ handle_purse_merged ( struct ReserveSummary *rs; char *reserve_url; + /* should be monotonically increasing */ + GNUNET_assert (rowid >= ppr.last_purse_merges_serial_id); + ppr.last_purse_merges_serial_id = rowid + 1; reserve_url = TALER_reserve_make_payto (NULL == partner_base_url ? TALER_ARL_exchange_url @@ -1376,10 +1491,34 @@ handle_purse_merged ( GNUNET_break (0); return GNUNET_SYSERR; } + if (-1 == TALER_amount_cmp (balance, + amount)) + { + struct TALER_Amount loss; + + TALER_ARL_amount_subtract (&loss, + amount, + balance); + /* illegal merge, balance is still below total purse value */ + TALER_ARL_report (report_purse_balance_insufficient_inconsistencies, + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("operation", + "merge-purse"), + GNUNET_JSON_pack_uint64 ("row", + rowid), + TALER_JSON_pack_amount ("loss", + &loss), + GNUNET_JSON_pack_data_auto ("purse_pub", + purse_pub))); + TALER_ARL_amount_add (&total_balance_insufficient_loss, + &total_balance_insufficient_loss, + &loss); + return GNUNET_OK; + } TALER_ARL_amount_add (&rs->total_in, &rs->total_in, amount); - // rs->a_expiration_date = FIXME: set to what?; + // rs->a_expiration_date = FIXME: do we care? If so, set to what (so that the auditor no longer complains about the reserve not being closed) return GNUNET_OK; } @@ -1411,6 +1550,9 @@ handle_account_merged ( struct ReserveContext *rc = cls; struct ReserveSummary *rs; + /* should be monotonically increasing */ + GNUNET_assert (rowid >= ppr.last_account_merges_serial_id); + ppr.last_account_merges_serial_id = rowid + 1; if (GNUNET_OK != TALER_wallet_account_merge_verify (merge_timestamp, purse_pub, @@ -1476,6 +1618,9 @@ handle_history_request ( struct ReserveContext *rc = cls; struct ReserveSummary *rs; + /* should be monotonically increasing */ + GNUNET_assert (rowid >= ppr.last_history_requests_serial_id); + ppr.last_history_requests_serial_id = rowid + 1; if (GNUNET_OK != TALER_wallet_reserve_history_verify (ts, history_fee, @@ -1616,17 +1761,6 @@ analyze_reserves (void *cls) GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); return qs; } - /* Credit purse value (if last op)! */ - qs = TALER_ARL_edb->select_purse_merges_above_serial_id ( - TALER_ARL_edb->cls, - ppr.last_purse_merges_serial_id, - &handle_purse_merged, - &rc); - if (qs < 0) - { - GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); - return qs; - } qs = TALER_ARL_edb->select_purse_deposits_above_serial_id ( TALER_ARL_edb->cls, ppr.last_purse_deposits_serial_id, @@ -1648,6 +1782,17 @@ analyze_reserves (void *cls) GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); return qs; } + /* Credit purse value (if last op)! */ + qs = TALER_ARL_edb->select_purse_merges_above_serial_id ( + TALER_ARL_edb->cls, + ppr.last_purse_merges_serial_id, + &handle_purse_merged, + &rc); + if (qs < 0) + { + GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); + return qs; + } /* Charge history fee! */ qs = TALER_ARL_edb->select_history_requests_above_serial_id ( TALER_ARL_edb->cls, @@ -1822,6 +1967,9 @@ run (void *cls, GNUNET_assert (NULL != (report_reserve_balance_insufficient_inconsistencies = json_array ())); + GNUNET_assert (NULL != + (report_purse_balance_insufficient_inconsistencies + = json_array ())); GNUNET_assert (NULL != (report_reserve_not_closed_inconsistencies = json_array ())); @@ -1842,6 +1990,9 @@ run (void *cls, GNUNET_JSON_pack_array_steal ( "reserve_balance_insufficient_inconsistencies", report_reserve_balance_insufficient_inconsistencies), + GNUNET_JSON_pack_array_steal ( + "purse_balance_insufficient_inconsistencies", + report_purse_balance_insufficient_inconsistencies), /* Tested in test-auditor.sh #3 */ TALER_JSON_pack_amount ("total_loss_balance_insufficient", &total_balance_insufficient_loss), diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c index 523ccff48..5177ff55e 100644 --- a/src/exchangedb/plugin_exchangedb_postgres.c +++ b/src/exchangedb/plugin_exchangedb_postgres.c @@ -904,6 +904,14 @@ prepare_statements (struct PostgresClosure *pg) " FROM exchange_do_purse_deposit" " ($1,$2,$3,$4,$5,$6,$7,$8);", 8), + /* Used in #postgres_update_aggregation_transient() */ + GNUNET_PQ_make_prepare ( + "set_purse_balance", + "UPDATE purse_requests" + " SET balance_val=$2" + " ,balance_frac=$3" + " WHERE purse_pub=$1;", + 3), /* used in #postgres_expire_purse() */ GNUNET_PQ_make_prepare ( "call_expire_purse", @@ -1503,19 +1511,27 @@ prepare_statements (struct PostgresClosure *pg) GNUNET_PQ_make_prepare ( "audit_get_purse_deposits_incr", "SELECT" - " amount_with_fee_val" - ",amount_with_fee_frac" - ",purse_pub" - ",coin_sig" + " pd.amount_with_fee_val" + ",pd.amount_with_fee_frac" + ",pr.amount_with_fee_val AS total_val" + ",pr.amount_with_fee_frac AS total_frac" + ",pr.balance_val" + ",pr.balance_frac" + ",pr.flags" + ",pd.purse_pub" + ",pd.coin_sig" ",partner_base_url" ",denom.denom_pub" + ",pm.reserve_pub" ",kc.coin_pub" ",kc.age_commitment_hash" - ",purse_deposit_serial_id" - " FROM purse_deposits" + ",pd.purse_deposit_serial_id" + " FROM purse_deposits pd" " LEFT JOIN partners USING (partner_serial_id)" - " JOIN known_coins kc USING (coin_pub)" - " JOIN denominations denom USING (denominations_serial)" + " LEFT JOIN purse_merges pm USING (purse_pub)" + " JOIN purse_requests pr USING (purse_pub)" + " JOIN known_coins kc USING (coin_pub)" + " JOIN denominations denom USING (denominations_serial)" " WHERE (" " (purse_deposit_serial_id>=$1)" " )" @@ -1554,6 +1570,8 @@ prepare_statements (struct PostgresClosure *pg) ",partner_base_url" ",pr.amount_with_fee_val" ",pr.amount_with_fee_frac" + ",pr.balance_val" + ",pr.balance_frac" ",pr.flags" ",pr.merge_pub" ",pm.reserve_pub" @@ -10532,21 +10550,36 @@ purse_deposit_serial_helper_cb (void *cls, }; struct TALER_DenominationPublicKey denom_pub; uint64_t rowid; + uint32_t flags32; + struct TALER_ReservePublicKeyP reserve_pub; + bool not_merged = false; + struct TALER_Amount purse_balance; + struct TALER_Amount purse_total; struct GNUNET_PQ_ResultSpec rs[] = { TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee", &deposit.amount), + TALER_PQ_RESULT_SPEC_AMOUNT ("balance", + &purse_balance), + TALER_PQ_RESULT_SPEC_AMOUNT ("total", + &purse_total), TALER_PQ_RESULT_SPEC_AMOUNT ("deposit_fee", &deposit.deposit_fee), GNUNET_PQ_result_spec_allow_null ( GNUNET_PQ_result_spec_string ("partner_base_url", &deposit.exchange_base_url), NULL), + GNUNET_PQ_result_spec_allow_null ( + GNUNET_PQ_result_spec_auto_from_type ("reserve_pub", + &reserve_pub), + ¬_merged), TALER_PQ_result_spec_denom_pub ("denom_pub", &denom_pub), GNUNET_PQ_result_spec_auto_from_type ("purse_pub", &deposit.purse_pub), GNUNET_PQ_result_spec_auto_from_type ("coin_sig", &deposit.coin_sig), + GNUNET_PQ_result_spec_uint32 ("flags", + &flags32), GNUNET_PQ_result_spec_auto_from_type ("coin_pub", &deposit.coin_pub), GNUNET_PQ_result_spec_allow_null ( @@ -10574,6 +10607,10 @@ purse_deposit_serial_helper_cb (void *cls, ret = dsc->cb (dsc->cb_cls, rowid, &deposit, + not_merged ? NULL : &reserve_pub, + (enum TALER_WalletAccountMergeFlags) flags32, + &purse_balance, + &purse_total, &denom_pub); GNUNET_PQ_cleanup_result (rs); if (GNUNET_OK != ret) @@ -10827,6 +10864,7 @@ purse_merges_serial_helper_cb (void *cls, uint64_t rowid; char *partner_base_url = NULL; struct TALER_Amount amount; + struct TALER_Amount balance; uint32_t flags32; enum TALER_WalletAccountMergeFlags flags; struct TALER_PurseMergePublicKeyP merge_pub; @@ -10837,6 +10875,8 @@ purse_merges_serial_helper_cb (void *cls, struct GNUNET_PQ_ResultSpec rs[] = { TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee", &amount), + TALER_PQ_RESULT_SPEC_AMOUNT ("balance", + &balance), GNUNET_PQ_result_spec_allow_null ( GNUNET_PQ_result_spec_string ("partner_base_url", &partner_base_url), @@ -10873,6 +10913,7 @@ purse_merges_serial_helper_cb (void *cls, rowid, partner_base_url, &amount, + &balance, flags, &merge_pub, &reserve_pub, @@ -15540,6 +15581,35 @@ postgres_do_purse_deposit ( } +/** + * Set the current @a balance in the purse + * identified by @a purse_pub. Used by the auditor + * to update the balance as calculated by the auditor. + * + * @param cls closure + * @param purse_pub public key of a purse + * @param balance new balance to store under the purse + * @return transaction status + */ +static enum GNUNET_DB_QueryStatus +postgres_set_purse_balance ( + void *cls, + const struct TALER_PurseContractPublicKeyP *purse_pub, + const struct TALER_Amount *balance) +{ + struct PostgresClosure *pg = cls; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (purse_pub), + TALER_PQ_query_param_amount (balance), + GNUNET_PQ_query_param_end + }; + + return GNUNET_PQ_eval_prepared_non_select (pg->conn, + "set_purse_balance", + params); +} + + /** * Function called to obtain a coin deposit data from * depositing the coin into a purse. @@ -16171,6 +16241,8 @@ libtaler_plugin_exchangedb_postgres_init (void *cls) = &postgres_select_purse_by_merge_pub; plugin->do_purse_deposit = &postgres_do_purse_deposit; + plugin->set_purse_balance + = &postgres_set_purse_balance; plugin->get_purse_deposit = &postgres_get_purse_deposit; plugin->do_purse_merge diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h index 5ef4e74ad..2c59d6785 100644 --- a/src/include/taler_exchangedb_plugin.h +++ b/src/include/taler_exchangedb_plugin.h @@ -1990,6 +1990,11 @@ typedef enum GNUNET_GenericReturnValue * @param cls closure * @param rowid unique serial ID for the deposit in our DB * @param deposit deposit details + * @param reserve_pub which reserve is the purse merged into, NULL if unknown + * @param flags purse flags + * @param auditor_balance purse balance (according to the + * auditor during auditing) + * @param purse_total target amount the purse should reach * @param denom_pub denomination public key of @a coin_pub * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop */ @@ -1998,6 +2003,10 @@ typedef enum GNUNET_GenericReturnValue void *cls, uint64_t rowid, const struct TALER_EXCHANGEDB_PurseDeposit *deposit, + const struct TALER_ReservePublicKeyP *reserve_pub, + enum TALER_WalletAccountMergeFlags flags, + const struct TALER_Amount *auditor_balance, + const struct TALER_Amount *purse_total, const struct TALER_DenominationPublicKey *denom_pub); @@ -2033,6 +2042,15 @@ typedef enum GNUNET_GenericReturnValue * * @param cls closure * @param rowid unique serial ID for the deposit in our DB + * @param partner_base_url where is the reserve, NULL for this exchange + * @param amount total amount expected in the purse + * @param balance current balance in the purse (according to the auditor) + * @param flags purse flags + * @param merge_pub merge capability key + * @param reserve_pub reserve the merge affects + * @param merge_sig signature affirming the merge + * @param purse_pub purse key + * @param merge_timestamp when did the merge happen * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop */ typedef enum GNUNET_GenericReturnValue @@ -2041,6 +2059,7 @@ typedef enum GNUNET_GenericReturnValue uint64_t rowid, const char *partner_base_url, const struct TALER_Amount *amount, + const struct TALER_Amount *balance, enum TALER_WalletAccountMergeFlags flags, const struct TALER_PurseMergePublicKeyP *merge_pub, const struct TALER_ReservePublicKeyP *reserve_pub, @@ -5290,6 +5309,23 @@ struct TALER_EXCHANGEDB_Plugin bool *conflict); + /** + * Set the current @a balance in the purse + * identified by @a purse_pub. Used by the auditor + * to update the balance as calculated by the auditor. + * + * @param cls closure + * @param purse_pub public key of a purse + * @param balance new balance to store under the purse + * @return transaction status + */ + enum GNUNET_DB_QueryStatus + (*set_purse_balance)( + void *cls, + const struct TALER_PurseContractPublicKeyP *purse_pub, + const struct TALER_Amount *balance); + + /** * Function called to obtain a coin deposit data from * depositing the coin into a purse. diff --git a/src/lib/exchange_api_purse_merge.c b/src/lib/exchange_api_purse_merge.c index 6b6c37519..abe6d8cf9 100644 --- a/src/lib/exchange_api_purse_merge.c +++ b/src/lib/exchange_api_purse_merge.c @@ -119,50 +119,6 @@ struct TALER_EXCHANGE_AccountMergeHandle }; -static char * -make_payto (const char *exchange_url, - const struct TALER_ReservePublicKeyP *reserve_pub) -{ - char pub_str[sizeof (*reserve_pub) * 2]; - char *end; - bool is_http; - char *reserve_url; - - end = GNUNET_STRINGS_data_to_string ( - reserve_pub, - sizeof (*reserve_pub), - pub_str, - sizeof (pub_str)); - *end = '\0'; - if (0 == strncmp (exchange_url, - "http://", - strlen ("http://"))) - { - is_http = true; - exchange_url = &exchange_url[strlen ("http://")]; - } - else if (0 == strncmp (exchange_url, - "https://", - strlen ("https://"))) - { - is_http = false; - exchange_url = &exchange_url[strlen ("https://")]; - } - else - { - GNUNET_break (0); - return NULL; - } - /* exchange_url includes trailing '/' */ - GNUNET_asprintf (&reserve_url, - "payto://%s/%s%s", - is_http ? "taler+http" : "taler", - exchange_url, - pub_str); - return reserve_url; -} - - /** * Function called when we're done processing the * HTTP /purse/$PID/merge request. @@ -379,8 +335,8 @@ TALER_EXCHANGE_account_merge ( "/purses/%s/merge", pub_str); } - reserve_url = make_payto (pch->provider_url, - &pch->reserve_pub); + reserve_url = TALER_reserve_make_payto (pch->provider_url, + &pch->reserve_pub); if (NULL == reserve_url) { GNUNET_break (0); -- cgit v1.2.3