github.com/muhammedhassanm/blockchain@v0.0.0-20200120143007-697261defd4d/sawtooth-core-master/sdk/rust/src/consensus/engine.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 std::error; 19 use std::fmt; 20 use std::ops::Deref; 21 use std::sync::mpsc::Receiver; 22 23 use hex; 24 25 use consensus::service::Service; 26 27 /// An update from the validator 28 #[derive(Debug)] 29 pub enum Update { 30 PeerConnected(PeerInfo), 31 PeerDisconnected(PeerId), 32 PeerMessage(PeerMessage, PeerId), 33 BlockNew(Block), 34 BlockValid(BlockId), 35 BlockInvalid(BlockId), 36 BlockCommit(BlockId), 37 Shutdown, 38 } 39 40 #[derive(Clone, Default, Eq, Hash, PartialEq, PartialOrd)] 41 pub struct BlockId(Vec<u8>); 42 impl Deref for BlockId { 43 type Target = Vec<u8>; 44 45 fn deref(&self) -> &Vec<u8> { 46 &self.0 47 } 48 } 49 impl From<BlockId> for Vec<u8> { 50 fn from(id: BlockId) -> Vec<u8> { 51 id.0 52 } 53 } 54 impl From<Vec<u8>> for BlockId { 55 fn from(v: Vec<u8>) -> BlockId { 56 BlockId(v) 57 } 58 } 59 impl AsRef<[u8]> for BlockId { 60 fn as_ref(&self) -> &[u8] { 61 &self.0 62 } 63 } 64 impl fmt::Debug for BlockId { 65 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 66 write!(f, "{}", hex::encode(&self.0)) 67 } 68 } 69 70 /// All information about a block that is relevant to consensus 71 #[derive(Clone, Default)] 72 pub struct Block { 73 pub block_id: BlockId, 74 pub previous_id: BlockId, 75 pub signer_id: PeerId, 76 pub block_num: u64, 77 pub payload: Vec<u8>, 78 pub summary: Vec<u8>, 79 } 80 impl fmt::Debug for Block { 81 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 82 write!( 83 f, 84 "Block(block_num: {:?}, block_id: {:?}, previous_id: {:?}, signer_id: {:?}, payload: {}, summary: {})", 85 self.block_num, 86 self.block_id, 87 self.previous_id, 88 self.signer_id, 89 hex::encode(&self.payload), 90 hex::encode(&self.summary), 91 ) 92 } 93 } 94 95 #[derive(Clone, Default, PartialEq, Eq, Hash, PartialOrd)] 96 pub struct PeerId(Vec<u8>); 97 impl Deref for PeerId { 98 type Target = Vec<u8>; 99 100 fn deref(&self) -> &Vec<u8> { 101 &self.0 102 } 103 } 104 impl From<PeerId> for Vec<u8> { 105 fn from(id: PeerId) -> Vec<u8> { 106 id.0 107 } 108 } 109 impl From<Vec<u8>> for PeerId { 110 fn from(v: Vec<u8>) -> PeerId { 111 PeerId(v) 112 } 113 } 114 impl AsRef<[u8]> for PeerId { 115 fn as_ref(&self) -> &[u8] { 116 &self.0 117 } 118 } 119 impl fmt::Debug for PeerId { 120 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 121 write!(f, "{}", hex::encode(&self.0)) 122 } 123 } 124 125 /// Information about a peer that is relevant to consensus 126 #[derive(Default, Debug)] 127 pub struct PeerInfo { 128 pub peer_id: PeerId, 129 } 130 131 /// A consensus-related message sent between peers 132 #[derive(Default, Debug)] 133 pub struct PeerMessage { 134 pub message_type: String, 135 pub content: Vec<u8>, 136 } 137 138 /// Engine is the only trait that needs to be implemented when adding a new consensus engine. 139 /// 140 /// The consensus engine should listen for notifications from the validator about the status of 141 /// blocks and messages from peers. It must also determine internally when to build and publish 142 /// blocks based on its view of the network and the consensus algorithm it implements. Often this 143 /// will be some sort of timer-based interrupt. 144 /// 145 /// Based on the updates the engine receives through the `Receiver<Update>` and the specifics of 146 /// the algorithm being implemented, the engine utilizes the provided `Service` to create new 147 /// blocks, communicate with its peers, request that certain blocks be committed, and fail or 148 /// ignore blocks that should not be committed. 149 /// 150 /// While the validator may take actions beyond what the engine instructs it to do for performance 151 /// optimization reasons, it is the consensus engine's responsibility to drive the progress of the 152 /// validator and ensure liveness. 153 /// 154 /// It is not the engine's responsibility to manage blocks or memory, other than to ensure it 155 /// responds to every new block with a commit, fail, or ignore within a "reasonable amount of 156 /// time". The validator is responsible for guaranteeing the integrity of all blocks sent to the 157 /// engine until the engine responds. After the engine responds, the validator does not guarantee 158 /// that the block and its predecessors continue to be available unless the block was committed. 159 /// 160 /// Finally, as an optimization, the consensus engine can send prioritized lists of blocks to the 161 /// chain controller for checking instead of sending them one at a time, which allows the chain 162 /// controller to intelligently work ahead while the consensus engine makes its decisions. 163 pub trait Engine { 164 /// Called after the engine is initialized, when a connection to the validator has been 165 /// established. Notifications from the validator are sent along `updates`. `service` is used 166 /// to send requests to the validator. 167 fn start( 168 &mut self, 169 updates: Receiver<Update>, 170 service: Box<Service>, 171 startup_state: StartupState, 172 ); 173 174 /// Get the version of this engine 175 fn version(&self) -> String; 176 177 /// Get the name of the engine, typically the algorithm being implemented 178 fn name(&self) -> String; 179 } 180 181 /// State provided to an engine when it is started 182 #[derive(Debug, Default)] 183 pub struct StartupState { 184 pub chain_head: Block, 185 pub peers: Vec<PeerInfo>, 186 pub local_peer_info: PeerInfo, 187 } 188 189 #[derive(Debug)] 190 pub enum Error { 191 EncodingError(String), 192 SendError(String), 193 ReceiveError(String), 194 InvalidState(String), 195 UnknownBlock(String), 196 UnknownPeer(String), 197 NoChainHead, 198 BlockNotReady, 199 } 200 201 impl error::Error for Error { 202 fn description(&self) -> &str { 203 use self::Error::*; 204 match *self { 205 EncodingError(ref s) => s, 206 SendError(ref s) => s, 207 ReceiveError(ref s) => s, 208 InvalidState(ref s) => s, 209 UnknownBlock(ref s) => s, 210 UnknownPeer(ref s) => s, 211 NoChainHead => "No chain head", 212 BlockNotReady => "Block not ready to finalize", 213 } 214 } 215 216 fn cause(&self) -> Option<&error::Error> { 217 use self::Error::*; 218 match *self { 219 EncodingError(_) => None, 220 SendError(_) => None, 221 ReceiveError(_) => None, 222 InvalidState(_) => None, 223 UnknownBlock(_) => None, 224 UnknownPeer(_) => None, 225 NoChainHead => None, 226 BlockNotReady => None, 227 } 228 } 229 } 230 231 impl fmt::Display for Error { 232 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 233 use self::Error::*; 234 match *self { 235 EncodingError(ref s) => write!(f, "EncodingError: {}", s), 236 SendError(ref s) => write!(f, "SendError: {}", s), 237 ReceiveError(ref s) => write!(f, "ReceiveError: {}", s), 238 InvalidState(ref s) => write!(f, "InvalidState: {}", s), 239 UnknownBlock(ref s) => write!(f, "UnknownBlock: {}", s), 240 UnknownPeer(ref s) => write!(f, "UnknownPeer: {}", s), 241 NoChainHead => write!(f, "NoChainHead"), 242 BlockNotReady => write!(f, "BlockNotReady"), 243 } 244 } 245 } 246 247 #[cfg(test)] 248 pub mod tests { 249 use super::*; 250 251 use std::default::Default; 252 use std::sync::mpsc::{channel, RecvTimeoutError}; 253 use std::sync::{Arc, Mutex}; 254 use std::thread; 255 use std::time::Duration; 256 257 use consensus::service::tests::MockService; 258 259 pub struct MockEngine { 260 calls: Arc<Mutex<Vec<String>>>, 261 } 262 263 impl MockEngine { 264 pub fn new() -> Self { 265 MockEngine { 266 calls: Arc::new(Mutex::new(Vec::new())), 267 } 268 } 269 270 pub fn with(amv: Arc<Mutex<Vec<String>>>) -> Self { 271 MockEngine { calls: amv } 272 } 273 274 pub fn calls(&self) -> Vec<String> { 275 let calls = self.calls.lock().unwrap(); 276 let mut v = Vec::with_capacity((*calls).len()); 277 v.clone_from(&*calls); 278 v 279 } 280 } 281 282 impl Engine for MockEngine { 283 fn start( 284 &mut self, 285 updates: Receiver<Update>, 286 _service: Box<Service>, 287 _startup_state: StartupState, 288 ) { 289 (*self.calls.lock().unwrap()).push("start".into()); 290 loop { 291 match updates.recv_timeout(Duration::from_millis(100)) { 292 Ok(update) => { 293 // We don't check for exit() here because we want to drain all the updates 294 // before we exit. In a real implementation, exit() should also be checked 295 // here since there is no guarantee the queue will ever be empty. 296 match update { 297 Update::PeerConnected(_) => { 298 (*self.calls.lock().unwrap()).push("PeerConnected".into()) 299 } 300 Update::PeerDisconnected(_) => { 301 (*self.calls.lock().unwrap()).push("PeerDisconnected".into()) 302 } 303 Update::PeerMessage(_, _) => { 304 (*self.calls.lock().unwrap()).push("PeerMessage".into()) 305 } 306 Update::BlockNew(_) => { 307 (*self.calls.lock().unwrap()).push("BlockNew".into()) 308 } 309 Update::BlockValid(_) => { 310 (*self.calls.lock().unwrap()).push("BlockValid".into()) 311 } 312 Update::BlockInvalid(_) => { 313 (*self.calls.lock().unwrap()).push("BlockInvalid".into()) 314 } 315 Update::BlockCommit(_) => { 316 (*self.calls.lock().unwrap()).push("BlockCommit".into()) 317 } 318 Update::Shutdown => { 319 println!("shutdown"); 320 break; 321 } 322 }; 323 } 324 Err(RecvTimeoutError::Disconnected) => { 325 println!("disconnected"); 326 break; 327 } 328 Err(RecvTimeoutError::Timeout) => { 329 println!("timeout"); 330 } 331 } 332 } 333 } 334 fn version(&self) -> String { 335 "0".into() 336 } 337 fn name(&self) -> String { 338 "mock".into() 339 } 340 } 341 342 #[test] 343 fn test_engine() { 344 // Create the mock engine with this vec so we can refer to it later. Once we put the engine 345 // in a box, it is hard to get the vec back out. 346 let calls = Arc::new(Mutex::new(Vec::new())); 347 348 // We are going to run two threads to simulate the validator and the driver 349 let mut mock_engine = MockEngine::with(calls.clone()); 350 351 let (sender, receiver) = channel(); 352 sender 353 .send(Update::PeerConnected(Default::default())) 354 .unwrap(); 355 sender 356 .send(Update::PeerDisconnected(Default::default())) 357 .unwrap(); 358 sender 359 .send(Update::PeerMessage(Default::default(), Default::default())) 360 .unwrap(); 361 sender.send(Update::BlockNew(Default::default())).unwrap(); 362 sender.send(Update::BlockValid(Default::default())).unwrap(); 363 sender 364 .send(Update::BlockInvalid(Default::default())) 365 .unwrap(); 366 sender 367 .send(Update::BlockCommit(Default::default())) 368 .unwrap(); 369 let handle = thread::spawn(move || { 370 let svc = Box::new(MockService {}); 371 mock_engine.start(receiver, svc, Default::default()); 372 }); 373 sender.send(Update::Shutdown).unwrap(); 374 handle.join().unwrap(); 375 assert!(contains(&calls, "start")); 376 assert!(contains(&calls, "PeerConnected")); 377 assert!(contains(&calls, "PeerDisconnected")); 378 assert!(contains(&calls, "PeerMessage")); 379 assert!(contains(&calls, "BlockNew")); 380 assert!(contains(&calls, "BlockValid")); 381 assert!(contains(&calls, "BlockInvalid")); 382 assert!(contains(&calls, "BlockCommit")); 383 } 384 385 fn contains(calls: &Arc<Mutex<Vec<String>>>, expected: &str) -> bool { 386 for call in &*(calls.lock().unwrap()) { 387 if expected == call { 388 return true; 389 } 390 } 391 false 392 } 393 }