summaryrefslogtreecommitdiff
path: root/src/exchangedb
diff options
context:
space:
mode:
authorÖzgür Kesim <oec-taler@kesim.org>2022-11-04 12:18:16 +0100
committerÖzgür Kesim <oec-taler@kesim.org>2022-11-04 12:18:16 +0100
commit752f10273860d2496fc3eb1e03de6ad4451e7c0f (patch)
tree53d51969f58611dbf8afacdcd40a769f5c847dd8 /src/exchangedb
parentc89bfa9026d7180eb24ae9480f225b93db22c53a (diff)
downloadexchange-752f10273860d2496fc3eb1e03de6ad4451e7c0f.tar.gz
exchange-752f10273860d2496fc3eb1e03de6ad4451e7c0f.tar.bz2
exchange-752f10273860d2496fc3eb1e03de6ad4451e7c0f.zip
policy extensions and age restriction refactoring
- refactoring of extension-plugin-mechanism - refactoring of age restriction extension - added policy extensions plugin plumbing - added DB schema and api - policy_details - policy_fulfillments
Diffstat (limited to 'src/exchangedb')
-rw-r--r--src/exchangedb/common-0001.sql6
-rw-r--r--src/exchangedb/exchange-0001-part.sql100
-rw-r--r--src/exchangedb/pg_insert_records_by_table.c114
-rw-r--r--src/exchangedb/pg_lookup_records_by_table.c131
-rw-r--r--src/exchangedb/pg_lookup_serial_by_table.c18
-rw-r--r--src/exchangedb/plugin_exchangedb_postgres.c278
-rw-r--r--src/exchangedb/procedures.sql139
-rw-r--r--src/exchangedb/test_exchangedb.c58
8 files changed, 680 insertions, 164 deletions
diff --git a/src/exchangedb/common-0001.sql b/src/exchangedb/common-0001.sql
index ab4f8ea91..a95d74d2a 100644
--- a/src/exchangedb/common-0001.sql
+++ b/src/exchangedb/common-0001.sql
@@ -907,8 +907,8 @@ BEGIN
',wire_salt BYTEA NOT NULL CHECK (LENGTH(wire_salt)=16)'
',wire_target_h_payto BYTEA CHECK (LENGTH(wire_target_h_payto)=32)'
',done BOOLEAN NOT NULL DEFAULT FALSE'
- ',extension_blocked BOOLEAN NOT NULL DEFAULT FALSE'
- ',extension_details_serial_id INT8' -- REFERENCES extension_details (extension_details_serial_id) ON DELETE CASCADE'
+ ',policy_blocked BOOLEAN NOT NULL DEFAULT FALSE'
+ ',policy_details_serial_id INT8' -- REFERENCES policy_details (policy_details_serial_id) ON DELETE CASCADE'
') %s ;'
,table_name
,'PARTITION BY HASH (coin_pub)'
@@ -2619,7 +2619,7 @@ BEGIN
ALTER TABLE IF EXISTS deposits
DROP CONSTRAINT IF EXISTS deposits_pkey CASCADE
- ,DROP CONSTRAINT IF EXISTS deposits_extension_details_serial_id_fkey
+ ,DROP CONSTRAINT IF EXISTS deposits_policy_details_serial_id_fkey
,DROP CONSTRAINT IF EXISTS deposits_coin_pub_merchant_pub_h_contract_terms_key CASCADE
;
diff --git a/src/exchangedb/exchange-0001-part.sql b/src/exchangedb/exchange-0001-part.sql
index 99883a279..4599d2ee7 100644
--- a/src/exchangedb/exchange-0001-part.sql
+++ b/src/exchangedb/exchange-0001-part.sql
@@ -411,19 +411,19 @@ COMMENT ON TABLE signkey_revocations
IS 'Table storing which online signing keys have been revoked';
--- ------------------------------ extension ----------------------------------------
+-- ------------------------------ extensions ----------------------------------------
CREATE TABLE IF NOT EXISTS extensions
(extension_id BIGINT GENERATED BY DEFAULT AS IDENTITY UNIQUE
,name VARCHAR NOT NULL UNIQUE
- ,config BYTEA
+ ,manifest BYTEA
);
COMMENT ON TABLE extensions
IS 'Configurations of the activated extensions';
COMMENT ON COLUMN extensions.name
IS 'Name of the extension';
-COMMENT ON COLUMN extensions.config
- IS 'Configuration of the extension as JSON-blob, maybe NULL';
+COMMENT ON COLUMN extensions.manifest
+ IS 'Manifest of the extension as JSON-blob, maybe NULL. It contains common meta-information and extension-specific configuration.';
-- ------------------------------ known_coins ----------------------------------------
@@ -520,21 +520,69 @@ CREATE TABLE IF NOT EXISTS refresh_transfer_keys_default
SELECT add_constraints_to_refresh_transfer_keys_partition('default');
--- ------------------------------ extension_details ----------------------------------------
-
-CREATE TABLE IF NOT EXISTS extension_details
- (extension_details_serial_id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY
- ,extension_options VARCHAR)
- PARTITION BY HASH (extension_details_serial_id);
-COMMENT ON TABLE extension_details
- IS 'Extensions that were provided with deposits (not yet used).';
-COMMENT ON COLUMN extension_details.extension_options
- IS 'JSON object with options set that the exchange needs to consider when executing a deposit. Supported details depend on the extensions supported by the exchange.';
-
-CREATE TABLE IF NOT EXISTS extension_details_default
- PARTITION OF extension_details
- FOR VALUES WITH (MODULUS 1, REMAINDER 0);
+-- ------------------------------ policy_fulfillments -------------------------------------
+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
+ ,policy_hash_code BYTEA PRIMARY KEY CHECK(LENGTH(policy_hash_code)=16)
+ ,policy_json VARCHAR
+ ,deadline INT8 NOT NULL
+ ,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.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_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 (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 ----------------------------------------
@@ -552,10 +600,10 @@ COMMENT ON COLUMN deposits.wire_salt
IS 'Salt used when hashing the payto://-URI to get the h_wire';
COMMENT ON COLUMN deposits.done
IS 'Set to TRUE once we have included this deposit in some aggregate wire transfer to the merchant';
-COMMENT ON COLUMN deposits.extension_blocked
- IS 'True if the aggregation of the deposit is currently blocked by some extension mechanism. Used to filter out deposits that must not be processed by the canonical deposit logic.';
-COMMENT ON COLUMN deposits.extension_details_serial_id
- IS 'References extensions table, NULL if extensions are not used';
+COMMENT ON COLUMN deposits.policy_blocked
+ IS 'True if the aggregation of the deposit is currently blocked by some policy extension mechanism. Used to filter out deposits that must not be processed by the canonical deposit logic.';
+COMMENT ON COLUMN deposits.policy_details_serial_id
+ IS 'References policy extensions table, NULL if extensions are not used';
CREATE TABLE IF NOT EXISTS deposits_default
PARTITION OF deposits
@@ -591,7 +639,7 @@ CREATE OR REPLACE FUNCTION deposits_insert_trigger()
DECLARE
is_ready BOOLEAN;
BEGIN
- is_ready = NOT (NEW.done OR NEW.extension_blocked);
+ is_ready = NOT (NEW.done OR NEW.policy_blocked);
IF (is_ready)
THEN
@@ -635,8 +683,8 @@ DECLARE
DECLARE
is_ready BOOLEAN;
BEGIN
- was_ready = NOT (OLD.done OR OLD.extension_blocked);
- is_ready = NOT (NEW.done OR NEW.extension_blocked);
+ was_ready = NOT (OLD.done OR OLD.policy_blocked);
+ is_ready = NOT (NEW.done OR NEW.policy_blocked);
IF (was_ready AND NOT is_ready)
THEN
DELETE FROM exchange.deposits_by_ready
@@ -690,7 +738,7 @@ CREATE OR REPLACE FUNCTION deposits_delete_trigger()
DECLARE
was_ready BOOLEAN;
BEGIN
- was_ready = NOT (OLD.done OR OLD.extension_blocked);
+ was_ready = NOT (OLD.done OR OLD.policy_blocked);
IF (was_ready)
THEN
diff --git a/src/exchangedb/pg_insert_records_by_table.c b/src/exchangedb/pg_insert_records_by_table.c
index 0ac70bae3..d6630797a 100644
--- a/src/exchangedb/pg_insert_records_by_table.c
+++ b/src/exchangedb/pg_insert_records_by_table.c
@@ -872,11 +872,11 @@ irbt_cb_table_deposits (struct PostgresClosure *pg,
GNUNET_PQ_query_param_auto_from_type (&td->details.deposits.wire_salt),
GNUNET_PQ_query_param_auto_from_type (
&td->details.deposits.wire_target_h_payto),
- GNUNET_PQ_query_param_bool (td->details.deposits.extension_blocked),
- 0 == td->details.deposits.extension_details_serial_id
+ GNUNET_PQ_query_param_bool (td->details.deposits.policy_blocked),
+ 0 == td->details.deposits.policy_details_serial_id
? GNUNET_PQ_query_param_null ()
: GNUNET_PQ_query_param_uint64 (
- &td->details.deposits.extension_details_serial_id),
+ &td->details.deposits.policy_details_serial_id),
GNUNET_PQ_query_param_end
};
@@ -898,8 +898,8 @@ irbt_cb_table_deposits (struct PostgresClosure *pg,
",coin_sig"
",wire_salt"
",wire_target_h_payto"
- ",extension_blocked"
- ",extension_details_serial_id"
+ ",policy_blocked"
+ ",policy_details_serial_id"
") VALUES "
"($1, $2, $3, $4, $5, $6, $7, $8, $9, $10,"
" $11, $12, $13, $14, $15, $16, $17);");
@@ -1217,9 +1217,9 @@ irbt_cb_table_extensions (struct PostgresClosure *pg,
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_uint64 (&td->serial),
GNUNET_PQ_query_param_string (td->details.extensions.name),
- NULL == td->details.extensions.config ?
+ NULL == td->details.extensions.manifest ?
GNUNET_PQ_query_param_null () :
- GNUNET_PQ_query_param_string (td->details.extensions.config),
+ GNUNET_PQ_query_param_string (td->details.extensions.manifest),
GNUNET_PQ_query_param_end
};
@@ -1228,7 +1228,7 @@ irbt_cb_table_extensions (struct PostgresClosure *pg,
"INSERT INTO extensions"
"(extension_id"
",name"
- ",config"
+ ",manifest"
") VALUES "
"($1, $2, $3);");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
@@ -1238,34 +1238,99 @@ irbt_cb_table_extensions (struct PostgresClosure *pg,
/**
- * Function called with extension_details records to insert into table.
+ * Function called with policy_details records to insert into table.
*
* @param pg plugin context
* @param td record to insert
*/
static enum GNUNET_DB_QueryStatus
-irbt_cb_table_extension_details (struct PostgresClosure *pg,
- const struct TALER_EXCHANGEDB_TableData *td)
+irbt_cb_table_policy_details (struct PostgresClosure *pg,
+ const struct TALER_EXCHANGEDB_TableData *td)
{
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_uint64 (&td->serial),
- NULL ==
- td->details.extension_details.extension_options ?
- GNUNET_PQ_query_param_null () :
- GNUNET_PQ_query_param_string (
- td->details.extension_details.extension_options),
+ GNUNET_PQ_query_param_auto_from_type (
+ &td->details.policy_details.hash_code),
+ (td->details.policy_details.no_policy_json)
+ ? GNUNET_PQ_query_param_null ()
+ : TALER_PQ_query_param_json (td->details.policy_details.policy_json),
+ TALER_PQ_query_param_amount (&td->details.policy_details.commitment),
+ TALER_PQ_query_param_amount (&td->details.policy_details.accumulated_total),
+ TALER_PQ_query_param_amount (&td->details.policy_details.fee),
+ TALER_PQ_query_param_amount (&td->details.policy_details.transferable),
+ GNUNET_PQ_query_param_timestamp (&td->details.policy_details.deadline),
+ GNUNET_PQ_query_param_uint16 (
+ &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
};
PREPARE (pg,
- "insert_into_table_extension_details",
- "INSERT INTO extension_details"
- "(extension_details_serial_id"
- ",extension_options"
+ "insert_into_table_policy_details",
+ "INSERT INTO policy_details"
+ "(policy_details_serial_id"
+ ",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"
+ ",fulfillment_id"
") VALUES "
"($1, $2);");
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_into_table_extension_details",
+ "insert_into_table_policy_details",
+ params);
+}
+
+
+/**
+ * Function called with policy_fulfillment records to insert into table.
+ *
+ * @param pg plugin context
+ * @param td record to insert
+ */
+static enum GNUNET_DB_QueryStatus
+irbt_cb_table_policy_fulfillments (struct PostgresClosure *pg,
+ const struct TALER_EXCHANGEDB_TableData *td)
+{
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_uint64 (&td->serial),
+ GNUNET_PQ_query_param_timestamp (
+ &td->details.policy_fulfillments.fulfillment_timestamp),
+ (NULL == td->details.policy_fulfillments.fulfillment_proof)
+ ? GNUNET_PQ_query_param_null ()
+ : GNUNET_PQ_query_param_string (
+ td->details.policy_fulfillments.fulfillment_proof),
+ GNUNET_PQ_query_param_auto_from_type (
+ &td->details.policy_fulfillments.h_fulfillment_proof),
+ GNUNET_PQ_query_param_fixed_size (
+ td->details.policy_fulfillments.policy_hash_codes,
+ td->details.policy_fulfillments.policy_hash_codes_count),
+ GNUNET_PQ_query_param_end
+ };
+
+ PREPARE (pg,
+ "insert_into_table_policy_fulfillments",
+ "INSERT INTO policy_fulfillments "
+ "(fulfillment_id"
+ ",fulfillment_timestamp"
+ ",fulfillment_proof"
+ ",h_fulfillment_proof"
+ ",policy_hash_codes"
+ ") VALUES "
+ "($1, $2, $3, $4, $5);");
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "insert_into_table_policy_fulfillments",
params);
}
@@ -1900,8 +1965,11 @@ TEH_PG_insert_records_by_table (void *cls,
case TALER_EXCHANGEDB_RT_EXTENSIONS:
rh = &irbt_cb_table_extensions;
break;
- case TALER_EXCHANGEDB_RT_EXTENSION_DETAILS:
- rh = &irbt_cb_table_extension_details;
+ case TALER_EXCHANGEDB_RT_POLICY_DETAILS:
+ rh = &irbt_cb_table_policy_details;
+ break;
+ case TALER_EXCHANGEDB_RT_POLICY_FULFILLMENTS:
+ rh = &irbt_cb_table_policy_fulfillments;
break;
case TALER_EXCHANGEDB_RT_PURSE_REQUESTS:
rh = &irbt_cb_table_purse_requests;
diff --git a/src/exchangedb/pg_lookup_records_by_table.c b/src/exchangedb/pg_lookup_records_by_table.c
index 57c7c2b07..9d600f740 100644
--- a/src/exchangedb/pg_lookup_records_by_table.c
+++ b/src/exchangedb/pg_lookup_records_by_table.c
@@ -927,7 +927,7 @@ lrbt_cb_table_deposits (void *cls,
for (unsigned int i = 0; i<num_results; i++)
{
- bool no_extension;
+ bool no_policy;
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_uint64 (
"serial",
@@ -972,13 +972,13 @@ lrbt_cb_table_deposits (void *cls,
"wire_target_h_payto",
&td.details.deposits.wire_target_h_payto),
GNUNET_PQ_result_spec_auto_from_type (
- "extension_blocked",
- &td.details.deposits.extension_blocked),
+ "policy_blocked",
+ &td.details.deposits.policy_blocked),
GNUNET_PQ_result_spec_allow_null (
GNUNET_PQ_result_spec_uint64 (
- "extension_details_serial_id",
- &td.details.deposits.extension_details_serial_id),
- &no_extension),
+ "policy_details_serial_id",
+ &td.details.deposits.policy_details_serial_id),
+ &no_policy),
GNUNET_PQ_result_spec_end
};
@@ -1414,7 +1414,7 @@ lrbt_cb_table_extensions (void *cls,
struct TALER_EXCHANGEDB_TableData td = {
.table = TALER_EXCHANGEDB_RT_EXTENSIONS
};
- bool no_config = false;
+ bool no_manifest = false;
for (unsigned int i = 0; i<num_results; i++)
{
@@ -1424,9 +1424,9 @@ lrbt_cb_table_extensions (void *cls,
GNUNET_PQ_result_spec_string ("name",
&td.details.extensions.name),
GNUNET_PQ_result_spec_allow_null (
- GNUNET_PQ_result_spec_string ("config",
- &td.details.extensions.config),
- &no_config),
+ GNUNET_PQ_result_spec_string ("manifest",
+ &td.details.extensions.manifest),
+ &no_manifest),
GNUNET_PQ_result_spec_end
};
@@ -1447,33 +1447,112 @@ lrbt_cb_table_extensions (void *cls,
/**
- * Function called with extension_details table entries.
+ * Function called with policy_details 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_extension_details (void *cls,
- PGresult *result,
- unsigned int num_results)
+lrbt_cb_table_policy_details (void *cls,
+ PGresult *result,
+ 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++)
+ {
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_uint64 ("policy_details_serial_id",
+ &td.serial),
+ GNUNET_PQ_result_spec_auto_from_type ("hash_code",
+ &td.details.policy_details.
+ hash_code),
+ GNUNET_PQ_result_spec_allow_null (
+ TALER_PQ_result_spec_json ("policy_json",
+ &td.details.policy_details.
+ policy_json),
+ &td.details.policy_details.no_policy_json),
+ GNUNET_PQ_result_spec_timestamp ("deadline",
+ &td.details.policy_details.
+ deadline),
+ TALER_PQ_RESULT_SPEC_AMOUNT ("commitment",
+ &td.details.policy_details.
+ commitment),
+ TALER_PQ_RESULT_SPEC_AMOUNT ("accumulated_total",
+ &td.details.policy_details.
+ 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
+ };
+
+ 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 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_fulfillments (void *cls,
+ PGresult *result,
+ unsigned int num_results)
{
struct LookupRecordsByTableContext *ctx = cls;
struct TALER_EXCHANGEDB_TableData td = {
- .table = TALER_EXCHANGEDB_RT_EXTENSION_DETAILS
+ .table = TALER_EXCHANGEDB_RT_POLICY_FULFILLMENTS
};
for (unsigned int i = 0; i<num_results; i++)
{
- bool no_config = false;
+ bool no_proof = false;
+ bool no_timestamp = false;
struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_uint64 ("extension_details_serial_id",
+ GNUNET_PQ_result_spec_uint64 ("fulfillment_id",
&td.serial),
GNUNET_PQ_result_spec_allow_null (
- GNUNET_PQ_result_spec_string ("extension_options",
- &td.details.extension_details.
- extension_options),
- &no_config),
+ 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 ("fulfillment_proof",
+ &td.details.policy_fulfillments.
+ fulfillment_proof),
+ &no_proof),
GNUNET_PQ_result_spec_end
};
@@ -2607,9 +2686,13 @@ TEH_PG_lookup_records_by_table (void *cls,
statement = "select_above_serial_by_table_extensions";
rh = &lrbt_cb_table_extensions;
break;
- case TALER_EXCHANGEDB_RT_EXTENSION_DETAILS:
- statement = "select_above_serial_by_table_extension_details";
- rh = &lrbt_cb_table_extension_details;
+ case TALER_EXCHANGEDB_RT_POLICY_DETAILS:
+ statement = "select_above_serial_by_table_policy_details";
+ rh = &lrbt_cb_table_policy_details;
+ break;
+ case TALER_EXCHANGEDB_RT_POLICY_FULFILLMENTS:
+ statement = "select_above_serial_by_table_policy_fulfillments";
+ rh = &lrbt_cb_table_policy_fulfillments;
break;
case TALER_EXCHANGEDB_RT_PURSE_REQUESTS:
XPREPARE ("select_above_serial_by_table_purse_requests",
diff --git a/src/exchangedb/pg_lookup_serial_by_table.c b/src/exchangedb/pg_lookup_serial_by_table.c
index 202be30f8..7e150cd28 100644
--- a/src/exchangedb/pg_lookup_serial_by_table.c
+++ b/src/exchangedb/pg_lookup_serial_by_table.c
@@ -277,12 +277,20 @@ TEH_PG_lookup_serial_by_table (void *cls,
" ORDER BY extension_id DESC"
" LIMIT 1;");
break;
- case TALER_EXCHANGEDB_RT_EXTENSION_DETAILS:
- XPREPARE ("select_serial_by_table_extension_details",
+ case TALER_EXCHANGEDB_RT_POLICY_DETAILS:
+ XPREPARE ("select_serial_by_table_policy_details",
"SELECT"
- " extension_details_serial_id AS serial"
- " FROM extension_details"
- " ORDER BY extension_details_serial_id DESC"
+ " policy_details_serial_id AS serial"
+ " FROM policy_details"
+ " ORDER BY policy_details_serial_id DESC"
+ " LIMIT 1;");
+ break;
+ case TALER_EXCHANGEDB_RT_POLICY_FULFILLMENTS:
+ XPREPARE ("select_serial_by_table_policy_fulfillments",
+ "SELECT"
+ " fulfillment_id AS serial"
+ " FROM policy_fulfillments"
+ " ORDER BY fulfillment_id DESC"
" LIMIT 1;");
break;
case TALER_EXCHANGEDB_RT_PURSE_REQUESTS:
diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c
index 28dbdbaa8..0b03fe4b1 100644
--- a/src/exchangedb/plugin_exchangedb_postgres.c
+++ b/src/exchangedb/plugin_exchangedb_postgres.c
@@ -2099,17 +2099,17 @@ prepare_statements (struct PostgresClosure *pg)
" WHERE job_name=$1"
" AND start_row=$2"
" AND end_row=$3"),
- /* Used in #postgres_set_extension_config */
+ /* Used in #postgres_set_extension_manifest */
GNUNET_PQ_make_prepare (
- "set_extension_config",
- "INSERT INTO extensions (name, config) VALUES ($1, $2) "
+ "set_extension_manifest",
+ "INSERT INTO extensions (name, manifest) VALUES ($1, $2) "
"ON CONFLICT (name) "
- "DO UPDATE SET config=$2"),
- /* Used in #postgres_get_extension_config */
+ "DO UPDATE SET manifest=$2"),
+ /* Used in #postgres_get_extension_manifest */
GNUNET_PQ_make_prepare (
- "get_extension_config",
+ "get_extension_manifest",
"SELECT "
- " config "
+ " manifest "
"FROM extensions"
" WHERE name=$1;"),
/* Used in #postgres_insert_contract() */
@@ -4083,7 +4083,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 extension_blocked true if an extension is blocking the wire transfer
+ * @param _blocked true if an extension is blocking the wire transfer
* @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
@@ -4095,7 +4095,7 @@ postgres_do_deposit (
const struct TALER_EXCHANGEDB_Deposit *deposit,
uint64_t known_coin_id,
const struct TALER_PaytoHashP *h_payto,
- bool extension_blocked,
+ uint64_t *policy_details_serial_id,
struct GNUNET_TIME_Timestamp *exchange_timestamp,
bool *balance_ok,
bool *in_conflict)
@@ -4117,10 +4117,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 (extension_blocked),
- (NULL == deposit->extension_details)
+ GNUNET_PQ_query_param_bool (deposit->has_policy),
+ (NULL == policy_details_serial_id)
? GNUNET_PQ_query_param_null ()
- : TALER_PQ_query_param_json (deposit->extension_details),
+ : GNUNET_PQ_query_param_uint64 (policy_details_serial_id),
GNUNET_PQ_query_param_end
};
struct GNUNET_PQ_ResultSpec rs[] = {
@@ -4140,6 +4140,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.
@@ -4394,6 +4489,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;
+}
+
+
/**
* Get the balance of the specified reserve.
*
@@ -10465,8 +10672,8 @@ postgres_delete_shard_locks (void *cls)
/**
- * Function called to save the configuration of an extension
- * (age-restriction, peer2peer, ...). After successful storage of the
+ * Function called to save the manifest of an extension
+ * (age-restriction, policy_extension_...) After successful storage of the
* configuration it triggers the corresponding event.
*
* @param cls the @e cls of this struct with the plugin-specific state
@@ -10475,15 +10682,15 @@ postgres_delete_shard_locks (void *cls)
* @return transaction status code
*/
enum GNUNET_DB_QueryStatus
-postgres_set_extension_config (void *cls,
- const char *extension_name,
- const char *config)
+postgres_set_extension_manifest (void *cls,
+ const char *extension_name,
+ const char *manifest)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam pcfg =
- (NULL == config || 0 == *config)
+ (NULL == manifest || 0 == *manifest)
? GNUNET_PQ_query_param_null ()
- : GNUNET_PQ_query_param_string (config);
+ : GNUNET_PQ_query_param_string (manifest);
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_string (extension_name),
pcfg,
@@ -10491,24 +10698,24 @@ postgres_set_extension_config (void *cls,
};
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "set_extension_config",
+ "set_extension_manifest",
params);
}
/**
- * Function called to get the configuration of an extension
- * (age-restriction, peer2peer, ...)
+ * Function called to get the manifest of an extension
+ * (age-restriction, policy_extension_...)
*
* @param cls the @e cls of this struct with the plugin-specific state
* @param extension_name the name of the extension
- * @param[out] config JSON object of the configuration as string
+ * @param[out] manifest JSON object of the manifest as string
* @return transaction status code
*/
enum GNUNET_DB_QueryStatus
-postgres_get_extension_config (void *cls,
- const char *extension_name,
- char **config)
+postgres_get_extension_manifest (void *cls,
+ const char *extension_name,
+ char **manifest)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
@@ -10518,15 +10725,15 @@ postgres_get_extension_config (void *cls,
bool is_null;
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_allow_null (
- GNUNET_PQ_result_spec_string ("config",
- config),
+ GNUNET_PQ_result_spec_string ("manifest",
+ manifest),
&is_null),
GNUNET_PQ_result_spec_end
};
- *config = NULL;
+ *manifest = NULL;
return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "get_extension_config",
+ "get_extension_manifest",
params,
rs);
}
@@ -12311,8 +12518,11 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
plugin->get_withdraw_info = &postgres_get_withdraw_info;
plugin->do_withdraw = &postgres_do_withdraw;
plugin->do_batch_withdraw = &postgres_do_batch_withdraw;
+ plugin->get_policy_details = &postgres_get_policy_details;
+ plugin->persist_policy_details = &postgres_persist_policy_details;
plugin->do_batch_withdraw_insert = &postgres_do_batch_withdraw_insert;
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;
@@ -12446,10 +12656,10 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
= &postgres_release_revolving_shard;
plugin->delete_shard_locks
= &postgres_delete_shard_locks;
- plugin->set_extension_config
- = &postgres_set_extension_config;
- plugin->get_extension_config
- = &postgres_get_extension_config;
+ plugin->set_extension_manifest
+ = &postgres_set_extension_manifest;
+ plugin->get_extension_manifest
+ = &postgres_get_extension_manifest;
plugin->insert_partner
= &postgres_insert_partner;
plugin->insert_contract
diff --git a/src/exchangedb/procedures.sql b/src/exchangedb/procedures.sql
index e9075775c..30610e868 100644
--- a/src/exchangedb/procedures.sql
+++ b/src/exchangedb/procedures.sql
@@ -510,8 +510,8 @@ CREATE OR REPLACE FUNCTION exchange_do_deposit(
IN in_coin_pub BYTEA,
IN in_coin_sig BYTEA,
IN in_shard INT8,
- IN in_extension_blocked BOOLEAN,
- IN in_extension_details VARCHAR,
+ IN in_policy_blocked BOOLEAN,
+ IN in_policy_details_serial_id INT8,
OUT out_exchange_timestamp INT8,
OUT out_balance_ok BOOLEAN,
OUT out_conflict BOOLEAN)
@@ -519,26 +519,12 @@ LANGUAGE plpgsql
AS $$
DECLARE
wtsi INT8; -- wire target serial id
-DECLARE
- xdi INT8; -- eXstension details serial id
BEGIN
-- Shards: INSERT extension_details (by extension_details_serial_id)
-- 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_extension_details
-THEN
- INSERT INTO exchange.extension_details
- (extension_options)
- VALUES
- (in_extension_details)
- RETURNING extension_details_serial_id INTO xdi;
-ELSE
- xdi=NULL;
-END IF;
-
-
INSERT INTO exchange.wire_targets
(wire_target_h_payto
,payto_uri)
@@ -572,8 +558,8 @@ INSERT INTO exchange.deposits
,coin_sig
,wire_salt
,wire_target_h_payto
- ,extension_blocked
- ,extension_details_serial_id
+ ,policy_blocked
+ ,policy_details_serial_id
)
VALUES
(in_shard
@@ -590,8 +576,8 @@ INSERT INTO exchange.deposits
,in_coin_sig
,in_wire_salt
,in_h_payto
- ,in_extension_blocked
- ,xdi)
+ ,in_policy_blocked
+ ,in_policy_details_serial_id)
ON CONFLICT DO NOTHING;
IF NOT FOUND
@@ -611,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
@@ -2420,5 +2407,117 @@ RETURN;
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_commitment_val INT8;
+ cur_commitment_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)
+ ON CONFLICT (policy_hash_code) DO NOTHING
+ RETURNING policy_details_serial_id INTO out_policy_details_serial_id;
+
+ -- If the insert was successful, return
+ -- We assume that the fullfilment_state was correct in first place.
+ IF FOUND THEN
+ out_accumulated_total_val = in_accumulated_total_val;
+ out_accumulated_total_frac = in_accumulated_total_frac;
+ out_fulfillment_state = in_fulfillment_state;
+ 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;
diff --git a/src/exchangedb/test_exchangedb.c b/src/exchangedb/test_exchangedb.c
index eb990412e..111ee9365 100644
--- a/src/exchangedb/test_exchangedb.c
+++ b/src/exchangedb/test_exchangedb.c
@@ -112,53 +112,53 @@ mark_prepare_cb (void *cls,
* Simple check that config retrieval and setting for extensions work
*/
static enum GNUNET_GenericReturnValue
-test_extension_config (void)
+test_extension_manifest (void)
{
- char *config;
+ char *manifest;
FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
- plugin->get_extension_config (plugin->cls,
- "fnord",
- &config));
+ plugin->get_extension_manifest (plugin->cls,
+ "fnord",
+ &manifest));
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
- plugin->set_extension_config (plugin->cls,
- "fnord",
- "bar"));
+ plugin->set_extension_manifest (plugin->cls,
+ "fnord",
+ "bar"));
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
- plugin->get_extension_config (plugin->cls,
- "fnord",
- &config));
+ plugin->get_extension_manifest (plugin->cls,
+ "fnord",
+ &manifest));
- FAILIF (0 != strcmp ("bar", config));
- GNUNET_free (config);
+ FAILIF (0 != strcmp ("bar", manifest));
+ GNUNET_free (manifest);
/* let's do this again! */
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
- plugin->set_extension_config (plugin->cls,
- "fnord",
- "buzz"));
+ plugin->set_extension_manifest (plugin->cls,
+ "fnord",
+ "buzz"));
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
- plugin->get_extension_config (plugin->cls,
- "fnord",
- &config));
+ plugin->get_extension_manifest (plugin->cls,
+ "fnord",
+ &manifest));
- FAILIF (0 != strcmp ("buzz", config));
- GNUNET_free (config);
+ FAILIF (0 != strcmp ("buzz", manifest));
+ GNUNET_free (manifest);
/* let's do this again, with NULL */
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
- plugin->set_extension_config (plugin->cls,
- "fnord",
- NULL));
+ plugin->set_extension_manifest (plugin->cls,
+ "fnord",
+ NULL));
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
- plugin->get_extension_config (plugin->cls,
- "fnord",
- &config));
+ plugin->get_extension_manifest (plugin->cls,
+ "fnord",
+ &manifest));
- FAILIF (NULL != config);
+ FAILIF (NULL != manifest);
return GNUNET_OK;
drop:
@@ -1269,7 +1269,7 @@ run (void *cls)
NULL));
/* simple extension check */
FAILIF (GNUNET_OK !=
- test_extension_config ());
+ test_extension_manifest ());
RND_BLK (&reserve_pub);
GNUNET_assert (GNUNET_OK ==