github.com/muhammedhassanm/blockchain@v0.0.0-20200120143007-697261defd4d/sawtooth-supply-chain-master/ledger_sync/subscriber/index.js (about)

     1  /**
     2   * Copyright 2018 Intel Corporation
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   * ----------------------------------------------------------------------------
    16   */
    17  'use strict'
    18  
    19  const _ = require('lodash')
    20  const { Stream } = require('sawtooth-sdk/messaging/stream')
    21  const {
    22    Message,
    23    EventList,
    24    EventSubscription,
    25    EventFilter,
    26    StateChangeList,
    27    ClientEventsSubscribeRequest,
    28    ClientEventsSubscribeResponse
    29  } = require('sawtooth-sdk/protobuf')
    30  
    31  const deltas = require('./deltas')
    32  const config = require('../system/config')
    33  
    34  const PREFIX = '3400de'
    35  const NULL_BLOCK_ID = '0000000000000000'
    36  const VALIDATOR_URL = config.VALIDATOR_URL
    37  const stream = new Stream(VALIDATOR_URL)
    38  
    39  // Parse Block Commit Event
    40  const getBlock = events => {
    41    const block = _.chain(events)
    42      .find(e => e.eventType === 'sawtooth/block-commit')
    43      .get('attributes')
    44      .map(a => [a.key, a.value])
    45      .fromPairs()
    46      .value()
    47  
    48    return {
    49      blockNum: parseInt(block.block_num),
    50      blockId: block.block_id,
    51      stateRootHash: block.state_root_hash
    52    }
    53  }
    54  
    55  // Parse State Delta Event
    56  const getChanges = events => {
    57    const event = events.find(e => e.eventType === 'sawtooth/state-delta')
    58    if (!event) return []
    59  
    60    const changeList = StateChangeList.decode(event.data)
    61    return changeList.stateChanges
    62      .filter(change => change.address.slice(0, 6) === PREFIX)
    63  }
    64  
    65  // Handle event message received by stream
    66  const handleEvent = msg => {
    67    if (msg.messageType === Message.MessageType.CLIENT_EVENTS) {
    68      const events = EventList.decode(msg.content).events
    69      deltas.handle(getBlock(events), getChanges(events))
    70    } else {
    71      console.warn('Received message of unknown type:', msg.messageType)
    72    }
    73  }
    74  
    75  // Send delta event subscription request to validator
    76  const subscribe = () => {
    77    const blockSub = EventSubscription.create({
    78      eventType: 'sawtooth/block-commit'
    79    })
    80    const deltaSub = EventSubscription.create({
    81      eventType: 'sawtooth/state-delta',
    82      filters: [EventFilter.create({
    83        key: 'address',
    84        matchString: `^${PREFIX}.*`,
    85        filterType: EventFilter.FilterType.REGEX_ANY
    86      })]
    87    })
    88  
    89    return stream.send(
    90      Message.MessageType.CLIENT_EVENTS_SUBSCRIBE_REQUEST,
    91      ClientEventsSubscribeRequest.encode({
    92        lastKnownBlockIds: [NULL_BLOCK_ID],
    93        subscriptions: [blockSub, deltaSub]
    94      }).finish()
    95    )
    96      .then(response => ClientEventsSubscribeResponse.decode(response))
    97      .then(decoded => {
    98        const status = _.findKey(ClientEventsSubscribeResponse.Status,
    99                                 val => val === decoded.status)
   100        if (status !== 'OK') {
   101          throw new Error(`Validator responded with status "${status}"`)
   102        }
   103      })
   104  }
   105  
   106  // Start stream and send delta event subscription request
   107  const start = () => {
   108    return new Promise(resolve => {
   109      stream.connect(() => {
   110        stream.onReceive(handleEvent)
   111        subscribe().then(resolve)
   112      })
   113    })
   114  }
   115  
   116  module.exports = {
   117    start
   118  }