1use serde::{Deserialize, Serialize};
22use sp_runtime::{
23 traits::{Block as BlockT, HashingFor, Header as HeaderT, NumberFor},
24 DigestItem, Justification, Justifications,
25};
26use std::{any::Any, borrow::Cow, collections::HashMap, sync::Arc};
27
28use sc_client_api::PrefetchedIndexedTransactions;
29use sp_consensus::{BlockOrigin, Error};
30
31#[derive(Debug, PartialEq, Eq)]
33pub enum ImportResult {
34 Imported(ImportedAux),
36 AlreadyInChain,
38 KnownBad,
40 UnknownParent,
42 MissingState,
44}
45
46#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
48pub struct ImportedAux {
49 pub header_only: bool,
51 pub clear_justification_requests: bool,
53 pub needs_justification: bool,
55 pub bad_justification: bool,
57 pub is_new_best: bool,
59}
60
61impl ImportResult {
62 pub fn imported(is_new_best: bool) -> ImportResult {
66 let aux = ImportedAux { is_new_best, ..Default::default() };
67
68 ImportResult::Imported(aux)
69 }
70
71 pub fn handle_justification<B>(
74 &self,
75 hash: &B::Hash,
76 number: NumberFor<B>,
77 justification_sync_link: &dyn JustificationSyncLink<B>,
78 ) where
79 B: BlockT,
80 {
81 match self {
82 ImportResult::Imported(aux) => {
83 if aux.clear_justification_requests {
84 justification_sync_link.clear_justification_requests();
85 }
86
87 if aux.needs_justification {
88 justification_sync_link.request_justification(hash, number);
89 }
90 },
91 _ => {},
92 }
93 }
94}
95
96#[derive(Debug, PartialEq, Eq, Clone, Copy)]
98pub enum ForkChoiceStrategy {
99 LongestChain,
101 Custom(bool),
103}
104
105#[derive(Debug, PartialEq, Eq, Clone)]
107pub struct BlockCheckParams<Block: BlockT> {
108 pub hash: Block::Hash,
110 pub number: NumberFor<Block>,
112 pub parent_hash: Block::Hash,
114 pub allow_missing_state: bool,
116 pub allow_missing_parent: bool,
118 pub import_existing: bool,
120}
121
122pub enum StorageChanges<Block: BlockT> {
124 Changes(sp_state_machine::StorageChanges<HashingFor<Block>>),
126 Import(ImportedState<Block>),
128}
129
130#[derive(PartialEq, Eq, Clone)]
132pub struct ImportedState<B: BlockT> {
133 pub block: B::Hash,
135 pub state: sp_state_machine::KeyValueStates,
137}
138
139impl<B: BlockT> std::fmt::Debug for ImportedState<B> {
140 fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
141 fmt.debug_struct("ImportedState").field("block", &self.block).finish()
142 }
143}
144
145pub enum StateAction<Block: BlockT> {
147 ApplyChanges(StorageChanges<Block>),
149 Execute,
151 ExecuteIfPossible,
153 Skip,
155}
156
157impl<Block: BlockT> std::fmt::Debug for StateAction<Block> {
158 fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
159 match self {
160 Self::ApplyChanges(_) => fmt.write_str("ApplyChanges(..)"),
161 Self::Execute => fmt.write_str("Execute"),
162 Self::ExecuteIfPossible => fmt.write_str("ExecuteIfPossible"),
163 Self::Skip => fmt.write_str("Skip"),
164 }
165 }
166}
167
168impl<Block: BlockT> StateAction<Block> {
169 pub fn skip_execution_checks(&self) -> bool {
171 match self {
172 StateAction::ApplyChanges(_) |
173 StateAction::Execute |
174 StateAction::ExecuteIfPossible => false,
175 StateAction::Skip => true,
176 }
177 }
178
179 pub fn as_storage_changes(
181 &self,
182 ) -> Option<&sp_state_machine::StorageChanges<HashingFor<Block>>> {
183 match self {
184 StateAction::ApplyChanges(StorageChanges::Changes(changes)) => Some(&changes),
185 _ => None,
186 }
187 }
188}
189
190impl<Block: BlockT> From<StorageChanges<Block>> for StateAction<Block> {
191 fn from(value: StorageChanges<Block>) -> Self {
192 Self::ApplyChanges(value)
193 }
194}
195
196impl<Block: BlockT> From<sp_state_machine::StorageChanges<HashingFor<Block>>>
197 for StateAction<Block>
198{
199 fn from(value: sp_state_machine::StorageChanges<HashingFor<Block>>) -> Self {
200 Self::ApplyChanges(StorageChanges::Changes(value))
201 }
202}
203
204#[non_exhaustive]
206pub struct BlockImportParams<Block: BlockT> {
207 pub origin: BlockOrigin,
209 pub header: Block::Header,
221 pub justifications: Option<Justifications>,
223 pub post_digests: Vec<DigestItem>,
226 pub body: Option<Vec<Block::Extrinsic>>,
228 pub indexed_body: Option<Vec<Vec<u8>>>,
230 pub state_action: StateAction<Block>,
232 pub finalized: bool,
235 pub intermediates: HashMap<Cow<'static, [u8]>, Box<dyn Any + Send>>,
239 pub auxiliary: Vec<(Vec<u8>, Option<Vec<u8>>)>,
244 pub fork_choice: Option<ForkChoiceStrategy>,
251 pub import_existing: bool,
253 pub create_gap: bool,
255 pub post_hash: Option<Block::Hash>,
257 pub prefetched_indexed_transactions: PrefetchedIndexedTransactions,
260}
261
262impl<Block: BlockT> BlockImportParams<Block> {
263 pub fn new(origin: BlockOrigin, header: Block::Header) -> Self {
265 Self {
266 origin,
267 header,
268 justifications: None,
269 post_digests: Vec::new(),
270 body: None,
271 indexed_body: None,
272 state_action: if origin == BlockOrigin::WarpSync {
274 StateAction::Skip
275 } else {
276 StateAction::Execute
277 },
278 finalized: false,
279 intermediates: HashMap::new(),
280 auxiliary: Vec::new(),
281 fork_choice: None,
282 import_existing: false,
283 create_gap: origin != BlockOrigin::WarpSync,
290 post_hash: None,
291 prefetched_indexed_transactions: PrefetchedIndexedTransactions::default(),
292 }
293 }
294
295 pub fn post_hash(&self) -> Block::Hash {
297 if let Some(hash) = self.post_hash {
298 hash
299 } else {
300 self.post_header().hash()
301 }
302 }
303
304 pub fn post_header(&self) -> Block::Header {
306 if self.post_digests.is_empty() {
307 self.header.clone()
308 } else {
309 let mut hdr = self.header.clone();
310 for digest_item in &self.post_digests {
311 hdr.digest_mut().push(digest_item.clone());
312 }
313
314 hdr
315 }
316 }
317
318 pub fn insert_intermediate<T: 'static + Send>(&mut self, key: &'static [u8], value: T) {
320 self.intermediates.insert(Cow::from(key), Box::new(value));
321 }
322
323 pub fn remove_intermediate<T: 'static>(&mut self, key: &[u8]) -> Result<T, Error> {
325 let (k, v) = self.intermediates.remove_entry(key).ok_or(Error::NoIntermediate)?;
326
327 v.downcast::<T>().map(|v| *v).map_err(|v| {
328 self.intermediates.insert(k, v);
329 Error::InvalidIntermediate
330 })
331 }
332
333 pub fn get_intermediate<T: 'static>(&self, key: &[u8]) -> Result<&T, Error> {
335 self.intermediates
336 .get(key)
337 .ok_or(Error::NoIntermediate)?
338 .downcast_ref::<T>()
339 .ok_or(Error::InvalidIntermediate)
340 }
341
342 pub fn get_intermediate_mut<T: 'static>(&mut self, key: &[u8]) -> Result<&mut T, Error> {
344 self.intermediates
345 .get_mut(key)
346 .ok_or(Error::NoIntermediate)?
347 .downcast_mut::<T>()
348 .ok_or(Error::InvalidIntermediate)
349 }
350
351 pub fn with_state(&self) -> bool {
353 matches!(self.state_action, StateAction::ApplyChanges(StorageChanges::Import(_)))
354 }
355}
356
357#[async_trait::async_trait]
359pub trait BlockImport<B: BlockT> {
360 type Error: std::error::Error + Send + 'static;
362
363 async fn check_block(&self, block: BlockCheckParams<B>) -> Result<ImportResult, Self::Error>;
365
366 async fn import_block(&self, block: BlockImportParams<B>) -> Result<ImportResult, Self::Error>;
368}
369
370#[async_trait::async_trait]
371impl<B: BlockT> BlockImport<B> for crate::import_queue::BoxBlockImport<B> {
372 type Error = sp_consensus::error::Error;
373
374 async fn check_block(&self, block: BlockCheckParams<B>) -> Result<ImportResult, Self::Error> {
376 (**self).check_block(block).await
377 }
378
379 async fn import_block(&self, block: BlockImportParams<B>) -> Result<ImportResult, Self::Error> {
381 (**self).import_block(block).await
382 }
383}
384
385#[async_trait::async_trait]
386impl<B: BlockT, T, E: std::error::Error + Send + 'static> BlockImport<B> for Arc<T>
387where
388 for<'r> &'r T: BlockImport<B, Error = E>,
389 T: Send + Sync,
390{
391 type Error = E;
392
393 async fn check_block(&self, block: BlockCheckParams<B>) -> Result<ImportResult, Self::Error> {
394 (&**self).check_block(block).await
395 }
396
397 async fn import_block(&self, block: BlockImportParams<B>) -> Result<ImportResult, Self::Error> {
398 (&**self).import_block(block).await
399 }
400}
401
402#[async_trait::async_trait]
404pub trait JustificationImport<B: BlockT> {
405 type Error: std::error::Error + Send + 'static;
406
407 async fn on_start(&mut self) -> Vec<(B::Hash, NumberFor<B>)>;
410
411 async fn import_justification(
413 &mut self,
414 hash: B::Hash,
415 number: NumberFor<B>,
416 justification: Justification,
417 ) -> Result<(), Self::Error>;
418}
419
420pub trait JustificationSyncLink<B: BlockT>: Send + Sync {
426 fn request_justification(&self, hash: &B::Hash, number: NumberFor<B>);
428
429 fn clear_justification_requests(&self);
431}
432
433impl<B: BlockT> JustificationSyncLink<B> for () {
434 fn request_justification(&self, _hash: &B::Hash, _number: NumberFor<B>) {}
435
436 fn clear_justification_requests(&self) {}
437}
438
439impl<B: BlockT, L: JustificationSyncLink<B>> JustificationSyncLink<B> for Arc<L> {
440 fn request_justification(&self, hash: &B::Hash, number: NumberFor<B>) {
441 L::request_justification(self, hash, number);
442 }
443
444 fn clear_justification_requests(&self) {
445 L::clear_justification_requests(self);
446 }
447}