diff --git a/src/exchange/taler-exchange-httpd.c b/src/exchange/taler-exchange-httpd.c index a45c9d2b4..34f93879a 100644 --- a/src/exchange/taler-exchange-httpd.c +++ b/src/exchange/taler-exchange-httpd.c @@ -388,10 +388,6 @@ handle_post_reserves (struct TEH_RequestContext *rc, .op = "open", .handler = &TEH_handler_reserves_open }, - { - .op = "attest", - .handler = &TEH_handler_reserves_attest - }, { .op = "close", .handler = &TEH_handler_reserves_close @@ -1054,27 +1050,6 @@ handle_post_auditors (struct TEH_RequestContext *rc, } -/** - * Handle a GET "/reserves/$RID/$XXX" request. - * - * @param rc request context - * @param args array of additional options (length: 1, just the reserve_pub) - * @return MHD result code - */ -static MHD_RESULT -handler_reserves_get3 (struct TEH_RequestContext *rc, - const char *const args[3]) -{ - if (0 == strcmp (args[2], - "attest")) - return TEH_handler_reserves_get_attest (rc, - args); - GNUNET_break_op (0); - return r404 (rc->connection, - "/reserves/$RID/*"); -} - - /** * Handle incoming HTTP request. * @@ -1188,18 +1163,24 @@ handle_mhd_request (void *cls, .handler.get = &TEH_handler_reserves_get, .nargs = 1 }, - { - .url = "reserves", - .method = MHD_HTTP_METHOD_GET, - .handler.get = &handler_reserves_get3, - .nargs = 3 - }, { .url = "reserves", .method = MHD_HTTP_METHOD_POST, .handler.post = &handle_post_reserves, .nargs = 2 }, + { + .url = "reserves-attest", + .method = MHD_HTTP_METHOD_GET, + .handler.get = &TEH_handler_reserves_get_attest, + .nargs = 1 + }, + { + .url = "reserves-attest", + .method = MHD_HTTP_METHOD_POST, + .handler.post = &TEH_handler_reserves_attest, + .nargs = 1 + }, /* coins */ { .url = "coins", @@ -1441,7 +1422,8 @@ handle_mhd_request (void *cls, continue; found = true; /* The URL is a match! What we now do depends on the method. */ - if (0 == strcasecmp (method, MHD_HTTP_METHOD_OPTIONS)) + if (0 == strcasecmp (method, + MHD_HTTP_METHOD_OPTIONS)) { GNUNET_async_scope_restore (&old_scope); return TALER_MHD_reply_cors_preflight (connection); diff --git a/src/exchange/taler-exchange-httpd_reserves_attest.c b/src/exchange/taler-exchange-httpd_reserves_attest.c index a740bb25a..f88f2c300 100644 --- a/src/exchange/taler-exchange-httpd_reserves_attest.c +++ b/src/exchange/taler-exchange-httpd_reserves_attest.c @@ -48,7 +48,7 @@ struct ReserveAttestContext /** * Public key of the reserve the inquiry is about. */ - const struct TALER_ReservePublicKeyP *reserve_pub; + struct TALER_ReservePublicKeyP reserve_pub; /** * Hash of the payto URI of this reserve. @@ -122,7 +122,7 @@ reply_reserve_attest_success (struct MHD_Connection *connection, &TEH_keys_exchange_sign_, now, rhc->etime, - rhc->reserve_pub, + &rhc->reserve_pub, rhc->json_attest, &exchange_pub, &exchange_sig); @@ -273,8 +273,8 @@ reserve_attest_transaction (void *cls, MHD_RESULT TEH_handler_reserves_attest (struct TEH_RequestContext *rc, - const struct TALER_ReservePublicKeyP *reserve_pub, - const json_t *root) + const json_t *root, + const char *const args[1]) { struct ReserveAttestContext rsc = { .etime = GNUNET_TIME_UNIT_FOREVER_TS @@ -291,7 +291,18 @@ TEH_handler_reserves_attest (struct TEH_RequestContext *rc, }; struct GNUNET_TIME_Timestamp now; - rsc.reserve_pub = reserve_pub; + if (GNUNET_OK != + GNUNET_STRINGS_string_to_data (args[0], + strlen (args[0]), + &rsc.reserve_pub, + sizeof (rsc.reserve_pub))) + { + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (rc->connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_RESERVE_PUB_MALFORMED, + args[0]); + } { enum GNUNET_GenericReturnValue res; @@ -324,7 +335,7 @@ TEH_handler_reserves_attest (struct TEH_RequestContext *rc, if (GNUNET_OK != TALER_wallet_reserve_attest_request_verify (rsc.timestamp, rsc.details, - reserve_pub, + &rsc.reserve_pub, &rsc.reserve_sig)) { GNUNET_break_op (0); @@ -338,7 +349,7 @@ TEH_handler_reserves_attest (struct TEH_RequestContext *rc, char *payto_uri; payto_uri = TALER_reserve_make_payto (TEH_base_url, - rsc.reserve_pub); + &rsc.reserve_pub); TALER_payto_hash (payto_uri, &rsc.h_payto); GNUNET_free (payto_uri); @@ -360,7 +371,7 @@ TEH_handler_reserves_attest (struct TEH_RequestContext *rc, return TALER_MHD_reply_with_error (rc->connection, MHD_HTTP_NOT_FOUND, TALER_EC_EXCHANGE_GENERIC_RESERVE_UNKNOWN, - NULL); + args[0]); } if (TALER_EC_NONE != rsc.ec) { diff --git a/src/exchange/taler-exchange-httpd_reserves_attest.h b/src/exchange/taler-exchange-httpd_reserves_attest.h index d5ec8fd70..66bbdf712 100644 --- a/src/exchange/taler-exchange-httpd_reserves_attest.h +++ b/src/exchange/taler-exchange-httpd_reserves_attest.h @@ -26,16 +26,16 @@ /** - * Handle a POST "/reserves/$RID/attest" request. + * Handle a POST "/reserves-attest/$RID" request. * * @param rc request context - * @param reserve_pub public key of the reserve * @param root uploaded body from the client + * @param args args[0] has public key of the reserve * @return MHD result code */ MHD_RESULT TEH_handler_reserves_attest (struct TEH_RequestContext *rc, - const struct TALER_ReservePublicKeyP *reserve_pub, - const json_t *root); + const json_t *root, + const char *const args[1]); #endif diff --git a/src/exchange/taler-exchange-httpd_reserves_open.c b/src/exchange/taler-exchange-httpd_reserves_open.c index 6ad2592f2..ced291d77 100644 --- a/src/exchange/taler-exchange-httpd_reserves_open.c +++ b/src/exchange/taler-exchange-httpd_reserves_open.c @@ -108,6 +108,7 @@ struct ReserveOpenContext * for the operation. */ bool no_funds; + }; @@ -122,6 +123,8 @@ static MHD_RESULT reply_reserve_open_success (struct MHD_Connection *connection, const struct ReserveOpenContext *rsc) { + struct GNUNET_TIME_Timestamp now; + struct GNUNET_TIME_Timestamp re; unsigned int status; status = MHD_HTTP_OK; @@ -129,11 +132,18 @@ reply_reserve_open_success (struct MHD_Connection *connection, <, rsc->desired_expiration)) status = MHD_HTTP_PAYMENT_REQUIRED; + now = GNUNET_TIME_timestamp_get (); + if (GNUNET_TIME_timestamp_cmp (rsc->reserve_expiration, + <, + now)) + re = now; + else + re = rsc->reserve_expiration; return TALER_MHD_REPLY_JSON_PACK ( connection, status, GNUNET_JSON_pack_timestamp ("reserve_expiration", - rsc->reserve_expiration), + re), TALER_JSON_pack_amount ("open_cost", &rsc->open_cost)); } @@ -234,7 +244,8 @@ reserve_open_transaction (void *cls, } GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Do reserve open\n"); + "Do reserve open with reserve payment of %s\n", + TALER_amount2s (&rsc->total)); qs = TEH_plugin->do_reserve_open (TEH_plugin->cls, /* inputs */ rsc->reserve_pub, diff --git a/src/exchangedb/common-0001.sql b/src/exchangedb/common-0001.sql index 21f531102..68d8643ed 100644 --- a/src/exchangedb/common-0001.sql +++ b/src/exchangedb/common-0001.sql @@ -460,8 +460,7 @@ BEGIN 'CREATE TABLE IF NOT EXISTS %I' '(reserve_open_deposit_uuid BIGINT GENERATED BY DEFAULT AS IDENTITY' -- UNIQUE / PRIMARY KEY' ',reserve_sig BYTEA NOT NULL CHECK (LENGTH(reserve_sig)=64)' - ',reserve_pub BYTEA NOT NULL CHECK (LENGTH(reserve_sig)=32)' - ',request_timestamp INT8 NOT NULL' + ',reserve_pub BYTEA NOT NULL CHECK (LENGTH(reserve_pub)=32)' ',coin_pub BYTEA NOT NULL CHECK (LENGTH(coin_pub)=32)' ',coin_sig BYTEA NOT NULL CHECK (LENGTH(coin_sig)=64)' ',contribution_val INT8 NOT NULL' @@ -482,7 +481,7 @@ BEGIN EXECUTE FORMAT ( 'CREATE INDEX IF NOT EXISTS ' || table_name || '_by_reserve ' 'ON ' || table_name || ' ' - '(reserve_pub,request_timestamp);' + '(reserve_pub);' ); END $$; diff --git a/src/exchangedb/exchange-0001-part.sql b/src/exchangedb/exchange-0001-part.sql index c9c3e2f04..48515a478 100644 --- a/src/exchangedb/exchange-0001-part.sql +++ b/src/exchangedb/exchange-0001-part.sql @@ -259,8 +259,8 @@ SELECT create_table_reserves_open_deposits(); COMMENT ON TABLE reserves_open_deposits IS 'coin contributions paying for a reserve to remain open'; -COMMENT ON COLUMN reserves_open_deposits.request_timestamp - IS 'Identifies the specific reserve open request being paid for.'; +COMMENT ON COLUMN reserves_open_deposits.reserve_pub + IS 'Identifies the specific reserve being paid for (possibly together with reserve_sig).'; CREATE TABLE IF NOT EXISTS reserves_open_deposits_default PARTITION OF reserves_open_deposits diff --git a/src/exchangedb/pg_insert_records_by_table.c b/src/exchangedb/pg_insert_records_by_table.c index f70cce225..90d389873 100644 --- a/src/exchangedb/pg_insert_records_by_table.c +++ b/src/exchangedb/pg_insert_records_by_table.c @@ -357,8 +357,6 @@ irbt_cb_table_reserves_open_requests (struct PostgresClosure *pg, { struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_uint64 (&td->serial), - GNUNET_PQ_query_param_timestamp ( - &td->details.reserves_open_requests.request_timestamp), GNUNET_PQ_query_param_timestamp ( &td->details.reserves_open_requests.expiration_date), GNUNET_PQ_query_param_auto_from_type ( @@ -402,8 +400,6 @@ irbt_cb_table_reserves_open_deposits ( { struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_uint64 (&td->serial), - GNUNET_PQ_query_param_timestamp ( - &td->details.reserves_open_deposits.request_timestamp), GNUNET_PQ_query_param_auto_from_type ( &td->details.reserves_open_deposits.coin_pub), GNUNET_PQ_query_param_auto_from_type ( @@ -421,13 +417,12 @@ irbt_cb_table_reserves_open_deposits ( "(reserve_open_deposit_uuid" ",reserve_sig" ",reserve_pub" - ",request_timestamp" ",coin_pub" ",coin_sig" ",contribution_val" ",contribution_frac" ") VALUES " - "($1, $2, $3, $4, $5, $6, $7, $8);"); + "($1, $2, $3, $4, $5, $6, $7);"); return GNUNET_PQ_eval_prepared_non_select (pg->conn, "insert_into_table_reserves_open_deposits", params); diff --git a/src/exchangedb/procedures.sql b/src/exchangedb/procedures.sql index 90fb7d321..912a37dbc 100644 --- a/src/exchangedb/procedures.sql +++ b/src/exchangedb/procedures.sql @@ -2119,7 +2119,6 @@ BEGIN INSERT INTO exchange.reserves_open_deposits (reserve_sig ,reserve_pub - ,request_timestamp ,coin_pub ,coin_sig ,contribution_val @@ -2128,7 +2127,6 @@ INSERT INTO exchange.reserves_open_deposits VALUES (in_reserve_sig ,in_reserve_pub - ,in_request_timestamp ,in_coin_pub ,in_coin_sig ,in_coin_total_val @@ -2237,8 +2235,9 @@ WHERE IF NOT FOUND THEN - -- FIXME: do we need to set a 'not found'? - RETURN; + -- FIXME: do we need to set a 'not found'? + RAISE NOTICE 'reserve not found'; + RETURN; END IF; -- Do not allow expiration time to start in the past already @@ -2272,9 +2271,10 @@ THEN my_purses_allowed = my_purses_allowed + (in_default_purse_limit * my_years_tmp); END IF; + -- Compute cost based on annual fees IF (my_years > 0) -THEN +THEN my_cost_val = my_years * in_open_fee_val; my_cost_tmp = my_years * in_open_fee_frac / 100000000; IF (CAST (my_cost_val + my_cost_tmp AS INT8) < my_cost_val) @@ -2282,8 +2282,9 @@ THEN out_open_cost_val=9223372036854775807; out_open_cost_frac=2147483647; out_final_expiration=my_expiration_date; - out_no_funds=true; - RETURN; + out_no_funds=FALSE; + RAISE NOTICE 'arithmetic issue computing amount'; + RETURN; END IF; my_cost_val = CAST (my_cost_val + my_cost_tmp AS INT8); my_cost_frac = my_years * in_open_fee_frac % 100000000; @@ -2297,6 +2298,7 @@ THEN out_open_cost_val = 0; out_open_cost_frac = 0; out_no_funds=FALSE; + RAISE NOTICE 'no change required'; RETURN; END IF; @@ -2305,10 +2307,22 @@ IF ( (in_total_paid_val < my_cost_val) OR ( (in_total_paid_val = my_cost_val) AND (in_total_paid_frac < my_cost_frac) ) ) THEN - out_final_expiration=my_reserve_expiration; out_open_cost_val = my_cost_val; out_open_cost_frac = my_cost_frac; - out_no_funds=TRUE; + out_no_funds=FALSE; + -- We must return a failure, which is indicated by + -- the expiration being below the desired expiration. + IF (my_reserve_expiration >= in_desired_expiration) + THEN + -- This case is relevant especially if the purse + -- count was to be increased and the payment was + -- insufficient to cover this for the full period. + RAISE NOTICE 'forcing low expiration time'; + out_final_expiration = 0; + ELSE + out_final_expiration = my_reserve_expiration; + END IF; + RAISE NOTICE 'amount paid too low'; RETURN; END IF; @@ -2329,11 +2343,12 @@ ELSE my_balance_val=0; my_balance_frac=my_balance_frac - in_reserve_payment_frac; ELSE - out_final_expiration=my_reserve_expiration; + out_final_expiration = my_reserve_expiration; out_open_cost_val = my_cost_val; out_open_cost_frac = my_cost_frac; out_no_funds=TRUE; - RETURN; + RAISE NOTICE 'reserve balance too low'; + RETURN; END IF; END IF; @@ -2341,12 +2356,12 @@ UPDATE reserves SET current_balance_val=my_balance_val ,current_balance_frac=my_balance_frac ,gc_date=my_reserve_expiration + in_reserve_gc_delay - ,expiration_date=my_reserve_expiration + ,expiration_date=my_expiration_date ,purses_allowed=my_purses_allowed WHERE reserve_pub=in_reserve_pub; -out_final_expiration=my_reserve_expiration; +out_final_expiration=my_expiration_date; out_open_cost_val = my_cost_val; out_open_cost_frac = my_cost_frac; out_no_funds=FALSE; diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h index 008909c31..06fa2479d 100644 --- a/src/include/taler_exchangedb_plugin.h +++ b/src/include/taler_exchangedb_plugin.h @@ -331,7 +331,6 @@ struct TALER_EXCHANGEDB_TableData struct { struct TALER_ReservePublicKeyP reserve_pub; - struct GNUNET_TIME_Timestamp request_timestamp; struct TALER_CoinSpendPublicKeyP coin_pub; struct TALER_CoinSpendSignatureP coin_sig; struct TALER_ReserveSignatureP reserve_sig; diff --git a/src/lib/exchange_api_reserves_attest.c b/src/lib/exchange_api_reserves_attest.c index a7a89a2ef..c1cf82761 100644 --- a/src/lib/exchange_api_reserves_attest.c +++ b/src/lib/exchange_api_reserves_attest.c @@ -16,7 +16,7 @@ */ /** * @file lib/exchange_api_reserves_attest.c - * @brief Implementation of the POST /reserves/$RESERVE_PUB/attest requests + * @brief Implementation of the POST /reserves-attest/$RESERVE_PUB requests * @author Christian Grothoff */ #include "platform.h" @@ -33,7 +33,7 @@ /** - * @brief A /reserves/$RID/attest Handle + * @brief A /reserves-attest/$RID Handle */ struct TALER_EXCHANGE_ReservesAttestHandle { @@ -141,7 +141,7 @@ handle_reserves_attest_ok (struct TALER_EXCHANGE_ReservesAttestHandle *rsh, /** * Function called when we're done processing the - * HTTP /reserves/$RID/attest request. + * HTTP /reserves-attest/$RID request. * * @param cls the `struct TALER_EXCHANGE_ReservesAttestHandle` * @param response_code HTTP response code, 0 on error @@ -280,7 +280,7 @@ TALER_EXCHANGE_reserves_attest ( *end = '\0'; GNUNET_snprintf (arg_str, sizeof (arg_str), - "/reserves/%s/attest", + "/reserves-attest/%s", pub_str); } rsh->url = TEAH_path_to_url (exchange, diff --git a/src/lib/exchange_api_reserves_get_attestable.c b/src/lib/exchange_api_reserves_get_attestable.c index 401418cd4..3a5fd25d8 100644 --- a/src/lib/exchange_api_reserves_get_attestable.c +++ b/src/lib/exchange_api_reserves_get_attestable.c @@ -133,7 +133,7 @@ handle_reserves_get_attestable_ok ( /** * Function called when we're done processing the - * HTTP GET /reserves/$RID/attest request. + * HTTP GET /reserves-attest/$RID request. * * @param cls the `struct TALER_EXCHANGE_ReservesGetAttestableHandle` * @param response_code HTTP response code, 0 on error @@ -241,7 +241,7 @@ TALER_EXCHANGE_reserves_get_attestable ( *end = '\0'; GNUNET_snprintf (arg_str, sizeof (arg_str), - "/reserves/%s/attest", + "/reserves-attest/%s", pub_str); } rgah = GNUNET_new (struct TALER_EXCHANGE_ReservesGetAttestHandle); diff --git a/src/testing/test_exchange_p2p.c b/src/testing/test_exchange_p2p.c index d0a0a9898..693391c6c 100644 --- a/src/testing/test_exchange_p2p.c +++ b/src/testing/test_exchange_p2p.c @@ -382,7 +382,7 @@ run (void *cls, MHD_HTTP_PAYMENT_REQUIRED, // FIXME: or CONFLICT? NULL, NULL), - TALER_TESTING_cmd_reserve_open ("reserve-open-101-ok", + TALER_TESTING_cmd_reserve_open ("reserve-open-101-ok-a", "create-reserve-101", "EUR:0.01", GNUNET_TIME_UNIT_MONTHS, @@ -394,30 +394,32 @@ run (void *cls, "create-reserve-101", "EUR:1.03", MHD_HTTP_OK), - TALER_TESTING_cmd_reserve_open ("reserve-open-101-ok", + TALER_TESTING_cmd_reserve_open ("reserve-open-101-ok-b", "create-reserve-101", "EUR:0", GNUNET_TIME_UNIT_MONTHS, 2, /* min purses */ MHD_HTTP_OK, "withdraw-coin-100", - "EUR:0.02", + "EUR:0.03", /* 0.02 for the reserve open, 0.01 for deposit fee */ NULL, NULL), - /* FIXME: use purse quota here */ + /* FIXME: use purse creation with purse quota here */ TALER_TESTING_cmd_reserve_get_attestable ("reserve-101-attestable", "create-reserve-101", - MHD_HTTP_OK, + MHD_HTTP_NOT_FOUND, NULL), TALER_TESTING_cmd_reserve_get_attestable ("reserve-101-attest", "create-reserve-101", - MHD_HTTP_CONFLICT, + MHD_HTTP_NOT_FOUND, "nx-attribute-name", NULL), +#if 0 TALER_TESTING_cmd_reserve_close ("reserve-101-close", "create-reserve-101", NULL, /* to origin */ MHD_HTTP_OK), +#endif TALER_TESTING_cmd_end () }; diff --git a/src/testing/testing_api_cmd_reserve_open.c b/src/testing/testing_api_cmd_reserve_open.c index 67209d02e..cc0e649d2 100644 --- a/src/testing/testing_api_cmd_reserve_open.c +++ b/src/testing/testing_api_cmd_reserve_open.c @@ -319,6 +319,7 @@ TALER_TESTING_cmd_reserve_open (const char *label, ss->cpl++; va_end (ap); GNUNET_assert (0 == (ss->cpl % 2)); + ss->cpl /= 2; /* name and amount per coin */ ss->cd = GNUNET_new_array (ss->cpl, struct CoinDetail); i = 0; @@ -326,11 +327,12 @@ TALER_TESTING_cmd_reserve_open (const char *label, expected_response_code); while (NULL != (name = va_arg (ap, const char *))) { - ss->cd[i].name = name; + struct CoinDetail *cd = &ss->cd[i]; + cd->name = name; GNUNET_assert (GNUNET_OK == TALER_string_to_amount (va_arg (ap, const char *), - &ss->cd[i].amount)); + &cd->amount)); i++; } va_end (ap);