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 sp_consensus::{BlockOrigin, Error};
29
30#[derive(Debug, PartialEq, Eq)]
32pub enum ImportResult {
33 Imported(ImportedAux),
35 AlreadyInChain,
37 KnownBad,
39 UnknownParent,
41 MissingState,
43}
44
45#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
47pub struct ImportedAux {
48 pub header_only: bool,
50 pub clear_justification_requests: bool,
52 pub needs_justification: bool,
54 pub bad_justification: bool,
56 pub is_new_best: bool,
58}
59
60impl ImportResult {
61 pub fn imported(is_new_best: bool) -> ImportResult {
65 let aux = ImportedAux { is_new_best, ..Default::default() };
66
67 ImportResult::Imported(aux)
68 }
69
70 pub fn handle_justification<B>(
73 &self,
74 hash: &B::Hash,
75 number: NumberFor<B>,
76 justification_sync_link: &dyn JustificationSyncLink<B>,
77 ) where
78 B: BlockT,
79 {
80 match self {
81 ImportResult::Imported(aux) => {
82 if aux.clear_justification_requests {
83 justification_sync_link.clear_justification_requests();
84 }
85
86 if aux.needs_justification {
87 justification_sync_link.request_justification(hash, number);
88 }
89 },
90 _ => {},
91 }
92 }
93}
94
95#[derive(Debug, PartialEq, Eq, Clone, Copy)]
97pub enum ForkChoiceStrategy {
98 LongestChain,
100 Custom(bool),
102}
103
104#[derive(Debug, PartialEq, Eq, Clone)]
106pub struct BlockCheckParams<Block: BlockT> {
107 pub hash: Block::Hash,
109 pub number: NumberFor<Block>,
111 pub parent_hash: Block::Hash,
113 pub allow_missing_state: bool,
115 pub allow_missing_parent: bool,
117 pub import_existing: bool,
119}
120
121pub enum StorageChanges<Block: BlockT> {
123 Changes(sp_state_machine::StorageChanges<HashingFor<Block>>),
125 Import(ImportedState<Block>),
127}
128
129#[derive(PartialEq, Eq, Clone)]
131pub struct ImportedState<B: BlockT> {
132 pub block: B::Hash,
134 pub state: sp_state_machine::KeyValueStates,
136}
137
138impl<B: BlockT> std::fmt::Debug for ImportedState<B> {
139 fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
140 fmt.debug_struct("ImportedState").field("block", &self.block).finish()
141 }
142}
143
144pub enum StateAction<Block: BlockT> {
146 ApplyChanges(StorageChanges<Block>),
148 Execute,
150 ExecuteIfPossible,
152 Skip,
154}
155
156impl<Block: BlockT> std::fmt::Debug for StateAction<Block> {
157 fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
158 match self {
159 Self::ApplyChanges(_) => fmt.write_str("ApplyChanges(..)"),
160 Self::Execute => fmt.write_str("Execute"),
161 Self::ExecuteIfPossible => fmt.write_str("ExecuteIfPossible"),
162 Self::Skip => fmt.write_str("Skip"),
163 }
164 }
165}
166
167impl<Block: BlockT> StateAction<Block> {
168 pub fn skip_execution_checks(&self) -> bool {
170 match self {
171 StateAction::ApplyChanges(_) |
172 StateAction::Execute |
173 StateAction::ExecuteIfPossible => false,
174 StateAction::Skip => true,
175 }
176 }
177
178 pub fn as_storage_changes(
180 &self,
181 ) -> Option<&sp_state_machine::StorageChanges<HashingFor<Block>>> {
182 match self {
183 StateAction::ApplyChanges(StorageChanges::Changes(changes)) => Some(&changes),
184 _ => None,
185 }
186 }
187}
188
189impl<Block: BlockT> From<StorageChanges<Block>> for StateAction<Block> {
190 fn from(value: StorageChanges<Block>) -> Self {
191 Self::ApplyChanges(value)
192 }
193}
194
195impl<Block: BlockT> From<sp_state_machine::StorageChanges<HashingFor<Block>>>
196 for StateAction<Block>
197{
198 fn from(value: sp_state_machine::StorageChanges<HashingFor<Block>>) -> Self {
199 Self::ApplyChanges(StorageChanges::Changes(value))
200 }
201}
202
203#[non_exhaustive]
205pub struct BlockImportParams<Block: BlockT> {
206 pub origin: BlockOrigin,
208 pub header: Block::Header,
220 pub justifications: Option<Justifications>,
222 pub post_digests: Vec<DigestItem>,
225 pub body: Option<Vec<Block::Extrinsic>>,
227 pub indexed_body: Option<Vec<Vec<u8>>>,
229 pub state_action: StateAction<Block>,
231 pub finalized: bool,
234 pub intermediates: HashMap<Cow<'static, [u8]>, Box<dyn Any + Send>>,
238 pub auxiliary: Vec<(Vec<u8>, Option<Vec<u8>>)>,
243 pub fork_choice: Option<ForkChoiceStrategy>,
250 pub import_existing: bool,
252 pub create_gap: bool,
254 pub post_hash: Option<Block::Hash>,
256}
257
258impl<Block: BlockT> BlockImportParams<Block> {
259 pub fn new(origin: BlockOrigin, header: Block::Header) -> Self {
261 Self {
262 origin,
263 header,
264 justifications: None,
265 post_digests: Vec::new(),
266 body: None,
267 indexed_body: None,
268 state_action: if origin == BlockOrigin::WarpSync {
270 StateAction::Skip
271 } else {
272 StateAction::Execute
273 },
274 finalized: false,
275 intermediates: HashMap::new(),
276 auxiliary: Vec::new(),
277 fork_choice: None,
278 import_existing: false,
279 create_gap: origin != BlockOrigin::WarpSync,
286 post_hash: None,
287 }
288 }
289
290 pub fn post_hash(&self) -> Block::Hash {
292 if let Some(hash) = self.post_hash {
293 hash
294 } else {
295 self.post_header().hash()
296 }
297 }
298
299 pub fn post_header(&self) -> Block::Header {
301 if self.post_digests.is_empty() {
302 self.header.clone()
303 } else {
304 let mut hdr = self.header.clone();
305 for digest_item in &self.post_digests {
306 hdr.digest_mut().push(digest_item.clone());
307 }
308
309 hdr
310 }
311 }
312
313 pub fn insert_intermediate<T: 'static + Send>(&mut self, key: &'static [u8], value: T) {
315 self.intermediates.insert(Cow::from(key), Box::new(value));
316 }
317
318 pub fn remove_intermediate<T: 'static>(&mut self, key: &[u8]) -> Result<T, Error> {
320 let (k, v) = self.intermediates.remove_entry(key).ok_or(Error::NoIntermediate)?;
321
322 v.downcast::<T>().map(|v| *v).map_err(|v| {
323 self.intermediates.insert(k, v);
324 Error::InvalidIntermediate
325 })
326 }
327
328 pub fn get_intermediate<T: 'static>(&self, key: &[u8]) -> Result<&T, Error> {
330 self.intermediates
331 .get(key)
332 .ok_or(Error::NoIntermediate)?
333 .downcast_ref::<T>()
334 .ok_or(Error::InvalidIntermediate)
335 }
336
337 pub fn get_intermediate_mut<T: 'static>(&mut self, key: &[u8]) -> Result<&mut T, Error> {
339 self.intermediates
340 .get_mut(key)
341 .ok_or(Error::NoIntermediate)?
342 .downcast_mut::<T>()
343 .ok_or(Error::InvalidIntermediate)
344 }
345
346 pub fn with_state(&self) -> bool {
348 matches!(self.state_action, StateAction::ApplyChanges(StorageChanges::Import(_)))
349 }
350}
351
352#[async_trait::async_trait]
354pub trait BlockImport<B: BlockT> {
355 type Error: std::error::Error + Send + 'static;
357
358 async fn check_block(&self, block: BlockCheckParams<B>) -> Result<ImportResult, Self::Error>;
360
361 async fn import_block(&self, block: BlockImportParams<B>) -> Result<ImportResult, Self::Error>;
363}
364
365#[async_trait::async_trait]
366impl<B: BlockT> BlockImport<B> for crate::import_queue::BoxBlockImport<B> {
367 type Error = sp_consensus::error::Error;
368
369 async fn check_block(&self, block: BlockCheckParams<B>) -> Result<ImportResult, Self::Error> {
371 (**self).check_block(block).await
372 }
373
374 async fn import_block(&self, block: BlockImportParams<B>) -> Result<ImportResult, Self::Error> {
376 (**self).import_block(block).await
377 }
378}
379
380#[async_trait::async_trait]
381impl<B: BlockT, T, E: std::error::Error + Send + 'static> BlockImport<B> for Arc<T>
382where
383 for<'r> &'r T: BlockImport<B, Error = E>,
384 T: Send + Sync,
385{
386 type Error = E;
387
388 async fn check_block(&self, block: BlockCheckParams<B>) -> Result<ImportResult, Self::Error> {
389 (&**self).check_block(block).await
390 }
391
392 async fn import_block(&self, block: BlockImportParams<B>) -> Result<ImportResult, Self::Error> {
393 (&**self).import_block(block).await
394 }
395}
396
397#[async_trait::async_trait]
399pub trait JustificationImport<B: BlockT> {
400 type Error: std::error::Error + Send + 'static;
401
402 async fn on_start(&mut self) -> Vec<(B::Hash, NumberFor<B>)>;
405
406 async fn import_justification(
408 &mut self,
409 hash: B::Hash,
410 number: NumberFor<B>,
411 justification: Justification,
412 ) -> Result<(), Self::Error>;
413}
414
415pub trait JustificationSyncLink<B: BlockT>: Send + Sync {
421 fn request_justification(&self, hash: &B::Hash, number: NumberFor<B>);
423
424 fn clear_justification_requests(&self);
426}
427
428impl<B: BlockT> JustificationSyncLink<B> for () {
429 fn request_justification(&self, _hash: &B::Hash, _number: NumberFor<B>) {}
430
431 fn clear_justification_requests(&self) {}
432}
433
434impl<B: BlockT, L: JustificationSyncLink<B>> JustificationSyncLink<B> for Arc<L> {
435 fn request_justification(&self, hash: &B::Hash, number: NumberFor<B>) {
436 L::request_justification(self, hash, number);
437 }
438
439 fn clear_justification_requests(&self) {
440 L::clear_justification_requests(self);
441 }
442}