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