1#![cfg_attr(not(feature = "std"), no_std)]
8
9#[cfg(doc)]
73#[cfg_attr(doc, aquamarine::aquamarine)]
74pub mod block_flowchart {}
101
102#[cfg(test)]
103mod tests;
104
105extern crate alloc;
106
107use codec::{Codec, Encode};
108use core::marker::PhantomData;
109use subsoil::runtime::{
110 generic::Digest,
111 traits::{
112 self, Applyable, CheckEqual, Checkable, Dispatchable, Header, LazyBlock, NumberFor, One,
113 ValidateUnsigned, Zero,
114 },
115 transaction_validity::{TransactionSource, TransactionValidity, TransactionValidityError},
116 ApplyExtrinsicResult, ExtrinsicInclusionMode,
117};
118use topsoil_core::{
119 defensive_assert,
120 dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo, PostDispatchInfo},
121 migrations::MultiStepMigrator,
122 pallet_prelude::InvalidTransaction,
123 traits::{
124 BeforeAllRuntimeMigrations, ExecuteBlock, Get, IsInherent, OffchainWorker, OnFinalize,
125 OnIdle, OnInitialize, OnPoll, OnRuntimeUpgrade, PostInherents, PostTransactions,
126 PreInherents,
127 },
128 weights::{Weight, WeightMeter},
129 MAX_EXTRINSIC_DEPTH,
130};
131use topsoil_core::system::pallet_prelude::BlockNumberFor;
132
133#[cfg(feature = "try-runtime")]
134use ::{
135 log,
136 subsoil::runtime::TryRuntimeError,
137 topsoil_core::{
138 traits::{TryDecodeEntireStorage, TryDecodeEntireStorageError, TryState},
139 StorageNoopGuard,
140 },
141 topsoil_try_runtime::{TryStateSelect, UpgradeCheckSelect},
142};
143
144#[allow(dead_code)]
145const LOG_TARGET: &str = "runtime::executive";
146
147pub type CheckedOf<E, C> = <E as Checkable<C>>::Checked;
148pub type CallOf<E, C> = <CheckedOf<E, C> as Applyable>::Call;
149pub type OriginOf<E, C> = <CallOf<E, C> as Dispatchable>::RuntimeOrigin;
150
151#[cfg(feature = "try-runtime")]
153#[derive(Debug, Clone)]
154pub struct TryRuntimeUpgradeConfig {
155 pub checks: UpgradeCheckSelect,
157 pub try_state_select: TryStateSelect,
159}
160
161#[cfg(feature = "try-runtime")]
162impl TryRuntimeUpgradeConfig {
163 pub fn new(checks: UpgradeCheckSelect) -> Self {
165 Self { checks, try_state_select: TryStateSelect::All }
166 }
167
168 pub fn with_try_state_select(mut self, try_state_select: TryStateSelect) -> Self {
170 self.try_state_select = try_state_select;
171 self
172 }
173}
174
175#[derive(PartialEq)]
176pub enum ExecutiveError {
177 UnableToDecodeExtrinsic,
178 InvalidInherentPosition(usize),
179 OnlyInherentsAllowed,
180 ApplyExtrinsic(TransactionValidityError),
181 Custom(&'static str),
182}
183
184impl core::fmt::Debug for ExecutiveError {
185 fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
186 match self {
187 ExecutiveError::UnableToDecodeExtrinsic => {
188 write!(fmt, "The extrinsic could not be decoded correctly")
189 },
190 ExecutiveError::InvalidInherentPosition(i) => {
191 write!(fmt, "Invalid inherent position for extrinsic at index {}", i)
192 },
193 ExecutiveError::OnlyInherentsAllowed => {
194 write!(fmt, "Only inherents are allowed in this block")
195 },
196 ExecutiveError::ApplyExtrinsic(e) => write!(
197 fmt,
198 "ExecuteBlockError applying extrinsic: {}",
199 Into::<&'static str>::into(*e)
200 ),
201 ExecutiveError::Custom(err) => write!(fmt, "{err}"),
202 }
203 }
204}
205
206#[allow(deprecated)]
218pub struct Executive<
219 System,
220 Block,
221 Context,
222 UnsignedValidator,
223 AllPalletsWithSystem,
224 OnRuntimeUpgrade = (),
225>(
226 PhantomData<(
227 System,
228 Block,
229 Context,
230 UnsignedValidator,
231 AllPalletsWithSystem,
232 OnRuntimeUpgrade,
233 )>,
234);
235
236#[allow(deprecated)]
240impl<
241 System: topsoil_core::system::Config + IsInherent<Block::Extrinsic>,
242 Block: traits::Block<
243 Header = topsoil_core::system::pallet_prelude::HeaderFor<System>,
244 Hash = System::Hash,
245 >,
246 Context: Default,
247 UnsignedValidator,
248 AllPalletsWithSystem: OnRuntimeUpgrade
249 + BeforeAllRuntimeMigrations
250 + OnInitializeWithWeightRegistration<System>
251 + OnIdle<BlockNumberFor<System>>
252 + OnFinalize<BlockNumberFor<System>>
253 + OffchainWorker<BlockNumberFor<System>>
254 + OnPoll<BlockNumberFor<System>>,
255 COnRuntimeUpgrade: OnRuntimeUpgrade,
256 > ExecuteBlock<Block>
257 for Executive<System, Block, Context, UnsignedValidator, AllPalletsWithSystem, COnRuntimeUpgrade>
258where
259 Block::Extrinsic: Checkable<Context> + Codec,
260 CheckedOf<Block::Extrinsic, Context>: Applyable + GetDispatchInfo,
261 CallOf<Block::Extrinsic, Context>:
262 Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,
263 OriginOf<Block::Extrinsic, Context>: From<Option<System::AccountId>>,
264 UnsignedValidator: ValidateUnsigned<Call = CallOf<Block::Extrinsic, Context>>,
265{
266 fn verify_and_remove_seal(_: &mut <Block as traits::Block>::LazyBlock) {
267 }
269
270 fn execute_verified_block(block: Block::LazyBlock) {
271 Executive::<
272 System,
273 Block,
274 Context,
275 UnsignedValidator,
276 AllPalletsWithSystem,
277 COnRuntimeUpgrade,
278 >::execute_block(block);
279 }
280}
281
282#[allow(deprecated)]
286#[cfg(feature = "try-runtime")]
287impl<
288 System: topsoil_core::system::Config + IsInherent<Block::Extrinsic>,
289 Block: traits::Block<
290 Header = topsoil_core::system::pallet_prelude::HeaderFor<System>,
291 Hash = System::Hash,
292 >,
293 Context: Default,
294 UnsignedValidator,
295 AllPalletsWithSystem: OnRuntimeUpgrade
296 + BeforeAllRuntimeMigrations
297 + OnInitializeWithWeightRegistration<System>
298 + OnIdle<BlockNumberFor<System>>
299 + OnFinalize<BlockNumberFor<System>>
300 + OffchainWorker<BlockNumberFor<System>>
301 + OnPoll<BlockNumberFor<System>>
302 + TryState<BlockNumberFor<System>>
303 + TryDecodeEntireStorage,
304 COnRuntimeUpgrade: OnRuntimeUpgrade,
305 > Executive<System, Block, Context, UnsignedValidator, AllPalletsWithSystem, COnRuntimeUpgrade>
306where
307 Block::Extrinsic: Checkable<Context> + Codec,
308 CheckedOf<Block::Extrinsic, Context>: Applyable + GetDispatchInfo,
309 CallOf<Block::Extrinsic, Context>:
310 Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,
311 OriginOf<Block::Extrinsic, Context>: From<Option<System::AccountId>>,
312 UnsignedValidator: ValidateUnsigned<Call = CallOf<Block::Extrinsic, Context>>,
313{
314 pub fn try_execute_block(
323 block: Block::LazyBlock,
324 state_root_check: bool,
325 signature_check: bool,
326 select: topsoil_try_runtime::TryStateSelect,
327 ) -> Result<Weight, ExecutiveError> {
328 log::info!(
329 target: LOG_TARGET,
330 "try-runtime: executing block #{:?} / state root check: {:?} / signature check: {:?} / try-state-select: {:?}",
331 block.header().number(),
332 state_root_check,
333 signature_check,
334 select,
335 );
336
337 let mode = Self::initialize_block(block.header());
338 Self::initial_checks(block.header());
339
340 let signature_check = if signature_check {
342 Block::Extrinsic::check
343 } else {
344 Block::Extrinsic::unchecked_into_checked_i_know_what_i_am_doing
345 };
346 Self::apply_extrinsics(mode, block.extrinsics(), |uxt, is_inherent| {
347 Self::do_apply_extrinsic(uxt, is_inherent, signature_check)
348 })?;
349
350 if !<topsoil_core::system::Pallet<System>>::inherents_applied() {
352 Self::inherents_applied();
353 }
354
355 <topsoil_core::system::Pallet<System>>::note_finished_extrinsics();
357 <System as topsoil_core::system::Config>::PostTransactions::post_transactions();
358
359 let header = block.header();
360 Self::on_idle_hook(*header.number());
361 Self::on_finalize_hook(*header.number());
362
363 let _guard = topsoil_core::StorageNoopGuard::default();
365 <AllPalletsWithSystem as topsoil_core::traits::TryState<
366 BlockNumberFor<System>,
367 >>::try_state(*header.number(), select.clone())
368 .map_err(|e| {
369 log::error!(target: LOG_TARGET, "failure: {:?}", e);
370 ExecutiveError::Custom(e.into())
371 })?;
372 if select.any() {
373 let res = AllPalletsWithSystem::try_decode_entire_state();
374 Self::log_decode_result(res).map_err(|e| ExecutiveError::Custom(e.into()))?;
375 }
376 drop(_guard);
377
378 {
381 let new_header = <topsoil_core::system::Pallet<System>>::finalize();
382 let items_zip = header.digest().logs().iter().zip(new_header.digest().logs().iter());
383 for (header_item, computed_item) in items_zip {
384 header_item.check_equal(computed_item);
385 assert!(header_item == computed_item, "Digest item must match that calculated.");
386 }
387
388 if state_root_check {
389 let storage_root = new_header.state_root();
390 header.state_root().check_equal(storage_root);
391 assert!(
392 header.state_root() == storage_root,
393 "Storage root must match that calculated."
394 );
395 }
396
397 assert!(
398 header.extrinsics_root() == new_header.extrinsics_root(),
399 "Transaction trie root must be valid.",
400 );
401 }
402
403 log::info!(
404 target: LOG_TARGET,
405 "try-runtime: Block #{:?} successfully executed",
406 header.number(),
407 );
408
409 Ok(topsoil_core::system::Pallet::<System>::block_weight().total())
410 }
411
412 pub fn try_runtime_upgrade(checks: UpgradeCheckSelect) -> Result<Weight, TryRuntimeError> {
424 Self::try_runtime_upgrade_with_config(TryRuntimeUpgradeConfig::new(checks))
425 }
426
427 pub fn try_runtime_upgrade_with_config(
437 config: TryRuntimeUpgradeConfig,
438 ) -> Result<Weight, TryRuntimeError> {
439 let checks = config.checks;
440 let try_state_select = config.try_state_select;
441 let before_all_weight =
442 <AllPalletsWithSystem as BeforeAllRuntimeMigrations>::before_all_runtime_migrations();
443
444 let try_on_runtime_upgrade_weight =
445 <(
446 COnRuntimeUpgrade,
447 <System as topsoil_core::system::Config>::SingleBlockMigrations,
448 AllPalletsWithSystem,
451 ) as OnRuntimeUpgrade>::try_on_runtime_upgrade(checks.pre_and_post())?;
452
453 topsoil_core::system::LastRuntimeUpgrade::<System>::put(
454 topsoil_core::system::LastRuntimeUpgradeInfo::from(
455 <System::Version as topsoil_core::traits::Get<_>>::get(),
456 ),
457 );
458
459 let _guard = StorageNoopGuard::default();
461
462 if checks.any() {
464 let res = AllPalletsWithSystem::try_decode_entire_state();
465 Self::log_decode_result(res)?;
466 }
467
468 if checks.try_state() {
470 AllPalletsWithSystem::try_state(
471 topsoil_core::system::Pallet::<System>::block_number(),
472 try_state_select,
473 )?;
474 }
475
476 Ok(before_all_weight.saturating_add(try_on_runtime_upgrade_weight))
477 }
478
479 fn log_decode_result(
481 res: Result<usize, alloc::vec::Vec<TryDecodeEntireStorageError>>,
482 ) -> Result<(), TryRuntimeError> {
483 match res {
484 Ok(bytes) => {
485 log::info!(
486 target: LOG_TARGET,
487 "✅ Entire runtime state decodes without error. {} bytes total.",
488 bytes
489 );
490
491 Ok(())
492 },
493 Err(errors) => {
494 log::error!(
495 target: LOG_TARGET,
496 "`try_decode_entire_state` failed with {} errors",
497 errors.len(),
498 );
499
500 for (i, err) in errors.iter().enumerate() {
501 log::error!(target: LOG_TARGET, "- {i}. error: {err}");
503 log::debug!(target: LOG_TARGET, "- {i}. error: {err:?}");
504 }
505
506 Err("`try_decode_entire_state` failed".into())
507 },
508 }
509 }
510}
511
512pub trait OnInitializeWithWeightRegistration<T: topsoil_core::system::Config> {
519 fn on_initialize_with_weight_registration(_n: BlockNumberFor<T>) -> Weight;
521}
522
523topsoil_core::impl_for_tuples_attr! {
524 #[tuple_types_custom_trait_bound(OnInitialize<topsoil_core::system::pallet_prelude::BlockNumberFor<T>>)]
525 impl<T: topsoil_core::system::Config> OnInitializeWithWeightRegistration<T> for Tuple {
526 fn on_initialize_with_weight_registration(n: BlockNumberFor<T>) -> Weight {
527 let mut weight = Weight::zero();
528 for_tuples!( #(
529 let individual_weight = Tuple::on_initialize(n);
530
531 <topsoil_core::system::Pallet<T>>::register_extra_weight_unchecked(
532 individual_weight,
533 DispatchClass::Mandatory,
534 );
535
536 weight = weight.saturating_add(individual_weight);
537 )* );
538
539 weight
540 }
541 }
542}
543
544#[allow(deprecated)]
548impl<
549 System: topsoil_core::system::Config + IsInherent<Block::Extrinsic>,
550 Block: traits::Block<
551 Header = topsoil_core::system::pallet_prelude::HeaderFor<System>,
552 Hash = System::Hash,
553 >,
554 Context: Default,
555 UnsignedValidator,
556 AllPalletsWithSystem: OnRuntimeUpgrade
557 + BeforeAllRuntimeMigrations
558 + OnInitializeWithWeightRegistration<System>
559 + OnIdle<BlockNumberFor<System>>
560 + OnFinalize<BlockNumberFor<System>>
561 + OffchainWorker<BlockNumberFor<System>>
562 + OnPoll<BlockNumberFor<System>>,
563 COnRuntimeUpgrade: OnRuntimeUpgrade,
564 > Executive<System, Block, Context, UnsignedValidator, AllPalletsWithSystem, COnRuntimeUpgrade>
565where
566 Block::Extrinsic: Checkable<Context> + Codec,
567 CheckedOf<Block::Extrinsic, Context>: Applyable + GetDispatchInfo,
568 CallOf<Block::Extrinsic, Context>:
569 Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,
570 OriginOf<Block::Extrinsic, Context>: From<Option<System::AccountId>>,
571 UnsignedValidator: ValidateUnsigned<Call = CallOf<Block::Extrinsic, Context>>,
572{
573 pub fn execute_on_runtime_upgrade() -> Weight {
575 let before_all_weight =
576 <AllPalletsWithSystem as BeforeAllRuntimeMigrations>::before_all_runtime_migrations();
577
578 let runtime_upgrade_weight = <(
579 COnRuntimeUpgrade,
580 <System as topsoil_core::system::Config>::SingleBlockMigrations,
581 AllPalletsWithSystem,
584 ) as OnRuntimeUpgrade>::on_runtime_upgrade();
585
586 before_all_weight.saturating_add(runtime_upgrade_weight)
587 }
588
589 pub fn initialize_block(
591 header: &topsoil_core::system::pallet_prelude::HeaderFor<System>,
592 ) -> ExtrinsicInclusionMode {
593 subsoil::io::init_tracing();
594 subsoil::enter_span!(subsoil::tracing::Level::TRACE, "init_block");
595 let digests = Self::extract_pre_digest(header);
596 Self::initialize_block_impl(header.number(), header.parent_hash(), &digests);
597
598 Self::extrinsic_mode()
599 }
600
601 fn extrinsic_mode() -> ExtrinsicInclusionMode {
602 if <System as topsoil_core::system::Config>::MultiBlockMigrator::ongoing() {
603 ExtrinsicInclusionMode::OnlyInherents
604 } else {
605 ExtrinsicInclusionMode::AllExtrinsics
606 }
607 }
608
609 fn extract_pre_digest(header: &topsoil_core::system::pallet_prelude::HeaderFor<System>) -> Digest {
610 let mut digest = <Digest>::default();
611 header.digest().logs().iter().for_each(|d| {
612 if d.as_pre_runtime().is_some() {
613 digest.push(d.clone())
614 }
615 });
616 digest
617 }
618
619 fn initialize_block_impl(
620 block_number: &BlockNumberFor<System>,
621 parent_hash: &System::Hash,
622 digest: &Digest,
623 ) {
624 <topsoil_core::system::Pallet<System>>::reset_events();
628
629 let mut weight = Weight::zero();
630 if Self::runtime_upgraded() {
631 weight = weight.saturating_add(Self::execute_on_runtime_upgrade());
632
633 topsoil_core::system::LastRuntimeUpgrade::<System>::put(
634 topsoil_core::system::LastRuntimeUpgradeInfo::from(
635 <System::Version as topsoil_core::traits::Get<_>>::get(),
636 ),
637 );
638 }
639 <topsoil_core::system::Pallet<System>>::initialize(block_number, parent_hash, digest);
640
641 weight = System::BlockWeights::get().base_block.saturating_add(weight);
642 <topsoil_core::system::Pallet<System>>::register_extra_weight_unchecked(
644 weight,
645 DispatchClass::Mandatory,
646 );
647
648 weight = weight
649 .saturating_add(<AllPalletsWithSystem as OnInitializeWithWeightRegistration<
650 System,
651 >>::on_initialize_with_weight_registration(*block_number));
652
653 log::debug!(
654 target: LOG_TARGET,
655 "[{block_number:?}]: Block initialization weight consumption: {weight:?}",
656 );
657
658 topsoil_core::system::Pallet::<System>::note_finished_initialize();
659 <System as topsoil_core::system::Config>::PreInherents::pre_inherents();
660 }
661
662 fn runtime_upgraded() -> bool {
664 let last = topsoil_core::system::LastRuntimeUpgrade::<System>::get();
665 let current = <System::Version as topsoil_core::traits::Get<_>>::get();
666
667 last.map(|v| v.was_upgraded(¤t)).unwrap_or(true)
668 }
669
670 fn initial_checks(header: &Block::Header) {
671 subsoil::enter_span!(subsoil::tracing::Level::TRACE, "initial_checks");
672
673 let n = *header.number();
675 assert!(
676 n > BlockNumberFor::<System>::zero()
677 && <topsoil_core::system::Pallet<System>>::block_hash(
678 n - BlockNumberFor::<System>::one()
679 ) == *header.parent_hash(),
680 "Parent hash should be valid.",
681 );
682 }
683
684 pub fn execute_block(block: Block::LazyBlock) {
686 subsoil::io::init_tracing();
687 subsoil::within_span! {
688 subsoil::tracing::info_span!("execute_block", ?block);
689 let mode = Self::initialize_block(block.header());
691 Self::initial_checks(block.header());
692
693 let extrinsics = block.extrinsics();
694 if let Err(e) = Self::apply_extrinsics(
695 mode,
696 extrinsics,
697 |uxt, is_inherent| {
698 Self::do_apply_extrinsic(uxt, is_inherent, Block::Extrinsic::check)
699 }
700 ) {
701 panic!("{:?}", e)
702 }
703
704 if !<topsoil_core::system::Pallet<System>>::inherents_applied() {
706 Self::inherents_applied();
707 }
708
709 <topsoil_core::system::Pallet<System>>::note_finished_extrinsics();
710 <System as topsoil_core::system::Config>::PostTransactions::post_transactions();
711
712 let header = block.header();
713 Self::on_idle_hook(*header.number());
714 Self::on_finalize_hook(*header.number());
715 Self::final_checks(&header);
716 }
717 }
718
719 pub fn inherents_applied() {
723 <topsoil_core::system::Pallet<System>>::note_inherents_applied();
724 <System as topsoil_core::system::Config>::PostInherents::post_inherents();
725
726 if <System as topsoil_core::system::Config>::MultiBlockMigrator::ongoing() {
727 let used_weight = <System as topsoil_core::system::Config>::MultiBlockMigrator::step();
728 <topsoil_core::system::Pallet<System>>::register_extra_weight_unchecked(
729 used_weight,
730 DispatchClass::Mandatory,
731 );
732 } else {
733 let block_number = <topsoil_core::system::Pallet<System>>::block_number();
734 Self::on_poll_hook(block_number);
735 }
736 }
737
738 fn apply_extrinsics(
740 mode: ExtrinsicInclusionMode,
741 extrinsics: impl Iterator<Item = Result<Block::Extrinsic, codec::Error>>,
742 mut apply_extrinsic: impl FnMut(Block::Extrinsic, bool) -> ApplyExtrinsicResult,
743 ) -> Result<(), ExecutiveError> {
744 let mut first_non_inherent_idx = 0;
745 for (idx, maybe_uxt) in extrinsics.into_iter().enumerate() {
746 let uxt = maybe_uxt.map_err(|_| ExecutiveError::UnableToDecodeExtrinsic)?;
747 let is_inherent = System::is_inherent(&uxt);
748 if is_inherent {
749 if first_non_inherent_idx != idx {
751 return Err(ExecutiveError::InvalidInherentPosition(idx));
752 }
753 first_non_inherent_idx += 1;
754 } else {
755 if mode == ExtrinsicInclusionMode::OnlyInherents {
757 return Err(ExecutiveError::OnlyInherentsAllowed);
758 }
759 }
760
761 log::debug!(target: LOG_TARGET, "Executing transaction: {:?}", uxt);
762 if let Err(e) = apply_extrinsic(uxt, is_inherent) {
763 log::error!(
764 target: LOG_TARGET,
765 "Transaction({idx}) failed due to {e:?}. \
766 Aborting the rest of the block execution.",
767 );
768 return Err(ExecutiveError::ApplyExtrinsic(e.into()));
769 }
770 }
771
772 Ok(())
773 }
774
775 pub fn finalize_block() -> topsoil_core::system::pallet_prelude::HeaderFor<System> {
779 subsoil::io::init_tracing();
780 subsoil::enter_span!(subsoil::tracing::Level::TRACE, "finalize_block");
781
782 if !<topsoil_core::system::Pallet<System>>::inherents_applied() {
784 Self::inherents_applied();
785 }
786
787 <topsoil_core::system::Pallet<System>>::note_finished_extrinsics();
788 <System as topsoil_core::system::Config>::PostTransactions::post_transactions();
789 let block_number = <topsoil_core::system::Pallet<System>>::block_number();
790 Self::on_idle_hook(block_number);
791 Self::on_finalize_hook(block_number);
792 <topsoil_core::system::Pallet<System>>::finalize()
793 }
794
795 fn on_idle_hook(block_number: NumberFor<Block>) {
798 if <System as topsoil_core::system::Config>::MultiBlockMigrator::ongoing() {
799 return;
800 }
801
802 let weight = <topsoil_core::system::Pallet<System>>::block_weight();
803 let max_weight = <System::BlockWeights as topsoil_core::traits::Get<_>>::get().max_block;
804 let remaining_weight = max_weight.saturating_sub(weight.total());
805
806 if remaining_weight.all_gt(Weight::zero()) {
807 let used_weight = <AllPalletsWithSystem as OnIdle<BlockNumberFor<System>>>::on_idle(
808 block_number,
809 remaining_weight,
810 );
811 <topsoil_core::system::Pallet<System>>::register_extra_weight_unchecked(
812 used_weight,
813 DispatchClass::Mandatory,
814 );
815 }
816 }
817
818 fn on_poll_hook(block_number: NumberFor<Block>) {
819 defensive_assert!(
820 !<System as topsoil_core::system::Config>::MultiBlockMigrator::ongoing(),
821 "on_poll should not be called during migrations"
822 );
823
824 let weight = <topsoil_core::system::Pallet<System>>::block_weight();
825 let max_weight = <System::BlockWeights as topsoil_core::traits::Get<_>>::get().max_block;
826 let remaining = max_weight.saturating_sub(weight.total());
827
828 if remaining.all_gt(Weight::zero()) {
829 let mut meter = WeightMeter::with_limit(remaining);
830 <AllPalletsWithSystem as OnPoll<BlockNumberFor<System>>>::on_poll(
831 block_number,
832 &mut meter,
833 );
834 <topsoil_core::system::Pallet<System>>::register_extra_weight_unchecked(
835 meter.consumed(),
836 DispatchClass::Mandatory,
837 );
838 }
839 }
840
841 fn on_finalize_hook(block_number: NumberFor<Block>) {
843 <AllPalletsWithSystem as OnFinalize<BlockNumberFor<System>>>::on_finalize(block_number);
844 }
845
846 fn do_apply_extrinsic(
851 uxt: Block::Extrinsic,
852 is_inherent: bool,
853 check: impl FnOnce(
854 Block::Extrinsic,
855 &Context,
856 ) -> Result<CheckedOf<Block::Extrinsic, Context>, TransactionValidityError>,
857 ) -> ApplyExtrinsicResult {
858 subsoil::io::init_tracing();
859 let encoded = uxt.encode();
860 let encoded_len = encoded.len();
861 subsoil::enter_span!(subsoil::tracing::info_span!("apply_extrinsic",
862 ext=?subsoil::core::hexdisplay::HexDisplay::from(&encoded)));
863
864 let uxt = <Block::Extrinsic as codec::DecodeLimit>::decode_all_with_depth_limit(
865 MAX_EXTRINSIC_DEPTH,
866 &mut &encoded[..],
867 )
868 .map_err(|_| InvalidTransaction::Call)?;
869
870 let xt = check(uxt, &Context::default())?;
872
873 let dispatch_info = xt.get_dispatch_info();
874
875 if !is_inherent && !<topsoil_core::system::Pallet<System>>::inherents_applied() {
876 Self::inherents_applied();
877 }
878
879 <topsoil_core::system::Pallet<System>>::note_extrinsic(encoded);
883
884 let r = Applyable::apply::<UnsignedValidator>(xt, &dispatch_info, encoded_len)?;
887
888 if r.is_err() && dispatch_info.class == DispatchClass::Mandatory {
893 return Err(InvalidTransaction::BadMandatory.into());
894 }
895
896 <topsoil_core::system::Pallet<System>>::note_applied_extrinsic(&r, dispatch_info);
897
898 Ok(r.map(|_| ()).map_err(|e| e.error))
899 }
900
901 pub fn apply_extrinsic(uxt: Block::Extrinsic) -> ApplyExtrinsicResult {
906 let is_inherent = System::is_inherent(&uxt);
907 Self::do_apply_extrinsic(uxt, is_inherent, Block::Extrinsic::check)
908 }
909
910 fn final_checks(header: &topsoil_core::system::pallet_prelude::HeaderFor<System>) {
911 subsoil::enter_span!(subsoil::tracing::Level::TRACE, "final_checks");
912 let new_header = <topsoil_core::system::Pallet<System>>::finalize();
914
915 assert_eq!(
917 header.digest().logs().len(),
918 new_header.digest().logs().len(),
919 "Number of digest items must match that calculated."
920 );
921 let items_zip = header.digest().logs().iter().zip(new_header.digest().logs().iter());
922 for (header_item, computed_item) in items_zip {
923 header_item.check_equal(computed_item);
924 assert!(header_item == computed_item, "Digest item must match that calculated.");
925 }
926
927 let storage_root = new_header.state_root();
929 header.state_root().check_equal(storage_root);
930 assert!(header.state_root() == storage_root, "Storage root must match that calculated.");
931
932 assert!(
933 header.extrinsics_root() == new_header.extrinsics_root(),
934 "Transaction trie root must be valid.",
935 );
936 }
937
938 pub fn validate_transaction(
944 source: TransactionSource,
945 uxt: Block::Extrinsic,
946 block_hash: Block::Hash,
947 ) -> TransactionValidity {
948 subsoil::io::init_tracing();
949 use subsoil::{enter_span, within_span};
950
951 <topsoil_core::system::Pallet<System>>::initialize(
952 &(topsoil_core::system::Pallet::<System>::block_number() + One::one()),
953 &block_hash,
954 &Default::default(),
955 );
956
957 enter_span! { subsoil::tracing::Level::TRACE, "validate_transaction" };
958
959 let encoded = within_span! { subsoil::tracing::Level::TRACE, "using_encoded";
960 uxt.encode()
961 };
962
963 let uxt = <Block::Extrinsic as codec::DecodeLimit>::decode_all_with_depth_limit(
964 MAX_EXTRINSIC_DEPTH,
965 &mut &encoded[..],
966 )
967 .map_err(|_| InvalidTransaction::Call)?;
968
969 let xt = within_span! { subsoil::tracing::Level::TRACE, "check";
970 uxt.check(&Default::default())
971 }?;
972
973 let dispatch_info = within_span! { subsoil::tracing::Level::TRACE, "dispatch_info";
974 xt.get_dispatch_info()
975 };
976
977 if dispatch_info.class == DispatchClass::Mandatory {
978 return Err(InvalidTransaction::MandatoryValidation.into());
979 }
980
981 within_span! {
982 subsoil::tracing::Level::TRACE, "validate";
983 xt.validate::<UnsignedValidator>(source, &dispatch_info, encoded.len())
984 }
985 }
986
987 pub fn offchain_worker(header: &topsoil_core::system::pallet_prelude::HeaderFor<System>) {
989 subsoil::io::init_tracing();
990 let digests = header.digest().clone();
994
995 let existing_digest = topsoil_core::system::Pallet::<System>::digest();
997 for digest in digests.logs().iter().filter(|d| !existing_digest.logs.contains(d)) {
998 topsoil_core::system::Pallet::<System>::deposit_log(digest.clone());
999 }
1000
1001 topsoil_core::system::Pallet::<System>::initialize_intra_block_entropy(header.parent_hash());
1003
1004 topsoil_core::system::BlockHash::<System>::insert(header.number(), header.hash());
1008
1009 <AllPalletsWithSystem as OffchainWorker<BlockNumberFor<System>>>::offchain_worker(
1010 *header.number(),
1011 )
1012 }
1013}