github.com/muhammedhassanm/blockchain@v0.0.0-20200120143007-697261defd4d/sawtooth-core-master/sdk/python/sawtooth_sdk/consensus/zmq_driver.py (about)

     1  # Copyright 2018 Intel Corporation
     2  #
     3  # Licensed under the Apache License, Version 2.0 (the "License");
     4  # you may not use this file except in compliance with the License.
     5  # You may obtain a copy of the License at
     6  #
     7  #     http://www.apache.org/licenses/LICENSE-2.0
     8  #
     9  # Unless required by applicable law or agreed to in writing, software
    10  # distributed under the License is distributed on an "AS IS" BASIS,
    11  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  # See the License for the specific language governing permissions and
    13  # limitations under the License.
    14  # -----------------------------------------------------------------------------
    15  
    16  import concurrent
    17  import logging
    18  from queue import Queue
    19  from threading import Thread
    20  
    21  from sawtooth_sdk.consensus.driver import Driver
    22  from sawtooth_sdk.consensus.engine import StartupState
    23  from sawtooth_sdk.consensus.zmq_service import ZmqService
    24  from sawtooth_sdk.consensus import exceptions
    25  from sawtooth_sdk.messaging.stream import Stream
    26  from sawtooth_sdk.protobuf import consensus_pb2
    27  from sawtooth_sdk.protobuf.validator_pb2 import Message
    28  
    29  
    30  LOGGER = logging.getLogger(__name__)
    31  REGISTER_TIMEOUT = 300
    32  SERVICE_TIMEOUT = 300
    33  
    34  
    35  class ZmqDriver(Driver):
    36      def __init__(self, engine):
    37          super().__init__(engine)
    38          self._engine = engine
    39          self._stream = None
    40          self._exit = False
    41          self._updates = None
    42  
    43      def start(self, endpoint):
    44          self._stream = Stream(endpoint)
    45  
    46          startup_state = self._register()
    47  
    48          self._updates = Queue()
    49  
    50          driver_thread = Thread(
    51              target=self._driver_loop)
    52          driver_thread.start()
    53  
    54          try:
    55              self._engine.start(
    56                  self._updates,
    57                  ZmqService(
    58                      stream=self._stream,
    59                      timeout=SERVICE_TIMEOUT,
    60                      name=self._engine.name(),
    61                      version=self._engine.version()),
    62                  startup_state)
    63          except Exception:  # pylint: disable=broad-except
    64              LOGGER.exception("Uncaught engine exception")
    65  
    66          self.stop()
    67          driver_thread.join()
    68  
    69      def _driver_loop(self):
    70          try:
    71              future = self._stream.receive()
    72              while True:
    73                  if self._exit:
    74                      self._engine.stop()
    75                      break
    76  
    77                  try:
    78                      message = future.result(1)
    79                      future = self._stream.receive()
    80                  except concurrent.futures.TimeoutError:
    81                      continue
    82  
    83                  result = self._process(message)
    84  
    85                  self._updates.put(result)
    86          except Exception:  # pylint: disable=broad-except
    87              LOGGER.exception("Uncaught driver exception")
    88  
    89      def stop(self):
    90          self._exit = True
    91          self._engine.stop()
    92          self._stream.close()
    93  
    94      def _register(self):
    95          self._stream.wait_for_ready()
    96  
    97          request = consensus_pb2.ConsensusRegisterRequest(
    98              name=self._engine.name(),
    99              version=self._engine.version(),
   100          ).SerializeToString()
   101  
   102          while True:
   103              future = self._stream.send(
   104                  message_type=Message.CONSENSUS_REGISTER_REQUEST,
   105                  content=request)
   106              response = consensus_pb2.ConsensusRegisterResponse()
   107              response.ParseFromString(future.result(REGISTER_TIMEOUT).content)
   108  
   109              if (
   110                  response.status
   111                  == consensus_pb2.ConsensusRegisterResponse.NOT_READY
   112              ):
   113                  continue
   114  
   115              if response.status == consensus_pb2.ConsensusRegisterResponse.OK:
   116                  return StartupState(
   117                      response.chain_head,
   118                      response.peers,
   119                      response.local_peer_info)
   120  
   121              raise exceptions.ReceiveError(
   122                  'Registration failed with status {}'.format(response.status))
   123  
   124      def _process(self, message):
   125          type_tag = message.message_type
   126  
   127          if type_tag == Message.CONSENSUS_NOTIFY_PEER_CONNECTED:
   128              notification = consensus_pb2.ConsensusNotifyPeerConnected()
   129              notification.ParseFromString(message.content)
   130  
   131              data = notification.peer_info
   132  
   133          elif type_tag == Message.CONSENSUS_NOTIFY_PEER_DISCONNECTED:
   134              notification = consensus_pb2.ConsensusNotifyPeerDisconnected()
   135              notification.ParseFromString(message.content)
   136  
   137              data = notification.peer_id
   138  
   139          elif type_tag == Message.CONSENSUS_NOTIFY_PEER_MESSAGE:
   140              notification = consensus_pb2.ConsensusNotifyPeerMessage()
   141              notification.ParseFromString(message.content)
   142  
   143              data = notification.message, notification.sender_id
   144  
   145          elif type_tag == Message.CONSENSUS_NOTIFY_BLOCK_NEW:
   146              notification = consensus_pb2.ConsensusNotifyBlockNew()
   147              notification.ParseFromString(message.content)
   148  
   149              data = notification.block
   150  
   151          elif type_tag == Message.CONSENSUS_NOTIFY_BLOCK_VALID:
   152              notification = consensus_pb2.ConsensusNotifyBlockValid()
   153              notification.ParseFromString(message.content)
   154  
   155              data = notification.block_id
   156  
   157          elif type_tag == Message.CONSENSUS_NOTIFY_BLOCK_INVALID:
   158              notification = consensus_pb2.ConsensusNotifyBlockInvalid()
   159              notification.ParseFromString(message.content)
   160  
   161              data = notification.block_id
   162  
   163          elif type_tag == Message.CONSENSUS_NOTIFY_BLOCK_COMMIT:
   164              notification = consensus_pb2.ConsensusNotifyBlockCommit()
   165              notification.ParseFromString(message.content)
   166  
   167              data = notification.block_id
   168  
   169          else:
   170              raise exceptions.ReceiveError(
   171                  'Received unexpected message type: {}'.format(type_tag))
   172  
   173          self._stream.send_back(
   174              message_type=Message.CONSENSUS_NOTIFY_ACK,
   175              correlation_id=message.correlation_id,
   176              content=consensus_pb2.ConsensusNotifyAck().SerializeToString())
   177  
   178          return type_tag, data