1use std::error;
19use std::fmt;
20use std::sync::mpsc::Receiver;
21
22use crate::consensus::service::Service;
23
24#[derive(Debug)]
26#[allow(clippy::large_enum_variant)]
27pub enum Update {
28 PeerConnected(PeerInfo),
29 PeerDisconnected(PeerId),
30 PeerMessage(PeerMessage, PeerId),
31 BlockNew(Block),
32 BlockValid(BlockId),
33 BlockInvalid(BlockId),
34 BlockCommit(BlockId),
35 Shutdown,
36}
37
38pub type BlockId = Vec<u8>;
39
40#[derive(Clone, Default, PartialEq, Hash)]
42pub struct Block {
43 pub block_id: BlockId,
44 pub previous_id: BlockId,
45 pub signer_id: PeerId,
46 pub block_num: u64,
47 pub payload: Vec<u8>,
48 pub summary: Vec<u8>,
49}
50impl Eq for Block {}
51impl fmt::Debug for Block {
52 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
53 write!(
54 f,
55 "Block(block_num: {:?}, block_id: {:?}, previous_id: {:?}, signer_id: {:?}, payload: {}, summary: {})",
56 self.block_num,
57 self.block_id,
58 self.previous_id,
59 self.signer_id,
60 hex::encode(&self.payload),
61 hex::encode(&self.summary),
62 )
63 }
64}
65
66pub type PeerId = Vec<u8>;
67
68#[derive(Default, Debug, PartialEq, Hash)]
70pub struct PeerInfo {
71 pub peer_id: PeerId,
72}
73impl Eq for PeerInfo {}
74
75#[derive(Default, Debug, Clone)]
77pub struct PeerMessage {
78 pub header: PeerMessageHeader,
79 pub header_bytes: Vec<u8>,
80 pub header_signature: Vec<u8>,
81 pub content: Vec<u8>,
82}
83
84#[derive(Default, Debug, Clone)]
87pub struct PeerMessageHeader {
88 pub signer_id: Vec<u8>,
92 pub content_sha512: Vec<u8>,
93 pub message_type: String,
94 pub name: String,
95 pub version: String,
96}
97
98pub trait Engine {
124 fn start(
128 &mut self,
129 updates: Receiver<Update>,
130 service: Box<dyn Service>,
131 startup_state: StartupState,
132 ) -> Result<(), Error>;
133
134 fn version(&self) -> String;
136
137 fn name(&self) -> String;
139
140 fn additional_protocols(&self) -> Vec<(String, String)>;
142}
143
144#[derive(Debug, Default)]
146pub struct StartupState {
147 pub chain_head: Block,
148 pub peers: Vec<PeerInfo>,
149 pub local_peer_info: PeerInfo,
150}
151
152#[derive(Debug)]
153pub enum Error {
154 EncodingError(String),
155 SendError(String),
156 ReceiveError(String),
157 InvalidState(String),
158 UnknownBlock(String),
159 UnknownPeer(String),
160 NoChainHead,
161 BlockNotReady,
162}
163
164impl error::Error for Error {}
165
166impl fmt::Display for Error {
167 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
168 use self::Error::*;
169 match *self {
170 EncodingError(ref s) => write!(f, "EncodingError: {}", s),
171 SendError(ref s) => write!(f, "SendError: {}", s),
172 ReceiveError(ref s) => write!(f, "ReceiveError: {}", s),
173 InvalidState(ref s) => write!(f, "InvalidState: {}", s),
174 UnknownBlock(ref s) => write!(f, "UnknownBlock: {}", s),
175 UnknownPeer(ref s) => write!(f, "UnknownPeer: {}", s),
176 NoChainHead => write!(f, "NoChainHead"),
177 BlockNotReady => write!(f, "BlockNotReady"),
178 }
179 }
180}
181
182#[cfg(test)]
183pub mod tests {
184 use super::*;
185
186 use std::default::Default;
187 use std::sync::mpsc::{channel, RecvTimeoutError};
188 use std::sync::{Arc, Mutex};
189 use std::thread;
190 use std::time::Duration;
191
192 use crate::consensus::service::tests::MockService;
193
194 pub struct MockEngine {
195 calls: Arc<Mutex<Vec<String>>>,
196 }
197
198 impl MockEngine {
199 pub fn new() -> Self {
200 MockEngine {
201 calls: Arc::new(Mutex::new(Vec::new())),
202 }
203 }
204
205 pub fn with(amv: Arc<Mutex<Vec<String>>>) -> Self {
206 MockEngine { calls: amv }
207 }
208
209 pub fn calls(&self) -> Vec<String> {
210 let calls = self.calls.lock().unwrap();
211 let mut v = Vec::with_capacity((*calls).len());
212 v.clone_from(&*calls);
213 v
214 }
215 }
216
217 impl Engine for MockEngine {
218 fn start(
219 &mut self,
220 updates: Receiver<Update>,
221 _service: Box<dyn Service>,
222 _startup_state: StartupState,
223 ) -> Result<(), Error> {
224 (*self.calls.lock().unwrap()).push("start".into());
225 loop {
226 match updates.recv_timeout(Duration::from_millis(100)) {
227 Ok(update) => {
228 match update {
232 Update::PeerConnected(_) => {
233 (*self.calls.lock().unwrap()).push("PeerConnected".into())
234 }
235 Update::PeerDisconnected(_) => {
236 (*self.calls.lock().unwrap()).push("PeerDisconnected".into())
237 }
238 Update::PeerMessage(_, _) => {
239 (*self.calls.lock().unwrap()).push("PeerMessage".into())
240 }
241 Update::BlockNew(_) => {
242 (*self.calls.lock().unwrap()).push("BlockNew".into())
243 }
244 Update::BlockValid(_) => {
245 (*self.calls.lock().unwrap()).push("BlockValid".into())
246 }
247 Update::BlockInvalid(_) => {
248 (*self.calls.lock().unwrap()).push("BlockInvalid".into())
249 }
250 Update::BlockCommit(_) => {
251 (*self.calls.lock().unwrap()).push("BlockCommit".into())
252 }
253 Update::Shutdown => {
254 println!("shutdown");
255 break;
256 }
257 };
258 }
259 Err(RecvTimeoutError::Disconnected) => {
260 println!("disconnected");
261 break;
262 }
263 Err(RecvTimeoutError::Timeout) => {
264 println!("timeout");
265 }
266 }
267 }
268
269 Ok(())
270 }
271 fn version(&self) -> String {
272 "0".into()
273 }
274 fn name(&self) -> String {
275 "mock".into()
276 }
277 fn additional_protocols(&self) -> Vec<(String, String)> {
278 vec![("1".into(), "Mock".into())]
279 }
280 }
281
282 #[test]
283 fn test_engine() {
284 let calls = Arc::new(Mutex::new(Vec::new()));
287
288 let mut mock_engine = MockEngine::with(calls.clone());
290
291 let (sender, receiver) = channel();
292 sender
293 .send(Update::PeerConnected(Default::default()))
294 .unwrap();
295 sender
296 .send(Update::PeerDisconnected(Default::default()))
297 .unwrap();
298 sender
299 .send(Update::PeerMessage(Default::default(), Default::default()))
300 .unwrap();
301 sender.send(Update::BlockNew(Default::default())).unwrap();
302 sender.send(Update::BlockValid(Default::default())).unwrap();
303 sender
304 .send(Update::BlockInvalid(Default::default()))
305 .unwrap();
306 sender
307 .send(Update::BlockCommit(Default::default()))
308 .unwrap();
309 let handle = thread::spawn(move || {
310 let svc = Box::new(MockService {});
311 mock_engine
312 .start(receiver, svc, Default::default())
313 .unwrap();
314 });
315 sender.send(Update::Shutdown).unwrap();
316 handle.join().unwrap();
317 assert!(contains(&calls, "start"));
318 assert!(contains(&calls, "PeerConnected"));
319 assert!(contains(&calls, "PeerDisconnected"));
320 assert!(contains(&calls, "PeerMessage"));
321 assert!(contains(&calls, "BlockNew"));
322 assert!(contains(&calls, "BlockValid"));
323 assert!(contains(&calls, "BlockInvalid"));
324 assert!(contains(&calls, "BlockCommit"));
325 }
326
327 fn contains(calls: &Arc<Mutex<Vec<String>>>, expected: &str) -> bool {
328 for call in &*(calls.lock().unwrap()) {
329 if expected == call {
330 return true;
331 }
332 }
333 false
334 }
335}