diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h index 2abd6b2aa..6268f45ac 100644 --- a/src/include/taler_exchange_service.h +++ b/src/include/taler_exchange_service.h @@ -1505,7 +1505,7 @@ enum TALER_EXCHANGE_ReserveTransactionType /** * Reserve closed operation. */ - TALER_EXCHANGE_RTT_CLOSE, + TALER_EXCHANGE_RTT_CLOSING, /** * Reserve history request. @@ -1513,9 +1513,19 @@ enum TALER_EXCHANGE_ReserveTransactionType TALER_EXCHANGE_RTT_HISTORY, /** - * Reserve purese merge operation. + * Reserve purse merge operation. */ - TALER_EXCHANGE_RTT_MERGE + TALER_EXCHANGE_RTT_MERGE, + + /** + * Reserve open request operation. + */ + TALER_EXCHANGE_RTT_OPEN, + + /** + * Reserve close request operation. + */ + TALER_EXCHANGE_RTT_CLOSE }; @@ -1730,6 +1740,71 @@ struct TALER_EXCHANGE_ReserveHistoryEntry } merge_details; + /** + * Information about an open request operation on the reserve. + * @e type is #TALER_EXCHANGE_RTT_OPEN. + */ + struct + { + + /** + * Signature by the reserve approving the open. + */ + struct TALER_ReserveSignatureP reserve_sig; + + /** + * Amount to be paid from the reserve balance to open + * the reserve. + */ + struct TALER_Amount reserve_payment; + + /** + * When was the request created. + */ + struct GNUNET_TIME_Timestamp request_timestamp; + + /** + * For how long should the reserve be kept open. + * (Determines amount to be paid.) + */ + struct GNUNET_TIME_Timestamp reserve_expiration; + + /** + * How many open purses should be included with the + * open reserve? + * (Determines amount to be paid.) + */ + uint32_t purse_limit; + + } open_request; + + /** + * Information about an close request operation on the reserve. + * @e type is #TALER_EXCHANGE_RTT_CLOSE. + */ + struct + { + + /** + * Signature by the reserve approving the close. + */ + struct TALER_ReserveSignatureP reserve_sig; + + /** + * When was the request created. + */ + struct GNUNET_TIME_Timestamp request_timestamp; + + /** + * Hash of the payto://-URI of the target account + * for the closure, or all zeros for the reserve + * origin account. + */ + struct TALER_PaytoHashP target_account_h_payto; + + } close_request; + + } details; }; diff --git a/src/lib/exchange_api_common.c b/src/lib/exchange_api_common.c index 2cb379f8f..d758fc981 100644 --- a/src/lib/exchange_api_common.c +++ b/src/lib/exchange_api_common.c @@ -340,7 +340,7 @@ parse_closing (struct TALER_EXCHANGE_ReserveHistoryEntry *rh, GNUNET_JSON_spec_end () }; - rh->type = TALER_EXCHANGE_RTT_CLOSE; + rh->type = TALER_EXCHANGE_RTT_CLOSING; if (GNUNET_OK != GNUNET_JSON_parse (transaction, closing_spec, @@ -531,6 +531,120 @@ parse_history (struct TALER_EXCHANGE_ReserveHistoryEntry *rh, } +/** + * Parse "open" reserve open entry. + * + * @param[in,out] rh entry to parse + * @param uc our context + * @param transaction the transaction to parse + * @return #GNUNET_OK on success + */ +static enum GNUNET_GenericReturnValue +parse_open (struct TALER_EXCHANGE_ReserveHistoryEntry *rh, + struct HistoryParseContext *uc, + const json_t *transaction) +{ + struct GNUNET_JSON_Specification open_spec[] = { + GNUNET_JSON_spec_fixed_auto ("reserve_sig", + &rh->details.open_request.reserve_sig), + TALER_JSON_spec_amount_any ("open_payment", + &rh->details.open_request.reserve_payment), + GNUNET_JSON_spec_uint32 ("requested_min_purses", + &rh->details.open_request.purse_limit), + GNUNET_JSON_spec_timestamp ("request_timestamp", + &rh->details.open_request.request_timestamp), + GNUNET_JSON_spec_timestamp ("requested_expiration", + &rh->details.open_request.reserve_expiration), + GNUNET_JSON_spec_end () + }; + + rh->type = TALER_EXCHANGE_RTT_OPEN; + if (GNUNET_OK != + GNUNET_JSON_parse (transaction, + open_spec, + NULL, NULL)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (GNUNET_OK != + TALER_wallet_reserve_open_verify ( + &rh->amount, + rh->details.open_request.request_timestamp, + rh->details.open_request.reserve_expiration, + rh->details.open_request.purse_limit, + uc->reserve_pub, + &rh->details.open_request.reserve_sig)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (0 > + TALER_amount_add (uc->total_out, + uc->total_out, + &rh->amount)) + { + /* overflow in history already!? inconceivable! Bad exchange! */ + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** + * Parse "close" reserve close entry. + * + * @param[in,out] rh entry to parse + * @param uc our context + * @param transaction the transaction to parse + * @return #GNUNET_OK on success + */ +static enum GNUNET_GenericReturnValue +parse_close (struct TALER_EXCHANGE_ReserveHistoryEntry *rh, + struct HistoryParseContext *uc, + const json_t *transaction) +{ + struct GNUNET_JSON_Specification close_spec[] = { + GNUNET_JSON_spec_fixed_auto ("reserve_sig", + &rh->details.close_request.reserve_sig), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_fixed_auto ("h_payto", + &rh->details.close_request. + target_account_h_payto), + NULL), + GNUNET_JSON_spec_timestamp ("request_timestamp", + &rh->details.close_request.request_timestamp), + GNUNET_JSON_spec_end () + }; + + rh->type = TALER_EXCHANGE_RTT_CLOSE; + if (GNUNET_OK != + GNUNET_JSON_parse (transaction, + close_spec, + NULL, NULL)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + /* force amount to invalid */ + memset (&rh->amount, + 0, + sizeof (rh->amount)); + if (GNUNET_OK != + TALER_wallet_reserve_close_verify ( + rh->details.close_request.request_timestamp, + &rh->details.close_request.target_account_h_payto, + uc->reserve_pub, + &rh->details.close_request.reserve_sig)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + enum GNUNET_GenericReturnValue TALER_EXCHANGE_parse_reserve_history ( struct TALER_EXCHANGE_Handle *exchange, @@ -553,6 +667,8 @@ TALER_EXCHANGE_parse_reserve_history ( { "MERGE", &parse_merge }, { "CLOSING", &parse_closing }, { "HISTORY", &parse_history }, + { "OPEN", &parse_open }, + { "CLOSE", &parse_close }, { NULL, NULL } }; struct GNUNET_HashCode uuid[history_length]; @@ -651,12 +767,16 @@ TALER_EXCHANGE_free_reserve_history ( break; case TALER_EXCHANGE_RTT_RECOUP: break; - case TALER_EXCHANGE_RTT_CLOSE: + case TALER_EXCHANGE_RTT_CLOSING: break; case TALER_EXCHANGE_RTT_HISTORY: break; case TALER_EXCHANGE_RTT_MERGE: break; + case TALER_EXCHANGE_RTT_OPEN: + break; + case TALER_EXCHANGE_RTT_CLOSE: + break; } } GNUNET_free (rhistory); @@ -1253,6 +1373,8 @@ TALER_EXCHANGE_verify_coin_history ( { "RECOUP-REFRESH", &help_recoup_refresh }, { "OLD-COIN-RECOUP", &help_old_coin_recoup }, { "PURSE-DEPOSIT", &help_purse_deposit }, + // FIXME: PURSE-REFUND missing here! + // FIXME: RESERVE-DEPOSIT missing here! { NULL, NULL } }; struct CoinHistoryParseContext pc = { diff --git a/src/testing/testing_api_cmd_common.c b/src/testing/testing_api_cmd_common.c index 138e5502a..bb0eb3f04 100644 --- a/src/testing/testing_api_cmd_common.c +++ b/src/testing/testing_api_cmd_common.c @@ -70,7 +70,7 @@ TALER_TESTING_history_entry_cmp ( &h2->details.recoup_details.coin_pub)) ) return 0; return 1; - case TALER_EXCHANGE_RTT_CLOSE: + case TALER_EXCHANGE_RTT_CLOSING: /* testing_api_cmd_exec_closer doesn't set the receiver_account_details, exchange_sig, exchange_pub or wtid or timestamp so we cannot test for it here. but if the amount matches, @@ -130,6 +130,12 @@ TALER_TESTING_history_entry_cmp ( h2->details.merge_details.flags) ) return 0; return 1; + case TALER_EXCHANGE_RTT_OPEN: + // FIXME: verify response... + return 1; + case TALER_EXCHANGE_RTT_CLOSE: + // FIXME: verify response... + return 1; } GNUNET_assert (0); return 1; diff --git a/src/testing/testing_api_cmd_exec_closer.c b/src/testing/testing_api_cmd_exec_closer.c index 75eab2d9f..9ee436af0 100644 --- a/src/testing/testing_api_cmd_exec_closer.c +++ b/src/testing/testing_api_cmd_exec_closer.c @@ -221,11 +221,11 @@ TALER_TESTING_cmd_exec_closer (const char *label, /* expected amount includes fee, while our argument gives the amount _without_ the fee. So add the fee. */ GNUNET_assert (0 <= - TALER_amount_add (&as->reserve_history.amount, - &as->reserve_history.amount, - &as->reserve_history.details.close_details. - fee)); - as->reserve_history.type = TALER_EXCHANGE_RTT_CLOSE; + TALER_amount_add ( + &as->reserve_history.amount, + &as->reserve_history.amount, + &as->reserve_history.details.close_details.fee)); + as->reserve_history.type = TALER_EXCHANGE_RTT_CLOSING; } { struct TALER_TESTING_Command cmd = { diff --git a/src/util/wallet_signatures.c b/src/util/wallet_signatures.c index 1209bb699..192914394 100644 --- a/src/util/wallet_signatures.c +++ b/src/util/wallet_signatures.c @@ -1237,7 +1237,7 @@ TALER_wallet_account_merge_verify ( GNUNET_NETWORK_STRUCT_BEGIN /** - * Message signed by + * Message signed by reserve key. */ struct TALER_ReserveOpenPS { @@ -1404,7 +1404,7 @@ TALER_wallet_reserve_open_deposit_verify ( GNUNET_NETWORK_STRUCT_BEGIN /** - * Message signed by + * Message signed by reserve key. */ struct TALER_ReserveClosePS {