github.com/muhammedhassanm/blockchain@v0.0.0-20200120143007-697261defd4d/sawtooth-core-master/sdk/rust/src/consensus/zmq_driver.rs (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  
    18  use protobuf;
    19  use protobuf::{Message as ProtobufMessage, ProtobufError};
    20  use rand;
    21  use rand::Rng;
    22  
    23  use consensus::engine::*;
    24  use consensus::zmq_service::ZmqService;
    25  
    26  use messaging::stream::MessageConnection;
    27  use messaging::stream::MessageSender;
    28  use messaging::stream::ReceiveError;
    29  use messaging::stream::SendError;
    30  use messaging::zmq_stream::{ZmqMessageConnection, ZmqMessageSender};
    31  
    32  use messages::consensus::*;
    33  use messages::validator::{Message, Message_MessageType};
    34  
    35  use std::sync::mpsc::{self, channel, Receiver, RecvTimeoutError, Sender};
    36  use std::thread;
    37  use std::time::Duration;
    38  
    39  const REGISTER_TIMEOUT: u64 = 300;
    40  const SERVICE_TIMEOUT: u64 = 300;
    41  const INITAL_RETRY_DELAY: Duration = Duration::from_millis(100);
    42  const MAX_RETRY_DELAY: Duration = Duration::from_secs(3);
    43  
    44  /// Generates a random correlation id for use in Message
    45  fn generate_correlation_id() -> String {
    46      const LENGTH: usize = 16;
    47      rand::thread_rng().gen_ascii_chars().take(LENGTH).collect()
    48  }
    49  
    50  pub struct ZmqDriver {
    51      stop_receiver: Receiver<()>,
    52  }
    53  
    54  impl ZmqDriver {
    55      /// Create a new ZMQ-based Consensus Engine driver and a handle for stopping it
    56      pub fn new() -> (Self, Stop) {
    57          let (stop_sender, stop_receiver) = channel();
    58          let stop = Stop {
    59              sender: stop_sender,
    60          };
    61          let driver = ZmqDriver { stop_receiver };
    62          (driver, stop)
    63      }
    64  
    65      /// Start the driver with the given engine, consuming both
    66      ///
    67      /// The engine's start method will be run from the current thread and this method should block
    68      /// until the engine shutsdown.
    69      pub fn start<T: AsRef<str>, E: Engine>(self, endpoint: T, mut engine: E) -> Result<(), Error> {
    70          let validator_connection = ZmqMessageConnection::new(endpoint.as_ref());
    71          let (mut validator_sender, validator_receiver) = validator_connection.create();
    72  
    73          let validator_sender_clone = validator_sender.clone();
    74          let (update_sender, update_receiver) = channel();
    75  
    76          let startup_state = register(
    77              &mut validator_sender,
    78              Duration::from_secs(REGISTER_TIMEOUT),
    79              engine.name(),
    80              engine.version(),
    81          )?;
    82  
    83          let driver_thread = thread::spawn(move || {
    84              driver_loop(
    85                  update_sender,
    86                  self.stop_receiver,
    87                  validator_sender,
    88                  validator_receiver,
    89              )
    90          });
    91  
    92          let (name, version) = { (engine.name(), engine.version()) };
    93          engine.start(
    94              update_receiver,
    95              Box::new(ZmqService::new(
    96                  validator_sender_clone,
    97                  Duration::from_secs(SERVICE_TIMEOUT),
    98                  name,
    99                  version,
   100              )),
   101              startup_state,
   102          );
   103  
   104          driver_thread.join().expect("Driver panicked")
   105      }
   106  }
   107  
   108  /// Utility class for signaling that the driver should be shutdown
   109  #[derive(Clone)]
   110  pub struct Stop {
   111      sender: Sender<()>,
   112  }
   113  
   114  impl Stop {
   115      pub fn stop(&self) {
   116          self.sender
   117              .send(())
   118              .unwrap_or_else(|err| error!("Failed to send stop signal: {:?}", err));
   119      }
   120  }
   121  
   122  fn driver_loop(
   123      mut update_sender: Sender<Update>,
   124      stop_receiver: Receiver<()>,
   125      mut validator_sender: ZmqMessageSender,
   126      validator_receiver: Receiver<Result<Message, ReceiveError>>,
   127  ) -> Result<(), Error> {
   128      loop {
   129          match validator_receiver.recv_timeout(Duration::from_millis(100)) {
   130              Err(RecvTimeoutError::Timeout) => {
   131                  if let Ok(_) = stop_receiver.try_recv() {
   132                      update_sender.send(Update::Shutdown)?;
   133                      break Ok(());
   134                  }
   135              }
   136              Err(RecvTimeoutError::Disconnected) => {
   137                  break Err(Error::ReceiveError("Sender disconnected".into()));
   138              }
   139              Ok(Err(err)) => {
   140                  break Err(Error::ReceiveError(format!(
   141                      "Unexpected error while receiving: {}",
   142                      err
   143                  )));
   144              }
   145              Ok(Ok(msg)) => {
   146                  if let Err(err) = handle_update(&msg, &mut validator_sender, &mut update_sender) {
   147                      break Err(err);
   148                  }
   149                  if let Ok(_) = stop_receiver.try_recv() {
   150                      update_sender.send(Update::Shutdown)?;
   151                      break Ok(());
   152                  }
   153              }
   154          }
   155      }
   156  }
   157  
   158  pub fn register(
   159      sender: &mut MessageSender,
   160      timeout: Duration,
   161      name: String,
   162      version: String,
   163  ) -> Result<StartupState, Error> {
   164      let mut request = ConsensusRegisterRequest::new();
   165      request.set_name(name);
   166      request.set_version(version);
   167      let request = request.write_to_bytes()?;
   168  
   169      let mut msg = sender
   170          .send(
   171              Message_MessageType::CONSENSUS_REGISTER_REQUEST,
   172              &generate_correlation_id(),
   173              &request,
   174          )?
   175          .get_timeout(timeout)?;
   176  
   177      let ret: Result<StartupState, Error>;
   178  
   179      // Keep trying to register until the response is something other
   180      // than NOT_READY.
   181  
   182      let mut retry_delay = INITAL_RETRY_DELAY;
   183      loop {
   184          match msg.get_message_type() {
   185              Message_MessageType::CONSENSUS_REGISTER_RESPONSE => {
   186                  let mut response: ConsensusRegisterResponse =
   187                      protobuf::parse_from_bytes(msg.get_content())?;
   188  
   189                  match response.get_status() {
   190                      ConsensusRegisterResponse_Status::OK => {
   191                          ret = Ok(StartupState {
   192                              chain_head: response.take_chain_head().into(),
   193                              peers: response
   194                                  .take_peers()
   195                                  .into_iter()
   196                                  .map(|info| info.into())
   197                                  .collect(),
   198                              local_peer_info: response.take_local_peer_info().into(),
   199                          });
   200  
   201                          break;
   202                      }
   203                      ConsensusRegisterResponse_Status::NOT_READY => {
   204                          thread::sleep(retry_delay);
   205                          if retry_delay < MAX_RETRY_DELAY {
   206                              retry_delay = retry_delay * 2;
   207                              if retry_delay > MAX_RETRY_DELAY {
   208                                  retry_delay = MAX_RETRY_DELAY;
   209                              }
   210                          }
   211                          msg = sender
   212                              .send(
   213                                  Message_MessageType::CONSENSUS_REGISTER_REQUEST,
   214                                  &generate_correlation_id(),
   215                                  &request,
   216                              )?
   217                              .get_timeout(timeout)?;
   218  
   219                          continue;
   220                      }
   221                      status => {
   222                          ret = Err(Error::ReceiveError(format!(
   223                              "Registration failed with status {:?}",
   224                              status
   225                          )));
   226  
   227                          break;
   228                      }
   229                  };
   230              }
   231              unexpected => {
   232                  ret = Err(Error::ReceiveError(format!(
   233                      "Received unexpected message type: {:?}",
   234                      unexpected
   235                  )));
   236  
   237                  break;
   238              }
   239          }
   240      }
   241  
   242      ret
   243  }
   244  
   245  fn handle_update(
   246      msg: &Message,
   247      validator_sender: &mut MessageSender,
   248      update_sender: &mut Sender<Update>,
   249  ) -> Result<(), Error> {
   250      use self::Message_MessageType::*;
   251  
   252      let update = match msg.get_message_type() {
   253          CONSENSUS_NOTIFY_PEER_CONNECTED => {
   254              let mut request: ConsensusNotifyPeerConnected =
   255                  protobuf::parse_from_bytes(msg.get_content())?;
   256              Update::PeerConnected(request.take_peer_info().into())
   257          }
   258          CONSENSUS_NOTIFY_PEER_DISCONNECTED => {
   259              let mut request: ConsensusNotifyPeerDisconnected =
   260                  protobuf::parse_from_bytes(msg.get_content())?;
   261              Update::PeerDisconnected(request.take_peer_id().into())
   262          }
   263          CONSENSUS_NOTIFY_PEER_MESSAGE => {
   264              let mut request: ConsensusNotifyPeerMessage =
   265                  protobuf::parse_from_bytes(msg.get_content())?;
   266              Update::PeerMessage(
   267                  request.take_message().into(),
   268                  request.take_sender_id().into(),
   269              )
   270          }
   271          CONSENSUS_NOTIFY_BLOCK_NEW => {
   272              let mut request: ConsensusNotifyBlockNew =
   273                  protobuf::parse_from_bytes(msg.get_content())?;
   274              Update::BlockNew(request.take_block().into())
   275          }
   276          CONSENSUS_NOTIFY_BLOCK_VALID => {
   277              let mut request: ConsensusNotifyBlockValid =
   278                  protobuf::parse_from_bytes(msg.get_content())?;
   279              Update::BlockValid(request.take_block_id().into())
   280          }
   281          CONSENSUS_NOTIFY_BLOCK_INVALID => {
   282              let mut request: ConsensusNotifyBlockInvalid =
   283                  protobuf::parse_from_bytes(msg.get_content())?;
   284              Update::BlockInvalid(request.take_block_id().into())
   285          }
   286          CONSENSUS_NOTIFY_BLOCK_COMMIT => {
   287              let mut request: ConsensusNotifyBlockCommit =
   288                  protobuf::parse_from_bytes(msg.get_content())?;
   289              Update::BlockCommit(request.take_block_id().into())
   290          }
   291          unexpected => {
   292              return Err(Error::ReceiveError(format!(
   293                  "Received unexpected message type: {:?}",
   294                  unexpected
   295              )))
   296          }
   297      };
   298  
   299      update_sender.send(update)?;
   300      validator_sender.reply(
   301          Message_MessageType::CONSENSUS_NOTIFY_ACK,
   302          msg.get_correlation_id(),
   303          &[],
   304      )?;
   305      Ok(())
   306  }
   307  
   308  impl From<ConsensusBlock> for Block {
   309      fn from(mut c_block: ConsensusBlock) -> Block {
   310          Block {
   311              block_id: c_block.take_block_id().into(),
   312              previous_id: c_block.take_previous_id().into(),
   313              signer_id: c_block.take_signer_id().into(),
   314              block_num: c_block.get_block_num(),
   315              payload: c_block.take_payload(),
   316              summary: c_block.take_summary(),
   317          }
   318      }
   319  }
   320  
   321  impl From<ConsensusPeerInfo> for PeerInfo {
   322      fn from(mut c_peer_info: ConsensusPeerInfo) -> PeerInfo {
   323          PeerInfo {
   324              peer_id: c_peer_info.take_peer_id().into(),
   325          }
   326      }
   327  }
   328  
   329  impl From<ConsensusPeerMessage> for PeerMessage {
   330      fn from(mut c_msg: ConsensusPeerMessage) -> PeerMessage {
   331          PeerMessage {
   332              message_type: c_msg.take_message_type(),
   333              content: c_msg.take_content(),
   334          }
   335      }
   336  }
   337  
   338  impl From<ProtobufError> for Error {
   339      fn from(error: ProtobufError) -> Error {
   340          use self::ProtobufError::*;
   341          match error {
   342              IoError(err) => Error::EncodingError(format!("{}", err)),
   343              WireError(err) => Error::EncodingError(format!("{:?}", err)),
   344              Utf8(err) => Error::EncodingError(format!("{}", err)),
   345              MessageNotInitialized { message: err } => Error::EncodingError(format!("{}", err)),
   346          }
   347      }
   348  }
   349  
   350  impl From<SendError> for Error {
   351      fn from(error: SendError) -> Error {
   352          Error::SendError(format!("{}", error))
   353      }
   354  }
   355  
   356  impl From<mpsc::SendError<Update>> for Error {
   357      fn from(error: mpsc::SendError<Update>) -> Error {
   358          Error::SendError(format!("{}", error))
   359      }
   360  }
   361  
   362  impl From<ReceiveError> for Error {
   363      fn from(error: ReceiveError) -> Error {
   364          Error::ReceiveError(format!("{}", error))
   365      }
   366  }
   367  
   368  #[cfg(test)]
   369  mod tests {
   370      use super::*;
   371      use consensus::engine::tests::MockEngine;
   372      use std::sync::{Arc, Mutex};
   373      use zmq;
   374  
   375      fn send_req_rep<I: protobuf::Message, O: protobuf::Message>(
   376          connection_id: &[u8],
   377          socket: &zmq::Socket,
   378          request: I,
   379          request_type: Message_MessageType,
   380          response_type: Message_MessageType,
   381      ) -> O {
   382          let correlation_id = generate_correlation_id();
   383          let mut msg = Message::new();
   384          msg.set_message_type(request_type);
   385          msg.set_correlation_id(correlation_id.clone());
   386          msg.set_content(request.write_to_bytes().unwrap());
   387          socket
   388              .send_multipart(&[connection_id, &msg.write_to_bytes().unwrap()], 0)
   389              .unwrap();
   390          let msg: Message =
   391              protobuf::parse_from_bytes(&socket.recv_multipart(0).unwrap()[1]).unwrap();
   392          assert!(msg.get_message_type() == response_type);
   393          protobuf::parse_from_bytes(&msg.get_content()).unwrap()
   394      }
   395  
   396      fn recv_rep<I: protobuf::Message, O: protobuf::Message>(
   397          socket: &zmq::Socket,
   398          request_type: Message_MessageType,
   399          response: I,
   400          response_type: Message_MessageType,
   401      ) -> (Vec<u8>, O) {
   402          let mut parts = socket.recv_multipart(0).unwrap();
   403          assert!(parts.len() == 2);
   404  
   405          let mut msg: Message = protobuf::parse_from_bytes(&parts.pop().unwrap()).unwrap();
   406          let connection_id = parts.pop().unwrap();
   407          assert!(msg.get_message_type() == request_type);
   408          let request: O = protobuf::parse_from_bytes(&msg.get_content()).unwrap();
   409  
   410          let correlation_id = msg.take_correlation_id();
   411          let mut msg = Message::new();
   412          msg.set_message_type(response_type);
   413          msg.set_correlation_id(correlation_id);
   414          msg.set_content(response.write_to_bytes().unwrap());
   415          socket
   416              .send_multipart(&[&connection_id, &msg.write_to_bytes().unwrap()], 0)
   417              .unwrap();
   418  
   419          (connection_id, request)
   420      }
   421  
   422      #[test]
   423      fn test_zmq_driver() {
   424          let ctx = zmq::Context::new();
   425          let socket = ctx.socket(zmq::ROUTER).expect("Failed to create context");
   426          socket
   427              .bind("tcp://127.0.0.1:*")
   428              .expect("Failed to bind socket");
   429          let addr = socket.get_last_endpoint().unwrap().unwrap();
   430  
   431          // Create the mock engine with this vec so we can refer to it later. Once we put the engine
   432          // in a box, it is hard to get the vec back out.
   433          let calls = Arc::new(Mutex::new(Vec::new()));
   434  
   435          // We are going to run two threads to simulate the validator and the driver
   436          let mock_engine = MockEngine::with(calls.clone());
   437  
   438          let (driver, stop) = ZmqDriver::new();
   439  
   440          let driver_thread = thread::spawn(move || driver.start(&addr, mock_engine));
   441  
   442          let mut response = ConsensusRegisterResponse::new();
   443          response.set_status(ConsensusRegisterResponse_Status::OK);
   444          let (connection_id, request): (_, ConsensusRegisterRequest) = recv_rep(
   445              &socket,
   446              Message_MessageType::CONSENSUS_REGISTER_REQUEST,
   447              response,
   448              Message_MessageType::CONSENSUS_REGISTER_RESPONSE,
   449          );
   450          assert!("mock" == request.get_name());
   451          assert!("0" == request.get_version());
   452  
   453          let _: ConsensusNotifyAck = send_req_rep(
   454              &connection_id,
   455              &socket,
   456              ConsensusNotifyPeerConnected::new(),
   457              Message_MessageType::CONSENSUS_NOTIFY_PEER_CONNECTED,
   458              Message_MessageType::CONSENSUS_NOTIFY_ACK,
   459          );
   460  
   461          let _: ConsensusNotifyAck = send_req_rep(
   462              &connection_id,
   463              &socket,
   464              ConsensusNotifyPeerDisconnected::new(),
   465              Message_MessageType::CONSENSUS_NOTIFY_PEER_DISCONNECTED,
   466              Message_MessageType::CONSENSUS_NOTIFY_ACK,
   467          );
   468  
   469          let _: ConsensusNotifyAck = send_req_rep(
   470              &connection_id,
   471              &socket,
   472              ConsensusNotifyPeerMessage::new(),
   473              Message_MessageType::CONSENSUS_NOTIFY_PEER_MESSAGE,
   474              Message_MessageType::CONSENSUS_NOTIFY_ACK,
   475          );
   476  
   477          let _: ConsensusNotifyAck = send_req_rep(
   478              &connection_id,
   479              &socket,
   480              ConsensusNotifyBlockNew::new(),
   481              Message_MessageType::CONSENSUS_NOTIFY_BLOCK_NEW,
   482              Message_MessageType::CONSENSUS_NOTIFY_ACK,
   483          );
   484  
   485          let _: ConsensusNotifyAck = send_req_rep(
   486              &connection_id,
   487              &socket,
   488              ConsensusNotifyBlockValid::new(),
   489              Message_MessageType::CONSENSUS_NOTIFY_BLOCK_VALID,
   490              Message_MessageType::CONSENSUS_NOTIFY_ACK,
   491          );
   492  
   493          let _: ConsensusNotifyAck = send_req_rep(
   494              &connection_id,
   495              &socket,
   496              ConsensusNotifyBlockInvalid::new(),
   497              Message_MessageType::CONSENSUS_NOTIFY_BLOCK_INVALID,
   498              Message_MessageType::CONSENSUS_NOTIFY_ACK,
   499          );
   500  
   501          let _: ConsensusNotifyAck = send_req_rep(
   502              &connection_id,
   503              &socket,
   504              ConsensusNotifyBlockCommit::new(),
   505              Message_MessageType::CONSENSUS_NOTIFY_BLOCK_COMMIT,
   506              Message_MessageType::CONSENSUS_NOTIFY_ACK,
   507          );
   508  
   509          // Shut it down
   510          stop.stop();
   511          driver_thread
   512              .join()
   513              .expect("Driver thread panicked")
   514              .expect("Driver thread returned an error");
   515  
   516          // Assert we did what we expected
   517          let final_calls = calls.lock().unwrap();
   518          assert!(contains(&*final_calls, "start"));
   519          assert!(contains(&*final_calls, "PeerConnected"));
   520          assert!(contains(&*final_calls, "PeerDisconnected"));
   521          assert!(contains(&*final_calls, "PeerMessage"));
   522          assert!(contains(&*final_calls, "BlockNew"));
   523          assert!(contains(&*final_calls, "BlockValid"));
   524          assert!(contains(&*final_calls, "BlockInvalid"));
   525          assert!(contains(&*final_calls, "BlockCommit"));
   526      }
   527  
   528      fn contains(calls: &Vec<String>, expected: &str) -> bool {
   529          for call in calls {
   530              if expected == call.as_str() {
   531                  return true;
   532              }
   533          }
   534          false
   535      }
   536  }