diff options
| 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 | 
| commit | 752f10273860d2496fc3eb1e03de6ad4451e7c0f (patch) | |
| tree | 53d51969f58611dbf8afacdcd40a769f5c847dd8 /src/exchangedb | |
| parent | c89bfa9026d7180eb24ae9480f225b93db22c53a (diff) | |
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.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 ab4f8ea9..a95d74d2 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 99883a27..4599d2ee 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 0ac70bae..d6630797 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 57c7c2b0..9d600f74 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 202be30f..7e150cd2 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 28dbdbaa..0b03fe4b 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 e9075775..30610e86 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 eb990412..111ee936 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 == | 
