diff --git a/src/exchange/taler-exchange-httpd.c b/src/exchange/taler-exchange-httpd.c
index d97c68e33..32cbd8dd1 100644
--- a/src/exchange/taler-exchange-httpd.c
+++ b/src/exchange/taler-exchange-httpd.c
@@ -1070,18 +1070,32 @@ handle_get_extensions (struct TEH_RequestContext *rc,
"/extensions/$EXTENSION unknown");
}
- if (NULL == ext->http_get_handler)
+ if (NULL == ext->policy_get_handler)
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_NOT_IMPLEMENTED,
TALER_EC_EXCHANGE_GENERIC_OPERATION_UNKNOWN,
"GET /extensions/$EXTENSION not supported");
- return ext->http_get_handler (
+ return ext->policy_get_handler (
rc->connection,
&args[1]);
}
+/* @brief function pointer for TALER_extension.check */
+static enum GNUNET_GenericReturnValue
+check_serial_ids (
+ struct GNUNET_HashCode serial_ids[],
+ size_t size)
+{
+ for (size_t i = 0; i < size; i++)
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Got to check serial_id: %s\n",
+ GNUNET_h2s (&serial_ids[i]));
+ return GNUNET_OK;
+}
+
+
/**
* Handle POST "/extensions/..." requests.
*
@@ -1096,6 +1110,7 @@ handle_post_extensions (struct TEH_RequestContext *rc,
const char *const args[])
{
const struct TALER_Extension *ext = NULL;
+ json_t *output;
if (NULL == args[0])
{
@@ -1112,16 +1127,49 @@ handle_post_extensions (struct TEH_RequestContext *rc,
"/extensions/$EXTENSION unknown");
}
- if (NULL == ext->http_post_handler)
+ if (NULL == ext->policy_post_handler)
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_NOT_IMPLEMENTED,
TALER_EC_EXCHANGE_GENERIC_OPERATION_UNKNOWN,
"POST /extensions/$EXTENSION not supported");
- return ext->http_post_handler (
- rc->connection,
- root,
- &args[1]);
+ {
+ enum GNUNET_GenericReturnValue ret;
+ struct TALER_PolicyFulfilmentOutcome *outcome;
+
+ ret = ext->policy_post_handler (root,
+ &args[1],
+ &check_serial_ids,
+ &outcome,
+ &output);
+
+ if (GNUNET_OK != ret)
+ {
+ TALER_policy_fulfilment_outcome_free (outcome);
+ TALER_MHD_reply_json_steal (
+ rc->connection,
+ output,
+ MHD_HTTP_BAD_REQUEST);
+ }
+
+ /* TODO: deal with outcome */
+ {
+ for (size_t i = 0; i < outcome->len; i++)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Got outcome for serial_id: %s, state: %s, amount: %s\n",
+ GNUNET_h2s (&outcome->positions[i].serial_id),
+ TALER_policy_fulfilment_state_str (
+ outcome->positions[i].state),
+ TALER_amount_to_string (&outcome->positions[i].new_amount));
+ }
+ }
+
+ }
+
+ return TALER_MHD_reply_json_steal (rc->connection,
+ output,
+ MHD_HTTP_OK);
}
diff --git a/src/exchange/taler-exchange-httpd_deposit.c b/src/exchange/taler-exchange-httpd_deposit.c
index 5d38de82e..12741c6b5 100644
--- a/src/exchange/taler-exchange-httpd_deposit.c
+++ b/src/exchange/taler-exchange-httpd_deposit.c
@@ -337,15 +337,22 @@ TEH_handler_deposit (struct MHD_Connection *connection,
if (deposit.has_policy_details)
{
const char *error_hint = NULL;
+ enum TALER_PolicyFulfilmentState state_on_timeout;
+
if (GNUNET_OK !=
- TALER_extensions_serial_from_policy_details (deposit.policy_details,
- &deposit.policy_serial_id,
- &deposit.policy_deadline,
- &error_hint))
+ TALER_extensions_extract_meta_data_from_policy_details (
+ deposit.policy_details,
+ &deposit.policy_serial_id,
+ &deposit.policy_deadline,
+ &state_on_timeout,
+ &error_hint))
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_BAD_REQUEST,
TALER_EC_EXCHANGE_DEPOSITS_POLICY_NOT_ACCEPTED,
error_hint);
+
+ GNUNET_assert (TALER_PolicyFulfilmentStateMax >= state_on_timeout);
+ deposit.policy_state_on_timeout = state_on_timeout;
}
/* new deposit */
diff --git a/src/exchangedb/exchange-0001-part.sql b/src/exchangedb/exchange-0001-part.sql
index 7e2547db1..4a116d127 100644
--- a/src/exchangedb/exchange-0001-part.sql
+++ b/src/exchangedb/exchange-0001-part.sql
@@ -561,7 +561,8 @@ CREATE TABLE IF NOT EXISTS policy_details
,serial_id BYTEA PRIMARY KEY CHECK(LENGTH(serial_id)=64)
,policy_options VARCHAR
,deadline INT8 NOT NULL
- ,fulfilment_state INT4 NOT NULL CHECK(fulfilment_state between 0 and 3))
+ ,timeout_fulfilment_state smallint NOT NULL CHECK(timeout_fulfilment_state in (5, 6))
+ ,fulfilment_state smallint NOT NULL CHECK(fulfilment_state between 0 and 6))
PARTITION BY HASH (serial_id);
COMMENT ON TABLE policy_details
IS 'Policies that were provided with deposits via policy extensions.';
@@ -571,8 +572,17 @@ COMMENT ON COLUMN policy_details.policy_options
IS 'JSON object with options set that the exchange needs to consider when executing a deposit. Supported details depend on the policy extensions supported by the exchange.';
COMMENT ON COLUMN policy_details.deadline
IS 'Deadline until the policy must be marked as fulfilled or unfulfilled (maybe "forever")';
+COMMENT ON COLUMN policy_details.timeout_fulfilment_state
+ IS 'State that a pending policy should be put into, once the deadline is reached. Allowed values are 5 (TIMEOUT, transfer coins) or 6 (TIMEOUT, coins refreshable)';
COMMENT ON COLUMN policy_details.fulfilment_state
- IS 'State of the fulfilment: 0 (PENDING), 1 (FULFILLED), 2 (NOT FULFILLED), 3 (TIMED OUT)';
+ IS 'State of the fulfilment:
+ - 0 (PENDING)
+ - 1 (SUCCESS, transfer coins)
+ - 2 (SUCCESS, coins refreshable)
+ - 3 (FAILURE, transfer coins)
+ - 4 (FAILURE, coins refreshable)
+ - 5 (TIMEOUT, tranfer coins)
+ - 6 (TIMEOUT, coins refrehsable)';
CREATE TABLE IF NOT EXISTS policy_details_default
PARTITION OF policy_details
diff --git a/src/exchangedb/irbt_callbacks.c b/src/exchangedb/irbt_callbacks.c
index 7c4944183..e9cce43cb 100644
--- a/src/exchangedb/irbt_callbacks.c
+++ b/src/exchangedb/irbt_callbacks.c
@@ -929,11 +929,16 @@ irbt_cb_table_policy_details (struct PostgresClosure *pg,
{
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_uint64 (&td->serial),
- NULL ==
- td->details.policy_details.policy_options ?
+ NULL == td->details.policy_details.policy_options ?
GNUNET_PQ_query_param_null () :
GNUNET_PQ_query_param_string (
td->details.policy_details.policy_options),
+ GNUNET_PQ_query_param_timestamp (
+ &td->details.policy_details.deadline),
+ GNUNET_PQ_query_param_uint16 (
+ &td->details.policy_details.timeout_fulfilment_state),
+ GNUNET_PQ_query_param_uint16 (
+ &td->details.policy_details.fulfilment_state),
GNUNET_PQ_query_param_end
};
diff --git a/src/exchangedb/lrbt_callbacks.c b/src/exchangedb/lrbt_callbacks.c
index a2c654f4f..5fe0817e0 100644
--- a/src/exchangedb/lrbt_callbacks.c
+++ b/src/exchangedb/lrbt_callbacks.c
@@ -1456,7 +1456,10 @@ lrbt_cb_table_policy_details (void *cls,
GNUNET_PQ_result_spec_timestamp ("deadline",
&td.details.policy_details.
deadline),
- GNUNET_PQ_result_spec_uint64 ("fulfilment_state",
+ GNUNET_PQ_result_spec_uint16 ("timeout_fulfilment_state",
+ &td.details.policy_details.
+ timeout_fulfilment_state),
+ GNUNET_PQ_result_spec_uint16 ("fulfilment_state",
&td.details.policy_details.
fulfilment_state),
GNUNET_PQ_result_spec_end
@@ -1502,16 +1505,16 @@ lrbt_cb_table_policy_fulfilments (void *cls,
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_uint64 ("fulfilment_id",
&td.serial),
- GNUNET_PQ_result_spec_allow_null (
- GNUNET_PQ_result_spec_string ("fulfilment_proof",
- &td.details.policy_fulfilments.
- fulfilment_proof),
- &no_config),
GNUNET_PQ_result_spec_allow_null (
GNUNET_PQ_result_spec_timestamp ("fulfilment_timestamp",
&td.details.policy_fulfilments.
fulfilment_timestamp),
&no_timestamp),
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_string ("fulfilment_proof",
+ &td.details.policy_fulfilments.
+ fulfilment_proof),
+ &no_config),
GNUNET_PQ_result_spec_end
};
diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c
index ebac70eab..415417cbc 100644
--- a/src/exchangedb/plugin_exchangedb_postgres.c
+++ b/src/exchangedb/plugin_exchangedb_postgres.c
@@ -822,8 +822,8 @@ prepare_statements (struct PostgresClosure *pg)
",out_balance_ok AS balance_ok"
",out_conflict AS conflicted"
" FROM exchange_do_deposit"
- " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19);",
- 19),
+ " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20);",
+ 20),
/* used in postgres_do_purse_deposit() */
GNUNET_PQ_make_prepare (
"call_purse_deposit",
@@ -3933,10 +3933,11 @@ prepare_statements (struct PostgresClosure *pg)
",serial_id"
",policy_options"
",deadline"
+ ",timeout_fulfilment_state"
",fulfilment_state"
") VALUES "
- "($1, $2, $3, $4, $5);",
- 5),
+ "($1, $2, $3, $4, $5, $6);",
+ 6),
GNUNET_PQ_make_prepare (
"insert_into_table_policy_fulfilments",
"INSERT INTO policy_fulfilments"
@@ -6292,6 +6293,9 @@ postgres_do_deposit (
(deposit->has_policy_details)
? GNUNET_PQ_query_param_timestamp (&deposit->policy_deadline)
: GNUNET_PQ_query_param_null (),
+ (deposit->has_policy_details)
+ ? GNUNET_PQ_query_param_uint16 (&deposit->policy_state_on_timeout)
+ : GNUNET_PQ_query_param_null (),
GNUNET_PQ_query_param_end
};
struct GNUNET_PQ_ResultSpec rs[] = {
@@ -14651,6 +14655,7 @@ postgres_insert_records_by_table (void *cls,
case TALER_EXCHANGEDB_RT_POLICY_DETAILS:
rh = &irbt_cb_table_policy_details;
break;
+ /* TODO: policy_details_fulfilments and policy_fulfilments */
case TALER_EXCHANGEDB_RT_PURSE_REQUESTS:
rh = &irbt_cb_table_purse_requests;
break;
diff --git a/src/exchangedb/procedures.sql b/src/exchangedb/procedures.sql
index 3d49bab1e..aeed5de03 100644
--- a/src/exchangedb/procedures.sql
+++ b/src/exchangedb/procedures.sql
@@ -513,7 +513,8 @@ CREATE OR REPLACE FUNCTION exchange_do_deposit(
IN in_policy_blocked BOOLEAN,
IN in_policy_details VARCHAR,
IN in_policy_serial_id BYTEA,
- IN in_policy_deadline INT8,
+ IN in_policy_deadline SMALLINT,
+ IN in_policy_timeout_fulfilment_state SMALLINT,
OUT out_exchange_timestamp INT8,
OUT out_balance_ok BOOLEAN,
OUT out_conflict BOOLEAN)
@@ -535,11 +536,13 @@ THEN
(serial_id
,policy_options
,deadline
+ ,timeout_fulfilment_state
,fulfilment_state)
VALUES
(in_policy_serial_id
,in_policy_details
,in_policy_deadline
+ ,in_policy_timeout_fulfilment_state
,0) -- 0 == pending
RETURNING policy_details_serial_id INTO xdi;
ELSE
diff --git a/src/extensions/age_restriction/age_restriction.c b/src/extensions/age_restriction/age_restriction.c
index 576a60391..3c38d0f8a 100644
--- a/src/extensions/age_restriction/age_restriction.c
+++ b/src/extensions/age_restriction/age_restriction.c
@@ -154,8 +154,8 @@ struct TALER_Extension TE_age_restriction = {
/* This extension is not a policy extension */
.parse_policy_details = NULL,
- .http_get_handler = NULL,
- .http_post_handler = NULL,
+ .policy_get_handler = NULL,
+ .policy_post_handler = NULL,
};
diff --git a/src/extensions/extensions.c b/src/extensions/extensions.c
index 52f9061a6..cfc109400 100644
--- a/src/extensions/extensions.c
+++ b/src/extensions/extensions.c
@@ -353,13 +353,38 @@ TALER_extensions_load_manifests (
}
+/*
+ * Policy related
+ */
+
+static char *fulfilment2str[] = {
+ [TALER_PolicyFulfilmentPending] = "Pending",
+ [TALER_PolicyFulfilmentSuccessTransfer] = "SuccessTransfer",
+ [TALER_PolicyFulfilmentSuccessRefreshable] = "SuccessRefreshable",
+ [TALER_PolicyFulfilmentFailureTransfer] = "FailureTransfer",
+ [TALER_PolicyFulfilmentFailureRefreshable] = "FailureRefreshable",
+ [TALER_PolicyFulfilmentTimeoutTransfer] = "TimeoutTransfer",
+ [TALER_PolicyFulfilmentTimeoutRefreshable] = "TimeoutRefreshable",
+};
+
+const char *
+TALER_policy_fulfilment_state_str (
+ enum TALER_PolicyFulfilmentState state)
+{
+ GNUNET_assert (TALER_PolicyFulfilmentStateMax >= state);
+ return fulfilment2str[state];
+}
+
+
enum GNUNET_GenericReturnValue
-TALER_extensions_serial_from_policy_details (
+TALER_extensions_extract_meta_data_from_policy_details (
const json_t *policy_details,
struct GNUNET_HashCode *serial,
struct GNUNET_TIME_Timestamp *deadline,
+ enum TALER_PolicyFulfilmentState *state_on_deadline,
const char **error_hint)
{
+ enum GNUNET_GenericReturnValue ret;
const struct TALER_Extension *extension;
const json_t *jtype;
const char *type;
@@ -399,12 +424,49 @@ TALER_extensions_serial_from_policy_details (
}
*deadline = GNUNET_TIME_UNIT_FOREVER_TS;
- return extension->parse_policy_details (policy_details,
- serial,
- deadline,
- error_hint);
+ ret = extension->parse_policy_details (policy_details,
+ serial,
+ deadline,
+ state_on_deadline,
+ error_hint);
+
+ GNUNET_assert ((TALER_PolicyFulfilmentTimeoutRefreshable ==
+ *state_on_deadline) ||
+ (TALER_PolicyFulfilmentTimeoutTransfer ==
+ *state_on_deadline));
+
+ return ret;
}
+struct TALER_PolicyFulfilmentOutcome *
+TALER_policy_fulfilment_outcome_new (size_t len)
+{
+ struct TALER_PolicyFulfilmentOutcome *out;
+
+ out = GNUNET_new (struct TALER_PolicyFulfilmentOutcome);
+ out->len = len;
+ out->positions = GNUNET_new_array (len,
+ struct
+ TALER_PolicyFulfilmentOutcomePosition);
+
+ return out;
+}
+
+
+void
+TALER_policy_fulfilment_outcome_free (
+ struct TALER_PolicyFulfilmentOutcome *outcome)
+{
+ if (NULL == outcome)
+ return;
+
+ if (NULL != outcome->positions)
+ GNUNET_free (outcome->positions);
+
+ GNUNET_free (outcome);
+}
+
+
/* end of extensions.c */
diff --git a/src/extensions/policy_brandt_vickrey_auction/policy_brandt_vickrey_auction.c b/src/extensions/policy_brandt_vickrey_auction/policy_brandt_vickrey_auction.c
index 8521711b6..bfd7b813f 100644
--- a/src/extensions/policy_brandt_vickrey_auction/policy_brandt_vickrey_auction.c
+++ b/src/extensions/policy_brandt_vickrey_auction/policy_brandt_vickrey_auction.c
@@ -14,7 +14,7 @@
TALER; see the file COPYING. If not, see
*/
/**
- * @file policy_brandt_vickery_auction.c
+ * @file policy_brandt_vickrey_auction.c
* @brief Extension for replay of auctions of type Brandt
* @author Özgür Kesim
*/
@@ -26,8 +26,8 @@
#include "stdint.h"
#include
-#define POLICY_AUCTION "policy_brandt_vickery_auction"
-#define LOG_PREFIX "[policy_brandt_vickery_auction] "
+#define POLICY_AUCTION "policy_brandt_vickrey_auction"
+#define LOG_PREFIX "[policy_brandt_vickrey_auction] "
#define MAX_RESULT_SIZE 10 * 1024
/* (public) configuration of this extension */
@@ -54,7 +54,7 @@ struct result
{
uint16_t bidder;
uint16_t price_idx;
- const char *price;
+ const char *price;
};
/*
@@ -73,12 +73,19 @@ struct transcript
/* Payto URL */
const char *payto;
- /* Number of bidders + 1 (for seller) */
+ /* Number of bidders */
uint16_t n;
/* (n-1) public keys of bidders */
struct GNUNET_CRYPTO_EddsaPublicKey *bidder_pub;
+ /* Hash of the auction */
+ struct GNUNET_HashCode h_auction;
+
+ /* (n-1) calculated serial_ids */
+ struct GNUNET_HashCode *serial_ids;
+
+
/* Type of auction, see libbrandt */
uint16_t m;
@@ -137,6 +144,25 @@ json_error (json_t **output,
};
+/* Create serial as H(bidder_pub, h_auction) */
+static void
+calculate_serial (
+ struct GNUNET_CRYPTO_EddsaPublicKey *pub,
+ struct GNUNET_HashCode *hc,
+ struct GNUNET_HashCode *serial)
+{
+ struct GNUNET_HashContext *ctx = GNUNET_CRYPTO_hash_context_start ();
+ GNUNET_CRYPTO_hash_context_read (ctx,
+ pub,
+ sizeof(*pub));
+ GNUNET_CRYPTO_hash_context_read (ctx,
+ hc,
+ sizeof(*hc));
+ GNUNET_CRYPTO_hash_context_finish (ctx,
+ serial);
+}
+
+
/*
* @brief Parses a given json as transcript.
*
@@ -165,8 +191,8 @@ parse_transcript (const json_t *jtr,
char *perr;
unsigned int eline;
struct GNUNET_JSON_Specification au_spec[] = {
- GNUNET_JSON_spec_bool ("public", &tr->public),
- GNUNET_JSON_spec_uint16 ("type", &tr->m),
+ GNUNET_JSON_spec_bool ("outcome_public", &tr->public),
+ GNUNET_JSON_spec_uint16 ("auction_type", &tr->m),
GNUNET_JSON_spec_fixed_auto ("pubkey", &tr->seller_pub),
GNUNET_JSON_spec_timestamp ("time_start", &tr->time_start),
GNUNET_JSON_spec_relative_time ("time_round", &tr->time_round),
@@ -187,6 +213,13 @@ parse_transcript (const json_t *jtr,
return json_error (jerror,
perr);
+ {
+ const char *auc_js = json_dumps (auc, JSON_COMPACT);
+ GNUNET_CRYPTO_hash (auc_js,
+ strlen (auc_js),
+ &tr->h_auction);
+ }
+
// Prices...
{
size_t idx;
@@ -235,15 +268,23 @@ parse_transcript (const json_t *jtr,
tr->n = json_array_size (bidders);
- tr->bidder_pub = GNUNET_new_array (tr->n, struct
- GNUNET_CRYPTO_EddsaPublicKey);
+ tr->bidder_pub = GNUNET_new_array (
+ tr->n,
+ struct GNUNET_CRYPTO_EddsaPublicKey);
+
+ tr->serial_ids = GNUNET_new_array (
+ tr->n,
+ struct GNUNET_HashCode);
+
json_array_foreach (bidders, idx, val)
{
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto (NULL,
- &(tr->bidder_pub[idx])),
+ &tr->bidder_pub[idx]),
GNUNET_JSON_spec_end (),
};
+
+ /* TODO: cleanup */
if (GNUNET_OK !=
GNUNET_JSON_parse (val,
spec,
@@ -252,12 +293,13 @@ parse_transcript (const json_t *jtr,
return json_error (jerror,
"bidder no %ld public key couldn't be parsed",
idx + 1);
+
+ calculate_serial (&tr->bidder_pub[idx],
+ &tr->h_auction,
+ &tr->serial_ids[idx]);
}
}
- // TODO: parse and verify signatures from bidders of the auction
-
-
// Messages
{
size_t nm;
@@ -322,7 +364,6 @@ parse_transcript (const json_t *jtr,
DONE:
- *jerror = NULL;
return GNUNET_OK;
}
@@ -331,7 +372,8 @@ DONE:
* @brief replay an auction using the external program
*
* @param[in] root The original JSON transcript
- * @param[in] transcript The transcript object parsed so far
+ * @param[in,out] transcript The transcript object parsed so far
+ * @param[out] outcome Outcome object to fill
* @param[out] result The JSON result from the program
* @return GNUNET_OK on success
*
@@ -340,8 +382,10 @@ DONE:
static enum GNUNET_GenericReturnValue
replay_transcript (const json_t*root,
struct transcript *tr,
+ struct TALER_PolicyFulfilmentOutcome **outcome,
json_t **result)
{
+ enum GNUNET_GenericReturnValue ret = GNUNET_SYSERR;
struct GNUNET_DISK_PipeHandle *pi;
struct GNUNET_DISK_PipeHandle *po;
const struct GNUNET_DISK_FileHandle *fd;
@@ -444,32 +488,106 @@ replay_transcript (const json_t*root,
return json_error (result, "internal error");
}
+ // TODO: check each winner with tr->expected, if applicable
+
+
+ // Create the outcome object
{
- // TODO: check each winner with tr->expected, if applicable
- json_object_set (res, "exchange_sig", json_string (
- "sig(priv_E, winners)"));
+ json_t *w;
+ size_t idx;
+ struct TALER_PolicyFulfilmentOutcomePosition *pos;
+ *outcome =
+ TALER_policy_fulfilment_outcome_new (tr->n);
+
+ /* Set outcome for all bidders to a default value first */
+ for (uint16_t i = 0; in; i++)
+ {
+ pos = &((*outcome)->positions[i]);
+ pos->serial_id = tr->serial_ids[i];
+ pos->has_new_amount = false;
+ pos->state = TALER_PolicyFulfilmentFailureRefreshable;
+ }
+
+ /* Set the outcome of the winners */
+ json_array_foreach (winners, idx, w)
+ {
+ enum GNUNET_GenericReturnValue ret;
+ const char *jerror;
+ uint16_t bidder;
+ uint16_t price_idx;
+ struct TALER_Amount price;
+
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_uint16 ("bidder",
+ &bidder),
+ GNUNET_JSON_spec_uint16 ("price_idx",
+ &price_idx),
+ TALER_JSON_spec_amount ("price",
+ BV_config.auction_fee.currency,
+ &price),
+ GNUNET_JSON_spec_end ()
+ };
+
+ ret = GNUNET_JSON_parse (w,
+ spec,
+ &jerror,
+ NULL);
+
+ if (GNUNET_OK != ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ LOG_PREFIX
+ "couldn't parse output of replay program: %s\n",
+ jerror);
+ ret = json_error (result, "internal error");
+ goto DONE;
+ }
+
+ if (bidder > tr->n - 1)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ LOG_PREFIX
+ "replay program sent a bidder out of range\n");
+ ret = json_error (result, "internal error");
+ goto DONE;
+ }
+
+ // Fill the outcome position for this winning bidder.
+ pos = &((*outcome)->positions[idx]);
+ pos->has_new_amount = true;
+ pos->new_amount = price;
+ pos->state = TALER_PolicyFulfilmentSuccessTransfer;
+ }
+
+ // TODO: return own result object.
+ // TODO: sign the result by the exchange
+ *result = json_copy (res);
+ json_decref (res);
}
-
- // TODO: return own result object.
- *result = json_copy (res);
- json_decref (res);
}
-
+ ret = GNUNET_OK;
}
- if (GNUNET_OK != GNUNET_OS_process_wait (proc))
+ ret = GNUNET_OS_process_wait (proc);
+ if (GNUNET_OK != ret)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- LOG_PREFIX "error while launching auction replay program '%s'\n",
+ LOG_PREFIX
+ "error waiting for auction replay program '%s'\n",
replay_program);
json_object_clear (*result);
- return json_error (result, "internal error");
+ ret = json_error (result, "internal error");
}
-
- return GNUNET_OK;
+DONE:
+ if (GNUNET_OK != ret)
+ {
+ TALER_policy_fulfilment_outcome_free (*outcome);
+ *outcome = NULL;
+ }
+ return ret;
}
@@ -531,60 +649,58 @@ auction_load_config (
/**
- * @brief implements the TALER_Extension.http_get_handler
+ * @brief implements the TALER_Extension.policy_get_handler
*/
static MHD_RESULT
-auction_http_get_handler (
+auction_policy_get_handler (
struct MHD_Connection *connection,
const char *const args[])
{
/* TODO: return some meta-data about supported version, limits, etc.*/
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- LOG_PREFIX "auction_http_get_handler not implemented yet\n");
+ LOG_PREFIX "auction_policy_get_handler not implemented yet\n");
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_NOT_IMPLEMENTED,
TALER_EC_EXCHANGE_GENERIC_OPERATION_UNKNOWN,
- "auction_http_get_handler not implemented yet\n");
+ "auction_policy_get_handler not implemented yet\n");
}
/**
- * @brief implements the TALER_Extension.http_post_handler
+ * @brief implements the TALER_Extension.policy_post_handler
*
* TODO: make this non-blocking
*/
-static MHD_RESULT
-auction_http_post_handler (
- struct MHD_Connection *connection,
+enum GNUNET_GenericReturnValue
+auction_policy_post_handler (
const json_t *root,
- const char *const args[])
+ const char *const args[],
+ enum GNUNET_GenericReturnValue (*serial_id_check)(struct GNUNET_HashCode
+ serial_ids[], size_t size),
+ struct TALER_PolicyFulfilmentOutcome **outcome,
+ json_t **output)
{
struct transcript tr = {};
enum GNUNET_GenericReturnValue ret;
- json_t *result1;
- json_t *result2;
+ *outcome = NULL;
ret = parse_transcript (root,
&tr,
- &result1);
+ output);
+
+ /* TODO: cleanups! */
if (GNUNET_OK != ret)
- return TALER_MHD_reply_json_steal (connection,
- result1,
- MHD_HTTP_BAD_REQUEST);
- GNUNET_assert (NULL == result1);
+ return ret;
- ret = replay_transcript (root,
- &tr,
- &result2);
+ serial_id_check (tr.serial_ids, tr.n);
- return TALER_MHD_reply_json_steal (connection,
- result2,
- GNUNET_OK == ret?
- MHD_HTTP_OK :
- MHD_HTTP_BAD_REQUEST);
+ return replay_transcript (root,
+ &tr,
+ outcome,
+ output);
}
@@ -594,6 +710,7 @@ auction_http_post_handler (
* @param[in] input The policy_details for this handler during deposit
* @param[out] serial On success will contain the serial-ID under which the
* @param[out] deadline On success will contain a deadline, might be "forever"
+ * @param[out] state_on_timeout On success, will be set to the default state that the policy shall be put in case of a timeout.
* @param[out] error_hint On error, will contain a hint
* exchange should store the policy_details in the policy_details table.
* @return GNUNET_OK if the request was OK
@@ -603,6 +720,7 @@ auction_parse_policy_details (
const json_t *input,
struct GNUNET_HashCode *serial,
struct GNUNET_TIME_Timestamp *deadline,
+ enum TALER_PolicyFulfilmentState *state_on_timeout,
const char **error_hint)
{
enum GNUNET_GenericReturnValue ret = GNUNET_NO;
@@ -636,22 +754,14 @@ auction_parse_policy_details (
LOG_PREFIX "check of deadline %ld not implemented!\n",
deadline->abs_time.abs_value_us);
- /* Create serial as H(bidder_pub, h_auction) */
- {
- struct GNUNET_HashContext *hc = GNUNET_CRYPTO_hash_context_start ();
- GNUNET_CRYPTO_hash_context_read (hc,
- &pub,
- sizeof(pub));
- GNUNET_CRYPTO_hash_context_read (hc,
- &hc,
- sizeof(hc));
- GNUNET_CRYPTO_hash_context_finish (hc,
- serial);
- }
+ calculate_serial (&pub, &hc, serial);
ret = GNUNET_OK;
} while(0);
+ /* In case of timeout, the coin shall be refreshable by the owner */
+ *state_on_timeout = TALER_PolicyFulfilmentTimeoutRefreshable;
+
return ret;
}
@@ -668,8 +778,8 @@ struct TALER_Extension TE_auction_brandt = {
.load_config = &auction_load_config,
.manifest = &auction_manifest,
.parse_policy_details = &auction_parse_policy_details,
- .http_get_handler = &auction_http_get_handler,
- .http_post_handler = &auction_http_post_handler,
+ .policy_get_handler = &auction_policy_get_handler,
+ .policy_post_handler = &auction_policy_post_handler,
};
@@ -687,7 +797,7 @@ struct TALER_Extension TE_auction_brandt = {
* @return Pointer to TE_auction_brandt
*/
struct TALER_Extension *
-libtaler_extension_policy_brandt_vickery_auction_init (void *arg)
+libtaler_extension_policy_brandt_vickrey_auction_init (void *arg)
{
const struct GNUNET_CONFIGURATION_Handle *cfg = arg;
@@ -751,7 +861,7 @@ libtaler_extension_policy_brandt_vickery_auction_init (void *arg)
* @return null
*/
void *
-libtaler_extension_policy_brandt_vickery_auction_done (void *arg)
+libtaler_extension_policy_brandt_vickrey_auction_done (void *arg)
{
auction_disable (&TE_auction_brandt);
GNUNET_free (replay_program);
@@ -761,4 +871,4 @@ libtaler_extension_policy_brandt_vickery_auction_done (void *arg)
}
-/* end of policy_brandt_vickery_auction.c */
+/* end of policy_brandt_vickrey_auction.c */
diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h
index 10e1a8159..80a19b676 100644
--- a/src/include/taler_exchangedb_plugin.h
+++ b/src/include/taler_exchangedb_plugin.h
@@ -531,7 +531,8 @@ struct TALER_EXCHANGEDB_TableData
char *policy_options;
struct GNUNET_HashCode serial_id;
struct GNUNET_TIME_Timestamp deadline;
- uint64_t fulfilment_state;
+ uint16_t timeout_fulfilment_state;
+ uint16_t fulfilment_state;
} policy_details;
struct
@@ -1464,6 +1465,11 @@ struct TALER_EXCHANGEDB_Deposit
*/
struct GNUNET_TIME_Timestamp policy_deadline;
+ /**
+ * The state that a _pending_ policy should be put into once the timeout triggers
+ */
+ uint16_t policy_state_on_timeout;
+
/**
* Hash over the @e policy_details. Only filled if has_policy_details is
diff --git a/src/include/taler_extensions.h b/src/include/taler_extensions.h
index b2d256783..5a5841e52 100644
--- a/src/include/taler_extensions.h
+++ b/src/include/taler_extensions.h
@@ -53,6 +53,10 @@ struct TALER_Extensions
const struct TALER_Extension *extension;
};
+/* Forward declarations */
+enum TALER_PolicyFulfilmentState;
+struct TALER_PolicyFulfilmentOutcome;
+
/*
* @brief Represents the implementation of an extension.
*
@@ -159,6 +163,7 @@ struct TALER_Extension
* Policy related handlers
* =========================
*/
+
/**
* @brief Handler to check a policy. Can be NULL;
*
@@ -166,44 +171,55 @@ struct TALER_Extension
* (see https://docs.taler.net/core/api-exchange.html#deposit), this handler
* will be called before the deposit transaction.
*
- * @param[in] policy_details Details about the policy, provided by the client
- * during a deposit request.
+ * @param[in] policy_details Details about the policy, provided by the client
+ * during a deposit request.
* @param[out] serial On success, will contain the serial-ID under which the
- * exchange should save the policy_details in the deposit table.
+ * exchange should save the policy_details in the deposit table.
* @param[out] deadline On success, set to the deadline until the policy must
- * be fulfilled. Might be "forever". This value is used by an external
+ * be fulfilled. Might be "forever". This value is used by an
+ * external mechanism to detect timeouts.
+ * @param[out] state_on_timeout On GNUNET_OK, which state shall the
+ * fulfilment of this policy be put in. MUST be either
+ * TALER_PolicyFulfilmentTimeoutTransfer or
+ * TALER_PolicyFulfilmentTimeoutRefreshable
* @param[out] error_hint On error, will contain a hint
- * mechanism to detect timeouts.
- * @return GNUNET_OK if the data was accepted by the extension.
+ * @return GNUNET_OK if the data was accepted by the extension.
*/
enum GNUNET_GenericReturnValue (*parse_policy_details)(
const json_t *policy_details,
struct GNUNET_HashCode *serial,
struct GNUNET_TIME_Timestamp *deadline,
+ enum TALER_PolicyFulfilmentState *state_on_timeout,
const char **error_hint);
/**
- * @brief Handler for POST-requests to the /policy/$name endpoint. Can be NULL.
+ * @brief Handler for POST-requests to the /extensions/$name endpoint. Can be NULL.
*
- * @param connection The current connection
- * @param root The JSON body from the request
- * @param args Additional query parameters of the request.
- * @return MDH result
+ * @param[in] root The JSON body from the request
+ * @param[in] args Additional query parameters of the request.
+ * @param[in] serial_id_check Helper function to check the presence of serial_ids in policy_details. Can be used by the handler to ensure the presence of entries before starting calculations.
+ * @param[out] outcome Result of the operation. Must be freed via TALER_policy_fulfilment_outcome_free after use.
+ * @param[out] output JSON output to return to the client
+ * @return GNUNET_OK on success.
*/
- MHD_RESULT (*http_post_handler)(
- struct MHD_Connection *connection,
+ enum GNUNET_GenericReturnValue (*policy_post_handler)(
const json_t *root,
- const char *const args[]);
+ const char *const args[],
+ enum GNUNET_GenericReturnValue (*serial_id_check)(struct GNUNET_HashCode
+ serial_ids[], size_t
+ size),
+ struct TALER_PolicyFulfilmentOutcome **outcome,
+ json_t **output);
/**
- * @brief Handler for GET-requests to the /policy/$name endpoint. Can be NULL.
+ * @brief Handler for GET-requests to the /extensions/$name endpoint. Can be NULL.
*
* @param connection The current connection
* @param root The JSON body from the request
* @param args Additional query parameters of the request.
* @return MDH result
*/
- MHD_RESULT (*http_get_handler)(
+ MHD_RESULT (*policy_get_handler)(
struct MHD_Connection *connection,
const char *const args[]);
};
@@ -382,28 +398,123 @@ TALER_extensions_get_age_restriction_mask ();
/*
* ===================================
- * Policy extensions related functions
+ * Policy extensions related API
* ===================================
*/
+
/*
- * @brief Finds the extension for a given policy
+ * @brief Describes the states of fulfilment of a policy bound to a deposit
+ */
+enum TALER_PolicyFulfilmentState
+{
+ /* Initial state of the policy */
+ TALER_PolicyFulfilmentPending = 0,
+
+ /*
+ * Policy provably fulfilled. The semantics of the policy require that
+ * the exchange MUST transfer amount in the associated deposit to the
+ * payto-URI */
+ TALER_PolicyFulfilmentSuccessTransfer = 1,
+
+ /*
+ * Policy provably fulfilled. The semantics of the policy require that
+ * the coins' value in the associated deposit remains and the owner can
+ * refresh them. */
+ TALER_PolicyFulfilmentSuccessRefreshable = 2,
+
+ /*
+ * Policy provably UNfulfilled. The semantics of the policy require
+ * that the exchange MUST transfer amount in the associated deposit to
+ * the payto-URI. */
+ TALER_PolicyFulfilmentFailureTransfer = 3,
+
+ /*
+ * Policy provably UNfulfilled. The semantics of the policy require that
+ * the coins' value in the associated deposit remains and the owner can
+ * refresh them. */
+ TALER_PolicyFulfilmentFailureRefreshable = 4,
+
+ /*
+ * Policy timed out. The semantics of the policy require that the
+ * exchange MUST transfer amount in the associated deposit to the
+ * payto-URI. */
+ TALER_PolicyFulfilmentTimeoutTransfer = 5,
+
+ /*
+ * Policy timed out. The semantics of the policy require that the
+ * coins' value in the associated deposit remains and the owner can
+ * refresh them. */
+ TALER_PolicyFulfilmentTimeoutRefreshable = 6,
+
+ TALER_PolicyFulfilmentStateMax = TALER_PolicyFulfilmentTimeoutRefreshable
+};
+
+
+const char *
+TALER_policy_fulfilment_state_str (enum TALER_PolicyFulfilmentState state);
+
+/*
+ * @brief Respresents the outcome of a policy fulfilment evaluation
+ * returned by a http_post_handler.
+ */
+struct TALER_PolicyFulfilmentOutcome
+{
+ size_t len;
+ struct TALER_PolicyFulfilmentOutcomePosition
+ {
+ /* Identifies the particular policy in the policy_details */
+ struct GNUNET_HashCode serial_id;
+
+ /* The state that the policy should be be put into. */
+ enum TALER_PolicyFulfilmentState state;
+
+ /* If @e has_new_amount is true, the actual amount to be transfered
+ * according to the @e state is not taken from the associated deposit
+ * entry, but provided with @new_amount
+ */
+ bool has_new_amount;
+ struct TALER_Amount new_amount;
+
+ } *positions;
+};
+
+
+/*
+ * @brief allocate a TALER_PolicyFulfilmentOutcome
+ */
+struct TALER_PolicyFulfilmentOutcome *
+TALER_policy_fulfilment_outcome_new (size_t len);
+
+/*
+ * @brief free the content of a TALER_PolicyFulfilmentOutcome
+ */
+void
+TALER_policy_fulfilment_outcome_free (
+ struct TALER_PolicyFulfilmentOutcome *outcome);
+
+
+/*
+ * @brief Extracts meta information from policy_details
*
* @param[in] policy_details JSON of the policy detail from a deposit request
* @param[out] serial On GNUNET_OK, the hash code that should be used to save the policy_details in the policy_details table
* @param[out] deadline On GNUNET_OK, the deadline that should be saved in the policy_details table
+ * @param[out] state_on_timeout On GNUNET_OK, which state shall the fulfilment of this policy be put in
* @param[out] error_hint On GNUNET_SYSERR, will contain a hint for the reason why it failed
* @return GNUNET_OK on success, with *extension set to the correct extension.
* GNUNET_NO, when no extension was found. GNUNET_SYSERR when the JSON was
* invalid, with *error_hint maybe non-NULL.
*/
enum GNUNET_GenericReturnValue
-TALER_extensions_serial_from_policy_details (
+TALER_extensions_extract_meta_data_from_policy_details (
const json_t *policy_details,
struct GNUNET_HashCode *serial,
struct GNUNET_TIME_Timestamp *deadline,
+ enum TALER_PolicyFulfilmentState *state_on_timeout,
const char **error_hint);
+
/*
* ================================
* Merchant refund policy