client/arch/counters.js

// Manages op_id counters and generation
module.exports = function (jiffClient) {

  /**
   * Resets all the counters for op_ids
   * @method counters.reset
   * @memberof module:jiff-client~JIFFClient
   * @instance
   */
  jiffClient.counters.reset = function () {
    jiffClient.counters.op_count = {};
    jiffClient.counters.op_count_preprocessing = {};

    if (jiffClient.counters.pending_opens == null) {
      jiffClient.counters.pending_opens = 0;
    }

    // stores a seed for generating unique op_ids.
    jiffClient.op_id_seed = '';
  };

  // initialize the counters for the first time
  jiffClient.counters.reset();

  /**
   * Shorthand for generating unique operation ids.
   * All primitives called after this seed will use their usual default ids prefixed by the seed.
   * Helpful when we have nested callbacks/functions (e.g. share_arrays) that may be executed in arbitrary order,
   * using this function as a the first call inside such callbacks with an appropriate deterministic unique base_op_id
   * ensures that regardless of the order of execution, operations in the same callback are matched correctly across
   * all parties.
   * Check out demos/graph-pip/mpc.js for an example on using this.
   * @method seed_ids
   * @memberof module:jiff-client~JIFFClient
   * @instance
   * @param {string|number} base_op_id - the base seed to use as a prefix for all future op_ids.
   */
  jiffClient.seed_ids = function (base_op_id) {
    if (base_op_id == null || base_op_id === '') {
      jiffClient.op_id_seed = '';
    } else {
      jiffClient.op_id_seed = base_op_id.toString() + ':';
    }
  };

  /**
   * Generate a unique operation id for a new operation object.
   * The returned op_id will be unique with respect to other operations, and identifies the same
   * operation across all parties, as long as all parties are executing instructions in the same order.
   * @method gen_op_id
   * @memberof module:jiff-client~JIFFClient
   * @instance
   * @param {string} op - the type/name of operation performed.
   * @param {Array} holders - an array containing the ids of all the parties carrying out the operation.
   * @return {string} the op_id for the operation.
   */
  jiffClient.counters.gen_op_id = function (op, holders) {
    var label = jiffClient.op_id_seed + op + ':' + holders.join(',');
    if (jiffClient.counters.op_count[label] == null) {
      jiffClient.counters.op_count[label] = 0;
    }
    return label + ':' + (jiffClient.counters.op_count[label]++);
  };

  /**
   * Generate a unique operation id for a new operation object given two distinct executing parties lists.
   * For example, when sharing, this is given two potentially different lists of senders and receivers.
   * The returned op_id will be unique with respect to other operations, and identifies the same
   * operation across all parties, as long as all parties are executing instructions in the same order.
   * @method gen_op_id2
   * @memberof module:jiff-client~JIFFClient
   * @instance
   * @param {string} op - the type/name of operation performed.
   * @param {Array} receivers - an array containing the ids of all the parties carrying out the receiving portion of the operation.
   * @param {Array} senders - an array containing the ids of all the parties carrying out the sending portion of the operation.
   * @return {string} the op_id for the operation.
   */
  jiffClient.counters.gen_op_id2 = function (op, receivers, senders) {
    var label = jiffClient.op_id_seed + op + ':' + senders.join(',') + ':' + receivers.join(',');
    if (jiffClient.counters.op_count[label] == null) {
      jiffClient.counters.op_count[label] = 0;
    }
    return label + ':' + (jiffClient.counters.op_count[label]++);
  };

  /**
   * Generate a unique operation id for a new operation object (for preprocessing)
   * The returned op_id will be unique with respect to other operations, and identifies the same
   * operation across all parties, as long as all parties are executing instructions in the same order.
   * @method gen_op_id_preprocessing
   * @memberof module:jiff-client~JIFFClient
   * @instance
   * @param {string} op - the type/name of operation performed.
   * @param {Array} holders - an array containing the ids of all the parties carrying out the operation.
   * @return {string} the op_id for the operation.
   */
  jiffClient.counters.gen_op_id_preprocessing = function (op, holders) {
    var label = jiffClient.op_id_seed + op + ':' + holders.join(',');
    if (jiffClient.counters.op_count_preprocessing[label] == null) {
      jiffClient.counters.op_count_preprocessing[label] = 0;
    }
    return label + ':' + (jiffClient.counters.op_count_preprocessing[label]++);
  };

  /**
   * Generate a unique operation id for a new operation object given two distinct executing parties lists (for preprocessing).
   * For example, when sharing, this is given two potentially different lists of senders and receivers.
   * The returned op_id will be unique with respect to other operations, and identifies the same
   * operation across all parties, as long as all parties are executing instructions in the same order.
   * @method gen_op_id2_preprocessing
   * @memberof module:jiff-client~JIFFClient
   * @instance
   * @param {string} op - the type/name of operation performed.
   * @param {Array} receivers - an array containing the ids of all the parties carrying out the receiving portion of the operation.
   * @param {Array} senders - an array containing the ids of all the parties carrying out the sending portion of the operation.
   * @return {string} the op_id for the operation.
   */
  jiffClient.counters.gen_op_id2_preprocessing = function (op, receivers, senders) {
    var label = jiffClient.op_id_seed + op + ':' + senders.join(',') + ':' + receivers.join(',');
    if (jiffClient.counters.op_count_preprocessing[label] == null) {
      jiffClient.counters.op_count_preprocessing[label] = 0;
    }
    return label + ':' + (jiffClient.counters.op_count_preprocessing[label]++);
  };
};