1use serde::{Deserialize, Serialize};
10use std::{any::Any, borrow::Cow, collections::HashMap, sync::Arc};
11use subsoil::runtime::{
12 traits::{Block as BlockT, HashingFor, Header as HeaderT, NumberFor},
13 DigestItem, Justification, Justifications,
14};
15
16use crate::consensus::{BlockOrigin, Error};
17
18#[derive(Debug, PartialEq, Eq)]
20pub enum ImportResult {
21 Imported(ImportedAux),
23 AlreadyInChain,
25 KnownBad,
27 UnknownParent,
29 MissingState,
31}
32
33#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
35pub struct ImportedAux {
36 pub header_only: bool,
38 pub clear_justification_requests: bool,
40 pub needs_justification: bool,
42 pub bad_justification: bool,
44 pub is_new_best: bool,
46}
47
48impl ImportResult {
49 pub fn imported(is_new_best: bool) -> ImportResult {
53 let aux = ImportedAux { is_new_best, ..Default::default() };
54
55 ImportResult::Imported(aux)
56 }
57
58 pub fn handle_justification<B>(
61 &self,
62 hash: &B::Hash,
63 number: NumberFor<B>,
64 justification_sync_link: &dyn JustificationSyncLink<B>,
65 ) where
66 B: BlockT,
67 {
68 match self {
69 ImportResult::Imported(aux) => {
70 if aux.clear_justification_requests {
71 justification_sync_link.clear_justification_requests();
72 }
73
74 if aux.needs_justification {
75 justification_sync_link.request_justification(hash, number);
76 }
77 },
78 _ => {},
79 }
80 }
81}
82
83#[derive(Debug, PartialEq, Eq, Clone, Copy)]
85pub enum ForkChoiceStrategy {
86 LongestChain,
88 Custom(bool),
90}
91
92#[derive(Debug, PartialEq, Eq, Clone)]
94pub struct BlockCheckParams<Block: BlockT> {
95 pub hash: Block::Hash,
97 pub number: NumberFor<Block>,
99 pub parent_hash: Block::Hash,
101 pub allow_missing_state: bool,
103 pub allow_missing_parent: bool,
105 pub import_existing: bool,
107}
108
109pub enum StorageChanges<Block: BlockT> {
111 Changes(subsoil::state_machine::StorageChanges<HashingFor<Block>>),
113 Import(ImportedState<Block>),
115}
116
117#[derive(PartialEq, Eq, Clone)]
119pub struct ImportedState<B: BlockT> {
120 pub block: B::Hash,
122 pub state: subsoil::state_machine::KeyValueStates,
124}
125
126impl<B: BlockT> std::fmt::Debug for ImportedState<B> {
127 fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
128 fmt.debug_struct("ImportedState").field("block", &self.block).finish()
129 }
130}
131
132pub enum StateAction<Block: BlockT> {
134 ApplyChanges(StorageChanges<Block>),
136 Execute,
138 ExecuteIfPossible,
140 Skip,
142}
143
144impl<Block: BlockT> StateAction<Block> {
145 pub fn skip_execution_checks(&self) -> bool {
147 match self {
148 StateAction::ApplyChanges(_)
149 | StateAction::Execute
150 | StateAction::ExecuteIfPossible => false,
151 StateAction::Skip => true,
152 }
153 }
154}
155
156impl<Block: BlockT> From<StorageChanges<Block>> for StateAction<Block> {
157 fn from(value: StorageChanges<Block>) -> Self {
158 Self::ApplyChanges(value)
159 }
160}
161
162impl<Block: BlockT> From<subsoil::state_machine::StorageChanges<HashingFor<Block>>>
163 for StateAction<Block>
164{
165 fn from(value: subsoil::state_machine::StorageChanges<HashingFor<Block>>) -> Self {
166 Self::ApplyChanges(StorageChanges::Changes(value))
167 }
168}
169
170#[non_exhaustive]
172pub struct BlockImportParams<Block: BlockT> {
173 pub origin: BlockOrigin,
175 pub header: Block::Header,
187 pub justifications: Option<Justifications>,
189 pub post_digests: Vec<DigestItem>,
192 pub body: Option<Vec<Block::Extrinsic>>,
194 pub indexed_body: Option<Vec<Vec<u8>>>,
196 pub state_action: StateAction<Block>,
198 pub finalized: bool,
201 pub intermediates: HashMap<Cow<'static, [u8]>, Box<dyn Any + Send>>,
205 pub auxiliary: Vec<(Vec<u8>, Option<Vec<u8>>)>,
210 pub fork_choice: Option<ForkChoiceStrategy>,
217 pub import_existing: bool,
219 pub create_gap: bool,
221 pub post_hash: Option<Block::Hash>,
223}
224
225impl<Block: BlockT> BlockImportParams<Block> {
226 pub fn new(origin: BlockOrigin, header: Block::Header) -> Self {
228 Self {
229 origin,
230 header,
231 justifications: None,
232 post_digests: Vec::new(),
233 body: None,
234 indexed_body: None,
235 state_action: if origin == BlockOrigin::WarpSync {
237 StateAction::Skip
238 } else {
239 StateAction::Execute
240 },
241 finalized: false,
242 intermediates: HashMap::new(),
243 auxiliary: Vec::new(),
244 fork_choice: None,
245 import_existing: false,
246 create_gap: origin != BlockOrigin::WarpSync,
253 post_hash: None,
254 }
255 }
256
257 pub fn post_hash(&self) -> Block::Hash {
259 if let Some(hash) = self.post_hash {
260 hash
261 } else {
262 self.post_header().hash()
263 }
264 }
265
266 pub fn post_header(&self) -> Block::Header {
268 if self.post_digests.is_empty() {
269 self.header.clone()
270 } else {
271 let mut hdr = self.header.clone();
272 for digest_item in &self.post_digests {
273 hdr.digest_mut().push(digest_item.clone());
274 }
275
276 hdr
277 }
278 }
279
280 pub fn insert_intermediate<T: 'static + Send>(&mut self, key: &'static [u8], value: T) {
282 self.intermediates.insert(Cow::from(key), Box::new(value));
283 }
284
285 pub fn remove_intermediate<T: 'static>(&mut self, key: &[u8]) -> Result<T, Error> {
287 let (k, v) = self.intermediates.remove_entry(key).ok_or(Error::NoIntermediate)?;
288
289 v.downcast::<T>().map(|v| *v).map_err(|v| {
290 self.intermediates.insert(k, v);
291 Error::InvalidIntermediate
292 })
293 }
294
295 pub fn get_intermediate<T: 'static>(&self, key: &[u8]) -> Result<&T, Error> {
297 self.intermediates
298 .get(key)
299 .ok_or(Error::NoIntermediate)?
300 .downcast_ref::<T>()
301 .ok_or(Error::InvalidIntermediate)
302 }
303
304 pub fn get_intermediate_mut<T: 'static>(&mut self, key: &[u8]) -> Result<&mut T, Error> {
306 self.intermediates
307 .get_mut(key)
308 .ok_or(Error::NoIntermediate)?
309 .downcast_mut::<T>()
310 .ok_or(Error::InvalidIntermediate)
311 }
312
313 pub fn with_state(&self) -> bool {
315 matches!(self.state_action, StateAction::ApplyChanges(StorageChanges::Import(_)))
316 }
317}
318
319#[async_trait::async_trait]
321pub trait BlockImport<B: BlockT> {
322 type Error: std::error::Error + Send + 'static;
324
325 async fn check_block(&self, block: BlockCheckParams<B>) -> Result<ImportResult, Self::Error>;
327
328 async fn import_block(&self, block: BlockImportParams<B>) -> Result<ImportResult, Self::Error>;
330}
331
332#[async_trait::async_trait]
333impl<B: BlockT> BlockImport<B> for crate::import::queue::BoxBlockImport<B> {
334 type Error = crate::consensus::error::Error;
335
336 async fn check_block(&self, block: BlockCheckParams<B>) -> Result<ImportResult, Self::Error> {
338 (**self).check_block(block).await
339 }
340
341 async fn import_block(&self, block: BlockImportParams<B>) -> Result<ImportResult, Self::Error> {
343 (**self).import_block(block).await
344 }
345}
346
347#[async_trait::async_trait]
348impl<B: BlockT, T, E: std::error::Error + Send + 'static> BlockImport<B> for Arc<T>
349where
350 for<'r> &'r T: BlockImport<B, Error = E>,
351 T: Send + Sync,
352{
353 type Error = E;
354
355 async fn check_block(&self, block: BlockCheckParams<B>) -> Result<ImportResult, Self::Error> {
356 (&**self).check_block(block).await
357 }
358
359 async fn import_block(&self, block: BlockImportParams<B>) -> Result<ImportResult, Self::Error> {
360 (&**self).import_block(block).await
361 }
362}
363
364#[async_trait::async_trait]
366pub trait JustificationImport<B: BlockT> {
367 type Error: std::error::Error + Send + 'static;
368
369 async fn on_start(&mut self) -> Vec<(B::Hash, NumberFor<B>)>;
372
373 async fn import_justification(
375 &mut self,
376 hash: B::Hash,
377 number: NumberFor<B>,
378 justification: Justification,
379 ) -> Result<(), Self::Error>;
380}
381
382pub trait JustificationSyncLink<B: BlockT>: Send + Sync {
388 fn request_justification(&self, hash: &B::Hash, number: NumberFor<B>);
390
391 fn clear_justification_requests(&self);
393}
394
395impl<B: BlockT> JustificationSyncLink<B> for () {
396 fn request_justification(&self, _hash: &B::Hash, _number: NumberFor<B>) {}
397
398 fn clear_justification_requests(&self) {}
399}
400
401impl<B: BlockT, L: JustificationSyncLink<B>> JustificationSyncLink<B> for Arc<L> {
402 fn request_justification(&self, hash: &B::Hash, number: NumberFor<B>) {
403 L::request_justification(self, hash, number);
404 }
405
406 fn clear_justification_requests(&self) {
407 L::clear_justification_requests(self);
408 }
409}