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 }