diff options
Diffstat (limited to 'src/exchangedb')
-rw-r--r-- | src/exchangedb/common-0001.sql | 6 | ||||
-rw-r--r-- | src/exchangedb/exchange-0001-part.sql | 100 | ||||
-rw-r--r-- | src/exchangedb/pg_insert_records_by_table.c | 114 | ||||
-rw-r--r-- | src/exchangedb/pg_lookup_records_by_table.c | 131 | ||||
-rw-r--r-- | src/exchangedb/pg_lookup_serial_by_table.c | 18 | ||||
-rw-r--r-- | src/exchangedb/plugin_exchangedb_postgres.c | 278 | ||||
-rw-r--r-- | src/exchangedb/procedures.sql | 139 | ||||
-rw-r--r-- | src/exchangedb/test_exchangedb.c | 58 |
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 == |