WIP: policy_details handling continued
- policy details generated on deposit/batch-deposit requests - insert or update of policy details in the DB - accumulation of amounts of multiple deposits for the same policy_details
This commit is contained in:
parent
956e3c3065
commit
054e157af8
@ -115,7 +115,6 @@ static struct Table tables[] = {
|
||||
{ .rt = TALER_EXCHANGEDB_RT_EXTENSIONS},
|
||||
{ .rt = TALER_EXCHANGEDB_RT_POLICY_DETAILS },
|
||||
{ .rt = TALER_EXCHANGEDB_RT_POLICY_FULFILMENTS },
|
||||
{ .rt = TALER_EXCHANGEDB_RT_POLICY_DETAILS_FULFILMENTS },
|
||||
{ .rt = TALER_EXCHANGEDB_RT_PURSE_REQUESTS},
|
||||
{ .rt = TALER_EXCHANGEDB_RT_PURSE_REFUNDS},
|
||||
{ .rt = TALER_EXCHANGEDB_RT_PURSE_MERGES},
|
||||
|
@ -1626,8 +1626,8 @@ deposit_cb (void *cls,
|
||||
&h_wire,
|
||||
&deposit->h_contract_terms,
|
||||
&deposit->coin.h_age_commitment,
|
||||
deposit->has_policy_details ?
|
||||
&deposit->h_policy :NULL, &h_denom_pub,
|
||||
deposit->has_policy ? &deposit->h_policy : NULL,
|
||||
&h_denom_pub,
|
||||
deposit->timestamp,
|
||||
&deposit->merchant_pub,
|
||||
deposit->refund_deadline,
|
||||
|
@ -1041,138 +1041,6 @@ handle_post_auditors (struct TEH_RequestContext *rc,
|
||||
root);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle GET "/extensions/..." requests.
|
||||
*
|
||||
* @param rc request context
|
||||
* @param args array of additional options
|
||||
* @return MHD result code
|
||||
*/
|
||||
static MHD_RESULT
|
||||
handle_get_extensions (struct TEH_RequestContext *rc,
|
||||
const char *const args[])
|
||||
{
|
||||
const struct TALER_Extension *ext = NULL;
|
||||
|
||||
if (NULL == args[0])
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return r404 (rc->connection,
|
||||
"/extensions/$EXTENSION");
|
||||
}
|
||||
|
||||
ext = TALER_extensions_get_by_name (args[0]);
|
||||
if (NULL == ext)
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return r404 (rc->connection,
|
||||
"/extensions/$EXTENSION unknown");
|
||||
}
|
||||
|
||||
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->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.
|
||||
*
|
||||
* @param rc request context
|
||||
* @param root uploaded JSON data
|
||||
* @param args array of additional options
|
||||
* @return MHD result code
|
||||
*/
|
||||
static MHD_RESULT
|
||||
handle_post_extensions (struct TEH_RequestContext *rc,
|
||||
const json_t *root,
|
||||
const char *const args[])
|
||||
{
|
||||
const struct TALER_Extension *ext = NULL;
|
||||
json_t *output;
|
||||
|
||||
if (NULL == args[0])
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return r404 (rc->connection,
|
||||
"/extensions/$EXTENSION");
|
||||
}
|
||||
|
||||
ext = TALER_extensions_get_by_name (args[0]);
|
||||
if (NULL == ext)
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return r404 (rc->connection,
|
||||
"/extensions/$EXTENSION unknown");
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle incoming HTTP request.
|
||||
*
|
||||
@ -1391,17 +1259,10 @@ handle_mhd_request (void *cls,
|
||||
.nargs_is_upper_bound = true
|
||||
},
|
||||
/* extensions endpoints */
|
||||
{
|
||||
.url = "extensions",
|
||||
.method = MHD_HTTP_METHOD_GET,
|
||||
.handler.get = &handle_get_extensions,
|
||||
.nargs = 4, /* Arbitrary upper bound */
|
||||
.nargs_is_upper_bound = true,
|
||||
},
|
||||
{
|
||||
.url = "extensions",
|
||||
.method = MHD_HTTP_METHOD_POST,
|
||||
.handler.post = &handle_post_extensions,
|
||||
.handler.post = &TEH_extensions_post_handler,
|
||||
.nargs = 4, /* Arbitrary upper bound */
|
||||
.nargs_is_upper_bound = true,
|
||||
},
|
||||
|
@ -90,14 +90,31 @@ struct BatchDepositContext
|
||||
* Additional details for policy relevant for this
|
||||
* deposit operation, possibly NULL!
|
||||
*/
|
||||
json_t *policy_details;
|
||||
bool has_policy_details;
|
||||
json_t *policy_json;
|
||||
|
||||
/**
|
||||
* Will be true if policy_json were provided
|
||||
*/
|
||||
bool has_policy;
|
||||
|
||||
/**
|
||||
* Hash over @e policy_details, might be all zero;
|
||||
*/
|
||||
struct TALER_ExtensionPolicyHashP h_policy;
|
||||
|
||||
/**
|
||||
* If @e policy_json was present, the corresponding policy extension
|
||||
* calculates these details. These will be persisted in the policy_details
|
||||
* table.
|
||||
*/
|
||||
struct TALER_PolicyDetails policy_details;
|
||||
|
||||
/**
|
||||
* When @e policy_details are persisted, this contains the id of the record
|
||||
* in the policy_details table.
|
||||
*/
|
||||
uint64_t policy_details_serial_id;
|
||||
|
||||
/**
|
||||
* Time when this request was generated. Used, for example, to
|
||||
* assess when (roughly) the income was achieved for tax purposes.
|
||||
@ -174,7 +191,7 @@ again:
|
||||
&TEH_keys_exchange_sign_,
|
||||
&bdc->h_contract_terms,
|
||||
&bdc->h_wire,
|
||||
bdc->has_policy_details ? &bdc->h_policy : NULL,
|
||||
bdc->has_policy ? &bdc->h_policy : NULL,
|
||||
bdc->exchange_timestamp,
|
||||
bdc->wire_deadline,
|
||||
bdc->refund_deadline,
|
||||
@ -247,6 +264,21 @@ batch_deposit_transaction (void *cls,
|
||||
bool balance_ok;
|
||||
bool in_conflict;
|
||||
|
||||
|
||||
/* If the deposit has a policy associated to it, persist it. This will
|
||||
* insert or update the record. */
|
||||
if (dc->has_policy)
|
||||
{
|
||||
qs = TEH_plugin->persist_policy_details (TEH_plugin->cls,
|
||||
&dc->policy_details,
|
||||
&dc->policy_details_serial_id,
|
||||
&dc->policy_details.accumulated_total,
|
||||
&dc->policy_details.fulfillment_state);
|
||||
if (qs < 0)
|
||||
return qs;
|
||||
}
|
||||
|
||||
/* deposit the individutal coins */
|
||||
for (unsigned int i = 0; i<dc->num_coins; i++)
|
||||
{
|
||||
const struct TALER_EXCHANGEDB_Deposit *deposit = &dc->deposits[i];
|
||||
@ -258,13 +290,19 @@ batch_deposit_transaction (void *cls,
|
||||
mhd_ret);
|
||||
if (qs < 0)
|
||||
return qs;
|
||||
qs = TEH_plugin->do_deposit (TEH_plugin->cls,
|
||||
|
||||
qs = TEH_plugin->do_deposit (
|
||||
TEH_plugin->cls,
|
||||
deposit,
|
||||
known_coin_id,
|
||||
&dc->h_payto,
|
||||
(dc->has_policy)
|
||||
? &dc->policy_details_serial_id
|
||||
: NULL,
|
||||
&dc->exchange_timestamp,
|
||||
&balance_ok,
|
||||
&in_conflict);
|
||||
|
||||
if (qs < 0)
|
||||
{
|
||||
if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
|
||||
@ -474,7 +512,7 @@ parse_coin (struct MHD_Connection *connection,
|
||||
&dc->h_wire,
|
||||
&dc->h_contract_terms,
|
||||
&deposit->coin.h_age_commitment,
|
||||
dc->has_policy_details ? &dc->h_policy :
|
||||
dc->has_policy ? &dc->h_policy :
|
||||
NULL,
|
||||
&deposit->coin.denom_pub_hash,
|
||||
dc->timestamp,
|
||||
@ -501,7 +539,7 @@ parse_coin (struct MHD_Connection *connection,
|
||||
but rather insert them ONCE and then per-coin only use
|
||||
the resulting extension UUID/serial; so the data structure
|
||||
here should be changed once we look at extensions in earnest. */
|
||||
deposit->policy_details = dc->policy_details;
|
||||
deposit->policy_json = dc->policy_json;
|
||||
deposit->timestamp = dc->timestamp;
|
||||
deposit->refund_deadline = dc->refund_deadline;
|
||||
deposit->wire_deadline = dc->wire_deadline;
|
||||
@ -518,7 +556,7 @@ TEH_handler_batch_deposit (struct TEH_RequestContext *rc,
|
||||
struct BatchDepositContext dc;
|
||||
json_t *coins;
|
||||
bool no_refund_deadline = true;
|
||||
bool no_policy_details = true;
|
||||
bool no_policy_json = true;
|
||||
struct GNUNET_JSON_Specification spec[] = {
|
||||
GNUNET_JSON_spec_string ("merchant_payto_uri",
|
||||
&dc.payto_uri),
|
||||
@ -532,8 +570,8 @@ TEH_handler_batch_deposit (struct TEH_RequestContext *rc,
|
||||
&coins),
|
||||
GNUNET_JSON_spec_mark_optional (
|
||||
GNUNET_JSON_spec_json ("policy",
|
||||
&dc.policy_details),
|
||||
&no_policy_details),
|
||||
&dc.policy_json),
|
||||
&no_policy_json),
|
||||
GNUNET_JSON_spec_timestamp ("timestamp",
|
||||
&dc.timestamp),
|
||||
GNUNET_JSON_spec_mark_optional (
|
||||
@ -564,7 +602,7 @@ TEH_handler_batch_deposit (struct TEH_RequestContext *rc,
|
||||
return MHD_YES; /* failure */
|
||||
}
|
||||
|
||||
dc.has_policy_details = ! no_policy_details;
|
||||
dc.has_policy = ! no_policy_json;
|
||||
|
||||
/* validate merchant's wire details (as far as we can) */
|
||||
{
|
||||
@ -610,11 +648,26 @@ TEH_handler_batch_deposit (struct TEH_RequestContext *rc,
|
||||
TALER_merchant_wire_signature_hash (dc.payto_uri,
|
||||
&dc.wire_salt,
|
||||
&dc.h_wire);
|
||||
if (dc.has_policy_details)
|
||||
|
||||
/* handle policy, if present */
|
||||
if (dc.has_policy)
|
||||
{
|
||||
TALER_deposit_policy_hash (dc.policy_details,
|
||||
const char *error_hint = NULL;
|
||||
|
||||
if (GNUNET_OK !=
|
||||
TALER_extensions_create_policy_details (
|
||||
dc.policy_json,
|
||||
&dc.policy_details,
|
||||
&error_hint))
|
||||
return TALER_MHD_reply_with_error (connection,
|
||||
MHD_HTTP_BAD_REQUEST,
|
||||
TALER_EC_EXCHANGE_DEPOSITS_POLICY_NOT_ACCEPTED,
|
||||
error_hint);
|
||||
|
||||
TALER_deposit_policy_hash (dc.policy_json,
|
||||
&dc.h_policy);
|
||||
}
|
||||
|
||||
dc.num_coins = json_array_size (coins);
|
||||
if (0 == dc.num_coins)
|
||||
{
|
||||
@ -651,6 +704,8 @@ TEH_handler_batch_deposit (struct TEH_RequestContext *rc,
|
||||
GNUNET_JSON_parse_free (spec);
|
||||
return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
|
||||
}
|
||||
|
||||
/* FIXME: sum all contributions for the policy_details.accumulated_total */
|
||||
}
|
||||
|
||||
dc.exchange_timestamp = GNUNET_TIME_timestamp_get ();
|
||||
|
@ -132,6 +132,12 @@ struct DepositContext
|
||||
*/
|
||||
uint64_t known_coin_id;
|
||||
|
||||
/**
|
||||
* When deposit->has_policy is true, and deposit->policy_details are
|
||||
* persisted, this contains the id of the record in the policy_details table.
|
||||
*/
|
||||
uint64_t policy_details_serial_id;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@ -165,14 +171,36 @@ deposit_transaction (void *cls,
|
||||
if (qs < 0)
|
||||
return qs;
|
||||
|
||||
/* If the deposit has a policy associated to it, persist it. This will
|
||||
* insert or update the record. */
|
||||
if (dc->deposit->has_policy)
|
||||
{
|
||||
struct TALER_Amount accumulated_total;
|
||||
enum TALER_PolicyFulfillmentState fulfillment_state;
|
||||
qs = TEH_plugin->persist_policy_details (TEH_plugin->cls,
|
||||
&dc->deposit->policy_details,
|
||||
&dc->policy_details_serial_id,
|
||||
&accumulated_total,
|
||||
&fulfillment_state);
|
||||
|
||||
qs = TEH_plugin->do_deposit (TEH_plugin->cls,
|
||||
/* FIXME: what to do with accumulated_total and fulfillment_state ? */
|
||||
|
||||
if (qs < 0)
|
||||
return qs;
|
||||
}
|
||||
|
||||
qs = TEH_plugin->do_deposit (
|
||||
TEH_plugin->cls,
|
||||
dc->deposit,
|
||||
dc->known_coin_id,
|
||||
&dc->h_payto,
|
||||
(dc->deposit->has_policy)
|
||||
? &dc->policy_details_serial_id
|
||||
: NULL,
|
||||
&dc->exchange_timestamp,
|
||||
&balance_ok,
|
||||
&in_conflict);
|
||||
|
||||
if (qs < 0)
|
||||
{
|
||||
if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
|
||||
@ -219,7 +247,7 @@ TEH_handler_deposit (struct MHD_Connection *connection,
|
||||
struct TALER_EXCHANGEDB_Deposit deposit;
|
||||
const char *payto_uri;
|
||||
struct TALER_ExtensionPolicyHashP *ph_policy = NULL;
|
||||
bool no_policy_details;
|
||||
bool no_policy_json;
|
||||
struct GNUNET_JSON_Specification spec[] = {
|
||||
GNUNET_JSON_spec_string ("merchant_payto_uri",
|
||||
&payto_uri),
|
||||
@ -255,8 +283,8 @@ TEH_handler_deposit (struct MHD_Connection *connection,
|
||||
&deposit.wire_deadline),
|
||||
GNUNET_JSON_spec_mark_optional (
|
||||
GNUNET_JSON_spec_json ("policy",
|
||||
&deposit.policy_details),
|
||||
&no_policy_details),
|
||||
&deposit.policy_json),
|
||||
&no_policy_json),
|
||||
GNUNET_JSON_spec_end ()
|
||||
};
|
||||
struct TALER_MerchantWireHashP h_wire;
|
||||
@ -284,7 +312,7 @@ TEH_handler_deposit (struct MHD_Connection *connection,
|
||||
}
|
||||
|
||||
/* set the state of the policy presence in the deposit struct */
|
||||
deposit.has_policy_details = ! no_policy_details;
|
||||
deposit.has_policy = ! no_policy_json;
|
||||
|
||||
/* validate merchant's wire details (as far as we can) */
|
||||
{
|
||||
@ -333,28 +361,6 @@ TEH_handler_deposit (struct MHD_Connection *connection,
|
||||
&h_wire);
|
||||
dc.deposit = &deposit;
|
||||
|
||||
/* Check policy */
|
||||
if (deposit.has_policy_details)
|
||||
{
|
||||
const char *error_hint = NULL;
|
||||
enum TALER_PolicyFulfilmentState state_on_timeout;
|
||||
|
||||
if (GNUNET_OK !=
|
||||
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 */
|
||||
dc.exchange_timestamp = GNUNET_TIME_timestamp_get ();
|
||||
/* check denomination exists and is valid */
|
||||
@ -420,13 +426,6 @@ TEH_handler_deposit (struct MHD_Connection *connection,
|
||||
NULL);
|
||||
}
|
||||
|
||||
if (deposit.has_policy_details)
|
||||
{
|
||||
TALER_deposit_policy_hash (deposit.policy_details,
|
||||
&deposit.h_policy);
|
||||
ph_policy = &deposit.h_policy;
|
||||
}
|
||||
|
||||
deposit.deposit_fee = dk->meta.fees.deposit;
|
||||
/* check coin signature */
|
||||
switch (dk->denom_pub.cipher)
|
||||
@ -463,6 +462,27 @@ TEH_handler_deposit (struct MHD_Connection *connection,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/* Check policy input and create policy details */
|
||||
if (deposit.has_policy)
|
||||
{
|
||||
const char *error_hint = NULL;
|
||||
|
||||
if (GNUNET_OK !=
|
||||
TALER_extensions_create_policy_details (
|
||||
deposit.policy_json,
|
||||
&deposit.policy_details,
|
||||
&error_hint))
|
||||
return TALER_MHD_reply_with_error (connection,
|
||||
MHD_HTTP_BAD_REQUEST,
|
||||
TALER_EC_EXCHANGE_DEPOSITS_POLICY_NOT_ACCEPTED,
|
||||
error_hint);
|
||||
|
||||
TALER_deposit_policy_hash (deposit.policy_json,
|
||||
&deposit.h_policy);
|
||||
ph_policy = &deposit.h_policy;
|
||||
}
|
||||
|
||||
|
||||
TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++;
|
||||
if (GNUNET_OK !=
|
||||
TALER_wallet_deposit_verify (&deposit.amount_with_fee,
|
||||
|
@ -14,7 +14,7 @@
|
||||
*/
|
||||
/**
|
||||
* @file taler-exchange-httpd_extensions.c
|
||||
* @brief Handle extensions (age-restriction, peer2peer)
|
||||
* @brief Handle extensions (age-restriction, policy extensions)
|
||||
* @author Özgür Kesim
|
||||
*/
|
||||
#include "platform.h"
|
||||
@ -232,4 +232,168 @@ TEH_extensions_done ()
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* @brief Execute database transactions for /extensions/policy_* POST requests.
|
||||
*
|
||||
* @param cls a `struct TALER_PolicyFulfillmentOutcome`
|
||||
* @param connection MHD request context
|
||||
* @param[out] mhd_ret set to MHD status on error
|
||||
* @return transaction status
|
||||
*/
|
||||
static enum GNUNET_DB_QueryStatus
|
||||
policy_fulfillment_transaction (
|
||||
void *cls,
|
||||
struct MHD_Connection *connection,
|
||||
MHD_RESULT *mhd_ret)
|
||||
{
|
||||
struct TALER_PolicyFulfillmentTransactionData *fulfillment = cls;
|
||||
|
||||
return TEH_plugin->add_policy_fulfillment_proof (TEH_plugin->cls,
|
||||
fulfillment);
|
||||
}
|
||||
|
||||
|
||||
MHD_RESULT
|
||||
TEH_extensions_post_handler (
|
||||
struct TEH_RequestContext *rc,
|
||||
const json_t *root,
|
||||
const char *const args[])
|
||||
{
|
||||
const struct TALER_Extension *ext = NULL;
|
||||
json_t *output;
|
||||
struct TALER_PolicyDetails *policy_details = NULL;
|
||||
size_t policy_details_count = 0;
|
||||
|
||||
|
||||
if (NULL == args[0])
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return TALER_MHD_reply_with_error (rc->connection,
|
||||
MHD_HTTP_NOT_FOUND,
|
||||
TALER_EC_EXCHANGE_GENERIC_OPERATION_UNKNOWN,
|
||||
"/extensions/$EXTENSION");
|
||||
}
|
||||
|
||||
ext = TALER_extensions_get_by_name (args[0]);
|
||||
if (NULL == ext)
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return TALER_MHD_reply_with_error (rc->connection,
|
||||
MHD_HTTP_NOT_FOUND,
|
||||
TALER_EC_EXCHANGE_GENERIC_OPERATION_UNKNOWN,
|
||||
"/extensions/$EXTENSION unknown");
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
/* Extract hash_codes and retrieve related policy_details from the DB */
|
||||
{
|
||||
enum GNUNET_GenericReturnValue ret;
|
||||
enum GNUNET_DB_QueryStatus qs;
|
||||
const char *error_msg;
|
||||
struct GNUNET_HashCode *hcs;
|
||||
size_t len;
|
||||
json_t*val;
|
||||
size_t idx;
|
||||
json_t *jhash_codes = json_object_get (root,
|
||||
"policy_hash_codes");
|
||||
if (! json_is_array (jhash_codes))
|
||||
return TALER_MHD_reply_with_error (rc->connection,
|
||||
MHD_HTTP_BAD_REQUEST,
|
||||
TALER_EC_EXCHANGE_GENERIC_OPERATION_UNKNOWN,
|
||||
"policy_hash_codes are missing");
|
||||
|
||||
len = json_array_size (jhash_codes);
|
||||
hcs = GNUNET_new_array (len,
|
||||
struct GNUNET_HashCode);
|
||||
policy_details = GNUNET_new_array (len,
|
||||
struct TALER_PolicyDetails);
|
||||
|
||||
json_array_foreach (jhash_codes, idx, val)
|
||||
{
|
||||
struct GNUNET_JSON_Specification spec[] = {
|
||||
GNUNET_JSON_spec_fixed_auto (NULL, &hcs[idx]),
|
||||
GNUNET_JSON_spec_end ()
|
||||
};
|
||||
|
||||
ret = GNUNET_JSON_parse (val,
|
||||
spec,
|
||||
&error_msg,
|
||||
NULL);
|
||||
if (GNUNET_OK != ret)
|
||||
break;
|
||||
|
||||
qs = TEH_plugin->get_policy_details (TEH_plugin->cls,
|
||||
&hcs[idx],
|
||||
&policy_details[idx]);
|
||||
if (qs < 0)
|
||||
{
|
||||
error_msg = "a policy_hash_code couldn't be found";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
GNUNET_free (hcs);
|
||||
if (GNUNET_OK != ret)
|
||||
{
|
||||
GNUNET_free (policy_details);
|
||||
return TALER_MHD_reply_with_error (rc->connection,
|
||||
MHD_HTTP_BAD_REQUEST,
|
||||
TALER_EC_EXCHANGE_GENERIC_OPERATION_UNKNOWN,
|
||||
error_msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
enum GNUNET_GenericReturnValue ret;
|
||||
|
||||
ret = ext->policy_post_handler (root,
|
||||
&args[1],
|
||||
policy_details,
|
||||
policy_details_count,
|
||||
&output);
|
||||
|
||||
if (GNUNET_OK != ret)
|
||||
{
|
||||
TALER_MHD_reply_json_steal (
|
||||
rc->connection,
|
||||
output,
|
||||
MHD_HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
/* execute fulfillment transaction */
|
||||
{
|
||||
MHD_RESULT mhd_ret;
|
||||
struct TALER_PolicyFulfillmentTransactionData fulfillment = {
|
||||
.proof = root,
|
||||
.timestamp = GNUNET_TIME_timestamp_get (),
|
||||
.details = policy_details,
|
||||
.details_count = policy_details_count
|
||||
};
|
||||
|
||||
if (GNUNET_OK !=
|
||||
TEH_DB_run_transaction (rc->connection,
|
||||
"execute policy fulfillment",
|
||||
TEH_MT_REQUEST_POLICY_FULFILMENT,
|
||||
&mhd_ret,
|
||||
&policy_fulfillment_transaction,
|
||||
&fulfillment))
|
||||
{
|
||||
json_decref (output);
|
||||
return mhd_ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TALER_MHD_reply_json_steal (rc->connection,
|
||||
output,
|
||||
MHD_HTTP_OK);
|
||||
}
|
||||
|
||||
|
||||
/* end of taler-exchange-httpd_extensions.c */
|
||||
|
@ -40,4 +40,19 @@ TEH_extensions_init (void);
|
||||
void
|
||||
TEH_extensions_done (void);
|
||||
|
||||
|
||||
/**
|
||||
* Handle POST "/extensions/..." requests.
|
||||
*
|
||||
* @param rc request context
|
||||
* @param root uploaded JSON data
|
||||
* @param args array of additional options
|
||||
* @return MHD result code
|
||||
*/
|
||||
MHD_RESULT
|
||||
TEH_extensions_post_handler (
|
||||
struct TEH_RequestContext *rc,
|
||||
const json_t *root,
|
||||
const char *const args[]);
|
||||
|
||||
#endif
|
||||
|
@ -44,7 +44,8 @@ enum TEH_MetricTypeRequest
|
||||
TEH_MT_REQUEST_IDEMPOTENT_MELT = 10,
|
||||
TEH_MT_REQUEST_IDEMPOTENT_BATCH_WITHDRAW = 11,
|
||||
TEH_MT_REQUEST_BATCH_DEPOSIT = 12,
|
||||
TEH_MT_REQUEST_COUNT = 13 /* MUST BE LAST! */
|
||||
TEH_MT_REQUEST_POLICY_FULFILMENT = 13,
|
||||
TEH_MT_REQUEST_COUNT = 14 /* MUST BE LAST! */
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -536,76 +536,69 @@ CREATE TABLE IF NOT EXISTS refresh_transfer_keys_default
|
||||
SELECT add_constraints_to_refresh_transfer_keys_partition('default');
|
||||
|
||||
|
||||
-- ------------------------------ policy_fulfilments -------------------------------------
|
||||
-- ------------------------------ policy_fulfillments -------------------------------------
|
||||
|
||||
CREATE TABLE IF NOT EXISTS policy_fulfilments
|
||||
(fulfilment_id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY
|
||||
,fulfilment_timestamp INT8 NOT NULL
|
||||
,fulfilment_proof VARCHAR)
|
||||
PARTITION BY HASH (fulfilment_id);
|
||||
COMMENT ON TABLE policy_fulfilments
|
||||
IS 'Proofs of fulfilment of policies that were set in deposits';
|
||||
COMMENT ON COLUMN policy_fulfilments.fulfilment_timestamp
|
||||
IS 'Timestamp of the arrival of a proof of fulfilment';
|
||||
COMMENT ON COLUMN policy_fulfilments.fulfilment_proof
|
||||
IS 'JSON object with a proof of the fulfilment of a policy. Supported details depend on the policy extensions supported by the exchange.';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS policy_fulfilments_default
|
||||
PARTITION OF policy_fulfilments
|
||||
FOR VALUES WITH (MODULUS 1, REMAINDER 0);
|
||||
CREATE TABLE IF NOT EXISTS policy_fulfillments
|
||||
(fulfillment_id BIGINT GENERATED BY DEFAULT AS IDENTITY UNIQUE PRIMARY KEY
|
||||
,fulfillment_timestamp INT8 NOT NULL
|
||||
,fulfillment_proof VARCHAR
|
||||
,h_fulfillment_proof BYTEA NOT NULL CHECK(LENGTH(h_fulfillment_proof) = 64) UNIQUE
|
||||
,policy_hash_codes BYTEA NOT NULL CHECK(0 = MOD(LENGTH(policy_hash_codes), 16))
|
||||
);
|
||||
COMMENT ON TABLE policy_fulfillments
|
||||
IS 'Proofs of fulfillment of policies that were set in deposits';
|
||||
COMMENT ON COLUMN policy_fulfillments.fulfillment_timestamp
|
||||
IS 'Timestamp of the arrival of a proof of fulfillment';
|
||||
COMMENT ON COLUMN policy_fulfillments.fulfillment_proof
|
||||
IS 'JSON object with a proof of the fulfillment of a policy. Supported details depend on the policy extensions supported by the exchange.';
|
||||
COMMENT ON COLUMN policy_fulfillments.h_fulfillment_proof
|
||||
IS 'Hash of the fulfillment_proof';
|
||||
COMMENT ON COLUMN policy_fulfillments.policy_hash_codes
|
||||
IS 'Concatenation of the policy_hash_code of all policy_details that are fulfilled by this proof';
|
||||
|
||||
-- ------------------------------ policy_details ----------------------------------------
|
||||
|
||||
CREATE TABLE IF NOT EXISTS policy_details
|
||||
(policy_details_serial_id BIGINT GENERATED BY DEFAULT AS IDENTITY
|
||||
,serial_id BYTEA PRIMARY KEY CHECK(LENGTH(serial_id)=64)
|
||||
,policy_options VARCHAR
|
||||
,policy_hash_code BYTEA PRIMARY KEY CHECK(LENGTH(policy_hash_code)=16)
|
||||
,policy_json VARCHAR
|
||||
,deadline INT8 NOT NULL
|
||||
,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);
|
||||
,commitment_val INT8 NOT NULL
|
||||
,commitment_frac INT4 NOT NULL
|
||||
,accumulated_total_val INT8 NOT NULL
|
||||
,accumulated_total_frac INT4 NOT NULL
|
||||
,fee_val INT8 NOT NULL
|
||||
,fee_frac INT4 NOT NULL
|
||||
,transferable_val INT8 NOT NULL
|
||||
,transferable_frac INT8 NOT NULL
|
||||
,fulfillment_state smallint NOT NULL CHECK(fulfillment_state between 0 and 5)
|
||||
,fulfillment_id BIGINT NULL REFERENCES policy_fulfillments (fulfillment_id) ON DELETE CASCADE
|
||||
);
|
||||
COMMENT ON TABLE policy_details
|
||||
IS 'Policies that were provided with deposits via policy extensions.';
|
||||
COMMENT ON COLUMN policy_details.serial_id
|
||||
COMMENT ON COLUMN policy_details.policy_hash_code
|
||||
IS 'ID (GNUNET_HashCode) that identifies a policy. Will be calculated by the policy extension based on the content';
|
||||
COMMENT ON COLUMN policy_details.policy_options
|
||||
COMMENT ON COLUMN policy_details.policy_json
|
||||
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 (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
|
||||
FOR VALUES WITH (MODULUS 1, REMAINDER 0);
|
||||
|
||||
-- ------------------------------ policy_details_fulfilments -----------------------------
|
||||
|
||||
CREATE TABLE IF NOT EXISTS policy_details_fulfilments
|
||||
(fulfilment_id BIGINT NOT NULL REFERENCES policy_fulfilments(fulfilment_id) ON DELETE CASCADE
|
||||
,serial_id BYTEA NOT NULL UNIQUE REFERENCES policy_details(serial_id) ON DELETE CASCADE)
|
||||
PARTITION BY HASH (serial_id); -- FIXME: choose other thing to hash here?
|
||||
-- FIXME: define a primary key here?
|
||||
COMMENT ON TABLE policy_details_fulfilments
|
||||
IS 'Links policy_details.serial_id''s with policy_fulfilments.id''s. The same proof of fulfilment can be associated with multiple serial-id''s';
|
||||
COMMENT ON COLUMN policy_details_fulfilments.fulfilment_id
|
||||
IS 'ID of the proof of fulfilment';
|
||||
COMMENT ON COLUMN policy_details_fulfilments.serial_id
|
||||
IS 'Serial-ID of the corresponding policy_detail';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS policy_details_fulfilments_default
|
||||
PARTITION OF policy_details_fulfilments
|
||||
FOR VALUES WITH (MODULUS 1, REMAINDER 0);
|
||||
|
||||
IS 'Deadline until the policy must be marked as fulfilled (maybe "forever")';
|
||||
COMMENT ON COLUMN policy_details.commitment_val
|
||||
IS 'The amount that this policy commits to. Invariant: commitment >= fee';
|
||||
COMMENT ON COLUMN policy_details.accumulated_total_val
|
||||
IS 'The sum of all contributions of all deposit that reference this policy. Invariant: The fulfilment_state must be Insufficient as long as accumulated_total < commitment';
|
||||
COMMENT ON COLUMN policy_details.fee_val
|
||||
IS 'The fee for this policy, due when the policy is fulfilled or timed out';
|
||||
COMMENT ON COLUMN policy_details.transferable_val
|
||||
IS 'The amount that on fulfilment or timeout will be transfered to the payto-URI''s of the corresponding deposit''s. The policy fees must have been already deducted from it. Invariant: fee+transferable <= accumulated_total. The remaining amount (accumulated_total - fee - transferable) can be refreshed by the owner of the coins when the state is Timeout or Success.';
|
||||
COMMENT ON COLUMN policy_details.fulfillment_state
|
||||
IS 'State of the fulfillment:
|
||||
- 0 (Failure)
|
||||
- 1 (Insufficient)
|
||||
- 2 (Ready)
|
||||
- 4 (Success)
|
||||
- 5 (Timeout)';
|
||||
COMMENT ON COLUMN policy_details.fulfillment_id
|
||||
IS 'Reference to the proof of the fulfillment of this policy, if it exists. Invariant: If not NULL, this entry''s .hash_code MUST be part of the corresponding policy_fulfillments.policy_hash_codes array.';
|
||||
|
||||
-- ------------------------------ deposits ----------------------------------------
|
||||
|
||||
|
@ -929,16 +929,18 @@ 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 ?
|
||||
GNUNET_PQ_query_param_null () :
|
||||
GNUNET_PQ_query_param_string (
|
||||
td->details.policy_details.policy_options),
|
||||
((NULL == td->details.policy_details.policy_json) ||
|
||||
(td->details.policy_details.no_policy_json))
|
||||
? GNUNET_PQ_query_param_null ()
|
||||
: TALER_PQ_query_param_json (td->details.policy_details.policy_json),
|
||||
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),
|
||||
&td->details.policy_details.fulfillment_state),
|
||||
(td->details.policy_details.no_fulfillment_id)
|
||||
? GNUNET_PQ_query_param_null ()
|
||||
: GNUNET_PQ_query_param_uint64 (
|
||||
&td->details.policy_details.fulfillment_id),
|
||||
GNUNET_PQ_query_param_end
|
||||
};
|
||||
|
||||
|
@ -1435,33 +1435,47 @@ lrbt_cb_table_policy_details (void *cls,
|
||||
unsigned int num_results)
|
||||
{
|
||||
struct LookupRecordsByTableContext *ctx = cls;
|
||||
struct PostgresClosure *pg = ctx->pg;
|
||||
struct TALER_EXCHANGEDB_TableData td = {
|
||||
.table = TALER_EXCHANGEDB_RT_POLICY_DETAILS
|
||||
};
|
||||
|
||||
for (unsigned int i = 0; i<num_results; i++)
|
||||
{
|
||||
bool no_config = false;
|
||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||
GNUNET_PQ_result_spec_uint64 ("policy_details_serial_id",
|
||||
&td.serial),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("serial_id",
|
||||
GNUNET_PQ_result_spec_auto_from_type ("hash_code",
|
||||
&td.details.policy_details.
|
||||
serial_id),
|
||||
hash_code),
|
||||
GNUNET_PQ_result_spec_allow_null (
|
||||
GNUNET_PQ_result_spec_string ("policy_options",
|
||||
TALER_PQ_result_spec_json ("policy_json",
|
||||
&td.details.policy_details.
|
||||
policy_options),
|
||||
&no_config),
|
||||
policy_json),
|
||||
&td.details.policy_details.no_policy_json),
|
||||
GNUNET_PQ_result_spec_timestamp ("deadline",
|
||||
&td.details.policy_details.
|
||||
deadline),
|
||||
GNUNET_PQ_result_spec_uint16 ("timeout_fulfilment_state",
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("commitment",
|
||||
&td.details.policy_details.
|
||||
timeout_fulfilment_state),
|
||||
GNUNET_PQ_result_spec_uint16 ("fulfilment_state",
|
||||
commitment),
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("accumulated_total",
|
||||
&td.details.policy_details.
|
||||
fulfilment_state),
|
||||
accumulated_total),
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("fee",
|
||||
&td.details.policy_details.
|
||||
fee),
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("transferable",
|
||||
&td.details.policy_details.
|
||||
transferable),
|
||||
GNUNET_PQ_result_spec_uint16 ("fulfillment_state",
|
||||
&td.details.policy_details.
|
||||
fulfillment_state),
|
||||
GNUNET_PQ_result_spec_allow_null (
|
||||
GNUNET_PQ_result_spec_uint64 ("fulfillment_id",
|
||||
&td.details.policy_details.
|
||||
fulfillment_id),
|
||||
&td.details.policy_details.no_fulfillment_id),
|
||||
GNUNET_PQ_result_spec_end
|
||||
};
|
||||
|
||||
@ -1482,14 +1496,14 @@ lrbt_cb_table_policy_details (void *cls,
|
||||
|
||||
|
||||
/**
|
||||
* Function called with policy_fulfilments table entries.
|
||||
* Function called with policy_fulfillments table entries.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param result the postgres result
|
||||
* @param num_results the number of results in @a result
|
||||
*/
|
||||
static void
|
||||
lrbt_cb_table_policy_fulfilments (void *cls,
|
||||
lrbt_cb_table_policy_fulfillments (void *cls,
|
||||
PGresult *result,
|
||||
unsigned int num_results)
|
||||
{
|
||||
@ -1503,17 +1517,17 @@ lrbt_cb_table_policy_fulfilments (void *cls,
|
||||
bool no_config = false;
|
||||
bool no_timestamp = false;
|
||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||
GNUNET_PQ_result_spec_uint64 ("fulfilment_id",
|
||||
GNUNET_PQ_result_spec_uint64 ("fulfillment_id",
|
||||
&td.serial),
|
||||
GNUNET_PQ_result_spec_allow_null (
|
||||
GNUNET_PQ_result_spec_timestamp ("fulfilment_timestamp",
|
||||
&td.details.policy_fulfilments.
|
||||
fulfilment_timestamp),
|
||||
GNUNET_PQ_result_spec_timestamp ("fulfillment_timestamp",
|
||||
&td.details.policy_fulfillments.
|
||||
fulfillment_timestamp),
|
||||
&no_timestamp),
|
||||
GNUNET_PQ_result_spec_allow_null (
|
||||
GNUNET_PQ_result_spec_string ("fulfilment_proof",
|
||||
&td.details.policy_fulfilments.
|
||||
fulfilment_proof),
|
||||
GNUNET_PQ_result_spec_string ("fulfillment_proof",
|
||||
&td.details.policy_fulfillments.
|
||||
fulfillment_proof),
|
||||
&no_config),
|
||||
GNUNET_PQ_result_spec_end
|
||||
};
|
||||
@ -1534,52 +1548,6 @@ lrbt_cb_table_policy_fulfilments (void *cls,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function called with policy_details_fulfilments table entries.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param result the postgres result
|
||||
* @param num_results the number of results in @a result
|
||||
*/
|
||||
static void
|
||||
lrbt_cb_table_policy_details_fulfilments (void *cls,
|
||||
PGresult *result,
|
||||
unsigned int num_results)
|
||||
{
|
||||
struct LookupRecordsByTableContext *ctx = cls;
|
||||
struct TALER_EXCHANGEDB_TableData td = {
|
||||
.table = TALER_EXCHANGEDB_RT_POLICY_DETAILS_FULFILMENTS
|
||||
};
|
||||
|
||||
for (unsigned int i = 0; i<num_results; i++)
|
||||
{
|
||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||
GNUNET_PQ_result_spec_uint64 ("fulfilment_id",
|
||||
&td.details.policy_details_fulfilments.
|
||||
fulfilment_id),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("serial_id",
|
||||
&td.details.
|
||||
policy_details_fulfilments.
|
||||
serial_id),
|
||||
GNUNET_PQ_result_spec_end
|
||||
};
|
||||
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_PQ_extract_result (result,
|
||||
rs,
|
||||
i))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
ctx->error = true;
|
||||
return;
|
||||
}
|
||||
ctx->cb (ctx->cb_cls,
|
||||
&td);
|
||||
GNUNET_PQ_cleanup_result (rs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function called with purse_requests table entries.
|
||||
*
|
||||
|
@ -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,$20);",
|
||||
20),
|
||||
" ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17);",
|
||||
17),
|
||||
/* used in postgres_do_purse_deposit() */
|
||||
GNUNET_PQ_make_prepare (
|
||||
"call_purse_deposit",
|
||||
@ -3927,37 +3927,45 @@ prepare_statements (struct PostgresClosure *pg)
|
||||
"($1, $2, $3);",
|
||||
3),
|
||||
GNUNET_PQ_make_prepare (
|
||||
"insert_into_table_policy_details",
|
||||
"INSERT INTO policy_details"
|
||||
"(policy_details_serial_id"
|
||||
",serial_id"
|
||||
",policy_options"
|
||||
",deadline"
|
||||
",timeout_fulfilment_state"
|
||||
",fulfilment_state"
|
||||
") VALUES "
|
||||
"($1, $2, $3, $4, $5, $6);",
|
||||
6),
|
||||
"call_insert_or_update_policy_details",
|
||||
"SELECT "
|
||||
" out_policy_details_serial_id as policy_serial_id"
|
||||
",out_accumulated_total_val as accumulated_total_val"
|
||||
",out_accumulated_total_frac as accumulated_total_frac"
|
||||
",out_fulfillment_state as fulfillment_state"
|
||||
" FROM insert_or_update_policy_details"
|
||||
" ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12);",
|
||||
12),
|
||||
GNUNET_PQ_make_prepare (
|
||||
"insert_into_table_policy_fulfilments",
|
||||
"INSERT INTO policy_fulfilments"
|
||||
"(fulfilment_id"
|
||||
",fulfilment_timestamp"
|
||||
",fulfilment_proof"
|
||||
"insert_proof_into_policy_fulfillments",
|
||||
"INSERT INTO policy_fulfillments "
|
||||
"(fulfillment_timestamp "
|
||||
",fulfillment_proof"
|
||||
",h_fulfillment_proof"
|
||||
",policy_hash_codes"
|
||||
") VALUES "
|
||||
"($1, $2, $3);",
|
||||
3),
|
||||
"($1, $2, $3, $4) "
|
||||
"RETURNING fulfillment_id;",
|
||||
4),
|
||||
GNUNET_PQ_make_prepare (
|
||||
"insert_into_table_policy_details_fulfilments",
|
||||
"INSERT INTO policy_details_fulfilments"
|
||||
"(fulfilment_id"
|
||||
",serial_id"
|
||||
") VALUES "
|
||||
"($1, $2);",
|
||||
2),
|
||||
"update_policy_details",
|
||||
"UPDATE policy_details "
|
||||
"SET "
|
||||
" deadline=$2,"
|
||||
" commitment_val=$3,"
|
||||
" commitment_frac=$4,"
|
||||
" accumulated_total_val=$5,"
|
||||
" accumulated_total_frac=$6,"
|
||||
" fee_val=$7,"
|
||||
" fee_frac=$8,"
|
||||
" transferable_val=$9,"
|
||||
" transferable_frac=$10,"
|
||||
" fulfillment_state=$11 "
|
||||
"WHERE policy_hash_code=$1;",
|
||||
11),
|
||||
GNUNET_PQ_make_prepare (
|
||||
"insert_into_table_purse_requests",
|
||||
"INSERT INTO purse_requests"
|
||||
"INSERT INTO purse_requests "
|
||||
"(purse_requests_serial_id"
|
||||
",purse_pub"
|
||||
",merge_pub"
|
||||
@ -6250,7 +6258,7 @@ compute_shard (const struct TALER_MerchantPublicKeyP *merchant_pub)
|
||||
* @param deposit deposit operation details
|
||||
* @param known_coin_id row of the coin in the known_coins table
|
||||
* @param h_payto hash of the merchant's bank account details
|
||||
* @param policy_blocked true if an extension is blocking the wire transfer
|
||||
* @param policy_details_serial_id (pointer to) the row ID in the policy_details table, maybe NULL.
|
||||
* @param[in,out] exchange_timestamp time to use for the deposit (possibly updated)
|
||||
* @param[out] balance_ok set to true if the balance was sufficient
|
||||
* @param[out] in_conflict set to true if the deposit conflicted
|
||||
@ -6262,6 +6270,7 @@ postgres_do_deposit (
|
||||
const struct TALER_EXCHANGEDB_Deposit *deposit,
|
||||
uint64_t known_coin_id,
|
||||
const struct TALER_PaytoHashP *h_payto,
|
||||
uint64_t *policy_details_serial_id,
|
||||
struct GNUNET_TIME_Timestamp *exchange_timestamp,
|
||||
bool *balance_ok,
|
||||
bool *in_conflict)
|
||||
@ -6283,19 +6292,10 @@ postgres_do_deposit (
|
||||
GNUNET_PQ_query_param_auto_from_type (&deposit->coin.coin_pub),
|
||||
GNUNET_PQ_query_param_auto_from_type (&deposit->csig),
|
||||
GNUNET_PQ_query_param_uint64 (&deposit_shard),
|
||||
GNUNET_PQ_query_param_bool (deposit->has_policy_details),
|
||||
(deposit->has_policy_details)
|
||||
? TALER_PQ_query_param_json (deposit->policy_details)
|
||||
: GNUNET_PQ_query_param_null (),
|
||||
(deposit->has_policy_details)
|
||||
? GNUNET_PQ_query_param_auto_from_type (&deposit->policy_serial_id)
|
||||
: GNUNET_PQ_query_param_null (),
|
||||
(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_bool (deposit->has_policy),
|
||||
(NULL == policy_details_serial_id)
|
||||
? GNUNET_PQ_query_param_null ()
|
||||
: GNUNET_PQ_query_param_uint64 (policy_details_serial_id),
|
||||
GNUNET_PQ_query_param_end
|
||||
};
|
||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||
@ -6315,6 +6315,101 @@ postgres_do_deposit (
|
||||
}
|
||||
|
||||
|
||||
/* Get the details of a policy, referenced by its hash code
|
||||
*
|
||||
* @param cls the `struct PostgresClosure` with the plugin-specific state
|
||||
* @param hc The hash code under which the details to a particular policy should be found
|
||||
* @param[out] details The found details
|
||||
* @return query execution status
|
||||
* */
|
||||
static enum GNUNET_DB_QueryStatus
|
||||
postgres_get_policy_details (
|
||||
void *cls,
|
||||
const struct GNUNET_HashCode *hc,
|
||||
struct TALER_PolicyDetails *details)
|
||||
{
|
||||
struct PostgresClosure *pg = cls;
|
||||
struct GNUNET_PQ_QueryParam params[] = {
|
||||
GNUNET_PQ_query_param_auto_from_type (hc),
|
||||
GNUNET_PQ_query_param_end
|
||||
};
|
||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||
GNUNET_PQ_result_spec_timestamp ("deadline",
|
||||
&details->deadline),
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("commitment",
|
||||
&details->commitment),
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("accumulated_total",
|
||||
&details->accumulated_total),
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("policy_fee",
|
||||
&details->policy_fee),
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("transferable_amount",
|
||||
&details->transferable_amount),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("state",
|
||||
&details->fulfillment_state),
|
||||
GNUNET_PQ_result_spec_allow_null (
|
||||
GNUNET_PQ_result_spec_uint64 ("policy_fulfillment_id",
|
||||
&details->policy_fulfillment_id),
|
||||
&details->no_policy_fulfillment_id),
|
||||
GNUNET_PQ_result_spec_end
|
||||
};
|
||||
|
||||
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
|
||||
"get_policy_details",
|
||||
params,
|
||||
rs);
|
||||
}
|
||||
|
||||
|
||||
/* Persist the details to a policy in the policy_details table. If there
|
||||
* already exists a policy, update the fields accordingly.
|
||||
*
|
||||
* @param details The policy details that should be persisted. If an entry for
|
||||
* the given details->hash_code exists, the values will be updated.
|
||||
* @param[out] policy_details_serial_id The row ID of the policy details
|
||||
* @param[out] accumulated_total The total amount accumulated in that policy
|
||||
* @param[out] fulfillment_state The state of policy. If the state was Insufficient prior to the call and the provided deposit raises the accumulated_total above the commitment, it will be set to Ready.
|
||||
* @return query execution status
|
||||
*/
|
||||
static enum GNUNET_DB_QueryStatus
|
||||
postgres_persist_policy_details (
|
||||
void *cls,
|
||||
const struct TALER_PolicyDetails *details,
|
||||
uint64_t *policy_details_serial_id,
|
||||
struct TALER_Amount *accumulated_total,
|
||||
enum TALER_PolicyFulfillmentState *fulfillment_state)
|
||||
{
|
||||
struct PostgresClosure *pg = cls;
|
||||
struct GNUNET_PQ_QueryParam params[] = {
|
||||
GNUNET_PQ_query_param_auto_from_type (&details->hash_code),
|
||||
TALER_PQ_query_param_json (details->policy_json),
|
||||
GNUNET_PQ_query_param_timestamp (&details->deadline),
|
||||
TALER_PQ_query_param_amount (&details->commitment),
|
||||
TALER_PQ_query_param_amount (&details->accumulated_total),
|
||||
TALER_PQ_query_param_amount (&details->policy_fee),
|
||||
TALER_PQ_query_param_amount (&details->transferable_amount),
|
||||
GNUNET_PQ_query_param_auto_from_type (&details->fulfillment_state),
|
||||
(details->no_policy_fulfillment_id)
|
||||
? GNUNET_PQ_query_param_null ()
|
||||
: GNUNET_PQ_query_param_uint64 (&details->policy_fulfillment_id),
|
||||
GNUNET_PQ_query_param_end
|
||||
};
|
||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||
GNUNET_PQ_result_spec_uint64 ("policy_details_serial_id",
|
||||
policy_details_serial_id),
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("accumulated_total",
|
||||
accumulated_total),
|
||||
GNUNET_PQ_result_spec_uint32 ("fulfillment_state",
|
||||
fulfillment_state),
|
||||
GNUNET_PQ_result_spec_end
|
||||
};
|
||||
|
||||
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
|
||||
"call_insert_or_update_policy_details",
|
||||
params,
|
||||
rs);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Perform melt operation, checking for sufficient balance
|
||||
* of the coin and possibly persisting the melt details.
|
||||
@ -6569,6 +6664,118 @@ postgres_do_recoup_refresh (
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Compares two indices into an array of hash codes according to
|
||||
* GNUNET_CRYPTO_hash_cmp of the content at those index positions.
|
||||
*
|
||||
* Used in a call qsort_t in order to generate sorted policy_hash_codes.
|
||||
*/
|
||||
static int
|
||||
hash_code_cmp (
|
||||
const void *hc1,
|
||||
const void *hc2,
|
||||
void *arg)
|
||||
{
|
||||
size_t i1 = *(size_t *) hc1;
|
||||
size_t i2 = *(size_t *) hc2;
|
||||
const struct TALER_PolicyDetails *d = arg;
|
||||
|
||||
return GNUNET_CRYPTO_hash_cmp (&d[i1].hash_code,
|
||||
&d[i2].hash_code);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add a proof of fulfillment into the policy_fulfillments table
|
||||
*
|
||||
* @param cls the `struct PostgresClosure` with the plugin-specific state
|
||||
* @param[out] proof_id set record id for the proof
|
||||
* @return query execution status
|
||||
*/
|
||||
static enum GNUNET_DB_QueryStatus
|
||||
postgres_add_policy_fulfillment_proof (
|
||||
void *cls,
|
||||
struct TALER_PolicyFulfillmentTransactionData *fulfillment)
|
||||
{
|
||||
enum GNUNET_DB_QueryStatus qs;
|
||||
struct PostgresClosure *pg = cls;
|
||||
size_t count = fulfillment->details_count;
|
||||
struct GNUNET_HashCode hcs[count];
|
||||
|
||||
/* Create the sorted policy_hash_codes */
|
||||
{
|
||||
size_t idx[count];
|
||||
for (size_t i = 0; i < count; i++)
|
||||
idx[i] = i;
|
||||
|
||||
/* Sort the indices according to the hash codes of the corresponding
|
||||
* details. */
|
||||
qsort_r (idx,
|
||||
count,
|
||||
sizeof(size_t),
|
||||
hash_code_cmp,
|
||||
fulfillment->details);
|
||||
|
||||
/* Finally, concatenate all hash_codes in sorted order */
|
||||
for (size_t i = 0; i < count; i++)
|
||||
hcs[i] = fulfillment->details[idx[i]].hash_code;
|
||||
}
|
||||
|
||||
|
||||
/* Now, add the proof to the policy_fulfillments table, retrieve the
|
||||
* record_id */
|
||||
{
|
||||
struct GNUNET_PQ_QueryParam params[] = {
|
||||
GNUNET_PQ_query_param_timestamp (&fulfillment->timestamp),
|
||||
TALER_PQ_query_param_json (fulfillment->proof),
|
||||
GNUNET_PQ_query_param_auto_from_type (&fulfillment->h_proof),
|
||||
GNUNET_PQ_query_param_fixed_size (hcs,
|
||||
count * sizeof(struct GNUNET_HashCode)),
|
||||
GNUNET_PQ_query_param_end
|
||||
};
|
||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||
GNUNET_PQ_result_spec_uint64 ("fulfillment_id",
|
||||
&fulfillment->fulfillment_id),
|
||||
GNUNET_PQ_result_spec_end
|
||||
};
|
||||
|
||||
qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
|
||||
"insert_proof_into_policy_fulfillments",
|
||||
params,
|
||||
rs);
|
||||
if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
|
||||
return qs;
|
||||
}
|
||||
|
||||
/* Now, set the states of each entry corresponding to the hash_codes in
|
||||
* policy_details accordingly */
|
||||
for (size_t i = 0; i < count; i++)
|
||||
{
|
||||
struct TALER_PolicyDetails *pos = &fulfillment->details[i];
|
||||
{
|
||||
struct GNUNET_PQ_QueryParam params[] = {
|
||||
GNUNET_PQ_query_param_auto_from_type (&pos->hash_code),
|
||||
GNUNET_PQ_query_param_timestamp (&pos->deadline),
|
||||
TALER_PQ_query_param_amount (&pos->commitment),
|
||||
TALER_PQ_query_param_amount (&pos->accumulated_total),
|
||||
TALER_PQ_query_param_amount (&pos->policy_fee),
|
||||
TALER_PQ_query_param_amount (&pos->transferable_amount),
|
||||
GNUNET_PQ_query_param_auto_from_type (&pos->fulfillment_state),
|
||||
GNUNET_PQ_query_param_end
|
||||
};
|
||||
|
||||
qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
|
||||
"update_policy_details",
|
||||
params);
|
||||
if (qs < 0)
|
||||
return qs;
|
||||
}
|
||||
}
|
||||
|
||||
return qs;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Closure for callbacks invoked via #postgres_get_reserve_history.
|
||||
*/
|
||||
@ -14470,8 +14677,8 @@ postgres_lookup_records_by_table (void *cls,
|
||||
rh = &lrbt_cb_table_policy_details;
|
||||
break;
|
||||
case TALER_EXCHANGEDB_RT_POLICY_FULFILMENTS:
|
||||
statement = "select_above_serial_by_table_policy_fulfilments";
|
||||
rh = &lrbt_cb_table_policy_fulfilments;
|
||||
statement = "select_above_serial_by_table_policy_fulfillments";
|
||||
rh = &lrbt_cb_table_policy_fulfillments;
|
||||
break;
|
||||
case TALER_EXCHANGEDB_RT_PURSE_REQUESTS:
|
||||
statement = "select_above_serial_by_table_purse_requests";
|
||||
@ -14655,7 +14862,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 */
|
||||
/* TODO: policy_details_fulfillments and policy_fulfillments */
|
||||
case TALER_EXCHANGEDB_RT_PURSE_REQUESTS:
|
||||
rh = &irbt_cb_table_purse_requests;
|
||||
break;
|
||||
@ -17110,7 +17317,10 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
|
||||
plugin->do_withdraw = &postgres_do_withdraw;
|
||||
plugin->do_batch_withdraw = &postgres_do_batch_withdraw;
|
||||
plugin->do_batch_withdraw_insert = &postgres_do_batch_withdraw_insert;
|
||||
plugin->get_policy_details = &postgres_get_policy_details;
|
||||
plugin->persist_policy_details = &postgres_persist_policy_details;
|
||||
plugin->do_deposit = &postgres_do_deposit;
|
||||
plugin->add_policy_fulfillment_proof = &postgres_add_policy_fulfillment_proof;
|
||||
plugin->do_melt = &postgres_do_melt;
|
||||
plugin->do_refund = &postgres_do_refund;
|
||||
plugin->do_recoup = &postgres_do_recoup;
|
||||
|
@ -511,10 +511,7 @@ CREATE OR REPLACE FUNCTION exchange_do_deposit(
|
||||
IN in_coin_sig BYTEA,
|
||||
IN in_shard INT8,
|
||||
IN in_policy_blocked BOOLEAN,
|
||||
IN in_policy_details VARCHAR,
|
||||
IN in_policy_serial_id BYTEA,
|
||||
IN in_policy_deadline SMALLINT,
|
||||
IN in_policy_timeout_fulfilment_state SMALLINT,
|
||||
IN in_policy_details_serial_id INT8,
|
||||
OUT out_exchange_timestamp INT8,
|
||||
OUT out_balance_ok BOOLEAN,
|
||||
OUT out_conflict BOOLEAN)
|
||||
@ -522,34 +519,11 @@ LANGUAGE plpgsql
|
||||
AS $$
|
||||
DECLARE
|
||||
wtsi INT8; -- wire target serial id
|
||||
DECLARE
|
||||
xdi INT8; -- eXstension details serial id
|
||||
BEGIN
|
||||
-- Shards: INSERT policy_details (by policy_details_serial_id)
|
||||
-- INSERT wire_targets (by h_payto), on CONFLICT DO NOTHING;
|
||||
-- Shards: INSERT wire_targets (by h_payto), on CONFLICT DO NOTHING;
|
||||
-- INSERT deposits (by coin_pub, shard), ON CONFLICT DO NOTHING;
|
||||
-- UPDATE known_coins (by coin_pub)
|
||||
|
||||
IF NOT NULL in_policy_details
|
||||
THEN
|
||||
INSERT INTO exchange.policy_details
|
||||
(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
|
||||
xdi=NULL;
|
||||
END IF;
|
||||
|
||||
|
||||
INSERT INTO exchange.wire_targets
|
||||
(wire_target_h_payto
|
||||
,payto_uri)
|
||||
@ -602,7 +576,8 @@ INSERT INTO exchange.deposits
|
||||
,in_wire_salt
|
||||
,in_h_payto
|
||||
,in_policy_blocked
|
||||
,xdi)
|
||||
,in_policy_details_serial_id
|
||||
)
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
IF NOT FOUND
|
||||
@ -622,6 +597,7 @@ THEN
|
||||
AND wire_target_h_payto=in_h_payto
|
||||
AND coin_pub=in_coin_pub
|
||||
AND coin_sig=in_coin_sig;
|
||||
-- AND policy_details_serial_id=in_policy_details_serial_id; -- FIXME: is this required for idempotency?
|
||||
|
||||
IF NOT FOUND
|
||||
THEN
|
||||
@ -2211,5 +2187,123 @@ BEGIN
|
||||
|
||||
END $$;
|
||||
|
||||
CREATE OR REPLACE FUNCTION insert_or_update_policy_details(
|
||||
IN in_policy_hash_code BYTEA,
|
||||
IN in_policy_json VARCHAR,
|
||||
IN in_deadline INT8,
|
||||
IN in_commitment_val INT8,
|
||||
IN in_commitment_frac INT4,
|
||||
IN in_accumulated_total_val INT8,
|
||||
IN in_accumulated_total_frac INT4,
|
||||
IN in_fee_val INT8,
|
||||
IN in_fee_frac INT4,
|
||||
IN in_transferable_val INT8,
|
||||
IN in_transferable_frac INT4,
|
||||
IN in_fulfillment_state SMALLINT,
|
||||
OUT out_policy_details_serial_id INT8,
|
||||
OUT out_accumulated_total_val INT8,
|
||||
OUT out_accumulated_total_frac INT4,
|
||||
OUT out_fulfillment_state SMALLINT)
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
DECLARE
|
||||
cur_commiment_val INT8;
|
||||
cur_commiment_frac INT4;
|
||||
cur_accumulated_total_val INT8;
|
||||
cur_accumulated_total_frac INT4;
|
||||
BEGIN
|
||||
-- First, try to create a new entry.
|
||||
INSERT INTO policy_details
|
||||
(policy_hash_code,
|
||||
policy_json,
|
||||
deadline,
|
||||
commitment_val,
|
||||
commitment_frac,
|
||||
accumulated_total_val,
|
||||
accumulated_total_frac,
|
||||
fee_val,
|
||||
fee_frac,
|
||||
transferable_val,
|
||||
transferable_frac,
|
||||
fulfillment_state)
|
||||
VALUES (in_policy_hash_code,
|
||||
in_policy_json,
|
||||
in_deadline,
|
||||
in_commitment_val,
|
||||
in_commitment_frac,
|
||||
in_accumulated_total_val,
|
||||
in_accumulated_total_frac,
|
||||
in_fee_val,
|
||||
in_fee_frac,
|
||||
in_transferable_val,
|
||||
in_transferable_frac,
|
||||
in_fulfillment_state)
|
||||
RETURNING (policy_details_serial_id,
|
||||
accumulated_total_val,
|
||||
accumulated_total_frac,
|
||||
fulfillment_state)
|
||||
INTO (out_policy_details_serial_id,
|
||||
out_accumulated_total_val,
|
||||
out_accumulated_total_frac,
|
||||
out_fulfillment_state)
|
||||
ON CONFLICT (policy_hash_code) DO NOTHING;
|
||||
|
||||
-- If the insert was successful, return
|
||||
-- We assume that the fullfilment_state was correct in first place.
|
||||
IF FOUND THEN
|
||||
RETURN;
|
||||
END IF;
|
||||
|
||||
-- We had a conflict, grab the parts we need to update.
|
||||
SELECT (policy_details_serial_id,
|
||||
commitment_val,
|
||||
commitment_frac,
|
||||
accumulated_total_val,
|
||||
accumulated_total_frac)
|
||||
INTO (out_policy_details_serial_id,
|
||||
cur_commitment_val,
|
||||
cur_commitment_frac,
|
||||
cur_accumulated_total_val,
|
||||
cur_accumulated_total_frac)
|
||||
FROM policy_details
|
||||
WHERE policy_hash_code = in_policy_hash_code;
|
||||
|
||||
-- calculate the new values (overflows throws exception)
|
||||
out_accumulated_total_val = cur_accumulated_total_val + in_accumulated_total_val;
|
||||
out_accumulated_total_frac = cur_accumulated_total_frac + in_accumulated_total_frac;
|
||||
-- normalize
|
||||
out_accumulated_total_val = out_accumulated_total_val + out_accumulated_total_frac / 100000000;
|
||||
out_accumulated_total_frac = out_accumulated_total_frac % 100000000;
|
||||
|
||||
IF (out_accumulated_total_val > (1 << 52))
|
||||
THEN
|
||||
RAISE EXCEPTION "accumulation overflow";
|
||||
END IF;
|
||||
|
||||
|
||||
-- Set the fulfillment_state according to the values.
|
||||
-- For now, we only update the state when it was INSUFFICIENT.
|
||||
-- FIXME: What to do in case of Failure or other state?
|
||||
IF (out_fullfillment_state = 1) -- INSUFFICIENT
|
||||
THEN
|
||||
IF (out_accumulated_total_val >= cur_commitment_val OR
|
||||
(out_accumulated_total_val = cur_commitment_val AND
|
||||
out_accumulated_total_frac >= cur_commitment_frac))
|
||||
THEN
|
||||
out_fulfillment_state = 2; -- READY
|
||||
END IF;
|
||||
END IF;
|
||||
|
||||
-- Now, update the record
|
||||
UPDATE exchange.policy_details
|
||||
SET
|
||||
accumulated_val = out_accumulated_total_val,
|
||||
accumulated_frac = out_accumulated_total_frac,
|
||||
fulfillment_state = out_fulfillment_state
|
||||
WHERE
|
||||
policy_details_serial_id = out_policy_details_serial_id;
|
||||
END $$;
|
||||
|
||||
|
||||
|
||||
COMMIT;
|
||||
|
@ -1500,6 +1500,7 @@ run (void *cls)
|
||||
&deposit,
|
||||
known_coin_id,
|
||||
&h_payto,
|
||||
NULL, /* no policy_details_serial_id */
|
||||
&deposit_timestamp,
|
||||
&balance_ok,
|
||||
&in_conflict));
|
||||
|
@ -153,7 +153,7 @@ struct TALER_Extension TE_age_restriction = {
|
||||
.manifest = &age_restriction_manifest,
|
||||
|
||||
/* This extension is not a policy extension */
|
||||
.parse_policy_details = NULL,
|
||||
.create_policy_details = NULL,
|
||||
.policy_get_handler = NULL,
|
||||
.policy_post_handler = NULL,
|
||||
};
|
||||
|
@ -357,31 +357,27 @@ 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",
|
||||
static char *fulfillment2str[] = {
|
||||
[TALER_PolicyFulfillmentReady] = "Ready",
|
||||
[TALER_PolicyFulfillmentSuccess] = "Success",
|
||||
[TALER_PolicyFulfillmentFailure] = "Failure",
|
||||
[TALER_PolicyFulfillmentTimeout] = "Timeout",
|
||||
[TALER_PolicyFulfillmentInsufficient] = "Insufficient",
|
||||
};
|
||||
|
||||
const char *
|
||||
TALER_policy_fulfilment_state_str (
|
||||
enum TALER_PolicyFulfilmentState state)
|
||||
TALER_policy_fulfillment_state_str (
|
||||
enum TALER_PolicyFulfillmentState state)
|
||||
{
|
||||
GNUNET_assert (TALER_PolicyFulfilmentStateMax >= state);
|
||||
return fulfilment2str[state];
|
||||
GNUNET_assert (TALER_PolicyFulfillmentStateCount > state);
|
||||
return fulfillment2str[state];
|
||||
}
|
||||
|
||||
|
||||
enum GNUNET_GenericReturnValue
|
||||
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,
|
||||
TALER_extensions_create_policy_details (
|
||||
const json_t *policy_options,
|
||||
struct TALER_PolicyDetails *details,
|
||||
const char **error_hint)
|
||||
{
|
||||
enum GNUNET_GenericReturnValue ret;
|
||||
@ -391,14 +387,14 @@ TALER_extensions_extract_meta_data_from_policy_details (
|
||||
|
||||
*error_hint = NULL;
|
||||
|
||||
if ((NULL == policy_details) ||
|
||||
(! json_is_object (policy_details)))
|
||||
if ((NULL == policy_options) ||
|
||||
(! json_is_object (policy_options)))
|
||||
{
|
||||
*error_hint = "invalid policy object";
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
jtype = json_object_get (policy_details, "type");
|
||||
jtype = json_object_get (policy_options, "type");
|
||||
if (NULL == jtype)
|
||||
{
|
||||
*error_hint = "no type in policy object";
|
||||
@ -414,7 +410,7 @@ TALER_extensions_extract_meta_data_from_policy_details (
|
||||
|
||||
extension = TALER_extensions_get_by_name (type);
|
||||
if ((NULL == extension) ||
|
||||
(NULL == extension->parse_policy_details))
|
||||
(NULL == extension->create_policy_details))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
||||
@ -423,50 +419,13 @@ TALER_extensions_extract_meta_data_from_policy_details (
|
||||
return GNUNET_NO;
|
||||
}
|
||||
|
||||
*deadline = GNUNET_TIME_UNIT_FOREVER_TS;
|
||||
ret = extension->parse_policy_details (policy_details,
|
||||
serial,
|
||||
deadline,
|
||||
state_on_deadline,
|
||||
details->deadline = GNUNET_TIME_UNIT_FOREVER_TS;
|
||||
ret = extension->create_policy_details (policy_options,
|
||||
details,
|
||||
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 */
|
||||
|
@ -31,7 +31,7 @@
|
||||
#define MAX_RESULT_SIZE 10 * 1024
|
||||
|
||||
/* (public) configuration of this extension */
|
||||
/* TODO: these fields need to be set in the init handler */
|
||||
/* FIXME: these fields need to be set in the init handler */
|
||||
static struct TALER_ExtensionPolicyBrandtVickreyAuctionConfig BV_config = {
|
||||
.max_bidders = 10,
|
||||
.max_prices = 10,
|
||||
@ -82,8 +82,8 @@ struct transcript
|
||||
/* Hash of the auction */
|
||||
struct GNUNET_HashCode h_auction;
|
||||
|
||||
/* (n-1) calculated serial_ids */
|
||||
struct GNUNET_HashCode *serial_ids;
|
||||
/* (n-1) calculated hash_codes */
|
||||
struct GNUNET_HashCode *hash_codes;
|
||||
|
||||
|
||||
/* Type of auction, see libbrandt */
|
||||
@ -146,7 +146,7 @@ json_error (json_t **output,
|
||||
|
||||
/* Create serial as H(bidder_pub, h_auction) */
|
||||
static void
|
||||
calculate_serial (
|
||||
calculate_hashcode (
|
||||
struct GNUNET_CRYPTO_EddsaPublicKey *pub,
|
||||
struct GNUNET_HashCode *hc,
|
||||
struct GNUNET_HashCode *serial)
|
||||
@ -171,7 +171,7 @@ calculate_serial (
|
||||
* @param[out] jerror JSON output for errors
|
||||
* @return GNUNET_OK on succes
|
||||
*
|
||||
* TODO:
|
||||
* FIXME:
|
||||
* - parse and verify signatures
|
||||
*/
|
||||
static enum GNUNET_GenericReturnValue
|
||||
@ -181,7 +181,7 @@ parse_transcript (const json_t *jtr,
|
||||
{
|
||||
json_t *auc;
|
||||
|
||||
// TODO: struct GNUNET_CRYPTO_EddsaSignature sig;
|
||||
// FIXME: struct GNUNET_CRYPTO_EddsaSignature sig;
|
||||
|
||||
GNUNET_assert (jtr);
|
||||
GNUNET_assert (tr);
|
||||
@ -272,7 +272,7 @@ parse_transcript (const json_t *jtr,
|
||||
tr->n,
|
||||
struct GNUNET_CRYPTO_EddsaPublicKey);
|
||||
|
||||
tr->serial_ids = GNUNET_new_array (
|
||||
tr->hash_codes = GNUNET_new_array (
|
||||
tr->n,
|
||||
struct GNUNET_HashCode);
|
||||
|
||||
@ -284,7 +284,7 @@ parse_transcript (const json_t *jtr,
|
||||
GNUNET_JSON_spec_end (),
|
||||
};
|
||||
|
||||
/* TODO: cleanup */
|
||||
/* FIXME: cleanup */
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_JSON_parse (val,
|
||||
spec,
|
||||
@ -294,9 +294,9 @@ parse_transcript (const json_t *jtr,
|
||||
"bidder no %ld public key couldn't be parsed",
|
||||
idx + 1);
|
||||
|
||||
calculate_serial (&tr->bidder_pub[idx],
|
||||
calculate_hashcode (&tr->bidder_pub[idx],
|
||||
&tr->h_auction,
|
||||
&tr->serial_ids[idx]);
|
||||
&tr->hash_codes[idx]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -316,7 +316,7 @@ parse_transcript (const json_t *jtr,
|
||||
return json_error (jerror,
|
||||
"not the right no. of messages found");
|
||||
|
||||
/* TODO: parse and evaluate signatures */
|
||||
/* FIXME: parse and evaluate signatures */
|
||||
}
|
||||
|
||||
// Winners
|
||||
@ -358,9 +358,9 @@ parse_transcript (const json_t *jtr,
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: parse and evalue sig of seller
|
||||
// FIXME: parse and evalue sig of seller
|
||||
|
||||
// TODO: check for max values
|
||||
// FIXME: check for max values
|
||||
|
||||
DONE:
|
||||
|
||||
@ -373,16 +373,18 @@ DONE:
|
||||
*
|
||||
* @param[in] root The original JSON transcript
|
||||
* @param[in,out] transcript The transcript object parsed so far
|
||||
* @param[out] outcome Outcome object to fill
|
||||
* @param[in/out] details Array of policy details, provided by the exchange
|
||||
* @param[in] details_count number of elements in @e details
|
||||
* @param[out] result The JSON result from the program
|
||||
* @return GNUNET_OK on success
|
||||
*
|
||||
* TODO: Make this resumable
|
||||
* FIXME: Make this resumable
|
||||
*/
|
||||
static enum GNUNET_GenericReturnValue
|
||||
replay_transcript (const json_t*root,
|
||||
struct transcript *tr,
|
||||
struct TALER_PolicyFulfilmentOutcome **outcome,
|
||||
struct TALER_PolicyDetails *details,
|
||||
size_t details_count,
|
||||
json_t **result)
|
||||
{
|
||||
enum GNUNET_GenericReturnValue ret = GNUNET_SYSERR;
|
||||
@ -488,30 +490,33 @@ replay_transcript (const json_t*root,
|
||||
return json_error (result, "internal error");
|
||||
}
|
||||
|
||||
// TODO: check each winner with tr->expected, if applicable
|
||||
// FIXME: check each winner with tr->expected, if applicable
|
||||
|
||||
|
||||
// Create the outcome object
|
||||
/* First, set all details to default state and values */
|
||||
for (size_t i = 0; i< tr->n; i++)
|
||||
{
|
||||
/* no fees for non-winners */
|
||||
TALER_amount_set_zero (details[i].policy_fee.currency,
|
||||
&details[i].policy_fee);
|
||||
|
||||
/* no transferable amounts (=> accumulated_total becomes refreshable) */
|
||||
TALER_amount_set_zero (details[i].transferable_amount.currency,
|
||||
&details[i].transferable_amount);
|
||||
|
||||
details[i].fulfillment_state = TALER_PolicyFulfillmentSuccess;
|
||||
}
|
||||
|
||||
|
||||
/* Now, fill the winner details */
|
||||
{
|
||||
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; i<tr->n; 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)
|
||||
{
|
||||
// TODO
|
||||
enum GNUNET_GenericReturnValue ret;
|
||||
const char *jerror;
|
||||
uint16_t bidder;
|
||||
@ -540,7 +545,7 @@ replay_transcript (const json_t*root,
|
||||
LOG_PREFIX
|
||||
"couldn't parse output of replay program: %s\n",
|
||||
jerror);
|
||||
ret = json_error (result, "internal error");
|
||||
ret = json_error (result, "internal error (replay)");
|
||||
goto DONE;
|
||||
}
|
||||
|
||||
@ -549,19 +554,41 @@ replay_transcript (const json_t*root,
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
LOG_PREFIX
|
||||
"replay program sent a bidder out of range\n");
|
||||
ret = json_error (result, "internal error");
|
||||
ret = json_error (result, "internal error (bidder)");
|
||||
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;
|
||||
// Fill the details for this winning bidder.
|
||||
{
|
||||
struct TALER_PolicyDetails *det = NULL;
|
||||
struct GNUNET_HashCode *hc = &tr->hash_codes[idx];
|
||||
|
||||
/* Find the corresponding details */
|
||||
for (size_t i = 0; i < tr->n; i++)
|
||||
{
|
||||
if (GNUNET_CRYPTO_hash_cmp (hc,
|
||||
&details[idx].hash_code))
|
||||
{
|
||||
det = &details[idx];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: return own result object.
|
||||
// TODO: sign the result by the exchange
|
||||
if (NULL == det)
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
LOG_PREFIX
|
||||
"Couldeln't find calculate hash code %s in details\n",
|
||||
GNUNET_h2s (hc));
|
||||
ret = json_error (result, "internal error (details)");
|
||||
goto DONE;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: return own result object.
|
||||
// FIXME: sign the result by the exchange
|
||||
*result = json_copy (res);
|
||||
json_decref (res);
|
||||
}
|
||||
@ -582,11 +609,6 @@ replay_transcript (const json_t*root,
|
||||
}
|
||||
|
||||
DONE:
|
||||
if (GNUNET_OK != ret)
|
||||
{
|
||||
TALER_policy_fulfilment_outcome_free (*outcome);
|
||||
*outcome = NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -642,7 +664,7 @@ auction_load_config (
|
||||
struct TALER_Extension *ext,
|
||||
json_t *jconfig)
|
||||
{
|
||||
/* TODO: parse configuration */
|
||||
/* FIXME: parse configuration */
|
||||
ext->enabled = true;
|
||||
return GNUNET_OK;
|
||||
}
|
||||
@ -656,7 +678,7 @@ auction_policy_get_handler (
|
||||
struct MHD_Connection *connection,
|
||||
const char *const args[])
|
||||
{
|
||||
/* TODO: return some meta-data about supported version, limits, etc.*/
|
||||
/* FIXME: return some meta-data about supported version, limits, etc.*/
|
||||
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
||||
LOG_PREFIX "auction_policy_get_handler not implemented yet\n");
|
||||
@ -672,55 +694,89 @@ auction_policy_get_handler (
|
||||
/**
|
||||
* @brief implements the TALER_Extension.policy_post_handler
|
||||
*
|
||||
* TODO: make this non-blocking
|
||||
* FIXME: make this non-blocking
|
||||
*/
|
||||
enum GNUNET_GenericReturnValue
|
||||
auction_policy_post_handler (
|
||||
const json_t *root,
|
||||
const char *const args[],
|
||||
enum GNUNET_GenericReturnValue (*serial_id_check)(struct GNUNET_HashCode
|
||||
serial_ids[], size_t size),
|
||||
struct TALER_PolicyFulfilmentOutcome **outcome,
|
||||
struct TALER_PolicyDetails *details,
|
||||
size_t details_len,
|
||||
json_t **output)
|
||||
{
|
||||
struct transcript tr = {};
|
||||
struct transcript tr = {0};
|
||||
enum GNUNET_GenericReturnValue ret;
|
||||
|
||||
*outcome = NULL;
|
||||
do {
|
||||
ret = parse_transcript (root,
|
||||
&tr,
|
||||
output);
|
||||
|
||||
/* TODO: cleanups! */
|
||||
if (GNUNET_OK != ret)
|
||||
return ret;
|
||||
break;
|
||||
|
||||
serial_id_check (tr.serial_ids, tr.n);
|
||||
/* Compare the calculated hash_codes of policies with the provided onces */
|
||||
{
|
||||
if (details_len != tr.n)
|
||||
{
|
||||
ret = json_error (output, "wrong number of bidders");
|
||||
break;
|
||||
}
|
||||
|
||||
return replay_transcript (root,
|
||||
for (size_t i = 0; i<details_len; i++)
|
||||
{
|
||||
bool found = false;
|
||||
for (size_t j = 0; j<tr.n; j++)
|
||||
{
|
||||
if (GNUNET_CRYPTO_hash_cmp (&details[i].hash_code,
|
||||
&tr.hash_codes[j]))
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (! found)
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"details[%ld].hash_code %s not found in transcript\n",
|
||||
i,
|
||||
GNUNET_h2s (&details[i].hash_code));
|
||||
ret = json_error (output, "internal error (hash_code)");
|
||||
goto END;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret = replay_transcript (root,
|
||||
&tr,
|
||||
outcome,
|
||||
details,
|
||||
details_len,
|
||||
output);
|
||||
} while(0);
|
||||
|
||||
END:
|
||||
GNUNET_free (tr.prices);
|
||||
GNUNET_free (tr.bidder_pub);
|
||||
GNUNET_free (tr.hash_codes);
|
||||
GNUNET_free (tr.expected);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief implements the TALER_Extensions.parse_policy_details interface.
|
||||
* @brief implements the TALER_Extensions.create_policy_details interface.
|
||||
*
|
||||
* @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.
|
||||
* @param[out] details On success will contain the details to the policy
|
||||
* @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
|
||||
*/
|
||||
enum GNUNET_GenericReturnValue
|
||||
auction_parse_policy_details (
|
||||
auction_create_policy_details (
|
||||
const json_t *input,
|
||||
struct GNUNET_HashCode *serial,
|
||||
struct GNUNET_TIME_Timestamp *deadline,
|
||||
enum TALER_PolicyFulfilmentState *state_on_timeout,
|
||||
struct TALER_PolicyDetails *details,
|
||||
const char **error_hint)
|
||||
{
|
||||
enum GNUNET_GenericReturnValue ret = GNUNET_NO;
|
||||
@ -730,13 +786,15 @@ auction_parse_policy_details (
|
||||
/* We ignore the "type" field as it must have been parsed already upstream
|
||||
* - or this handler wouldn't have been called in first place. */
|
||||
GNUNET_JSON_spec_fixed_auto ("bidder_pub", &pub),
|
||||
TALER_JSON_spec_amount ("commitment",
|
||||
BV_config.auction_fee.currency,
|
||||
&details->commitment),
|
||||
GNUNET_JSON_spec_fixed_auto ("h_auction", &hc),
|
||||
GNUNET_JSON_spec_timestamp ("deadline", deadline),
|
||||
GNUNET_JSON_spec_timestamp ("deadline", &details->deadline),
|
||||
GNUNET_JSON_spec_end (),
|
||||
};
|
||||
|
||||
GNUNET_assert (serial);
|
||||
GNUNET_assert (deadline);
|
||||
GNUNET_assert (details);
|
||||
|
||||
error_hint = NULL;
|
||||
|
||||
@ -752,16 +810,13 @@ auction_parse_policy_details (
|
||||
/* FIXME: check the deadline */
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
||||
LOG_PREFIX "check of deadline %ld not implemented!\n",
|
||||
deadline->abs_time.abs_value_us);
|
||||
details->deadline.abs_time.abs_value_us);
|
||||
|
||||
calculate_serial (&pub, &hc, serial);
|
||||
calculate_hashcode (&pub, &hc, &details->hash_code);
|
||||
|
||||
ret = GNUNET_OK;
|
||||
} while(0);
|
||||
|
||||
/* In case of timeout, the coin shall be refreshable by the owner */
|
||||
*state_on_timeout = TALER_PolicyFulfilmentTimeoutRefreshable;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -777,7 +832,7 @@ struct TALER_Extension TE_auction_brandt = {
|
||||
.disable = &auction_disable,
|
||||
.load_config = &auction_load_config,
|
||||
.manifest = &auction_manifest,
|
||||
.parse_policy_details = &auction_parse_policy_details,
|
||||
.create_policy_details = &auction_create_policy_details,
|
||||
.policy_get_handler = &auction_policy_get_handler,
|
||||
.policy_post_handler = &auction_policy_post_handler,
|
||||
};
|
||||
@ -847,7 +902,7 @@ libtaler_extension_policy_brandt_vickrey_auction_init (void *arg)
|
||||
LOG_PREFIX "loading... using replay_program '%s'\n",
|
||||
replay_program);
|
||||
|
||||
/* TODO: read other config parameters and generate configuration */
|
||||
/* FIXME: read other config parameters and generate configuration */
|
||||
|
||||
return &TE_auction_brandt;
|
||||
}
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <gnunet/gnunet_db_lib.h>
|
||||
#include "taler_json_lib.h"
|
||||
#include "taler_signatures.h"
|
||||
#include "taler_extensions_policy.h"
|
||||
|
||||
|
||||
/**
|
||||
@ -223,7 +224,6 @@ enum TALER_EXCHANGEDB_ReplicatedTable
|
||||
TALER_EXCHANGEDB_RT_EXTENSIONS,
|
||||
TALER_EXCHANGEDB_RT_POLICY_DETAILS,
|
||||
TALER_EXCHANGEDB_RT_POLICY_FULFILMENTS,
|
||||
TALER_EXCHANGEDB_RT_POLICY_DETAILS_FULFILMENTS,
|
||||
TALER_EXCHANGEDB_RT_PURSE_REQUESTS,
|
||||
TALER_EXCHANGEDB_RT_PURSE_REFUNDS,
|
||||
TALER_EXCHANGEDB_RT_PURSE_MERGES,
|
||||
@ -528,24 +528,27 @@ struct TALER_EXCHANGEDB_TableData
|
||||
|
||||
struct
|
||||
{
|
||||
char *policy_options;
|
||||
struct GNUNET_HashCode serial_id;
|
||||
struct GNUNET_HashCode hash_code;
|
||||
json_t *policy_json;
|
||||
bool no_policy_json;
|
||||
struct GNUNET_TIME_Timestamp deadline;
|
||||
uint16_t timeout_fulfilment_state;
|
||||
uint16_t fulfilment_state;
|
||||
struct TALER_Amount commitment;
|
||||
struct TALER_Amount accumulated_total;
|
||||
struct TALER_Amount fee;
|
||||
struct TALER_Amount transferable;
|
||||
uint16_t fulfillment_state; /* will also be recomputed */
|
||||
uint64_t fulfillment_id;
|
||||
bool no_fulfillment_id;
|
||||
} policy_details;
|
||||
|
||||
struct
|
||||
{
|
||||
struct GNUNET_HashCode serial_id;
|
||||
uint64_t fulfilment_id;
|
||||
} policy_details_fulfilments;
|
||||
|
||||
struct
|
||||
{
|
||||
char *fulfilment_proof;
|
||||
struct GNUNET_TIME_Timestamp fulfilment_timestamp;
|
||||
} policy_fulfilments;
|
||||
struct GNUNET_TIME_Timestamp fulfillment_timestamp;
|
||||
char *fulfillment_proof;
|
||||
struct GNUNET_HashCode h_fulfillment_proof;
|
||||
struct GNUNET_HashCode *policy_hash_codes;
|
||||
size_t policy_hash_codes_count;
|
||||
} policy_fulfillments;
|
||||
|
||||
struct
|
||||
{
|
||||
@ -889,7 +892,6 @@ struct TALER_EXCHANGEDB_DenominationKeyMetaData
|
||||
struct TALER_AgeMask age_mask;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Signature of a function called with information about the exchange's
|
||||
* denomination keys.
|
||||
@ -1446,37 +1448,29 @@ struct TALER_EXCHANGEDB_Deposit
|
||||
char *receiver_wire_account;
|
||||
|
||||
/**
|
||||
* Additional details for a policy relevant for this
|
||||
* deposit operation, possibly NULL!
|
||||
* Additional policy and its options, relevant for this deposit operation,
|
||||
* possibly NULL!
|
||||
*/
|
||||
json_t *policy_details;
|
||||
bool has_policy_details;
|
||||
json_t *policy_json;
|
||||
|
||||
/*
|
||||
* True if @e policy_json was provided
|
||||
*/
|
||||
bool has_policy;
|
||||
|
||||
/**
|
||||
* If policy_details are present, the corresponding policy extension
|
||||
* calculates a serial id under which the policy_details shall be stored in
|
||||
* the policy_details table.
|
||||
*/
|
||||
struct GNUNET_HashCode policy_serial_id;
|
||||
|
||||
/**
|
||||
* If policy_details are present, the corresponding policy extension can set
|
||||
* a deadline for this policy. Can be "forever".
|
||||
*/
|
||||
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
|
||||
* true.
|
||||
* Hash over the @e policy_options. Only filled if @e has_policy is true.
|
||||
* Needed for the verification of the deposit's signature
|
||||
*/
|
||||
struct TALER_ExtensionPolicyHashP h_policy;
|
||||
|
||||
/**
|
||||
* If @e policy_json was present, the corresponding policy extension
|
||||
* calculates these details. These will be persisted in the policy_details
|
||||
* table.
|
||||
*/
|
||||
struct TALER_PolicyDetails policy_details;
|
||||
|
||||
/**
|
||||
* Time when this request was generated. Used, for example, to
|
||||
* assess when (roughly) the income was achieved for tax purposes.
|
||||
@ -1549,8 +1543,8 @@ struct TALER_EXCHANGEDB_DepositListEntry
|
||||
struct TALER_PrivateContractHashP h_contract_terms;
|
||||
|
||||
/**
|
||||
* Hash over the poliy data for this deposit
|
||||
* (remains unknown to the Exchange).
|
||||
* Hash over the policy data for this deposit (remains unknown to the
|
||||
* Exchange). Needed for the verification of the deposit's signature
|
||||
*/
|
||||
struct TALER_ExtensionPolicyHashP h_policy;
|
||||
|
||||
@ -3342,6 +3336,39 @@ struct TALER_EXCHANGEDB_Plugin
|
||||
bool *conflict,
|
||||
bool *nonce_reuse);
|
||||
|
||||
/**
|
||||
* Retrieve the details to a policy given by its hash_code
|
||||
*
|
||||
* @param cls the `struct PostgresClosure` with the plugin-specific state
|
||||
* @param hc Hash code that identifies the policy
|
||||
* @param[out] detail retrieved policy details
|
||||
* @return query execution status
|
||||
*/
|
||||
enum GNUNET_DB_QueryStatus
|
||||
(*get_policy_details)(
|
||||
void *cls,
|
||||
const struct GNUNET_HashCode *hc,
|
||||
struct TALER_PolicyDetails *detail);
|
||||
|
||||
/**
|
||||
* Persist the policy details that extends a deposit. The particular policy
|
||||
* - referenced by details->hash_code - might already exist in the table, in
|
||||
* which case the call will update the contents of the record with @e details
|
||||
*
|
||||
* @param cls the `struct PostgresClosure` with the plugin-specific state
|
||||
* @param details The parsed `struct TALER_PolicyDetails` according to the responsible policy extension.
|
||||
* @param[out] policy_details_serial_id The ID of the entry in the policy_details table
|
||||
* @param[out] accumulated_total The total amount accumulated in that policy
|
||||
* @param[out] fulfillment_state The state of policy. If the state was Insufficient prior to the call and the provided deposit raises the accumulated_total above the commitment, it will be set to Ready.
|
||||
* @return query execution status
|
||||
*/
|
||||
enum GNUNET_DB_QueryStatus
|
||||
(*persist_policy_details)(
|
||||
void *cls,
|
||||
const struct TALER_PolicyDetails *details,
|
||||
uint64_t *policy_details_serial_id,
|
||||
struct TALER_Amount *accumulated_total,
|
||||
enum TALER_PolicyFulfillmentState *fulfillment_state);
|
||||
|
||||
/**
|
||||
* Perform deposit operation, checking for sufficient balance
|
||||
@ -3351,6 +3378,7 @@ struct TALER_EXCHANGEDB_Plugin
|
||||
* @param deposit deposit operation details
|
||||
* @param known_coin_id row of the coin in the known_coins table
|
||||
* @param h_payto hash of the merchant's payto URI
|
||||
* @param policy_details_serial_id (pointer to) the row ID of the policy details, maybe NULL
|
||||
* @param[in,out] exchange_timestamp time to use for the deposit (possibly updated)
|
||||
* @param[out] balance_ok set to true if the balance was sufficient
|
||||
* @param[out] in_conflict set to true if the deposit conflicted
|
||||
@ -3362,6 +3390,7 @@ struct TALER_EXCHANGEDB_Plugin
|
||||
const struct TALER_EXCHANGEDB_Deposit *deposit,
|
||||
uint64_t known_coin_id,
|
||||
const struct TALER_PaytoHashP *h_payto,
|
||||
uint64_t *policy_details_serial_id,
|
||||
struct GNUNET_TIME_Timestamp *exchange_timestamp,
|
||||
bool *balance_ok,
|
||||
bool *in_conflict);
|
||||
@ -3389,6 +3418,18 @@ struct TALER_EXCHANGEDB_Plugin
|
||||
bool *zombie_required,
|
||||
bool *balance_ok);
|
||||
|
||||
/**
|
||||
* Add a proof of fulfillment of an policy
|
||||
*
|
||||
* @param cls the plugin-specific state
|
||||
* @param[in,out] fulfillment The proof of fulfillment and serial_ids of the policy_details along with their new state and potential new amounts.
|
||||
* @return query execution status
|
||||
*/
|
||||
enum GNUNET_DB_QueryStatus
|
||||
(*add_policy_fulfillment_proof)(
|
||||
void *cls,
|
||||
struct TALER_PolicyFulfillmentTransactionData *fulfillment);
|
||||
|
||||
|
||||
/**
|
||||
* Check if the given @a nonce was properly locked to the given @a old_coin_pub. If so, check if we already
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014-2021 Taler Systems SA
|
||||
Copyright (C) 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
|
||||
@ -25,7 +25,7 @@
|
||||
#include "taler_crypto_lib.h"
|
||||
#include "taler_json_lib.h"
|
||||
#include "taler_mhd_lib.h"
|
||||
#include "taler_exchangedb_plugin.h"
|
||||
#include "taler_extensions_policy.h"
|
||||
|
||||
|
||||
#define TALER_EXTENSION_SECTION_PREFIX "exchange-extension-"
|
||||
@ -54,8 +54,8 @@ struct TALER_Extensions
|
||||
};
|
||||
|
||||
/* Forward declarations */
|
||||
enum TALER_PolicyFulfilmentState;
|
||||
struct TALER_PolicyFulfilmentOutcome;
|
||||
enum TALER_PolicyFulfillmentState;
|
||||
struct TALER_PolicyFulfillmentOutcome;
|
||||
|
||||
/*
|
||||
* @brief Represents the implementation of an extension.
|
||||
@ -165,31 +165,23 @@ struct TALER_Extension
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Handler to check a policy. Can be NULL;
|
||||
* @brief Handler to check an incoming policy and create a
|
||||
* TALER_PolicyDetails. Can be NULL;
|
||||
*
|
||||
* When a deposit request refers to this extension in its policy
|
||||
* (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
|
||||
* @param[in] policy_json 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.
|
||||
* @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 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] details On success, will contain the details to the policy,
|
||||
* evaluated by the corresponding policy handler.
|
||||
* @param[out] error_hint On error, will contain a hint
|
||||
* @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,
|
||||
enum GNUNET_GenericReturnValue (*create_policy_details)(
|
||||
const json_t *policy_json,
|
||||
struct TALER_PolicyDetails *details,
|
||||
const char **error_hint);
|
||||
|
||||
/**
|
||||
@ -197,18 +189,16 @@ struct TALER_Extension
|
||||
*
|
||||
* @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[in,out] details List of policy details related to the incoming fulfillment proof
|
||||
* @param[in] details_len Size of the list @e details
|
||||
* @param[out] output JSON output to return to the client
|
||||
* @return GNUNET_OK on success.
|
||||
*/
|
||||
enum GNUNET_GenericReturnValue (*policy_post_handler)(
|
||||
const json_t *root,
|
||||
const char *const args[],
|
||||
enum GNUNET_GenericReturnValue (*serial_id_check)(struct GNUNET_HashCode
|
||||
serial_ids[], size_t
|
||||
size),
|
||||
struct TALER_PolicyFulfilmentOutcome **outcome,
|
||||
struct TALER_PolicyDetails *details,
|
||||
size_t details_len,
|
||||
json_t **output);
|
||||
|
||||
/**
|
||||
@ -395,163 +385,4 @@ TALER_extensions_is_age_restriction_enabled ();
|
||||
struct TALER_AgeMask
|
||||
TALER_extensions_get_age_restriction_mask ();
|
||||
|
||||
|
||||
/*
|
||||
* ===================================
|
||||
* Policy extensions related API
|
||||
* ===================================
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* @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_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
|
||||
* ================================
|
||||
*/
|
||||
struct TALER_ExtensionPolicyMerchantRefundPolicyConfig
|
||||
{
|
||||
struct GNUNET_TIME_Relative max_timeout;
|
||||
};
|
||||
|
||||
/*
|
||||
* ================================
|
||||
* Brandt-Vickrey Auctions policy
|
||||
* ================================
|
||||
*/
|
||||
/*
|
||||
* @brief Configuration for Brandt-Vickrey auctions policy
|
||||
*/
|
||||
struct TALER_ExtensionPolicyBrandtVickreyAuctionConfig
|
||||
{
|
||||
uint16_t max_bidders;
|
||||
uint16_t max_prices;
|
||||
struct TALER_Amount auction_fee;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* ================================
|
||||
* Escrowed Payments policy
|
||||
* ================================
|
||||
*/
|
||||
/*
|
||||
* @brief Configuration for escrowed payments policy
|
||||
*/
|
||||
struct TALER_ExtensionPolicyEscrowedPaymentsConfig
|
||||
{
|
||||
struct GNUNET_TIME_Relative max_timeout;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
199
src/include/taler_extensions_policy.h
Normal file
199
src/include/taler_extensions_policy.h
Normal file
@ -0,0 +1,199 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 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
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
/**
|
||||
* @file include/taler_extensions_policy.h
|
||||
* @brief Interface for policy extensions
|
||||
* @author Özgür Kesim
|
||||
*/
|
||||
#ifndef TALER_EXTENSIONS_POLICY_H
|
||||
#define TALER_EXTENSIONS_POLICY_H
|
||||
|
||||
#include <gnunet/gnunet_util_lib.h>
|
||||
#include "taler_crypto_lib.h"
|
||||
#include "taler_json_lib.h"
|
||||
#include "taler_mhd_lib.h"
|
||||
|
||||
/*
|
||||
* @brief Describes the states of fulfillment of a policy bound to a deposit
|
||||
*/
|
||||
enum TALER_PolicyFulfillmentState
|
||||
{
|
||||
/* General error state of an fulfillment. */
|
||||
TALER_PolicyFulfillmentFailure = 0,
|
||||
|
||||
/* The policy is not yet ready due to insufficient funding. More deposits are
|
||||
* necessary for it to become ready . */
|
||||
TALER_PolicyFulfillmentInsufficient = 1,
|
||||
|
||||
/* The policy is funded and ready, pending */
|
||||
TALER_PolicyFulfillmentReady = 2,
|
||||
|
||||
/* Policy is provably fulfilled. */
|
||||
TALER_PolicyFulfillmentSuccess = 3,
|
||||
|
||||
/* Policy fulfillment has timed out */
|
||||
TALER_PolicyFulfillmentTimeout = 4,
|
||||
|
||||
TALER_PolicyFulfillmentStateCount = TALER_PolicyFulfillmentTimeout + 1
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* @brief Returns a string representation of the state of a policy fulfillment
|
||||
*/
|
||||
const char *
|
||||
TALER_policy_fulfillment_state_str (enum TALER_PolicyFulfillmentState state);
|
||||
|
||||
|
||||
/* @brief Details of a policy for a deposit request */
|
||||
struct TALER_PolicyDetails
|
||||
{
|
||||
/* Hash code that should be used for the .policy_hash_code field when
|
||||
* this policy is saved in the policy_details table. */
|
||||
struct GNUNET_HashCode hash_code;
|
||||
|
||||
/* Content of the policy in its original JSON form */
|
||||
const json_t *policy_json;
|
||||
|
||||
/* When the deadline is meat and the policy is still in "Ready" state,
|
||||
* a timeout-handler will transfer the amount
|
||||
* (total_amount - policy_fee - refreshable_amount)
|
||||
* to the payto-URI from the corresponding deposit. The value
|
||||
* amount_refreshable will be refreshable by the owner of the
|
||||
* associated deposits's coins */
|
||||
struct GNUNET_TIME_Timestamp deadline;
|
||||
|
||||
/* The amount to which this policy commits to. It must be at least as
|
||||
* large as @e policy_fee. */
|
||||
struct TALER_Amount commitment;
|
||||
|
||||
/* The total sum of contributions from coins so far to fund this
|
||||
* policy. It must be at least as large as @commitment in order to be
|
||||
* sufficiently funded. */
|
||||
struct TALER_Amount accumulated_total;
|
||||
|
||||
/* The fee from the exchange for handling the policy. It is due when
|
||||
* the state changes to Timeout or Success. */
|
||||
struct TALER_Amount policy_fee;
|
||||
|
||||
/* The amount that will be transfered to the payto-URIs from the
|
||||
* corresponding deposits when the fulfillment state changes to Timeout
|
||||
* or Success. Note that a fulfillment handler can alter this upon
|
||||
* arrival of a proof of fulfillment. The remaining amount
|
||||
* (accumulated_amount - policy_amount - transferable_amount) */
|
||||
struct TALER_Amount transferable_amount;
|
||||
|
||||
/* The state of fulfillment of a policy.
|
||||
* - If the state is Insufficient, the client is required to call
|
||||
* /deposit -maybe multiple times- with enough coins and the same
|
||||
* policy details in order to reach the required amount. The state is
|
||||
* then changed to Ready.
|
||||
* - If the state changes to Timeout or Success, a handler will transfer
|
||||
* the amount (total_amount - policy_fee - refreshable_amount) to the
|
||||
* payto-URI from the corresponding deposit. The value
|
||||
* amount_refreshable will be refreshable by the owner of the
|
||||
* associated deposits's coins. */
|
||||
enum TALER_PolicyFulfillmentState fulfillment_state;
|
||||
|
||||
/* If there is a proof of fulfillment, the row ID from the
|
||||
* policy_fulfillment table */
|
||||
uint64_t policy_fulfillment_id;
|
||||
bool no_policy_fulfillment_id;
|
||||
};
|
||||
|
||||
/*
|
||||
* @brief All information required for the database transaction when handling a
|
||||
* proof of fulfillment request.
|
||||
*/
|
||||
struct TALER_PolicyFulfillmentTransactionData
|
||||
{
|
||||
/* The incoming proof, provided by a client */
|
||||
const json_t *proof;
|
||||
|
||||
/* The Hash of the proof */
|
||||
struct GNUNET_HashCode h_proof;
|
||||
|
||||
/* The timestamp of retrieval of the proof */
|
||||
struct GNUNET_TIME_Timestamp timestamp;
|
||||
|
||||
/* The ID of the proof in the policy_fulfillment table. Will be set
|
||||
* during the transaction. Needed to fill the table
|
||||
* policy_details_fulfillments. */
|
||||
uint64_t fulfillment_id;
|
||||
|
||||
/* The list of policy details. Will be updated by the policy handler */
|
||||
struct TALER_PolicyDetails *details;
|
||||
size_t details_count;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* @brief Extracts policy details from the deposit's policy options and the policy extensions
|
||||
*
|
||||
* @param[in] policy_options JSON of the policy options from a deposit request
|
||||
* @param[out] details On GNUNET_OK, the parsed details
|
||||
* @param[out] error_hint On GNUNET_SYSERR, will contain a hint for the reason why it failed
|
||||
* @return GNUNET_OK on success, 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_create_policy_details (
|
||||
const json_t *policy_options,
|
||||
struct TALER_PolicyDetails *details,
|
||||
const char **error_hint);
|
||||
|
||||
|
||||
/*
|
||||
* ================================
|
||||
* Merchant refund policy
|
||||
* ================================
|
||||
*/
|
||||
struct TALER_ExtensionPolicyMerchantRefundPolicyConfig
|
||||
{
|
||||
struct GNUNET_TIME_Relative max_timeout;
|
||||
};
|
||||
|
||||
/*
|
||||
* ================================
|
||||
* Brandt-Vickrey Auctions policy
|
||||
* ================================
|
||||
*/
|
||||
/*
|
||||
* @brief Configuration for Brandt-Vickrey auctions policy
|
||||
*/
|
||||
struct TALER_ExtensionPolicyBrandtVickreyAuctionConfig
|
||||
{
|
||||
uint16_t max_bidders;
|
||||
uint16_t max_prices;
|
||||
struct TALER_Amount auction_fee;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* ================================
|
||||
* Escrowed Payments policy
|
||||
* ================================
|
||||
*/
|
||||
/*
|
||||
* @brief Configuration for escrowed payments policy
|
||||
*/
|
||||
struct TALER_ExtensionPolicyEscrowedPaymentsConfig
|
||||
{
|
||||
struct GNUNET_TIME_Relative max_timeout;
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user