1use crate::{error, error::Error};
20use codec::{Decode, IoReader as CodecIoReader};
21use futures::{future, prelude::*};
22use futures_timer::Delay;
23use log::{info, warn};
24use sc_chain_spec::ChainSpec;
25use sc_client_api::HeaderBackend;
26use sc_consensus::import_queue::{
27 BlockImportError, BlockImportStatus, ImportQueue, IncomingBlock, Link,
28};
29use serde_json::{de::IoRead as JsonIoRead, Deserializer, StreamDeserializer};
30use sp_consensus::BlockOrigin;
31use sp_runtime::{
32 generic::SignedBlock,
33 traits::{
34 Block as BlockT, CheckedDiv, Header, MaybeSerializeDeserialize, NumberFor, Saturating, Zero,
35 },
36};
37use std::{
38 io::Read,
39 pin::Pin,
40 sync::{
41 atomic::{AtomicBool, AtomicU64, Ordering},
42 Arc,
43 },
44 task::Poll,
45 time::{Duration, Instant},
46};
47
48const MAX_PENDING_BLOCKS: u64 = 10_000;
50
51const DELAY_TIME: u64 = 200;
53
54const TIME_BETWEEN_UPDATES: u64 = 3_000;
56
57pub fn build_spec(spec: &dyn ChainSpec, raw: bool) -> error::Result<String> {
59 spec.as_json(raw).map_err(Into::into)
60}
61
62enum BlockIter<R, B>
66where
67 R: std::io::Read,
68{
69 Binary {
70 num_expected_blocks: u64,
72 read_block_count: u64,
74 reader: CodecIoReader<R>,
76 },
77 Json {
78 read_block_count: u64,
80 reader: StreamDeserializer<'static, JsonIoRead<R>, SignedBlock<B>>,
82 },
83}
84
85impl<R, B> BlockIter<R, B>
86where
87 R: Read + 'static,
88 B: BlockT + MaybeSerializeDeserialize,
89{
90 fn new(input: R, binary: bool) -> Result<Self, String> {
91 if binary {
92 let mut reader = CodecIoReader(input);
93 let num_expected_blocks: u64 = Decode::decode(&mut reader)
96 .map_err(|e| format!("Failed to decode the number of blocks: {:?}", e))?;
97 Ok(BlockIter::Binary { num_expected_blocks, read_block_count: 0, reader })
98 } else {
99 let stream_deser = Deserializer::from_reader(input).into_iter::<SignedBlock<B>>();
100 Ok(BlockIter::Json { reader: stream_deser, read_block_count: 0 })
101 }
102 }
103
104 fn read_block_count(&self) -> u64 {
106 match self {
107 BlockIter::Binary { read_block_count, .. } |
108 BlockIter::Json { read_block_count, .. } => *read_block_count,
109 }
110 }
111
112 fn num_expected_blocks(&self) -> Option<u64> {
114 match self {
115 BlockIter::Binary { num_expected_blocks, .. } => Some(*num_expected_blocks),
116 BlockIter::Json { .. } => None,
117 }
118 }
119}
120
121impl<R, B> Iterator for BlockIter<R, B>
122where
123 R: Read + 'static,
124 B: BlockT + MaybeSerializeDeserialize,
125{
126 type Item = Result<SignedBlock<B>, String>;
127
128 fn next(&mut self) -> Option<Self::Item> {
129 match self {
130 BlockIter::Binary { num_expected_blocks, read_block_count, reader } => {
131 if read_block_count < num_expected_blocks {
132 let block_result: Result<SignedBlock<B>, _> =
133 SignedBlock::<B>::decode(reader).map_err(|e| e.to_string());
134 *read_block_count += 1;
135 Some(block_result)
136 } else {
137 None
139 }
140 },
141 BlockIter::Json { reader, read_block_count } => {
142 let res = Some(reader.next()?.map_err(|e| e.to_string()));
143 *read_block_count += 1;
144 res
145 },
146 }
147 }
148}
149
150fn import_block_to_queue<TBl, TImpQu>(
152 signed_block: SignedBlock<TBl>,
153 queue: &mut TImpQu,
154 force: bool,
155) where
156 TBl: BlockT + MaybeSerializeDeserialize,
157 TImpQu: 'static + ImportQueue<TBl>,
158{
159 let (header, extrinsics) = signed_block.block.deconstruct();
160 let hash = header.hash();
161 queue.service_ref().import_blocks(
163 BlockOrigin::File,
164 vec![IncomingBlock::<TBl> {
165 hash,
166 header: Some(header),
167 body: Some(extrinsics),
168 justifications: signed_block.justifications,
169 origin: None,
170 allow_missing_state: false,
171 import_existing: force,
172 state: None,
173 skip_execution: false,
174 }],
175 );
176}
177
178fn importing_is_done(
180 num_expected_blocks: Option<u64>,
181 read_block_count: u64,
182 imported_blocks: u64,
183) -> bool {
184 if let Some(num_expected_blocks) = num_expected_blocks {
185 imported_blocks >= num_expected_blocks
186 } else {
187 imported_blocks >= read_block_count
188 }
189}
190
191struct Speedometer<B: BlockT> {
193 best_number: NumberFor<B>,
194 last_number: Option<NumberFor<B>>,
195 last_update: Instant,
196}
197
198impl<B: BlockT> Speedometer<B> {
199 fn new() -> Self {
201 Self {
202 best_number: NumberFor::<B>::from(0u32),
203 last_number: None,
204 last_update: Instant::now(),
205 }
206 }
207
208 fn display_speed(&self) {
211 let elapsed_ms = {
213 let elapsed = self.last_update.elapsed();
214 let since_last_millis = elapsed.as_secs() * 1000;
215 let since_last_subsec_millis = elapsed.subsec_millis() as u64;
216 since_last_millis + since_last_subsec_millis
217 };
218
219 let diff = match self.last_number {
221 None => return,
222 Some(n) => self.best_number.saturating_sub(n),
223 };
224
225 if let Ok(diff) = TryInto::<u128>::try_into(diff) {
226 let speed = diff
229 .saturating_mul(10_000)
230 .checked_div(u128::from(elapsed_ms))
231 .map_or(0.0, |s| s as f64) /
232 10.0;
233 info!("๐ฆ Current best block: {} ({:4.1} bps)", self.best_number, speed);
234 } else {
235 let one_thousand = NumberFor::<B>::from(1_000u32);
238 let elapsed =
239 NumberFor::<B>::from(<u32 as TryFrom<_>>::try_from(elapsed_ms).unwrap_or(u32::MAX));
240
241 let speed = diff
242 .saturating_mul(one_thousand)
243 .checked_div(&elapsed)
244 .unwrap_or_else(Zero::zero);
245 info!("๐ฆ Current best block: {} ({} bps)", self.best_number, speed)
246 }
247 }
248
249 fn update(&mut self, best_number: NumberFor<B>) {
251 self.last_number = Some(self.best_number);
252 self.best_number = best_number;
253 self.last_update = Instant::now();
254 }
255
256 fn notify_user(&mut self, best_number: NumberFor<B>) {
259 let delta = Duration::from_millis(TIME_BETWEEN_UPDATES);
260 if Instant::now().duration_since(self.last_update) >= delta {
261 self.display_speed();
262 self.update(best_number);
263 }
264 }
265}
266
267enum ImportState<R, B>
269where
270 R: Read + 'static,
271 B: BlockT + MaybeSerializeDeserialize,
272{
273 Reading { block_iter: BlockIter<R, B> },
276 WaitingForImportQueueToCatchUp {
279 block_iter: BlockIter<R, B>,
280 delay: Delay,
281 block: SignedBlock<B>,
282 },
283 WaitingForImportQueueToFinish {
285 num_expected_blocks: Option<u64>,
286 read_block_count: u64,
287 delay: Delay,
288 },
289}
290
291pub fn import_blocks<B, IQ, C>(
293 client: Arc<C>,
294 mut import_queue: IQ,
295 input: impl Read + Send + 'static,
296 force: bool,
297 binary: bool,
298) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send>>
299where
300 C: HeaderBackend<B> + Send + Sync + 'static,
301 B: BlockT + for<'de> serde::Deserialize<'de>,
302 IQ: ImportQueue<B> + 'static,
303{
304 struct WaitLink {
305 imported_blocks: AtomicU64,
306 has_error: AtomicBool,
307 }
308
309 impl WaitLink {
310 fn new() -> WaitLink {
311 WaitLink { imported_blocks: AtomicU64::new(0), has_error: AtomicBool::new(false) }
312 }
313 }
314
315 impl<B: BlockT> Link<B> for WaitLink {
316 fn blocks_processed(
317 &self,
318 imported: usize,
319 _num_expected_blocks: usize,
320 results: Vec<(Result<BlockImportStatus<NumberFor<B>>, BlockImportError>, B::Hash)>,
321 ) {
322 self.imported_blocks.fetch_add(imported as u64, Ordering::AcqRel);
323
324 for result in results {
325 if let (Err(err), hash) = result {
326 warn!("There was an error importing block with hash {:?}: {}", hash, err);
327 self.has_error.store(true, Ordering::Release);
328 break;
329 }
330 }
331 }
332 }
333
334 let mut link = WaitLink::new();
335 let block_iter_res: Result<BlockIter<_, B>, String> = BlockIter::new(input, binary);
336
337 let block_iter = match block_iter_res {
338 Ok(block_iter) => block_iter,
339 Err(e) => {
340 return future::ready(Err(Error::Other(e))).boxed();
343 },
344 };
345
346 let mut state = Some(ImportState::Reading { block_iter });
347 let mut speedometer = Speedometer::<B>::new();
348
349 let import = future::poll_fn(move |cx| {
357 let client = &client;
358 let queue = &mut import_queue;
359 match state.take().expect("state should never be None; qed") {
360 ImportState::Reading { mut block_iter } => {
361 match block_iter.next() {
362 None => {
363 let num_expected_blocks = block_iter.num_expected_blocks();
365 let read_block_count = block_iter.read_block_count();
366 let delay = Delay::new(Duration::from_millis(DELAY_TIME));
367 state = Some(ImportState::WaitingForImportQueueToFinish {
368 num_expected_blocks,
369 read_block_count,
370 delay,
371 });
372 },
373 Some(block_result) => {
374 let read_block_count = block_iter.read_block_count();
375 match block_result {
376 Ok(block) => {
377 if read_block_count - link.imported_blocks.load(Ordering::Acquire) >=
378 MAX_PENDING_BLOCKS
379 {
380 let delay = Delay::new(Duration::from_millis(DELAY_TIME));
383 state = Some(ImportState::WaitingForImportQueueToCatchUp {
384 block_iter,
385 delay,
386 block,
387 });
388 } else {
389 import_block_to_queue(block, queue, force);
391 state = Some(ImportState::Reading { block_iter });
392 }
393 },
394 Err(e) => {
395 return Poll::Ready(Err(Error::Other(format!(
396 "Error reading block #{}: {}",
397 read_block_count, e
398 ))))
399 },
400 }
401 },
402 }
403 },
404 ImportState::WaitingForImportQueueToCatchUp { block_iter, mut delay, block } => {
405 let read_block_count = block_iter.read_block_count();
406 if read_block_count - link.imported_blocks.load(Ordering::Acquire) >=
407 MAX_PENDING_BLOCKS
408 {
409 match Pin::new(&mut delay).poll(cx) {
411 Poll::Pending => {
412 state = Some(ImportState::WaitingForImportQueueToCatchUp {
413 block_iter,
414 delay,
415 block,
416 });
417 return Poll::Pending;
418 },
419 Poll::Ready(_) => {
420 delay.reset(Duration::from_millis(DELAY_TIME));
421 },
422 }
423 state = Some(ImportState::WaitingForImportQueueToCatchUp {
424 block_iter,
425 delay,
426 block,
427 });
428 } else {
429 import_block_to_queue(block, queue, force);
431 state = Some(ImportState::Reading { block_iter });
433 }
434 },
435 ImportState::WaitingForImportQueueToFinish {
436 num_expected_blocks,
437 read_block_count,
438 mut delay,
439 } => {
440 if importing_is_done(
443 num_expected_blocks,
444 read_block_count,
445 link.imported_blocks.load(Ordering::Acquire),
446 ) {
447 info!(
449 "๐ Imported {} blocks. Best: #{}",
450 read_block_count,
451 client.info().best_number
452 );
453 return Poll::Ready(Ok(()));
454 } else {
455 match Pin::new(&mut delay).poll(cx) {
458 Poll::Pending => {
459 state = Some(ImportState::WaitingForImportQueueToFinish {
460 num_expected_blocks,
461 read_block_count,
462 delay,
463 });
464 return Poll::Pending;
465 },
466 Poll::Ready(_) => {
467 delay.reset(Duration::from_millis(DELAY_TIME));
468 },
469 }
470
471 state = Some(ImportState::WaitingForImportQueueToFinish {
472 num_expected_blocks,
473 read_block_count,
474 delay,
475 });
476 }
477 },
478 }
479
480 queue.poll_actions(cx, &mut link);
481
482 let best_number = client.info().best_number;
483 speedometer.notify_user(best_number);
484
485 if link.has_error.load(Ordering::Acquire) {
486 return Poll::Ready(Err(Error::Other(format!(
487 "Stopping after #{} blocks because of an error",
488 link.imported_blocks.load(Ordering::Acquire)
489 ))));
490 }
491
492 cx.waker().wake_by_ref();
493 Poll::Pending
494 });
495 Box::pin(import)
496}