github.com/muhammedhassanm/blockchain@v0.0.0-20200120143007-697261defd4d/build-blockchain-insurance-app-master/web/www/blockchain/utils.js (about)

     1  'use strict';
     2  
     3  import {
     4    resolve
     5  } from 'path';
     6  import EventEmitter from 'events';
     7  
     8  import {
     9    load as loadProto
    10  } from 'grpc';
    11  import Long from 'long';
    12  import hfc from 'fabric-client';
    13  import utils from 'fabric-client/lib/utils';
    14  import Orderer from 'fabric-client/lib/Orderer';
    15  import Peer from 'fabric-client/lib/Peer';
    16  import EventHub from 'fabric-client/lib/EventHub';
    17  import User from 'fabric-client/lib/User';
    18  import CAClient from 'fabric-ca-client';
    19  import {
    20    snakeToCamelCase,
    21    camelToSnakeCase
    22  } from 'json-style-converter';
    23  
    24  process.env.GOPATH = resolve(__dirname, '../../chaincode');
    25  const JOIN_TIMEOUT = 120000,
    26    TRANSACTION_TIMEOUT = 120000;
    27  
    28  export class OrganizationClient extends EventEmitter {
    29  
    30    constructor(channelName, ordererConfig, peerConfig, caConfig, admin) {
    31      super();
    32      this._channelName = channelName;
    33      this._ordererConfig = ordererConfig;
    34      this._peerConfig = peerConfig;
    35      this._caConfig = caConfig;
    36      this._admin = admin;
    37      this._peers = [];
    38      this._eventHubs = [];
    39      this._client = new hfc();
    40  
    41      // Setup channel
    42      this._channel = this._client.newChannel(channelName);
    43  
    44      // Setup orderer and peers
    45      const orderer = this._client.newOrderer(ordererConfig.url, {
    46        pem: ordererConfig.pem,
    47        'ssl-target-name-override': ordererConfig.hostname
    48      });
    49      this._channel.addOrderer(orderer);
    50  
    51      const defaultPeer = this._client.newPeer(peerConfig.url, {
    52        pem: peerConfig.pem,
    53        'ssl-target-name-override': peerConfig.hostname
    54      });
    55      this._peers.push(defaultPeer);
    56      this._channel.addPeer(defaultPeer);
    57      this._adminUser = null;
    58    }
    59  
    60    async login() {
    61      try {
    62        this._client.setStateStore(
    63          await hfc.newDefaultKeyValueStore({
    64            path: `./${this._peerConfig.hostname}`
    65          }));
    66        this._adminUser = await getSubmitter(
    67          this._client, "admin", "adminpw", this._caConfig);
    68      } catch (e) {
    69        console.log(`Failed to enroll user. Error: ${e.message}`);
    70        throw e;
    71      }
    72    }
    73  
    74    initEventHubs() {
    75      // Setup event hubs
    76      try {
    77        const defaultEventHub = this._client.newEventHub();
    78        defaultEventHub.setPeerAddr(this._peerConfig.eventHubUrl, {
    79          pem: this._peerConfig.pem,
    80          'ssl-target-name-override': this._peerConfig.hostname
    81        });
    82        defaultEventHub.connect();
    83        defaultEventHub.registerBlockEvent(
    84          block => {
    85            this.emit('block', unmarshalBlock(block));
    86          });
    87        this._eventHubs.push(defaultEventHub);
    88      } catch (e) {
    89        console.log(`Failed to configure event hubs. Error ${e.message}`);
    90        throw e;
    91      }
    92    }
    93  
    94    async getOrgAdmin() {
    95      return this._client.createUser({
    96        username: `Admin@${this._peerConfig.hostname}`,
    97        mspid: this._caConfig.mspId,
    98        cryptoContent: {
    99          privateKeyPEM: this._admin.key,
   100          signedCertPEM: this._admin.cert
   101        }
   102      });
   103    }
   104  
   105    async initialize() {
   106      try {
   107        await this._channel.initialize();
   108      } catch (e) {
   109        console.log(`Failed to initialize chain. Error: ${e.message}`);
   110        throw e;
   111      }
   112    }
   113  
   114    async createChannel(envelope) {
   115      const txId = this._client.newTransactionID();
   116      const channelConfig = this._client.extractChannelConfig(envelope);
   117      const signature = this._client.signChannelConfig(channelConfig);
   118      const request = {
   119        name: this._channelName,
   120        orderer: this._channel.getOrderers()[0],
   121        config: channelConfig,
   122        signatures: [signature],
   123        txId
   124      };
   125      const response = await this._client.createChannel(request);
   126  
   127      // Wait for 5sec to create channel
   128      await new Promise(resolve => {
   129        setTimeout(resolve, 5000);
   130      });
   131      return response;
   132    }
   133  
   134    async joinChannel() {
   135      try {
   136        const genesisBlock = await this._channel.getGenesisBlock({
   137          txId: this._client.newTransactionID()
   138        });
   139        const request = {
   140          targets: this._peers,
   141          txId: this._client.newTransactionID(),
   142          block: genesisBlock
   143        };
   144        const joinedChannelPromises = this._eventHubs.map(eh => {
   145          eh.connect();
   146          return new Promise((resolve, reject) => {
   147            let blockRegistration;
   148            const cb = block => {
   149              clearTimeout(responseTimeout);
   150              eh.unregisterBlockEvent(blockRegistration);
   151              if (block.data.data.length === 1) {
   152                const channelHeader =
   153                  block.data.data[0].payload.header.channel_header;
   154                if (channelHeader.channel_id === this._channelName) {
   155                  resolve();
   156                } else {
   157                  reject(new Error('Peer did not join an expected channel.'));
   158                }
   159              }
   160            };
   161  
   162            blockRegistration = eh.registerBlockEvent(cb);
   163            const responseTimeout = setTimeout(() => {
   164              eh.unregisterBlockEvent(blockRegistration);
   165              reject(new Error('Peer did not respond in a timely fashion!'));
   166            }, JOIN_TIMEOUT);
   167          });
   168        });
   169  
   170        const completedPromise = joinedChannelPromises.concat([
   171          this._channel.joinChannel(request)
   172        ]);
   173        await Promise.all(completedPromise);
   174      } catch (e) {
   175        console.log(`Error joining peer to channel. Error: ${e.message}`);
   176        throw e;
   177      }
   178    }
   179  
   180    async checkChannelMembership() {
   181      try {
   182        const { channels } = await this._client.queryChannels(this._peers[0]);
   183        if (!Array.isArray(channels)) {
   184          return false;
   185        }
   186        return channels.some(({channel_id}) => channel_id === this._channelName);
   187      } catch (e) {
   188        return false;
   189      }
   190    }
   191  
   192    async checkInstalled(chaincodeId, chaincodeVersion, chaincodePath) {
   193      let {
   194        chaincodes
   195      } = await this._channel.queryInstantiatedChaincodes();
   196      if (!Array.isArray(chaincodes)) {
   197        return false;
   198      }
   199      return chaincodes.some(cc =>
   200        cc.name === chaincodeId &&
   201        cc.path === chaincodePath &&
   202        cc.version === chaincodeVersion);
   203    }
   204  
   205    async install(chaincodeId, chaincodeVersion, chaincodePath) {
   206      const request = {
   207        targets: this._peers,
   208        chaincodePath,
   209        chaincodeId,
   210        chaincodeVersion
   211      };
   212  
   213      // Make install proposal to all peers
   214      let results;
   215      try {
   216        results = await this._client.installChaincode(request);
   217      } catch (e) {
   218        console.log(
   219          `Error sending install proposal to peer! Error: ${e.message}`);
   220        throw e;
   221      }
   222      const proposalResponses = results[0];
   223      const allGood = proposalResponses
   224        .every(pr => pr.response && pr.response.status == 200);
   225      return allGood;
   226    }
   227  
   228    async instantiate(chaincodeId, chaincodeVersion, ...args) {
   229      let proposalResponses, proposal;
   230      const txId = this._client.newTransactionID();
   231      try {
   232        const request = {
   233          chaincodeType: 'golang',
   234          chaincodeId,
   235          chaincodeVersion,
   236          fcn: 'init',
   237          args: marshalArgs(args),
   238          txId
   239        };
   240        const results = await this._channel.sendInstantiateProposal(request);
   241        proposalResponses = results[0];
   242        proposal = results[1];
   243  
   244        let allGood = proposalResponses
   245          .every(pr => pr.response && pr.response.status == 200);
   246  
   247        if (!allGood) {
   248          throw new Error(
   249            `Proposal rejected by some (all) of the peers: ${proposalResponses}`);
   250        }
   251      } catch (e) {
   252        throw e;
   253      }
   254  
   255      try {
   256        const request = {
   257          proposalResponses,
   258          proposal
   259        };
   260        const deployId = txId.getTransactionID();
   261        const transactionCompletePromises = this._eventHubs.map(eh => {
   262          eh.connect();
   263  
   264          return new Promise((resolve, reject) => {
   265            // Set timeout for the transaction response from the current peer
   266            const responseTimeout = setTimeout(() => {
   267              eh.unregisterTxEvent(deployId);
   268              reject(new Error('Peer did not respond in a timely fashion!'));
   269            }, TRANSACTION_TIMEOUT);
   270  
   271            eh.registerTxEvent(deployId, (tx, code) => {
   272              clearTimeout(responseTimeout);
   273              eh.unregisterTxEvent(deployId);
   274              if (code != 'VALID') {
   275                reject(new Error(
   276                  `Peer has rejected transaction with code: ${code}`));
   277              } else {
   278                resolve();
   279              }
   280            });
   281          });
   282        });
   283  
   284        transactionCompletePromises.push(this._channel.sendTransaction(request));
   285        await transactionCompletePromises;
   286      } catch (e) {
   287        throw e;
   288      }
   289    }
   290  
   291    async invoke(chaincodeId, chaincodeVersion, fcn, ...args) {
   292      let proposalResponses, proposal;
   293      const txId = this._client.newTransactionID();
   294      try {
   295        const request = {
   296          chaincodeId,
   297          chaincodeVersion,
   298          fcn,
   299          args: marshalArgs(args),
   300          txId
   301        };
   302        const results = await this._channel.sendTransactionProposal(request);
   303        proposalResponses = results[0];
   304        proposal = results[1];
   305  
   306        const allGood = proposalResponses
   307          .every(pr => pr.response && pr.response.status == 200);
   308  
   309        if (!allGood) {
   310          throw new Error(
   311            `Proposal rejected by some (all) of the peers: ${proposalResponses}`);
   312        }
   313      } catch (e) {
   314        throw e;
   315      }
   316  
   317      try {
   318        const request = {
   319          proposalResponses,
   320          proposal
   321        };
   322  
   323        const transactionId = txId.getTransactionID();
   324        const transactionCompletePromises = this._eventHubs.map(eh => {
   325          eh.connect();
   326  
   327          return new Promise((resolve, reject) => {
   328            // Set timeout for the transaction response from the current peer
   329            const responseTimeout = setTimeout(() => {
   330              eh.unregisterTxEvent(transactionId);
   331              reject(new Error('Peer did not respond in a timely fashion!'));
   332            }, TRANSACTION_TIMEOUT);
   333  
   334            eh.registerTxEvent(transactionId, (tx, code) => {
   335              clearTimeout(responseTimeout);
   336              eh.unregisterTxEvent(transactionId);
   337              if (code != 'VALID') {
   338                reject(new Error(
   339                  `Peer has rejected transaction with code: ${code}`));
   340              } else {
   341                resolve();
   342              }
   343            });
   344          });
   345        });
   346  
   347        transactionCompletePromises.push(this._channel.sendTransaction(request));
   348        try {
   349          await transactionCompletePromises;
   350          const payload = proposalResponses[0].response.payload;
   351          return unmarshalResult([payload]);
   352        } catch (e) {
   353          throw e;
   354        }
   355      } catch (e) {
   356        throw e;
   357      }
   358    }
   359  
   360    async query(chaincodeId, chaincodeVersion, fcn, ...args) {
   361      const request = {
   362        chaincodeId,
   363        chaincodeVersion,
   364        fcn,
   365        args: marshalArgs(args),
   366        txId: this._client.newTransactionID(),
   367      };
   368      return unmarshalResult(await this._channel.queryByChaincode(request));
   369    }
   370  
   371    async getBlocks(noOfLastBlocks) {
   372      if (typeof noOfLastBlocks !== 'number' &&
   373        typeof noOfLastBlocks !== 'string') {
   374        return [];
   375      }
   376  
   377      const {
   378        height
   379      } = await this._channel.queryInfo();
   380      let blockCount;
   381      if (height.comp(noOfLastBlocks) > 0) {
   382        blockCount = noOfLastBlocks;
   383      } else {
   384        blockCount = height;
   385      }
   386      if (typeof blockCount === 'number') {
   387        blockCount = Long.fromNumber(blockCount, height.unsigned);
   388      } else if (typeof blockCount === 'string') {
   389        blockCount = Long.fromString(blockCount, height.unsigned);
   390      }
   391      blockCount = blockCount.toNumber();
   392      const queryBlock = this._channel.queryBlock.bind(this._channel);
   393      const blockPromises = {};
   394      blockPromises[Symbol.iterator] = function* () {
   395        for (let i = 1; i <= blockCount; i++) {
   396          yield queryBlock(height.sub(i).toNumber());
   397        }
   398      };
   399      const blocks = await Promise.all([...blockPromises]);
   400      return blocks.map(unmarshalBlock);
   401    }
   402  }
   403  
   404  /**
   405   * Enrolls a user with the respective CA.
   406   *
   407   * @export
   408   * @param {string} client
   409   * @param {string} enrollmentID
   410   * @param {string} enrollmentSecret
   411   * @param {object} { url, mspId }
   412   * @returns the User object
   413   */
   414  async function getSubmitter(
   415    client, enrollmentID, enrollmentSecret, {
   416      url,
   417      mspId
   418    }) {
   419  
   420    try {
   421      let user = await client.getUserContext(enrollmentID, true);
   422      if (user && user.isEnrolled()) {
   423        return user;
   424      }
   425  
   426      // Need to enroll with CA server
   427      const ca = new CAClient(url, {
   428        verify: false
   429      });
   430      try {
   431        const enrollment = await ca.enroll({
   432          enrollmentID,
   433          enrollmentSecret
   434        });
   435        user = new User(enrollmentID, client);
   436        await user.setEnrollment(enrollment.key, enrollment.certificate, mspId);
   437        await client.setUserContext(user);
   438        return user;
   439      } catch (e) {
   440        throw new Error(
   441          `Failed to enroll and persist User. Error: ${e.message}`);
   442      }
   443    } catch (e) {
   444      throw new Error(`Could not get UserContext! Error: ${e.message}`);
   445    }
   446  }
   447  
   448  export function wrapError(message, innerError) {
   449    let error = new Error(message);
   450    error.inner = innerError;
   451    console.log(error.message);
   452    throw error;
   453  }
   454  
   455  function marshalArgs(args) {
   456    if (!args) {
   457      return args;
   458    }
   459  
   460    if (typeof args === 'string') {
   461      return [args];
   462    }
   463  
   464    let snakeArgs = camelToSnakeCase(args);
   465  
   466    if (Array.isArray(args)) {
   467      return snakeArgs.map(
   468        arg => typeof arg === 'object' ? JSON.stringify(arg) : arg.toString());
   469    }
   470  
   471    if (typeof args === 'object') {
   472      return [JSON.stringify(snakeArgs)];
   473    }
   474  }
   475  
   476  function unmarshalResult(result) {
   477    if (!Array.isArray(result)) {
   478      return result;
   479    }
   480    let buff = Buffer.concat(result);
   481    if (!Buffer.isBuffer(buff)) {
   482      return result;
   483    }
   484    let json = buff.toString('utf8');
   485    if (!json) {
   486      return null;
   487    }
   488    let obj = JSON.parse(json);
   489    return snakeToCamelCase(obj);
   490  }
   491  
   492  function unmarshalBlock(block) {
   493    const transactions = Array.isArray(block.data.data) ?
   494      block.data.data.map(({
   495        payload: {
   496          header,
   497          data
   498        }
   499      }) => {
   500        const {
   501          channel_header
   502        } = header;
   503        const {
   504          type,
   505          timestamp,
   506          epoch
   507        } = channel_header;
   508        return {
   509          type,
   510          timestamp
   511        };
   512      }) : [];
   513    return {
   514      id: block.header.number.toString(),
   515      fingerprint: block.header.data_hash.slice(0, 20),
   516      transactions
   517    };
   518  }