diff --git a/src/exchange/taler-exchange-httpd_responses.c b/src/exchange/taler-exchange-httpd_responses.c index 4d40303bd..89d557c7d 100644 --- a/src/exchange/taler-exchange-httpd_responses.c +++ b/src/exchange/taler-exchange-httpd_responses.c @@ -735,6 +735,71 @@ TEH_RESPONSE_compile_reserve_history ( } } break; + case TALER_EXCHANGEDB_RO_PURSE_MERGE: + { + const struct TALER_EXCHANGEDB_PurseMerge *merge = + pos->details.merge; + struct TALER_Amount amount; + + GNUNET_assert (0 >= + TALER_amount_subtract (&amount, + &merge->amount_with_fee, + &merge->purse_fee)); + if (0 != + json_array_append_new ( + json_history, + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("type", + "MERGE"), + GNUNET_JSON_pack_data_auto ("h_contract_terms", + &merge->h_contract_terms), + GNUNET_JSON_pack_data_auto ("merge_pub", + &merge->merge_pub), + GNUNET_JSON_pack_data_auto ("purse_sig", + &merge->purse_sig), + GNUNET_JSON_pack_data_auto ("purse_pub", + &merge->purse_pub), + GNUNET_JSON_pack_data_auto ("merge_sig", + &merge->merge_sig), + GNUNET_JSON_pack_data_auto ("reserve_sig", + &merge->reserve_sig), + GNUNET_JSON_pack_timestamp ("merge_timestamp", + merge->merge_timestamp), + TALER_JSON_pack_amount ("amount", + &amount), + TALER_JSON_pack_amount ("purse_fee", + &merge->purse_fee)))) + { + GNUNET_break (0); + json_decref (json_history); + return NULL; + } + } + break; + case TALER_EXCHANGEDB_RO_HISTORY_REQUEST: + { + const struct TALER_EXCHANGEDB_HistoryRequest *history = + pos->details.history; + + if (0 != + json_array_append_new ( + json_history, + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("type", + "HISTORY"), + GNUNET_JSON_pack_data_auto ("reserve_sig", + &history->reserve_sig), + GNUNET_JSON_pack_timestamp ("request_timestamp", + history->request_timestamp), + TALER_JSON_pack_amount ("history_fee", + &history->history_fee)))) + { + GNUNET_break (0); + json_decref (json_history); + return NULL; + } + } + break; } } diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c index 8f1828008..5ecbeb5ce 100644 --- a/src/exchangedb/plugin_exchangedb_postgres.c +++ b/src/exchangedb/plugin_exchangedb_postgres.c @@ -6186,8 +6186,56 @@ add_p2p_merge (void *cls, while (0 < num_results) { - // FIXME! - GNUNET_break (0); + struct TALER_EXCHANGEDB_PurseMerge *merge; + struct TALER_EXCHANGEDB_ReserveHistory *tail; + + merge = GNUNET_new (struct TALER_EXCHANGEDB_PurseMerge); + { + struct GNUNET_PQ_ResultSpec rs[] = { + TALER_PQ_RESULT_SPEC_AMOUNT ("purse_fee", + &merge->purse_fee), + TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee", + &merge->amount_with_fee), + GNUNET_PQ_result_spec_timestamp ("merge_timestamp", + &merge->merge_timestamp), + GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms", + &merge->h_contract_terms), + GNUNET_PQ_result_spec_auto_from_type ("merge_pub", + &merge->merge_pub), + GNUNET_PQ_result_spec_auto_from_type ("purse_sig", + &merge->purse_sig), + GNUNET_PQ_result_spec_auto_from_type ("purse_pub", + &merge->purse_pub), + GNUNET_PQ_result_spec_auto_from_type ("merge_sig", + &merge->merge_sig), + GNUNET_PQ_result_spec_auto_from_type ("reserve_sig", + &merge->reserve_sig), + GNUNET_PQ_result_spec_end + }; + + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, + rs, + --num_results)) + { + GNUNET_break (0); + GNUNET_free (merge); + rhc->status = GNUNET_SYSERR; + return; + } + } + GNUNET_assert (0 <= + TALER_amount_add (&rhc->balance_out, + &rhc->balance_out, + &merge->amount_with_fee)); + GNUNET_assert (0 <= + TALER_amount_subtract (&rhc->balance_out, + &rhc->balance_out, + &merge->purse_fee)); + merge->reserve_pub = *rhc->reserve_pub; + tail = append_rh (rhc); + tail->type = TALER_EXCHANGEDB_RO_PURSE_MERGE; + tail->details.merge = merge; } } @@ -6210,8 +6258,40 @@ add_history_requests (void *cls, while (0 < num_results) { - // FIXME! - GNUNET_break (0); + struct TALER_EXCHANGEDB_HistoryRequest *history; + struct TALER_EXCHANGEDB_ReserveHistory *tail; + + history = GNUNET_new (struct TALER_EXCHANGEDB_HistoryRequest); + { + struct GNUNET_PQ_ResultSpec rs[] = { + TALER_PQ_RESULT_SPEC_AMOUNT ("history_fee", + &history->history_fee), + GNUNET_PQ_result_spec_timestamp ("request_timestamp", + &history->request_timestamp), + GNUNET_PQ_result_spec_auto_from_type ("reserve_sig", + &history->reserve_sig), + GNUNET_PQ_result_spec_end + }; + + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, + rs, + --num_results)) + { + GNUNET_break (0); + GNUNET_free (history); + rhc->status = GNUNET_SYSERR; + return; + } + } + GNUNET_assert (0 <= + TALER_amount_subtract (&rhc->balance_out, + &rhc->balance_out, + &history->history_fee)); + history->reserve_pub = *rhc->reserve_pub; + tail = append_rh (rhc); + tail->type = TALER_EXCHANGEDB_RO_HISTORY_REQUEST; + tail->details.history = history; } } diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h index c615ca7c3..7b62c9098 100644 --- a/src/include/taler_exchange_service.h +++ b/src/include/taler_exchange_service.h @@ -1318,7 +1318,17 @@ enum TALER_EXCHANGE_ReserveTransactionType /** * Reserve closed operation. */ - TALER_EXCHANGE_RTT_CLOSE + TALER_EXCHANGE_RTT_CLOSE, + + /** + * Reserve history request. + */ + TALER_EXCHANGE_RTT_HISTORY, + + /** + * Reserve purese merge operation. + */ + TALER_EXCHANGE_RTT_MERGE }; @@ -1454,6 +1464,79 @@ struct TALER_EXCHANGE_ReserveHistoryEntry } close_details; + /** + * Information about a history operation of the reserve. + * @e type is #TALER_EXCHANGE_RTT_HISTORY. + */ + struct + { + + /** + * Fee paid for the request. + */ + struct TALER_Amount history_fee; + + /** + * When was the request made. + */ + struct GNUNET_TIME_Timestamp request_timestamp; + + /** + * Signature by the reserve approving the history request. + */ + struct TALER_ReserveSignatureP reserve_sig; + + } history_details; + + /** + * Information about a merge operation on the reserve. + * @e type is #TALER_EXCHANGE_RTT_MERGE. + */ + struct + { + + /** + * Fee paid for the purse. + */ + struct TALER_Amount purse_fee; + + /** + * Hash over the contract. + */ + struct TALER_PrivateContractHashP h_contract_terms; + + /** + * Merge capability key. + */ + struct TALER_PurseMergePublicKeyP merge_pub; + + /** + * Purse signature. + */ + struct TALER_PurseContractSignatureP purse_sig; + + /** + * Purse public key. + */ + struct TALER_PurseContractPublicKeyP purse_pub; + + /** + * Merge signature. + */ + struct TALER_PurseMergePublicKeyP merge_sig; + + /** + * Signature by the reserve approving the merge. + */ + struct TALER_ReserveSignatureP reserve_sig; + + /** + * When was the merge made. + */ + struct GNUNET_TIME_Timestamp merge_timestamp; + + } merge_details; + } details; }; diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h index 68faf34f9..8762b1928 100644 --- a/src/include/taler_exchangedb_plugin.h +++ b/src/include/taler_exchangedb_plugin.h @@ -983,6 +983,12 @@ struct TALER_EXCHANGEDB_RecoupRefreshListEntry */ struct TALER_EXCHANGEDB_PurseMerge { + + /** + * Public key of the reserve the coin was merged into. + */ + struct TALER_ReservePublicKeyP reserve_pub; + /** * Amount in the purse, with fees. */ @@ -1036,6 +1042,11 @@ struct TALER_EXCHANGEDB_PurseMerge */ struct TALER_EXCHANGEDB_HistoryRequest { + /** + * Public key of the reserve the history request was for. + */ + struct TALER_ReservePublicKeyP reserve_pub; + /** * Fee paid for the request. */ diff --git a/src/lib/exchange_api_common.c b/src/lib/exchange_api_common.c index 04f2a4df8..e3eb4caad 100644 --- a/src/lib/exchange_api_common.c +++ b/src/lib/exchange_api_common.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2015-2021 Taler Systems SA + Copyright (C) 2015-2022 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -26,6 +26,8 @@ #include "taler_signatures.h" +// FIXME: refactor, use switching table instead +// of long if-then-else-else-else list! enum GNUNET_GenericReturnValue TALER_EXCHANGE_parse_reserve_history ( struct TALER_EXCHANGE_Handle *exchange, @@ -340,6 +342,34 @@ TALER_EXCHANGE_parse_reserve_history ( } /* end type==CLOSING */ } + else if (0 == strcasecmp (type, + "MERGE")) + { + GNUNET_break (0); // FIXME: implement! + if (0 > + TALER_amount_add (total_in, + total_in, + &rh->amount)) + { + /* overflow in history already!? inconceivable! Bad exchange! */ + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + } + else if (0 == strcasecmp (type, + "HISTORY")) + { + GNUNET_break (0); // FIXME: implement! + if (0 > + TALER_amount_add (total_out, + total_out, + &amount)) + { + /* overflow in history already!? inconceivable! Bad exchange! */ + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + } else { /* unexpected 'type', protocol incompatibility, complain! */ @@ -369,6 +399,10 @@ TALER_EXCHANGE_free_reserve_history ( break; case TALER_EXCHANGE_RTT_CLOSE: break; + case TALER_EXCHANGE_RTT_HISTORY: + break; + case TALER_EXCHANGE_RTT_MERGE: + break; } } GNUNET_free (rhistory); diff --git a/src/lib/exchange_api_reserves_get.c b/src/lib/exchange_api_reserves_get.c index 4c2886e0b..d829b4593 100644 --- a/src/lib/exchange_api_reserves_get.c +++ b/src/lib/exchange_api_reserves_get.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014-2021 Taler Systems SA + Copyright (C) 2014-2022 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software